diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b26ab6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.pdb diff --git a/CMakeLists.txt b/CMakeLists.txt index 793b15c..87bf8da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +set(root_folder ${CMAKE_CURRENT_LIST_DIR}) + add_subdirectory(thirdparty) add_subdirectory(sources) diff --git a/README.md b/README.md index 22dcdbb..5c40a76 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ So now it is time for that hidden project to emerge on a surface. Releasing it a #### Project milestones: Order is a subject to change, but here are main things to do: -- [ ] boilerplate code for window, input handling, etc; -- [ ] basic boilerplate code for ray-tracing; -- [ ] simplest CPU path-tracer; +- [x] boilerplate code for window, input handling, etc; +- [x] basic boilerplate code for ray-tracing; +- [x] simplest CPU path-tracer; - [ ] OptiX and GPU-related code basics; -- [ ] additional code for ray-tracing; +- [x] additional code for ray-tracing; - [ ] VCM integrators (CPU and GPU); - [ ] cross-platform, cross-API support; ... maintaining code, adding new features. @@ -58,8 +58,10 @@ Order is a subject to change, but here are main things to do: This part of the description would be updated during the development of the project, at the moment there is nothing to build here. All updates will be located here: [BUILDING.md](docs/BUILDING.md) -#### Docs -[Code style](docs/CODESTYLE.md) - code style may confuse you. But there is an explanation for that :) +#### Sponsors +This project is GitHub-sponsored by: +* [Traverse-Research](https://github.com/Traverse-Research) +* [voxel-tracer](https://github.com/voxel-tracer) #### Links Links to the books/papers/publications/resources I've used during the development: diff --git a/bin/assets/cornellbox/cornellbox.json b/bin/assets/cornellbox/cornellbox.json new file mode 100644 index 0000000..e3d6e4d --- /dev/null +++ b/bin/assets/cornellbox/cornellbox.json @@ -0,0 +1,12 @@ +{ + "geometry" : "cornellbox.obj", + "camera" : { + "viewport" : [640.0, 640.0], + "origin" : [0.0, 1.0, 5.15], + "target" : [0.0, 1.0, 0.0], + "up" : [0.0, 1.0, 0.0], + "fov" : 26.99, + "lens-radius" : 0.25, + "focal-distance" : 4.6 + } +} diff --git a/bin/assets/cornellbox/cornellbox.mtl b/bin/assets/cornellbox/cornellbox.mtl new file mode 100644 index 0000000..a0ef786 --- /dev/null +++ b/bin/assets/cornellbox/cornellbox.mtl @@ -0,0 +1,36 @@ +newmtl et::medium +sigma_a 0.01 0.01 0.01 +sigma_s 0.075 0.075 0.075 +g 0.75 + +newmtl white + Kd 1.0 1.0 1.0 + +newmtl leftWall + Kd 1.0 0.0 0.0 + +newmtl rightWall + Kd 0.0 1.0 0.0 + +newmtl floor + Kd 1.0 1.0 1.0 + +newmtl ceiling + Kd 1.0 1.0 1.0 + +newmtl frontWall + Kd 1.0 1.0 1.0 + +newmtl shortBox + Kd 1.0 1.0 1.0 + Ks 1.0 1.0 1.0 + Kt 1.0 1.0 1.0 + +newmtl tallBox + Kd 1.0 1.0 1.0 + Ks 1.0 1.0 1.0 + Kt 1.0 1.0 1.0 + +newmtl light + Kd 1.0 1.0 1.0 + Ke 4 4 4 diff --git a/bin/assets/cornellbox/cornellbox.obj b/bin/assets/cornellbox/cornellbox.obj new file mode 100644 index 0000000..d98b3c5 --- /dev/null +++ b/bin/assets/cornellbox/cornellbox.obj @@ -0,0 +1,289 @@ +# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware +# File Created: 22.11.2016 00:04:47 + +mtllib cornellbox.mtl + +# +# object ceiling_Mesh +# + +v -1.00000 2.00000 -1.00000 +v 1.00000 2.00000 -1.00000 +v 1.00000 2.00000 1.00000 +v -1.00000 2.00000 1.00000 +# 4 vertices + +vn 0.00000 -1.00000 -0.00000 +# 1 vertex normals + +vt 0.32937 0.33809 0.00000 +vt 0.65319 0.33809 0.00000 +vt 0.65319 0.66191 0.00000 +vt 0.32937 0.66191 0.00000 +# 4 texture coords + +g ceiling_Mesh +usemtl ceiling +s 1 +f 1/1/1 2/2/1 3/3/1 +f 3/3/1 4/4/1 1/1/1 +# 2 faces + +# +# object floor_Mesh +# + +v 1.00000 0.00000 1.00000 +v 1.00000 0.00000 -1.00000 +v -1.00000 0.00000 -1.00000 +v -1.00000 0.00000 1.00000 +# 4 vertices + +vn 0.00000 1.00000 -0.00000 +# 1 vertex normals + +vt 0.98133 0.33809 0.00000 +vt 0.98133 0.66191 0.00000 +vt 0.65751 0.66191 0.00000 +vt 0.65751 0.33809 0.00000 +# 4 texture coords + +g floor_Mesh +usemtl floor +s 1 +f 5/5/2 6/6/2 7/7/2 +f 7/7/2 8/8/2 5/5/2 +# 2 faces + +# +# object frontWall_Mesh +# + +v 1.00000 0.00000 -1.00000 +v 1.00000 2.00000 -1.00000 +v -1.00000 2.00000 -1.00000 +v -1.00000 0.00000 -1.00000 +# 4 vertices + +vn 0.00000 0.00000 1.00000 +# 1 vertex normals + +vt 0.65319 0.66623 0.00000 +vt 0.65319 0.99005 0.00000 +vt 0.32937 0.99005 0.00000 +vt 0.32937 0.66623 0.00000 +# 4 texture coords + +g frontWall_Mesh +usemtl frontWall +s 1 +f 9/9/3 10/10/3 11/11/3 +f 11/11/3 12/12/3 9/9/3 +# 2 faces + +# +# object leftWall_Mesh +# + +v -1.00000 0.00000 -1.00000 +v -1.00000 2.00000 -1.00000 +v -1.00000 2.00000 1.00000 +v -1.00000 0.00000 1.00000 +# 4 vertices + +vn 1.00000 0.00000 -0.00000 +# 1 vertex normals + +vt 0.98133 0.00995 0.00000 +vt 0.98133 0.33377 0.00000 +vt 0.65751 0.33377 0.00000 +vt 0.65751 0.00995 0.00000 +# 4 texture coords + +g leftWall_Mesh +usemtl leftWall +s 1 +f 13/13/4 14/14/4 15/15/4 +f 15/15/4 16/16/4 13/13/4 +# 2 faces + +# +# object light_Mesh +# + +v -0.24000 1.99900 -0.22000 +v 0.23000 1.99900 -0.22000 +v 0.23000 1.99900 0.22000 +v -0.24000 1.99900 0.22000 +# 4 vertices + +vn 0.00000 -1.00000 -0.00000 +# 1 vertex normals + +vt 0.65751 0.66623 0.00000 +vt 0.73361 0.66623 0.00000 +vt 0.73361 0.72776 0.00000 +vt 0.65751 0.72776 0.00000 +# 4 texture coords + +g light_Mesh +usemtl light +s 1 +f 17/17/5 18/18/5 19/19/5 +f 19/19/5 20/20/5 17/17/5 +# 2 faces + +# +# object rightWall_Mesh +# + +v 1.00000 0.00000 1.00000 +v 1.00000 2.00000 1.00000 +v 1.00000 2.00000 -1.00000 +v 1.00000 0.00000 -1.00000 +# 4 vertices + +vn -1.00000 0.00000 -0.00000 +# 1 vertex normals + +vt 0.65319 0.00995 0.00000 +vt 0.65319 0.33377 0.00000 +vt 0.32937 0.33377 0.00000 +vt 0.32937 0.00995 0.00000 +# 4 texture coords + +g rightWall_Mesh +usemtl rightWall +s 1 +f 21/21/6 22/22/6 23/23/6 +f 23/23/6 24/24/6 21/21/6 +# 2 faces + +# +# object shortBox_Mesh +# + +v 0.70000 0.60000 0.17000 +v 0.13000 0.60000 -0.00000 +v -0.05000 0.60000 0.57000 +v 0.53000 0.60000 0.75000 +v 0.13000 0.00000 -0.00000 +v -0.05000 0.00000 0.57000 +v 0.53000 0.00000 0.75000 +v 0.70000 0.00000 0.17000 +# 8 vertices + +vn 0.00000 1.00000 -0.00000 +vn -0.95358 0.00000 -0.30113 +vn -0.29640 0.00000 0.95506 +vn 0.95963 0.00000 0.28127 +vn 0.28580 0.00000 -0.95829 +# 5 vertex normals + +vt 0.13138 0.63182 0.00000 +vt 0.03909 0.65935 0.00000 +vt 0.00995 0.56706 0.00000 +vt 0.10386 0.53791 0.00000 +vt 0.32262 0.71129 0.00000 +vt 0.22811 0.71129 0.00000 +vt 0.22811 0.61181 0.00000 +vt 0.32262 0.61181 0.00000 +vt 0.22928 0.61136 0.00000 +vt 0.13319 0.61136 0.00000 +vt 0.13319 0.51196 0.00000 +vt 0.22928 0.51196 0.00000 +vt 0.22916 0.51136 0.00000 +vt 0.13330 0.51136 0.00000 +vt 0.13330 0.41219 0.00000 +vt 0.22916 0.41219 0.00000 +vt 0.22755 0.71117 0.00000 +vt 0.13327 0.71117 0.00000 +vt 0.13327 0.61193 0.00000 +vt 0.22755 0.61193 0.00000 +vt 0.13138 0.50729 0.00000 +vt 0.03909 0.53481 0.00000 +vt 0.00995 0.44253 0.00000 +vt 0.10386 0.41338 0.00000 +# 24 texture coords + +g shortBox_Mesh +usemtl shortBox +s 1 +f 25/25/7 26/26/7 27/27/7 +f 27/27/7 28/28/7 25/25/7 +f 27/29/8 26/30/8 29/31/8 +f 29/31/8 30/32/8 27/29/8 +f 28/33/9 27/34/9 30/35/9 +f 30/35/9 31/36/9 28/33/9 +f 25/37/10 28/38/10 31/39/10 +f 31/39/10 32/40/10 25/37/10 +f 26/41/11 25/42/11 32/43/11 +f 32/43/11 29/44/11 26/41/11 +f 32/45/7 29/46/7 30/47/7 +f 30/47/7 31/48/7 32/45/7 +# 12 faces + +# +# object tallBox_Mesh +# + +v 0.04000 1.20000 -0.09000 +v -0.14000 1.20000 -0.67000 +v -0.71000 1.20000 -0.49000 +v -0.53000 1.20000 0.09000 +v -0.71000 0.00000 -0.49000 +v -0.53000 0.00000 0.09000 +v -0.14000 0.00000 -0.67000 +v 0.04000 0.00000 -0.09000 +# 8 vertices + +vn 0.00000 1.00000 -0.00000 +vn -0.95506 0.00000 0.29640 +vn -0.30113 0.00000 -0.95358 +vn 0.95506 0.00000 -0.29640 +vn 0.30113 0.00000 0.95358 +# 5 vertex normals + +vt 0.32504 0.16747 0.00000 +vt 0.29590 0.26138 0.00000 +vt 0.20361 0.23224 0.00000 +vt 0.23276 0.13833 0.00000 +vt 0.10604 0.20884 0.00000 +vt 0.00995 0.20884 0.00000 +vt 0.00995 0.01003 0.00000 +vt 0.10604 0.01003 0.00000 +vt 0.20143 0.40787 0.00000 +vt 0.10692 0.40787 0.00000 +vt 0.10692 0.20890 0.00000 +vt 0.20143 0.20890 0.00000 +vt 0.10604 0.40779 0.00000 +vt 0.00995 0.40779 0.00000 +vt 0.00995 0.20898 0.00000 +vt 0.10604 0.20898 0.00000 +vt 0.20143 0.20891 0.00000 +vt 0.10692 0.20891 0.00000 +vt 0.10692 0.00995 0.00000 +vt 0.20143 0.00995 0.00000 +vt 0.32504 0.04087 0.00000 +vt 0.29590 0.13478 0.00000 +vt 0.20361 0.10564 0.00000 +vt 0.23276 0.01173 0.00000 +# 24 texture coords + +g tallBox_Mesh +usemtl tallBox +s 1 +f 33/49/12 34/50/12 35/51/12 +f 35/51/12 36/52/12 33/49/12 +f 36/53/13 35/54/13 37/55/13 +f 37/55/13 38/56/13 36/53/13 +f 35/57/14 34/58/14 39/59/14 +f 39/59/14 37/60/14 35/57/14 +f 34/61/15 33/62/15 40/63/15 +f 40/63/15 39/64/15 34/61/15 +f 33/65/16 36/66/16 38/67/16 +f 38/67/16 40/68/16 33/65/16 +f 40/69/12 39/70/12 37/71/12 +f 37/71/12 38/72/12 40/69/12 +# 12 faces + diff --git a/bin/assets/hdri/environment.exr b/bin/assets/hdri/environment.exr new file mode 100644 index 0000000..0a97cc3 Binary files /dev/null and b/bin/assets/hdri/environment.exr differ diff --git a/bin/assets/materials-showcase/materials-showcase-materials.mtl b/bin/assets/materials-showcase/materials-showcase-materials.mtl new file mode 100644 index 0000000..dc39298 --- /dev/null +++ b/bin/assets/materials-showcase/materials-showcase-materials.mtl @@ -0,0 +1,78 @@ +newmtl et::env +image ../hdri/environment.exr + +newmtl et::medium +id torus.000 +sigma_a 0.6 0.3 0.15 + +newmtl box +material class plastic +int_ior plastic +Pr 0.5 +Kd 0.8 0.8 0.8 + +newmtl box-left +material class plastic +int_ior plastic +Pr 0.5 +Kd 0.8 0.1 0.1 + +newmtl box-right +material class plastic +int_ior plastic +Pr 0.5 +Kd 0.1 0.8 0.1 + +newmtl bubble +material class thinfilm +thinfilm image ../textures/clouds.png range 180.0 840.0 + +newmtl curtain +material class translucent +Kd 0.395292 0.557676 0.8 + +newmtl curtain-bar +material class conductor +int_ior nickel +Pr 0.2 + +newmtl emitter-left +emitter blackbody 12000.0 scale 0.00025 collimated 65536.0 +Ke 1 1 1 + +newmtl emitter-right +emitter blackbody 2700.0 scale 0.25 collimated 65536.0 +Ke 1 1 1 + +newmtl projector-box +material class coating +Ks 0.04 0.04 0.04 +Kd 0.131063 0.121089 0.113964 + +newmtl projector-holder +material class conductor +int_ior chrome +Pr 0.5 + +newmtl projector-interior +material class mirror + +newmtl torus-stand +material class conductor uroughness 0.5 vroughness 0.01 +int_ior gold + +newmtl torus.000 +material class dielectric +int_ior sapphire +int_medium torus.000 +Pr 0.0 + +newmtl torus.001 +material class dielectric +int_ior diamond +Pr 0.1 + +newmtl torus.002 +material class dielectric +int_ior glass +Pr 0.05 diff --git a/bin/assets/materials-showcase/materials-showcase.blend b/bin/assets/materials-showcase/materials-showcase.blend new file mode 100644 index 0000000..4abb5b7 Binary files /dev/null and b/bin/assets/materials-showcase/materials-showcase.blend differ diff --git a/bin/assets/materials-showcase/materials-showcase.json b/bin/assets/materials-showcase/materials-showcase.json new file mode 100644 index 0000000..ef8942d --- /dev/null +++ b/bin/assets/materials-showcase/materials-showcase.json @@ -0,0 +1,13 @@ +{ + "geometry": "materials-showcase.obj", + "materials" : "materials-showcase-materials.mtl", + "camera": { + "viewport": [ 1280.0, 720.0 ], + "origin": [ 0.0, 5.0, 25.75 ], + "target": [ 0.0, 5.0, 0.0 ], + "up": [ 0.0, 1.0, 0.0 ], + "fov": 26.99, + "lens-radius": 0.0, + "focal-distance": 0.0 + } +} diff --git a/bin/assets/materials-showcase/materials-showcase.obj b/bin/assets/materials-showcase/materials-showcase.obj new file mode 100644 index 0000000..95934aa --- /dev/null +++ b/bin/assets/materials-showcase/materials-showcase.obj @@ -0,0 +1,59091 @@ +# Blender v3.0.0 OBJ File: 'materials-showcase.blend' +# www.blender.org +mtllib materials-showcase-materials.mtl +g box_Cube.001 +v -8.888850 0.000000 5.000000 +v -8.888850 10.000000 -5.000000 +v -8.888850 0.000000 -5.000000 +v -8.888850 10.000000 5.000000 +v 8.894624 10.005774 -5.005774 +v 8.894624 -0.005773 -5.005774 +v 8.895921 10.007071 5.000000 +v 8.895921 -0.007071 5.000000 +v -8.894624 10.005774 -5.005774 +v -8.894624 -0.005773 -5.005774 +v -8.895921 10.007071 5.000000 +v -8.895921 -0.007071 5.000000 +v 8.888850 10.000000 -5.000000 +v 8.888850 0.000000 -5.000000 +v 8.888850 10.000000 5.000000 +v 8.888850 0.000000 5.000000 +vt 0.375000 0.250000 +vt 0.625000 0.000000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.750000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.125000 0.750000 +vt 0.375000 0.500000 +vt 0.125000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.375000 0.750000 +vt 0.875000 0.750000 +vt 0.875000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 0.000000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 1.0000 -0.0001 +vn 0.0000 -1.0000 -0.0001 +vn 0.0000 0.0000 -1.0000 +vn -0.0001 0.0000 1.0000 +vn 0.0001 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +g box_Cube.001_box-left +usemtl box-left +s off +f 3/1/1 4/2/1 1/3/1 +f 3/1/1 2/4/1 4/2/1 +g box_Cube.001_box +usemtl box +f 15/5/2 2/6/2 13/7/2 +f 1/8/3 14/9/3 3/10/3 +f 14/9/4 2/4/4 3/1/4 +f 9/11/5 7/12/5 5/13/5 +f 6/14/6 12/15/6 10/16/6 +f 9/17/7 6/14/7 10/18/7 +f 4/2/4 12/19/4 1/3/4 +f 16/20/8 7/12/8 15/5/8 +f 15/5/4 11/21/4 4/22/4 +f 1/8/4 8/23/4 16/20/4 +f 15/5/2 4/22/2 2/6/2 +f 1/8/3 16/20/3 14/9/3 +f 14/9/4 13/7/4 2/4/4 +f 9/11/5 11/21/5 7/12/5 +f 6/14/6 8/23/6 12/15/6 +f 9/17/7 5/13/7 6/14/7 +f 4/2/8 11/24/8 12/19/8 +f 16/20/9 8/23/9 7/12/9 +f 15/5/4 7/12/4 11/21/4 +f 1/8/4 12/15/4 8/23/4 +g box_Cube.001_box-right +usemtl box-right +f 16/20/10 13/7/10 14/9/10 +f 16/20/10 15/5/10 13/7/10 +g projector-left_Cylinder.001 +v -7.330874 9.396918 3.327657 +v -7.286443 10.004840 3.263703 +v -7.266821 9.393319 3.381049 +v -7.221969 10.004877 3.316490 +v -7.276927 9.437387 3.458300 +v -7.234998 10.005307 3.397948 +v -7.352085 9.474021 3.483597 +v -7.312500 10.005698 3.426620 +v -7.415562 9.483992 3.429374 +v -7.376974 10.005660 3.373832 +v -7.404000 9.455996 3.350028 +v -7.363946 10.005231 3.292374 +v -7.292693 9.386420 3.347007 +v -7.247416 10.004797 3.281837 +v -7.308659 9.642163 3.295680 +v -7.244395 9.640884 3.348769 +v -7.261367 9.413056 3.421688 +v -7.217835 10.005066 3.359028 +v -7.255962 9.668819 3.428124 +v -7.310481 9.458505 3.480778 +v -7.269891 10.005538 3.422352 +v -7.332293 9.692515 3.455108 +v -7.390415 9.482891 3.464460 +v -7.351527 10.005741 3.408486 +v -7.396268 9.696980 3.401603 +v -7.419961 9.475892 3.387218 +v -7.381108 10.005472 3.331295 +v -7.383973 9.677081 3.321201 +v -7.371352 9.424870 3.328856 +v -7.329053 10.005000 3.267970 +v -7.270054 9.636329 3.314422 +v -7.239601 9.653339 3.390357 +v -7.290186 9.682549 3.451565 +v -7.370971 9.697536 3.436473 +v -7.400535 9.690344 3.359257 +v -7.350203 9.658347 3.298413 +v -6.397258 7.957366 4.111898 +v -5.916734 8.738810 3.713849 +v -7.703983 9.200889 4.975682 +v -7.223459 9.982331 4.577633 +v -7.567239 7.852294 2.493225 +v -7.086715 8.633738 2.095176 +v -8.873964 9.095817 3.357009 +v -8.393440 9.877259 2.958960 +v -6.421633 7.981279 4.040599 +v -5.975086 8.707468 3.670695 +v -7.686164 9.184516 4.892529 +v -7.233383 9.920843 4.517462 +v -7.508886 7.883636 2.536379 +v -7.062340 8.609825 2.166475 +v -8.788596 9.085510 3.367310 +v -8.335815 9.821837 2.992242 +v -7.686164 9.184516 4.892529 +v -7.233383 9.920843 4.517462 +v -8.788596 9.085510 3.367310 +v -8.335815 9.821837 2.992242 +vt 1.000000 0.500000 +vt 0.916667 0.750000 +vt 0.916667 0.500000 +vt 1.000000 0.750000 +vt 0.916667 1.000000 +vt 0.833333 0.750000 +vt 0.833333 0.500000 +vt 0.750000 0.500000 +vt 0.833333 1.000000 +vt 0.750000 0.750000 +vt 0.750000 1.000000 +vt 0.666667 0.750000 +vt 0.666667 0.500000 +vt 0.583333 0.500000 +vt 0.666667 1.000000 +vt 0.583333 0.750000 +vt 0.583333 1.000000 +vt 0.500000 0.750000 +vt 0.500000 0.500000 +vt 0.416667 0.500000 +vt 0.500000 1.000000 +vt 0.416667 0.750000 +vt 0.416667 1.000000 +vt 0.333333 0.750000 +vt 0.333333 0.500000 +vt 0.250000 0.750000 +vt 0.250000 0.500000 +vt 0.333333 1.000000 +vt 0.166667 1.000000 +vt 0.166667 0.750000 +vt 0.166667 0.500000 +vt 0.083333 0.750000 +vt 0.083333 0.500000 +vt 0.083333 1.000000 +vt -0.000000 1.000000 +vt -0.000000 0.750000 +vt -0.000000 0.500000 +vt 1.000000 1.000000 +vt 0.250000 1.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.375000 0.250000 +vt 0.625000 0.000000 +vt 0.375000 0.000000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.875000 0.500000 +vt 0.375000 0.750000 +vt 0.875000 0.750000 +vt 0.625000 0.250000 +vt 0.875000 0.750000 +vt 0.375000 0.500000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vn 0.2245 -0.1459 -0.9635 +vn 0.6294 -0.1329 -0.7656 +vn 0.6348 -0.1562 -0.7567 +vn 0.1635 -0.1202 -0.9792 +vn 0.6292 -0.1067 -0.7699 +vn 0.9301 -0.1095 -0.3506 +vn 0.9144 -0.1327 -0.3824 +vn 0.9913 -0.0758 0.1071 +vn 0.9270 -0.0895 -0.3641 +vn 0.9854 -0.0567 0.1601 +vn 0.9884 -0.0484 0.1441 +vn 0.7761 0.0110 0.6304 +vn 0.8115 0.0027 0.5843 +vn 0.4002 0.0827 0.9127 +vn 0.7837 0.0070 0.6211 +vn 0.3563 0.0757 0.9313 +vn 0.3604 0.0617 0.9308 +vn -0.1588 0.1203 0.9799 +vn -0.1196 0.1390 0.9830 +vn -0.6111 0.1565 0.7759 +vn -0.1583 0.0993 0.9824 +vn -0.6306 0.1325 0.7647 +vn -0.6311 0.1091 0.7680 +vn -0.9325 0.1090 0.3444 +vn -0.9297 0.1292 0.3447 +vn -0.9841 0.0566 -0.1684 +vn -0.9788 0.0632 -0.1949 +vn -0.9341 0.0890 0.3457 +vn -0.7615 -0.0103 -0.6480 +vn -0.7699 -0.0100 -0.6381 +vn -0.7293 -0.0231 -0.6838 +vn -0.3480 -0.0746 -0.9345 +vn -0.2754 -0.0997 -0.9561 +vn -0.3350 -0.0621 -0.9402 +vn 0.1728 -0.0968 -0.9802 +vn -0.9838 0.0453 -0.1733 +vn 0.5850 0.0525 0.8093 +vn -0.6534 0.6218 0.4319 +vn -0.5850 -0.0525 -0.8093 +vn -0.4805 -0.7814 0.3980 +vn 0.4805 0.7814 -0.3980 +vn -0.5893 -0.0484 -0.8064 +vn 0.5806 0.0567 0.8122 +vn 0.4783 0.7835 -0.3966 +vn -0.4827 -0.7794 0.3995 +vn 0.6534 -0.6218 -0.4319 +g projector-left_Cylinder.001_projector-holder +usemtl projector-holder +s 1 +f 17/25/11 47/26/12 29/27/13 +f 31/28/14 30/29/15 47/26/12 +f 30/29/15 32/30/16 47/26/12 +f 47/26/12 19/31/17 29/27/13 +f 32/30/16 33/32/18 19/31/17 +f 20/33/19 48/34/20 32/30/16 +f 34/35/21 35/36/22 48/34/20 +f 48/34/20 21/37/23 33/32/18 +f 35/36/22 36/38/24 21/37/23 +f 22/39/25 49/40/26 35/36/22 +f 37/41/27 38/42/28 49/40/26 +f 49/40/26 23/43/29 36/38/24 +f 38/42/28 39/44/30 23/43/29 +f 24/45/31 50/46/32 38/42/28 +f 40/47/33 41/48/34 50/46/32 +f 50/46/32 25/49/35 39/44/30 +f 25/49/35 51/50/36 42/51/37 +f 26/52/38 51/50/36 41/48/34 +f 51/50/36 28/53/39 44/54/40 +f 42/51/37 44/54/40 27/55/41 +f 27/55/41 52/56/42 45/57/43 +f 44/54/40 46/58/44 52/56/42 +f 52/56/42 18/59/45 31/60/14 +f 45/57/43 31/60/14 17/61/11 +f 17/25/11 31/28/14 47/26/12 +f 31/28/14 18/62/45 30/29/15 +f 30/29/15 20/33/19 32/30/16 +f 47/26/12 32/30/16 19/31/17 +f 32/30/16 48/34/20 33/32/18 +f 20/33/19 34/35/21 48/34/20 +f 34/35/21 22/39/25 35/36/22 +f 48/34/20 35/36/22 21/37/23 +f 35/36/22 49/40/26 36/38/24 +f 22/39/25 37/41/27 49/40/26 +f 37/41/27 24/45/31 38/42/28 +f 49/40/26 38/42/28 23/43/29 +f 38/42/28 50/46/32 39/44/30 +f 24/45/31 40/47/33 50/46/32 +f 40/47/33 26/52/38 41/48/34 +f 50/46/32 41/48/34 25/49/35 +f 25/49/35 41/48/34 51/50/36 +f 26/52/38 43/63/46 51/50/36 +f 51/50/36 43/63/46 28/53/39 +f 42/51/37 51/50/36 44/54/40 +f 27/55/41 44/54/40 52/56/42 +f 44/54/40 28/53/39 46/58/44 +f 52/56/42 46/58/44 18/59/45 +f 45/57/43 52/56/42 31/60/14 +g projector-left_Cylinder.001_projector-box +usemtl projector-box +s off +f 54/64/47 55/65/47 53/66/47 +f 56/67/48 59/68/48 55/65/48 +f 59/68/49 58/69/49 57/70/49 +f 59/68/50 53/71/50 55/72/50 +f 56/73/51 58/69/51 60/74/51 +f 63/75/52 62/76/52 61/77/52 +f 67/78/53 66/79/53 68/80/53 +f 61/81/54 67/78/54 63/82/54 +f 66/79/55 64/83/55 68/80/55 +f 53/66/56 62/76/56 54/64/56 +f 58/69/56 65/84/56 57/70/56 +f 57/70/56 61/81/56 53/71/56 +f 54/85/56 66/79/56 58/69/56 +f 54/64/47 56/67/47 55/65/47 +f 56/67/48 60/74/48 59/68/48 +f 59/68/49 60/74/49 58/69/49 +f 59/68/50 57/70/50 53/71/50 +f 56/73/51 54/85/51 58/69/51 +f 63/75/52 64/86/52 62/76/52 +f 67/78/53 65/84/53 66/79/53 +f 61/81/54 65/84/54 67/78/54 +f 66/79/55 62/87/55 64/83/55 +f 53/66/56 61/77/56 62/76/56 +f 58/69/56 66/79/56 65/84/56 +f 57/70/56 65/84/56 61/81/56 +f 54/85/56 62/87/56 66/79/56 +g projector-left_Cylinder.001_emitter-left +usemtl emitter-left +f 71/88/56 70/89/56 69/90/56 +f 71/88/56 72/91/56 70/89/56 +g projector-right_Cylinder.003 +v 7.372598 9.424976 -3.360905 +v 7.422718 10.006106 -3.323762 +v 7.312867 9.430689 -3.418923 +v 7.363461 10.006426 -3.381429 +v 7.336753 9.467088 -3.497131 +v 7.384050 10.006549 -3.462080 +v 7.419242 9.486689 -3.518157 +v 7.463896 10.006352 -3.485065 +v 7.479624 9.487376 -3.459656 +v 7.523153 10.006032 -3.427398 +v 7.457380 9.467122 -3.380231 +v 7.502563 10.005910 -3.346747 +v 7.334484 9.420975 -3.382672 +v 7.385557 10.006271 -3.344823 +v 7.397658 9.671326 -3.342334 +v 7.338164 9.679370 -3.400176 +v 7.314217 9.448570 -3.460747 +v 7.363323 10.006526 -3.424356 +v 7.360402 9.699562 -3.479606 +v 7.375285 9.479810 -3.517879 +v 7.421073 10.006484 -3.483947 +v 7.441569 9.706167 -3.501611 +v 7.457190 9.489054 -3.496513 +v 7.501057 10.006186 -3.464005 +v 7.501389 9.701324 -3.443527 +v 7.479464 9.481185 -3.416951 +v 7.523291 10.005932 -3.384472 +v 7.479972 9.689203 -3.363489 +v 7.417825 9.444345 -3.360241 +v 7.465541 10.005975 -3.324881 +v 7.360020 9.672009 -3.363748 +v 7.338770 9.689936 -3.442552 +v 7.398179 9.704865 -3.500913 +v 7.479124 9.704666 -3.480259 +v 7.501377 9.696603 -3.400711 +v 7.441683 9.678874 -3.342561 +v 6.225616 8.150240 -4.147331 +v 5.884935 9.033563 -3.825341 +v 7.809453 9.058640 -4.963584 +v 7.468772 9.941962 -4.641594 +v 7.239127 7.918342 -2.438818 +v 6.898446 8.801663 -2.116827 +v 8.822964 8.826741 -3.255071 +v 8.482283 9.710064 -2.933080 +v 6.249403 8.173271 -4.075545 +v 5.932811 8.994135 -3.776321 +v 7.783155 9.051222 -4.881406 +v 7.462143 9.883546 -4.578005 +v 7.191250 7.957769 -2.487837 +v 6.874658 8.778633 -2.188614 +v 8.738151 8.832712 -3.271533 +v 8.417139 9.665035 -2.968132 +v 7.783155 9.051222 -4.881406 +v 7.462143 9.883546 -4.578005 +v 8.738151 8.832712 -3.271533 +v 8.417139 9.665035 -2.968132 +vt 1.000000 0.500000 +vt 0.916667 0.750000 +vt 0.916667 0.500000 +vt 1.000000 0.750000 +vt 0.916667 1.000000 +vt 0.833333 1.000000 +vt 0.833333 0.750000 +vt 0.833333 0.500000 +vt 0.750000 0.500000 +vt 0.750000 0.750000 +vt 0.750000 1.000000 +vt 0.666667 0.750000 +vt 0.666667 0.500000 +vt 0.583333 0.500000 +vt 0.666667 1.000000 +vt 0.583333 0.750000 +vt 0.583333 1.000000 +vt 0.500000 0.750000 +vt 0.500000 0.500000 +vt 0.416667 0.500000 +vt 0.500000 1.000000 +vt 0.416667 0.750000 +vt 0.416667 1.000000 +vt 0.333333 0.750000 +vt 0.333333 0.500000 +vt 0.250000 0.750000 +vt 0.250000 0.500000 +vt 0.333333 1.000000 +vt 0.166667 1.000000 +vt 0.166667 0.750000 +vt 0.166667 0.500000 +vt 0.083333 0.750000 +vt 0.083333 0.500000 +vt 0.083333 1.000000 +vt -0.000000 1.000000 +vt -0.000000 0.750000 +vt -0.000000 0.500000 +vt 1.000000 1.000000 +vt 0.250000 1.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 0.000000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.875000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 0.000000 +vt 0.875000 0.750000 +vt 0.375000 0.500000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.500000 +vt 0.625000 0.500000 +vt 0.125000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.250000 +vn -0.3136 -0.0396 0.9487 +vn -0.6945 0.0145 0.7194 +vn -0.7027 0.0179 0.7112 +vn -0.2452 -0.0426 0.9685 +vn -0.6868 0.0114 0.7267 +vn -0.9578 0.0578 0.2817 +vn -0.9587 0.0681 0.2761 +vn -0.9462 0.0725 0.3154 +vn -0.9770 0.1130 -0.1807 +vn -0.9646 0.1028 -0.2428 +vn -0.9666 0.0885 -0.2406 +vn -0.7104 0.1094 -0.6952 +vn -0.7533 0.1253 -0.6456 +vn -0.3131 0.1030 -0.9441 +vn -0.7131 0.0940 -0.6948 +vn -0.2660 0.0867 -0.9601 +vn -0.2663 0.0737 -0.9611 +vn 0.2495 0.0411 -0.9675 +vn 0.2110 0.0521 -0.9761 +vn 0.6810 -0.0141 -0.7321 +vn 0.2559 0.0341 -0.9661 +vn 0.6980 -0.0146 -0.7159 +vn 0.7069 -0.0130 -0.7072 +vn 0.9600 -0.0655 -0.2723 +vn 0.9579 -0.0766 -0.2765 +vn 0.9646 -0.0984 0.2445 +vn 0.9563 -0.1175 0.2678 +vn 0.9643 -0.0549 -0.2589 +vn 0.7164 -0.0874 0.6922 +vn 0.7105 -0.1060 0.6957 +vn 0.6622 -0.1231 0.7392 +vn 0.2676 -0.0865 0.9596 +vn 0.1847 -0.0925 0.9784 +vn 0.2827 -0.0714 0.9565 +vn -0.2292 -0.0360 0.9727 +vn 0.9646 -0.0815 0.2509 +vn -0.5068 0.1159 -0.8543 +vn 0.7919 0.4542 -0.4081 +vn 0.5068 -0.1159 0.8543 +vn 0.3407 -0.8833 -0.3220 +vn -0.3407 0.8833 0.3220 +vn -0.7919 -0.4542 0.4081 +vn -0.7919 -0.4542 0.4082 +vn 0.5120 -0.1129 0.8515 +vn -0.5015 0.1190 -0.8570 +vn -0.3380 0.8848 0.3206 +vn 0.3433 -0.8818 -0.3234 +g projector-right_Cylinder.003_projector-holder +usemtl projector-holder +s 1 +f 73/92/57 103/93/58 85/94/59 +f 87/95/60 86/96/61 103/93/58 +f 103/93/58 76/97/62 88/98/63 +f 103/93/58 75/99/64 85/94/59 +f 88/98/63 89/100/65 75/99/64 +f 76/97/62 104/101/66 88/98/63 +f 90/102/67 91/103/68 104/101/66 +f 104/101/66 77/104/69 89/100/65 +f 91/103/68 92/105/70 77/104/69 +f 78/106/71 105/107/72 91/103/68 +f 93/108/73 94/109/74 105/107/72 +f 105/107/72 79/110/75 92/105/70 +f 94/109/74 95/111/76 79/110/75 +f 80/112/77 106/113/78 94/109/74 +f 96/114/79 97/115/80 106/113/78 +f 106/113/78 81/116/81 95/111/76 +f 81/116/81 107/117/82 98/118/83 +f 82/119/84 107/117/82 97/115/80 +f 107/117/82 84/120/85 100/121/86 +f 98/118/83 100/121/86 83/122/87 +f 83/122/87 108/123/88 101/124/89 +f 100/121/86 102/125/90 108/123/88 +f 108/123/88 74/126/91 87/127/60 +f 101/124/89 87/127/60 73/128/57 +f 73/92/57 87/95/60 103/93/58 +f 87/95/60 74/129/91 86/96/61 +f 103/93/58 86/96/61 76/97/62 +f 103/93/58 88/98/63 75/99/64 +f 88/98/63 104/101/66 89/100/65 +f 76/97/62 90/102/67 104/101/66 +f 90/102/67 78/106/71 91/103/68 +f 104/101/66 91/103/68 77/104/69 +f 91/103/68 105/107/72 92/105/70 +f 78/106/71 93/108/73 105/107/72 +f 93/108/73 80/112/77 94/109/74 +f 105/107/72 94/109/74 79/110/75 +f 94/109/74 106/113/78 95/111/76 +f 80/112/77 96/114/79 106/113/78 +f 96/114/79 82/119/84 97/115/80 +f 106/113/78 97/115/80 81/116/81 +f 81/116/81 97/115/80 107/117/82 +f 82/119/84 99/130/92 107/117/82 +f 107/117/82 99/130/92 84/120/85 +f 98/118/83 107/117/82 100/121/86 +f 83/122/87 100/121/86 108/123/88 +f 100/121/86 84/120/85 102/125/90 +f 108/123/88 102/125/90 74/126/91 +f 101/124/89 108/123/88 87/127/60 +g projector-right_Cylinder.003_projector-box +usemtl projector-box +s off +f 110/131/93 111/132/93 109/133/93 +f 112/134/94 115/135/94 111/132/94 +f 115/135/95 114/136/95 113/137/95 +f 115/135/96 109/138/96 111/139/96 +f 112/140/97 114/136/97 116/141/97 +f 109/133/98 118/142/98 110/131/98 +f 114/136/98 121/143/98 113/137/98 +f 113/137/99 117/144/99 109/138/99 +f 110/145/98 122/146/98 114/136/98 +f 110/131/93 112/134/93 111/132/93 +f 112/134/94 116/141/94 115/135/94 +f 115/135/95 116/141/95 114/136/95 +f 115/135/96 113/137/96 109/138/96 +f 112/140/97 110/145/97 114/136/97 +f 109/133/98 117/147/98 118/142/98 +f 114/136/98 122/146/98 121/143/98 +f 113/137/98 121/143/98 117/144/98 +f 110/145/98 118/148/98 122/146/98 +g projector-right_Cylinder.003_emitter-right +usemtl emitter-right +f 127/149/98 126/150/98 125/151/98 +f 127/149/98 128/152/98 126/150/98 +g projector-right_Cylinder.003_projector-interior +usemtl projector-interior +f 119/153/100 118/142/100 117/147/100 +f 123/154/101 122/146/101 124/155/101 +f 117/144/102 123/154/102 119/156/102 +f 122/146/103 120/157/103 124/155/103 +f 119/153/100 120/158/100 118/142/100 +f 123/154/101 121/143/101 122/146/101 +f 117/144/102 121/143/102 123/154/102 +f 122/146/103 118/148/103 120/157/103 +g torus_Torus.001 +v -2.217009 0.640314 1.745822 +v -2.024911 0.794601 1.764241 +v -1.935425 1.023282 1.776271 +v -1.972528 1.265081 1.778688 +v -2.126278 1.455210 1.770846 +v -2.355479 1.542722 1.754845 +v -2.598716 1.504169 1.734972 +v -2.790813 1.349882 1.716554 +v -2.880300 1.121202 1.704524 +v -2.843197 0.879402 1.702106 +v -2.689447 0.689274 1.709949 +v -2.460246 0.601762 1.725950 +v -2.201318 0.730555 1.112961 +v -2.009626 0.882512 1.147726 +v -1.921246 1.104824 1.204414 +v -1.959862 1.337925 1.267837 +v -2.115125 1.519354 1.320999 +v -2.345433 1.600499 1.349656 +v -2.589075 1.559615 1.346130 +v -2.780767 1.407659 1.311365 +v -2.869146 1.185346 1.254677 +v -2.830531 0.952246 1.191254 +v -2.675268 0.770816 1.138092 +v -2.444960 0.689672 1.109435 +v -2.254160 0.967327 0.521310 +v -2.061103 1.113167 0.571357 +v -1.968995 1.318772 0.669796 +v -2.002516 1.529049 0.790250 +v -2.152685 1.687655 0.900445 +v -2.379264 1.752091 0.970852 +v -2.621542 1.705092 0.982608 +v -2.814599 1.559252 0.932562 +v -2.906707 1.353647 0.834123 +v -2.873186 1.143370 0.713668 +v -2.723017 0.984764 0.603474 +v -2.496437 0.920328 0.533066 +v -2.371934 1.334492 0.011190 +v -2.175834 1.470849 0.074413 +v -2.075416 1.650544 0.208849 +v -2.097584 1.825428 0.378476 +v -2.236401 1.948641 0.537844 +v -2.454669 1.987168 0.644249 +v -2.693904 1.930686 0.669181 +v -2.890004 1.794329 0.605958 +v -2.990422 1.614633 0.471522 +v -2.968254 1.439749 0.301894 +v -2.829437 1.316537 0.142527 +v -2.611169 1.278010 0.036122 +v -2.546613 1.807030 -0.382635 +v -2.346002 1.931182 -0.309240 +v -2.233257 2.077532 -0.147014 +v -2.238587 2.206866 0.060577 +v -2.360565 2.284528 0.257907 +v -2.566507 2.289710 0.392103 +v -2.801231 2.221022 0.427207 +v -3.001842 2.096870 0.353812 +v -3.114587 1.950520 0.191585 +v -3.109257 1.821187 -0.016005 +v -2.987278 1.743524 -0.213335 +v -2.781337 1.738342 -0.347531 +v -2.766294 2.352738 -0.633327 +v -2.560009 2.462795 -0.553457 +v -2.431762 2.570636 -0.373540 +v -2.415916 2.647366 -0.141784 +v -2.516718 2.672425 0.079712 +v -2.707158 2.639098 0.231598 +v -2.936207 2.556316 0.273177 +v -3.142492 2.446259 0.193307 +v -3.270740 2.338417 0.013390 +v -3.286585 2.261687 -0.218366 +v -3.185783 2.236628 -0.439862 +v -2.995343 2.269955 -0.591748 +v -3.016006 2.934426 -0.723802 +v -2.803271 3.029459 -0.641595 +v -2.657402 3.096253 -0.455294 +v -2.617486 3.116911 -0.214816 +v -2.694216 3.085898 0.015401 +v -2.867035 3.011523 0.173671 +v -3.089634 2.913716 0.217587 +v -3.302370 2.818684 0.135381 +v -3.448238 2.751890 -0.050921 +v -3.488155 2.731232 -0.291398 +v -3.411424 2.762245 -0.521616 +v -3.238605 2.836619 -0.679886 +v -3.278731 3.512455 -0.647894 +v -3.059210 3.592557 -0.567648 +v -2.894802 3.618562 -0.386702 +v -2.829560 3.583501 -0.153543 +v -2.880965 3.496769 0.069358 +v -3.035244 3.381605 0.222272 +v -3.251058 3.268868 0.264227 +v -3.470579 3.188766 0.183981 +v -3.634987 3.162761 0.003036 +v -3.700229 3.197822 -0.230124 +v -3.648823 3.284554 -0.453024 +v -3.494545 3.399718 -0.605939 +v -3.536565 4.047431 -0.410775 +v -3.310384 4.113716 -0.336654 +v -3.127782 4.101969 -0.172441 +v -3.037686 4.015339 0.037862 +v -3.064237 3.877038 0.237905 +v -3.200322 3.724123 0.374087 +v -3.409476 3.597568 0.409917 +v -3.635657 3.531284 0.335796 +v -3.818259 3.543030 0.171583 +v -3.908355 3.629660 -0.038720 +v -3.881804 3.767962 -0.238763 +v -3.745719 3.920876 -0.374945 +v -3.771937 4.502898 -0.028605 +v -3.539677 4.557419 0.035645 +v -3.340466 4.513532 0.172890 +v -3.227681 4.382997 0.346353 +v -3.231544 4.200790 0.509557 +v -3.351019 4.015735 0.618770 +v -3.554093 3.877416 0.644729 +v -3.786354 3.822896 0.580479 +v -3.985565 3.866782 0.443235 +v -4.098350 3.997318 0.269771 +v -4.094487 4.179523 0.106567 +v -3.975012 4.364579 -0.002646 +v -3.968807 4.847816 0.472570 +v -3.731462 4.893427 0.523876 +v -3.518358 4.825200 0.625754 +v -3.386596 4.661417 0.750907 +v -3.371481 4.445963 0.865800 +v -3.477064 4.236568 0.939647 +v -3.675054 4.089340 0.952662 +v -3.912399 4.043728 0.901356 +v -4.125503 4.111955 0.799478 +v -4.257265 4.275738 0.674325 +v -4.272380 4.491193 0.559432 +v -4.166797 4.700588 0.485585 +v -4.113759 5.058679 1.058599 +v -3.872669 5.098844 1.094768 +v -3.649337 5.015738 1.155293 +v -3.503602 4.831628 1.223955 +v -3.474515 4.595847 1.282357 +v -3.569869 4.371572 1.314851 +v -3.764115 4.218898 1.312729 +v -4.005204 4.178733 1.276560 +v -4.228537 4.261840 1.216035 +v -4.374271 4.445949 1.147373 +v -4.403358 4.681730 1.088971 +v -4.308004 4.906004 1.056477 +v -4.196913 5.121117 1.689543 +v -3.953676 5.159670 1.709415 +v -3.724476 5.072157 1.725416 +v -3.570725 4.882029 1.733259 +v -3.533623 4.640229 1.730841 +v -3.623109 4.411549 1.718812 +v -3.815207 4.257262 1.700393 +v -4.058444 4.218709 1.680521 +v -4.287644 4.306222 1.664519 +v -4.441395 4.496350 1.656677 +v -4.478498 4.738150 1.659094 +v -4.389011 4.966830 1.671124 +v -4.212604 5.030876 2.322404 +v -3.968962 5.071759 2.325930 +v -3.738654 4.990615 2.297273 +v -3.583391 4.809186 2.244111 +v -3.544776 4.576085 2.180689 +v -3.633155 4.353772 2.124000 +v -3.824848 4.201816 2.089235 +v -4.068490 4.160933 2.085709 +v -4.298798 4.242077 2.114367 +v -4.454061 4.423506 2.167529 +v -4.492676 4.656607 2.230951 +v -4.404297 4.878920 2.287639 +v -4.159762 4.794105 2.914055 +v -3.917485 4.841104 2.902299 +v -3.690906 4.776668 2.831891 +v -3.540737 4.618062 2.721697 +v -3.507215 4.407784 2.601242 +v -3.599323 4.202180 2.502804 +v -3.792381 4.056339 2.452757 +v -4.034658 4.009340 2.464513 +v -4.261237 4.073777 2.534920 +v -4.411406 4.232383 2.645115 +v -4.444928 4.442659 2.765569 +v -4.352819 4.648264 2.864008 +v -4.041988 4.426939 3.424175 +v -3.802753 4.483422 3.399243 +v -3.584485 4.444895 3.292838 +v -3.445669 4.321682 3.133471 +v -3.423500 4.146798 2.963843 +v -3.523919 3.967103 2.829407 +v -3.720018 3.830746 2.766185 +v -3.959253 3.774263 2.791116 +v -4.177522 3.812790 2.897521 +v -4.316338 3.936003 3.056889 +v -4.338507 4.110888 3.226516 +v -4.238088 4.290583 3.360952 +v -3.867309 3.954401 3.818001 +v -3.632586 4.023089 3.782897 +v -3.426644 4.017907 3.648701 +v -3.304666 3.940245 3.451371 +v -3.299335 3.810911 3.243780 +v -3.412081 3.664561 3.081553 +v -3.612692 3.540409 3.008159 +v -3.847415 3.471722 3.043262 +v -4.053357 3.476903 3.177458 +v -4.175335 3.554566 3.374789 +v -4.180665 3.683899 3.582379 +v -4.067920 3.830250 3.744606 +v -3.647628 3.408694 4.068692 +v -3.418579 3.491477 4.027113 +v -3.228139 3.524803 3.875227 +v -3.127337 3.499744 3.653732 +v -3.143183 3.423014 3.421976 +v -3.271430 3.315173 3.242058 +v -3.477715 3.205116 3.162189 +v -3.706765 3.122333 3.203767 +v -3.897205 3.089006 3.355654 +v -3.998007 3.114065 3.577149 +v -3.982161 3.190795 3.808906 +v -3.853914 3.298637 3.988822 +v -3.397916 2.827005 4.159167 +v -3.175317 2.924812 4.115252 +v -3.002498 2.999187 3.956981 +v -2.925767 3.030200 3.726764 +v -2.965684 3.009541 3.486287 +v -3.111553 2.942747 3.299985 +v -3.324288 2.847715 3.217778 +v -3.546887 2.749908 3.261694 +v -3.719706 2.675534 3.419964 +v -3.796437 2.644521 3.650182 +v -3.756520 2.665179 3.890659 +v -3.610651 2.731973 4.076961 +v -3.135192 2.248977 4.083259 +v -2.919378 2.361714 4.041304 +v -2.765099 2.476877 3.888390 +v -2.713693 2.563610 3.665490 +v -2.778935 2.598671 3.432330 +v -2.943343 2.572666 3.251384 +v -3.162864 2.492563 3.171139 +v -3.378678 2.379826 3.213094 +v -3.532957 2.264663 3.366008 +v -3.584363 2.177931 3.588908 +v -3.519121 2.142870 3.822068 +v -3.354713 2.168875 4.003013 +v -2.877357 1.714000 3.846140 +v -2.668203 1.840555 3.810310 +v -2.532119 1.993470 3.674129 +v -2.505567 2.131771 3.474085 +v -2.595663 2.218401 3.263783 +v -2.778265 2.230148 3.099570 +v -3.004446 2.163863 3.025449 +v -3.213600 2.037308 3.061279 +v -3.349685 1.884394 3.197460 +v -3.376236 1.746092 3.397503 +v -3.286140 1.659462 3.607806 +v -3.103538 1.647716 3.772019 +v -2.641985 1.258534 3.463972 +v -2.438911 1.396853 3.438012 +v -2.319436 1.581908 3.328799 +v -2.315573 1.764114 3.165595 +v -2.428357 1.894649 2.992131 +v -2.627569 1.938536 2.854887 +v -2.859829 1.884016 2.790637 +v -3.062904 1.745697 2.816596 +v -3.182379 1.560641 2.925809 +v -3.186242 1.378435 3.089013 +v -3.073457 1.247900 3.262477 +v -2.874246 1.204014 3.399721 +v -2.445116 0.913616 2.962795 +v -2.247126 1.060844 2.949780 +v -2.141543 1.270239 2.875933 +v -2.156657 1.485693 2.761040 +v -2.288419 1.649476 2.635888 +v -2.501523 1.717703 2.534009 +v -2.738868 1.672091 2.482704 +v -2.936858 1.524864 2.495718 +v -3.042441 1.315469 2.569566 +v -3.027327 1.100014 2.684458 +v -2.895565 0.936231 2.809611 +v -2.682461 0.868005 2.911489 +v -2.300164 0.702753 2.376766 +v -2.105918 0.855427 2.378888 +v -2.010564 1.079702 2.346395 +v -2.039651 1.315482 2.287992 +v -2.185386 1.499592 2.219330 +v -2.408718 1.582698 2.158805 +v -2.649807 1.542533 2.122636 +v -2.844053 1.389859 2.120514 +v -2.939407 1.165584 2.153008 +v -2.910320 0.929803 2.211410 +v -2.764585 0.745694 2.280073 +v -2.541253 0.662588 2.340597 +v -2.110902 0.705019 1.755545 +v -2.743446 1.923196 2.812085 +v -3.278128 1.552565 3.256733 +v -2.877661 0.997780 1.702015 +v -2.180393 1.161078 2.919522 +v -2.336200 0.605219 1.735728 +v -2.200566 0.666519 1.426908 +v -2.560886 1.818219 2.702699 +v -2.224497 1.574471 1.339036 +v -2.974398 1.008491 2.747886 +v -2.868612 1.139829 1.477835 +v -2.169519 0.940739 2.672326 +v -2.147807 1.029871 0.539124 +v -2.531166 1.578041 2.136900 +v -2.127908 1.591061 1.105206 +v -2.963021 1.000494 2.454556 +v -2.905797 1.245434 0.774664 +v -2.373106 0.930070 0.519308 +v -2.305345 1.136005 0.253744 +v -2.338965 1.979661 0.599842 +v -2.943090 1.473546 0.643932 +v -2.438328 1.864025 -0.358847 +v -2.293904 2.108562 0.386218 +v -3.127278 1.881360 0.090086 +v -2.663626 1.764225 -0.378664 +v -2.651710 2.072984 -0.527158 +v -2.603548 2.662817 0.167425 +v -3.189291 2.139564 0.088856 +v -2.904619 2.983971 -0.697759 +v -2.603533 2.877709 0.032880 +v -3.482759 2.735162 -0.168287 +v -3.129917 2.884171 -0.717576 +v -3.146855 3.226393 -0.706557 +v -2.947349 3.440888 0.157652 +v -3.541248 2.959424 -0.038664 +v -3.421738 4.089621 -0.386801 +v -2.973830 3.692411 0.139869 +v -3.876990 3.578066 0.068776 +v -2.057454 0.806471 2.074449 +v -3.647036 3.989821 -0.406618 +v -3.658105 4.287180 -0.236383 +v -3.278248 4.105392 0.573142 +v -3.904652 3.713447 0.295543 +v -3.851123 4.884716 0.490707 +v -3.305576 4.334368 0.678518 +v -4.204337 4.184215 0.737753 +v -4.076422 4.784916 0.470890 +v -4.048471 4.971105 0.757381 +v -3.507581 4.478273 1.302564 +v -4.182130 4.199591 1.001925 +v -4.077722 5.156213 1.699637 +v -3.509877 4.631569 1.504495 +v -4.377087 4.391192 1.659393 +v -4.303020 5.056412 1.679820 +v -4.213356 5.094912 2.008457 +v -3.573899 4.459620 2.150470 +v -4.299332 4.287595 1.891209 +v -4.040817 4.831361 2.916057 +v -3.531993 4.504379 2.396481 +v -4.348952 4.143538 2.586744 +v -4.266115 4.731561 2.896241 +v -4.108578 4.625427 3.181621 +v -3.459430 4.054430 2.889664 +v -4.224854 3.953878 2.725110 +v -3.750296 3.997206 3.814030 +v -3.365997 3.986877 3.115469 +v -4.127470 3.507612 3.271322 +v -3.975595 3.897406 3.794213 +v -3.762212 3.688448 3.962524 +v -3.194848 3.371274 3.322081 +v -2.870162 0.889237 1.959148 +v -3.978652 3.287860 3.280187 +v -3.284005 2.877260 4.152942 +v -3.056368 3.217730 3.468807 +v -3.771989 2.653810 3.529695 +v -3.509304 2.777460 4.133125 +v -3.267067 2.535038 4.141923 +v -2.851046 2.593202 3.331853 +v -3.626697 2.467999 3.407707 +v -2.766886 1.771610 3.841983 +v -2.686070 2.403028 3.361818 +v -3.377758 1.810907 3.292633 +v -2.992185 1.671810 3.822167 +v -2.755817 1.474252 3.671749 +v -2.520147 1.928699 2.916364 +v -1.965173 0.903216 1.771303 +v -3.263293 1.713977 3.073501 +v -2.337501 0.976515 2.964475 +v -2.778889 0.774245 1.704823 +v -2.354325 1.761071 2.823170 +v -2.008893 0.820130 1.453564 +v -3.050411 1.204757 2.623656 +v -2.469780 1.595307 1.352042 +v -2.562799 0.876715 2.944659 +v -2.365451 0.790327 2.677984 +v -2.829924 0.900555 1.444675 +v -2.290814 1.555817 2.186942 +v -2.000226 1.211754 0.615970 +v -2.985814 1.227833 2.367118 +v -2.356946 1.665086 1.155286 +v -2.810731 1.054526 0.655297 +v -2.110965 1.277488 0.310702 +v -2.575737 1.970368 0.667812 +v -2.914502 1.279528 0.497686 +v -2.276156 2.004018 -0.236906 +v -2.506463 2.131212 0.507676 +v -3.061392 1.774233 -0.119472 +v -2.448385 2.190266 -0.450031 +v -2.820646 2.602727 0.267549 +v -3.194092 2.035867 -0.132666 +v -2.719030 3.067721 -0.558799 +v -2.785354 2.824003 0.189416 +v -3.463707 2.740521 -0.411885 +v -2.930740 3.313885 -0.624796 +v -3.138883 3.322943 0.258503 +v -3.593777 2.966911 -0.277479 +v -3.210180 4.117846 -0.263456 +v -3.118890 3.557825 0.285783 +v -3.909876 3.694474 -0.143591 +v -3.428785 4.347272 -0.166766 +v -3.445178 3.938035 0.643098 +v -4.006464 3.823187 0.102050 +v -3.618002 4.873013 0.569984 +v -3.417701 4.136052 0.770957 +v -4.280350 4.380481 0.613522 +v -3.809069 5.013532 0.801330 +v -3.657458 4.283191 1.318282 +v -4.321571 4.375258 0.904227 +v -3.833222 5.130874 1.718203 +v -3.601721 4.403748 1.514936 +v -4.475859 4.614727 1.656585 +v -3.969695 5.134141 2.020092 +v -2.150023 1.463870 1.997192 +v -3.718844 4.265924 2.103140 +v -4.454667 4.475197 1.914108 +v -3.798170 4.822337 2.873535 +v -3.621641 4.289185 2.318370 +v -4.444017 4.334446 2.706111 +v -3.867623 4.676783 3.162954 +v -3.612887 3.890863 2.787370 +v -4.370090 4.096224 2.861097 +v -3.522239 4.030073 3.726412 +v -3.472124 3.823059 2.965981 +v -4.193357 3.614739 3.480880 +v -3.530203 3.764005 3.923687 +v -3.367978 3.258505 3.187633 +v -4.090500 3.339886 3.491449 +v -3.079365 2.966369 4.048305 +v -3.193234 3.130268 3.284241 +v -3.791041 2.648451 3.773293 +v -3.047848 2.640386 4.098453 +v -3.049741 2.538289 3.196679 +v -3.690814 2.408842 3.636262 +v -2.588215 1.916244 3.752962 +v -2.859697 2.396446 3.187873 +v -3.344872 1.694498 3.504999 +v -2.549803 1.606999 3.640423 +v -1.938063 1.146704 1.778780 +v -3.135674 1.656040 2.862224 +v -2.985137 1.414160 3.602132 +v -2.580701 0.630557 1.717162 +v -2.209585 1.577217 2.697613 +v -1.920567 1.046961 1.488098 +v -2.996221 1.625380 2.664408 +v -2.695078 1.495507 1.332226 +v -2.674589 0.712953 1.421776 +v -2.092351 1.386173 2.531138 +v -1.969905 1.426985 0.729254 +v -2.906341 1.283158 2.132801 +v -2.600124 1.621598 1.159601 +v -2.604853 0.747899 2.634035 +v -2.615753 0.939095 0.561829 +v -2.015245 1.471190 0.428022 +v -2.801035 1.870568 0.647995 +v -2.769267 1.137182 0.361700 +v -2.220566 2.146692 -0.045515 +v -2.743609 2.068919 0.538117 +v -2.891684 1.731359 -0.291047 +v -2.328223 2.317849 -0.277606 +v -3.045944 2.502927 0.247733 +v -3.082245 1.983841 -0.343928 +v -2.622881 3.112980 -0.337928 +v -3.011249 2.733761 0.232696 +v -3.334558 2.795062 -0.612939 +v -2.775638 3.360075 -0.439711 +v -3.364182 3.223143 0.238686 +v -3.529660 3.026068 -0.506033 +v -3.069051 4.066934 -0.069634 +v -3.331329 3.437979 0.325176 +v -3.825707 3.845187 -0.317597 +v -3.237606 4.318607 -0.014860 +v -3.670476 3.838236 0.623281 +v -3.991628 3.984600 -0.081182 +v -3.439524 4.752941 0.687479 +v -3.618086 3.992879 0.790777 +v -4.233530 4.600353 0.515844 +v -1.999493 1.274916 2.035730 +v -3.590343 4.936605 0.883111 +v -3.882756 4.183391 1.298465 +v -4.344365 4.602597 0.816789 +v -3.635033 4.987186 1.730543 +v -3.794682 4.249775 1.504742 +v -4.448749 4.858215 1.664062 +v -3.739334 5.048478 2.013589 +v -3.944142 4.166124 2.083323 +v -4.493355 4.714470 1.947267 +v -3.603191 4.706906 2.780068 +v -3.813798 4.139834 2.275764 +v -4.413697 4.549678 2.819395 +v -3.644655 4.624249 3.073665 +v -3.838186 3.791063 2.767553 +v -4.398677 4.290242 3.007343 +v -3.352530 3.987198 3.554837 +v -3.670313 3.692512 2.897248 +v -4.137766 3.757414 3.672272 +v -3.331678 3.777591 3.779293 +v -3.593277 3.158705 3.167816 +v -4.085700 3.443583 3.712971 +v -2.950215 3.020910 3.847250 +v -3.402674 3.027671 3.202669 +v -3.694892 2.693710 3.994164 +v -2.884263 2.735363 3.941399 +v -3.275040 2.438488 3.176863 +v -2.492789 0.613631 2.036158 +v -3.638284 2.401356 3.875077 +v -2.504046 2.066957 3.578957 +v -3.082593 2.323452 3.110189 +v -3.203742 1.643585 3.698822 +v -2.422295 1.776832 3.516548 +v -2.968745 1.823396 2.792268 +v -2.036835 1.370239 1.775972 +v -3.176316 1.442824 3.450226 +v -2.133573 1.380950 2.821844 +v -2.795837 1.768553 2.644588 +v -1.959255 1.286234 1.521257 +v -2.795920 0.888419 2.865382 +v -2.840024 1.301811 1.284896 +v -2.069557 1.158834 2.618577 +v -2.444228 0.627290 1.415273 +v -2.756464 1.478240 2.117083 +v -2.064971 1.617893 0.848621 +v -2.823579 0.824826 2.552255 +v -2.792281 1.472247 1.116995 +v -2.043833 1.665208 0.574268 +v -2.954492 1.707001 0.545701 +v -2.546300 1.084649 0.272411 +v -2.286452 2.253819 0.164043 +v -2.941798 1.938373 0.469385 +v -2.323422 2.421546 -0.056084 +v -3.219075 2.390158 0.113285 +v -2.883719 1.997427 -0.488322 +v -2.641933 3.107621 -0.094330 +v -3.220689 2.631163 0.151125 +v -2.723108 3.352590 -0.200896 +v -3.562876 3.168229 0.103512 +v -3.366075 3.121045 -0.663087 +v -3.036165 3.950525 0.142733 +v -3.554225 3.364985 0.247492 +v -3.135794 4.208867 0.178633 +v -3.893776 3.832733 0.519002 +v -3.864120 4.154432 -0.205057 +v -3.363511 4.556674 0.811710 +v -3.853036 3.943213 0.732666 +v -3.450902 4.760938 0.980809 +v -4.123108 4.205614 1.248424 +v -4.244404 4.820693 0.763039 +v -3.536261 4.763651 1.733350 +v -4.037055 4.210908 1.476645 +v -3.583998 4.860876 1.990690 +v -4.189425 4.186961 2.096329 +v -4.405029 4.941301 1.981802 +v -3.508126 4.515998 2.660701 +v -4.056976 4.096345 2.280079 +v -3.499420 4.481903 2.937679 +v -2.619241 1.511656 1.930623 +v -4.074957 3.781771 2.835524 +v -4.302958 4.483943 3.124663 +v -3.286644 3.880072 3.345279 +v -3.907459 3.630219 2.927690 +v -3.219831 3.725564 3.568031 +v -3.810375 3.098615 3.267940 +v -3.965538 3.571166 3.885396 +v -2.931163 3.026269 3.603652 +v -3.628568 2.937429 3.245950 +v -2.820145 2.794521 3.712844 +v -3.466573 2.320543 3.277713 +v -3.483182 2.447547 4.060162 +v -2.536932 2.183366 3.366590 +v -3.295032 2.203607 3.149582 +v -2.407459 1.938244 3.333315 +v -2.700450 2.076649 2.987916 +v -2.235024 1.513926 1.763632 +v -3.143135 1.304119 3.177443 +v -2.337450 1.213784 3.206451 +v -2.095315 0.794664 1.126866 +v -2.621185 1.708992 2.500840 +v -2.114590 1.473837 1.544157 +v -3.102170 1.226743 2.897139 +v -2.865778 1.066122 1.222735 +v -2.043630 0.962127 2.366601 +v -2.320613 0.694864 1.107049 +v -2.219302 0.831434 0.809376 +v -2.450518 1.638767 2.351660 +v -2.259949 1.733324 0.942089 +v -2.850161 0.827760 2.245603 +v -2.881929 1.257053 1.038884 +v -2.264802 1.394610 0.032375 +v -2.189068 1.807553 0.710255 +v -2.994989 1.523496 0.388339 +v -2.490101 1.294810 0.012559 +v -2.452831 1.559474 -0.202123 +v -2.456160 2.296693 0.335618 +v -3.047925 1.774554 0.319896 +v -2.656557 2.406127 -0.607883 +v -2.435270 2.473572 0.155178 +v -3.293647 2.294636 -0.099768 +v -2.881855 2.306326 -0.627699 +v -2.888429 2.641539 -0.699211 +v -2.771083 3.053080 0.106724 +v -3.357555 2.543701 -0.033442 +v -3.165607 3.558180 -0.622353 +v -2.787226 3.293432 0.027658 +v -3.681727 3.172916 -0.110800 +v -3.390906 3.458380 -0.642170 +v -3.409377 3.787691 -0.548695 +v -3.120334 3.799812 0.316739 +v -3.727852 3.358403 0.073547 +v -3.655555 4.542078 -0.007157 +v -3.150630 4.047455 0.361865 +v -4.055243 3.923001 0.358201 +v -3.880853 4.442278 -0.026974 +v -3.876088 4.690820 0.209095 +v -3.410331 4.336802 0.909388 +v -4.059597 4.000360 0.612195 +v -3.995117 5.094186 1.072863 +v -3.428108 4.533598 1.068247 +v -4.314112 4.343906 1.181565 +v -4.220415 4.994386 1.053046 +v -4.163507 5.108932 1.371110 +v -3.563371 4.520164 1.725873 +v -4.263899 4.297561 1.438173 +v -4.093309 5.066567 2.328316 +v -2.376867 1.550523 1.958720 +v -3.545310 4.621603 1.957531 +v -4.388970 4.322850 2.138673 +v -4.318608 4.966767 2.308500 +v -4.194621 4.929997 2.625989 +v -3.538446 4.300767 2.547417 +v -4.286015 4.170371 2.330159 +v -3.923821 4.466622 3.422807 +v -3.470833 4.287886 2.791432 +v -4.259759 3.865476 2.973069 +v -4.149120 4.366822 3.402990 +v -3.961091 4.201958 3.637488 +v -3.342235 3.737397 3.153888 +v -4.120018 3.652870 3.049147 +v -3.532067 3.455105 4.063065 +v -3.224631 3.621867 3.346509 +v -3.961101 3.094336 3.461176 +v -3.757366 3.355305 4.043248 +v -3.525494 3.119893 4.134577 +v -3.027312 2.981010 3.382782 +v -3.810390 2.883722 3.402485 +v -3.023017 2.303052 4.077536 +v -2.872675 2.802007 3.474029 +v -3.573021 2.216056 3.472208 +v -3.248315 2.203252 4.057719 +v -3.004545 1.973741 3.984061 +v -2.678061 2.234278 3.172767 +v -3.440092 2.069021 3.295496 +v -2.533070 1.319154 3.462340 +v -2.509271 2.047985 3.139823 +v -3.199505 1.465972 3.003208 +v -2.479524 1.539265 1.745067 +v -2.758368 1.219354 3.442523 +v -2.537834 1.070612 3.226271 +v -2.388064 1.697289 2.580117 +v -1.950369 0.988359 1.174195 +v -3.108347 1.427063 2.756848 +v -2.344951 1.559500 1.550660 +v -2.193507 0.767045 2.382319 +v -2.765440 0.851590 1.162399 +v -2.231792 1.561840 2.433440 +v -2.027145 0.980785 0.851982 +v -2.940636 1.045066 2.179843 +v -2.502596 1.742348 0.984611 +v -2.418806 0.667245 2.362502 +v -2.845048 1.033677 0.946198 +v -2.111346 1.558176 0.134670 +v -2.412035 1.860087 0.799544 +v -2.911674 1.369222 0.218075 +v -2.254642 1.690020 -0.133391 +v -2.684217 2.263827 0.423236 +v -3.033555 1.621357 0.129706 +v -2.483426 2.518896 -0.473436 +v -2.633795 2.459986 0.299572 +v -3.249680 2.241958 -0.334339 +v -2.678989 2.744136 -0.617640 +v -2.975723 2.963971 0.211362 +v -3.385174 2.494810 -0.271549 +v -2.966913 3.613094 -0.487179 +v -2.950811 3.198455 0.184712 +v -3.688888 3.235948 -0.346824 +v -3.186481 3.860684 -0.471012 +v -3.299005 3.655178 0.405760 +v -3.805688 3.419995 -0.150051 +v -2.250415 0.652498 2.064255 +v -3.432255 4.547582 0.097122 +v -3.278138 3.877622 0.485741 +v -4.111613 4.084854 0.183966 +v -3.641138 4.740487 0.267206 +v -3.567439 4.152239 0.954342 +v -4.182422 4.149010 0.461645 +v -3.754765 5.071963 1.122905 +v -3.528069 4.315504 1.121997 +v -4.404587 4.561212 1.115806 +v -3.921134 5.147800 1.399207 +v -3.709099 4.321967 1.710115 +v -4.414429 4.486515 1.399635 +v -3.848026 5.045731 2.315310 +v -3.633636 4.394771 1.922996 +v -4.489307 4.537382 2.199009 +v -3.951443 4.973486 2.621674 +v -3.686028 4.118883 2.470571 +v -4.439544 4.342076 2.412585 +v -3.687050 4.475914 3.354836 +v -3.566552 4.094184 2.674112 +v -4.343074 4.019750 3.143333 +v -3.723946 4.264251 3.607047 +v -3.504406 3.597404 3.031946 +v -4.251037 3.754395 3.229077 +v -3.314969 3.515195 3.962942 +v -3.344792 3.494285 3.174084 +v -2.904045 1.129862 1.930870 +v -4.005069 3.147015 3.695748 +v -3.299599 3.210135 4.091296 +v -3.212900 2.897260 3.243820 +v -3.899418 2.880942 3.630332 +v -2.831483 2.420997 3.976685 +v -3.027777 2.755816 3.288944 +v -3.565861 2.153025 3.708232 +v -2.792106 2.093587 3.944668 +v -2.889619 2.206053 3.049422 +v -3.478904 1.955757 3.508834 +v -2.366141 1.486509 3.392384 +v -2.358680 1.838431 3.077165 +v -3.135784 1.883810 2.949625 +v -2.704823 1.439464 1.725250 +v -2.231501 1.612422 2.973721 +v -1.924615 1.224049 1.236356 +v -3.003591 1.424629 2.525977 +v -2.588613 1.520270 1.539025 +v -2.772784 1.020945 3.168160 +v -2.565896 0.715700 1.120055 +v -2.099810 1.417525 2.253800 +v -1.937497 1.195979 0.930093 +v -2.885853 1.445928 2.313369 +v -2.727895 1.642548 0.964794 +v -2.691518 0.861971 0.863771 +v -2.070849 1.741681 0.292032 +v -2.652990 1.808731 0.818210 +v -2.726873 1.285517 0.080529 +v -2.148515 1.853839 0.016098 +v -2.909516 2.164027 0.403419 +v -2.902537 1.519831 -0.050224 +v -2.408854 2.614417 -0.260382 +v -2.865804 2.384429 0.338409 +v -3.098953 2.246236 -0.527576 +v -2.542123 2.831598 -0.433074 +v -3.201022 2.864171 0.191545 +v -3.296145 2.497590 -0.499395 +v -2.848062 3.608407 -0.272867 +v -3.170031 3.093107 0.228182 +v -3.582440 3.340435 -0.541319 +v -3.012854 3.867267 -0.297067 +v -3.524303 3.555378 0.385944 +v -3.766876 3.533259 -0.363389 +v -3.270787 4.457313 0.257923 +v -3.484153 3.744874 0.517067 +v -4.047782 4.274922 0.042982 +v -3.434577 4.683339 0.387677 +v -3.792738 4.052439 0.934525 +v -4.188599 4.349331 0.321355 +v -3.563761 4.933671 1.189763 +v -3.724001 4.165092 1.127655 +v -4.370292 4.799304 1.068764 +v -3.694290 5.061147 1.437679 +v -3.934398 4.222167 1.690299 +v -4.448312 4.727139 1.371357 +v -3.648482 4.909842 2.272966 +v -3.825310 4.241161 1.896340 +v -4.463553 4.773072 2.261170 +v -3.722404 4.899460 2.571594 +v -3.911326 4.019083 2.450754 +v -4.476426 4.565453 2.505272 +v -3.502248 4.392209 3.217290 +v -2.812201 1.357683 1.920429 +v -3.760932 3.952700 2.617155 +v -4.302577 4.203256 3.300695 +v -3.511386 4.241600 3.485590 +v -3.729705 3.497604 3.012130 +v -4.265408 3.907592 3.419267 +v -3.164243 3.519474 3.769705 +v -3.548118 3.377002 3.096957 +v -3.930496 3.242536 3.908801 +v -3.117778 3.263841 3.934762 +v -3.438199 2.797460 3.224004 +v -3.871799 2.929833 3.868439 +v -2.725035 2.525484 3.782189 +v -3.243892 2.668324 3.207183 +v -3.447010 2.148338 3.922544 +v -2.647046 2.228173 3.798754 +v -3.114918 2.106253 3.029606 +v -3.401068 1.894165 3.732432 +v -2.302309 1.676578 3.251400 +v -2.929770 2.016557 2.918299 +v -2.981668 1.213850 3.338243 +v -2.850551 1.241267 1.709492 +v -2.225324 1.412101 3.114012 +v -2.846483 1.609192 2.481024 +v -2.024952 1.438581 1.296692 +v -2.979346 1.078093 3.047689 +v -2.780286 1.366660 1.512369 +v -2.009335 1.200220 2.319560 +v -2.689921 1.596340 2.307710 +v -1.974378 1.419355 1.022780 +v -2.659158 0.689468 2.312461 +v -2.875476 1.460665 0.887948 +v -2.462479 0.787945 0.813691 +v -2.154163 1.895955 0.462296 +v -2.847370 1.667248 0.761253 +v -2.162885 2.007036 0.206288 +v -3.071687 2.024034 0.281478 +v -2.689977 1.497180 -0.171682 +v -2.452821 2.667096 -0.025811 +v -3.069130 2.267147 0.261281 +v -2.514504 2.880489 -0.194967 +v -3.386610 2.780421 0.052584 +v -3.114324 2.551296 -0.655931 +v -2.840901 3.545375 -0.036842 +v -3.386146 3.005615 0.146421 +v -2.935019 3.805674 -0.073469 +v -3.735861 3.527153 0.262599 +v -3.621816 3.667845 -0.509303 +v -3.214417 4.295460 0.432158 +v -3.713473 3.684782 0.447450 +v -3.311752 4.534689 0.538227 +v -4.025858 4.064143 0.855248 +v -4.076473 4.547647 0.228915 +v -1.965610 1.034291 2.064008 +v -3.473286 4.716365 1.255522 +v -3.963404 4.122664 1.083706 +v -3.543760 4.872194 1.476217 +v -4.178898 4.247505 1.671733 +v -4.356468 4.954961 1.360916 +v -3.548144 4.695310 2.212630 +v -4.068971 4.201932 1.884705 +v -3.568875 4.727755 2.489167 +v -4.153973 4.028108 2.493277 +v -4.386778 4.780647 2.583383 +v -3.418933 4.237936 3.047026 +v -4.001887 3.901345 2.635821 +v -3.380368 4.140075 3.305659 +v -3.957762 3.464738 3.099747 +v -4.159280 4.071411 3.568756 +v -3.120275 3.466795 3.535134 +v -3.780127 3.301445 3.135793 +v -3.028749 3.266621 3.706914 +v -3.642839 2.708351 3.328641 +v -3.734933 3.017295 4.053006 +v -2.732196 2.588516 3.546165 +v -3.463111 2.562976 3.250653 +v -2.719632 0.700284 1.997686 +v -2.608234 2.341436 3.585416 +v -3.293589 1.961619 3.118627 +v -3.227441 1.900747 3.906377 +v -2.094568 0.731051 1.438738 +v -1.949659 0.927941 1.470405 +v -1.923970 1.169164 1.505439 +v -2.024383 1.390085 1.534451 +v -2.223992 1.531508 1.549668 +v -2.469313 1.555539 1.547012 +v -2.694612 1.455739 1.527195 +v -2.839520 1.258849 1.495527 +v -2.865209 1.017626 1.460494 +v -2.764796 0.796705 1.431482 +v -2.565187 0.655282 1.416265 +v -2.319866 0.631251 1.418921 +v -2.113179 0.894876 0.825287 +v -1.967337 1.083539 0.887762 +v -1.940028 1.310512 0.976154 +v -2.038572 1.514979 1.066780 +v -2.236562 1.642152 1.135356 +v -2.480948 1.657956 1.163508 +v -2.706247 1.558155 1.143691 +v -2.852089 1.369493 1.081216 +v -2.879398 1.142520 0.992823 +v -2.780854 0.938053 0.902197 +v -2.582864 0.810880 0.833621 +v -2.338478 0.795076 0.805470 +v -2.198653 1.197434 0.273326 +v -2.048518 1.370902 0.363520 +v -2.013775 1.571559 0.499924 +v -2.103734 1.745636 0.645988 +v -2.294290 1.846493 0.762574 +v -2.534383 1.847102 0.818445 +v -2.759682 1.747302 0.798628 +v -2.909817 1.573833 0.708434 +v -2.944560 1.373177 0.572031 +v -2.854601 1.199099 0.425966 +v -2.664046 1.098243 0.309380 +v -2.423952 1.097634 0.253510 +v -2.345165 1.618105 -0.179528 +v -2.187673 1.770448 -0.066593 +v -2.140186 1.934513 0.109201 +v -2.215429 2.066339 0.300749 +v -2.393240 2.130604 0.456727 +v -2.625976 2.110088 0.535339 +v -2.851275 2.010288 0.515522 +v -3.008768 1.857945 0.402586 +v -3.056255 1.693880 0.226792 +v -2.981011 1.562053 0.035244 +v -2.803200 1.497788 -0.120733 +v -2.570464 1.518305 -0.199345 +v -2.542730 2.128221 -0.502415 +v -2.375316 2.254946 -0.373264 +v -2.310644 2.374640 -0.169385 +v -2.366045 2.455232 0.054593 +v -2.526671 2.475126 0.238656 +v -2.749486 2.428992 0.333483 +v -2.974784 2.329191 0.313666 +v -3.142199 2.202466 0.184515 +v -3.206870 2.082772 -0.019364 +v -3.151470 2.002181 -0.243343 +v -2.990843 1.982287 -0.427405 +v -2.768029 2.028421 -0.522233 +v -2.777884 2.693019 -0.673332 +v -2.598661 2.791381 -0.535597 +v -2.513535 2.861947 -0.316851 +v -2.545317 2.885811 -0.075706 +v -2.685490 2.856578 0.123222 +v -2.896495 2.782080 0.226633 +v -3.121793 2.682280 0.206816 +v -3.301017 2.583919 0.069082 +v -3.386142 2.513352 -0.149664 +v -3.354361 2.489488 -0.390809 +v -3.214188 2.518722 -0.589738 +v -3.003183 2.593219 -0.693149 +v -3.034603 3.274009 -0.680629 +v -2.842487 3.343194 -0.542529 +v -2.735031 3.363225 -0.323148 +v -2.741029 3.328735 -0.081270 +v -2.858871 3.248966 0.118294 +v -3.056984 3.145291 0.222071 +v -3.282283 3.045491 0.202254 +v -3.474399 2.976306 0.064154 +v -3.581854 2.956275 -0.155227 +v -3.575857 2.990765 -0.397105 +v -3.458014 3.070535 -0.596669 +v -3.259901 3.174209 -0.700446 +v -3.295390 3.831597 -0.523811 +v -3.090178 3.872780 -0.393585 +v -2.960038 3.844311 -0.187845 +v -2.939842 3.753818 0.038283 +v -3.035001 3.625548 0.224206 +v -3.220018 3.493872 0.320108 +v -3.445316 3.394072 0.300291 +v -3.650529 3.352889 0.170066 +v -3.780668 3.381358 -0.035675 +v -3.800864 3.471852 -0.261802 +v -3.705705 3.600121 -0.447726 +v -3.520689 3.731797 -0.543627 +v -3.542475 4.327785 -0.213562 +v -3.324854 4.344050 -0.098917 +v -3.173222 4.272421 0.079837 +v -3.128210 4.132092 0.274804 +v -3.201877 3.960663 0.433741 +v -3.374485 3.804069 0.514062 +v -3.599783 3.704268 0.494246 +v -3.817404 3.688004 0.379600 +v -3.969035 3.759633 0.200846 +v -4.014048 3.899962 0.005880 +v -3.940381 4.071391 -0.153057 +v -3.767773 4.227985 -0.233379 +v -3.759017 4.728758 0.228972 +v -3.530522 4.724887 0.321394 +v -3.360055 4.618381 0.461655 +v -3.293293 4.437778 0.612174 +v -3.348125 4.231471 0.732619 +v -3.509858 4.054740 0.790717 +v -3.735157 3.954940 0.770900 +v -3.963652 3.958812 0.678479 +v -4.134119 4.065319 0.538217 +v -4.200881 4.245921 0.387698 +v -4.146049 4.452228 0.267253 +v -3.984316 4.628959 0.209156 +v -3.930261 5.007191 0.773635 +v -3.693166 4.989336 0.838704 +v -3.507804 4.858612 0.931589 +v -3.423843 4.650043 1.027403 +v -3.463779 4.419518 1.100472 +v -3.616913 4.228805 1.131217 +v -3.842211 4.129005 1.111400 +v -4.079307 4.146859 1.046332 +v -4.264668 4.277585 0.953446 +v -4.348630 4.486153 0.857632 +v -4.308693 4.716678 0.784564 +v -4.155560 4.907392 0.753819 +v -4.044537 5.144109 1.383309 +v -3.801703 5.119378 1.417760 +v -3.606401 4.976744 1.457615 +v -3.510962 4.754424 1.492194 +v -3.540959 4.511990 1.512232 +v -3.688353 4.314400 1.512360 +v -3.913652 4.214600 1.492543 +v -4.156486 4.239330 1.458092 +v -4.351788 4.381965 1.418237 +v -4.447227 4.604285 1.383658 +v -4.417230 4.846719 1.363620 +v -4.269835 5.044309 1.363492 +v -4.094056 5.130180 2.016444 +v -3.848736 5.106149 2.019100 +v -3.649126 4.964726 2.003883 +v -3.548714 4.743805 1.974872 +v -3.574403 4.502583 1.939838 +v -3.719311 4.305693 1.908170 +v -3.944609 4.205893 1.888353 +v -4.189930 4.229923 1.885698 +v -4.389539 4.371346 1.900914 +v -4.489952 4.592267 1.929926 +v -4.464263 4.833490 1.964960 +v -4.319355 5.030380 1.996628 +v -4.075445 4.966355 2.629895 +v -3.831059 4.950551 2.601744 +v -3.633068 4.823378 2.533168 +v -3.534525 4.618912 2.442542 +v -3.561833 4.391939 2.354149 +v -3.707675 4.203276 2.291674 +v -3.932974 4.103476 2.271858 +v -4.177361 4.119280 2.300009 +v -4.375350 4.246453 2.368585 +v -4.473894 4.450919 2.459211 +v -4.446586 4.677893 2.547603 +v -4.300743 4.866555 2.610078 +v -3.989970 4.663798 3.181855 +v -3.749877 4.663188 3.125985 +v -3.559321 4.562332 3.009398 +v -3.469363 4.388254 2.863334 +v -3.504106 4.187598 2.726931 +v -3.654241 4.014130 2.636737 +v -3.879539 3.914330 2.616920 +v -4.119633 3.914939 2.672791 +v -4.310188 4.015795 2.789377 +v -4.400147 4.189873 2.935441 +v -4.365404 4.390529 3.071845 +v -4.215269 4.563998 3.162039 +v -3.843458 4.243126 3.634710 +v -3.610723 4.263643 3.556098 +v -3.432911 4.199378 3.400121 +v -3.357668 4.067552 3.208573 +v -3.405155 3.903486 3.032779 +v -3.562647 3.751143 2.919843 +v -3.787946 3.651343 2.900026 +v -4.020682 3.630827 2.978639 +v -4.198493 3.695092 3.134616 +v -4.273737 3.826919 3.326164 +v -4.226250 3.990984 3.501957 +v -4.068757 4.143327 3.614893 +v -3.645894 3.733010 3.957598 +v -3.423079 3.779144 3.862771 +v -3.262452 3.759250 3.678708 +v -3.207052 3.678659 3.454730 +v -3.271724 3.558965 3.250850 +v -3.439138 3.432240 3.121699 +v -3.664437 3.332440 3.101882 +v -3.887251 3.286306 3.196710 +v -4.047878 3.306200 3.380773 +v -4.103278 3.386791 3.604751 +v -4.038607 3.506485 3.808630 +v -3.871192 3.633210 3.937781 +v -3.410739 3.168212 4.128514 +v -3.199734 3.242710 4.025104 +v -3.059561 3.271943 3.826174 +v -3.027780 3.248080 3.585029 +v -3.112906 3.177513 3.366283 +v -3.292129 3.079151 3.228549 +v -3.517428 2.979351 3.208733 +v -3.728433 2.904854 3.312143 +v -3.868606 2.875620 3.511072 +v -3.900387 2.899484 3.752217 +v -3.815261 2.970051 3.970963 +v -3.636038 3.068412 4.108697 +v -3.154021 2.587223 4.135812 +v -2.955908 2.690897 4.032034 +v -2.838065 2.770666 3.832470 +v -2.832068 2.805156 3.590592 +v -2.939524 2.785125 3.371212 +v -3.131639 2.715940 3.233111 +v -3.356938 2.616140 3.213295 +v -3.555051 2.512466 3.317071 +v -3.672894 2.432697 3.516635 +v -3.678891 2.398207 3.758513 +v -3.571435 2.418238 3.977894 +v -3.379320 2.487422 4.115995 +v -2.893234 2.029634 3.978993 +v -2.708217 2.161310 3.883091 +v -2.613058 2.289580 3.697167 +v -2.633254 2.380073 3.471040 +v -2.763394 2.408542 3.265300 +v -2.968606 2.367359 3.135074 +v -3.193905 2.267559 3.115258 +v -3.378921 2.135883 3.211160 +v -3.474080 2.007614 3.397083 +v -3.453884 1.917120 3.623210 +v -3.323745 1.888651 3.828951 +v -3.118532 1.929834 3.959176 +v -2.646149 1.533447 3.668745 +v -2.473541 1.690041 3.588423 +v -2.399874 1.861469 3.429486 +v -2.444887 2.001799 3.234520 +v -2.596519 2.073428 3.055765 +v -2.814139 2.057163 2.941120 +v -3.039438 1.957363 2.921304 +v -3.212046 1.800768 3.001625 +v -3.285713 1.629340 3.160563 +v -3.240700 1.489010 3.355529 +v -3.089069 1.417381 3.534283 +v -2.871448 1.433646 3.648928 +v -2.429607 1.132473 3.226210 +v -2.267873 1.309204 3.168113 +v -2.213042 1.515511 3.047668 +v -2.279804 1.696113 2.897149 +v -2.450270 1.802619 2.756887 +v -2.678766 1.806491 2.664466 +v -2.904064 1.706691 2.644649 +v -3.065798 1.529960 2.702747 +v -3.120629 1.323654 2.823192 +v -3.053867 1.143051 2.973711 +v -2.883400 1.036545 3.113972 +v -2.654905 1.032673 3.206394 +v -2.258362 0.854040 2.681547 +v -2.105229 1.044754 2.650801 +v -2.065292 1.275279 2.577733 +v -2.149254 1.483847 2.481919 +v -2.334616 1.614572 2.389033 +v -2.571711 1.632426 2.323965 +v -2.797009 1.532626 2.304148 +v -2.950143 1.341913 2.334893 +v -2.990079 1.111387 2.407962 +v -2.906118 0.902820 2.503776 +v -2.720756 0.772094 2.596661 +v -2.483661 0.754240 2.661730 +v -2.144087 0.717123 2.071873 +v -1.996692 0.914712 2.071745 +v -1.966695 1.157147 2.051707 +v -2.062135 1.379467 2.017128 +v -2.257436 1.522101 1.977273 +v -2.500270 1.546831 1.942822 +v -2.725569 1.447031 1.923005 +v -2.872964 1.249442 1.923133 +v -2.902960 1.007007 1.943171 +v -2.807521 0.784687 1.977750 +v -2.612219 0.642053 2.017605 +v -2.369385 0.617323 2.052056 +v 0.161343 2.980090 -0.678240 +v 0.098074 3.218925 -0.678240 +v -0.074780 3.393765 -0.678240 +v -0.310903 3.457761 -0.678240 +v -0.547026 3.393765 -0.678240 +v -0.719879 3.218925 -0.678239 +v -0.783149 2.980090 -0.678240 +v -0.719880 2.741255 -0.678240 +v -0.547026 2.566415 -0.678240 +v -0.310903 2.502419 -0.678240 +v -0.074780 2.566415 -0.678240 +v 0.098074 2.741255 -0.678240 +v 0.077877 2.980090 -1.312225 +v 0.016764 3.218926 -1.295849 +v -0.150200 3.393765 -1.251111 +v -0.378277 3.457761 -1.189999 +v -0.606354 3.393765 -1.128885 +v -0.773318 3.218925 -1.084148 +v -0.834431 2.980090 -1.067772 +v -0.773319 2.741255 -1.084148 +v -0.606354 2.566415 -1.128885 +v -0.378277 2.502419 -1.189998 +v -0.150200 2.566415 -1.251111 +v 0.016764 2.741255 -1.295849 +v -0.166832 2.980090 -1.903005 +v -0.221625 3.218925 -1.871370 +v -0.371321 3.393765 -1.784943 +v -0.575809 3.457761 -1.666882 +v -0.780297 3.393765 -1.548821 +v -0.929993 3.218925 -1.462394 +v -0.984786 2.980090 -1.430759 +v -0.929993 2.741255 -1.462393 +v -0.780297 2.566415 -1.548821 +v -0.575809 2.502419 -1.666882 +v -0.371321 2.566415 -1.784943 +v -0.221624 2.741255 -1.871370 +v -0.556108 2.980090 -2.410318 +v -0.600846 3.218925 -2.365581 +v -0.723072 3.393765 -2.243355 +v -0.890036 3.457761 -2.076391 +v -1.057000 3.393765 -1.909427 +v -1.179226 3.218925 -1.787201 +v -1.223964 2.980090 -1.742463 +v -1.179226 2.741255 -1.787201 +v -1.057000 2.566415 -1.909427 +v -0.890036 2.502419 -2.076391 +v -0.723072 2.566415 -2.243354 +v -0.600846 2.741255 -2.365581 +v -1.063422 2.980090 -2.799595 +v -1.095057 3.218925 -2.744802 +v -1.181484 3.393765 -2.595106 +v -1.299545 3.457761 -2.390618 +v -1.417606 3.393765 -2.186130 +v -1.504033 3.218925 -2.036434 +v -1.535668 2.980090 -1.981641 +v -1.504033 2.741255 -2.036434 +v -1.417606 2.566415 -2.186130 +v -1.299545 2.502419 -2.390618 +v -1.181484 2.566415 -2.595106 +v -1.095057 2.741255 -2.744803 +v -1.654202 2.980090 -3.044304 +v -1.670577 3.218925 -2.983191 +v -1.715315 3.393765 -2.816227 +v -1.776428 3.457761 -2.588150 +v -1.837541 3.393765 -2.360072 +v -1.882279 3.218925 -2.193109 +v -1.898654 2.980090 -2.131996 +v -1.882279 2.741255 -2.193108 +v -1.837541 2.566415 -2.360073 +v -1.776428 2.502419 -2.588150 +v -1.715315 2.566415 -2.816227 +v -1.670577 2.741255 -2.983190 +v -2.288187 2.980090 -3.127769 +v -2.288187 3.218925 -3.064500 +v -2.288187 3.393765 -2.891647 +v -2.288187 3.457761 -2.655524 +v -2.288187 3.393765 -2.419401 +v -2.288187 3.218925 -2.246548 +v -2.288187 2.980090 -2.183279 +v -2.288187 2.741255 -2.246548 +v -2.288187 2.566415 -2.419401 +v -2.288187 2.502419 -2.655524 +v -2.288187 2.566415 -2.891647 +v -2.288187 2.741255 -3.064500 +v -2.922172 2.980090 -3.044304 +v -2.905797 3.218925 -2.983191 +v -2.861059 3.393765 -2.816227 +v -2.799946 3.457761 -2.588150 +v -2.738833 3.393765 -2.360073 +v -2.694095 3.218925 -2.193109 +v -2.677720 2.980090 -2.131995 +v -2.694095 2.741255 -2.193109 +v -2.738832 2.566415 -2.360073 +v -2.799946 2.502419 -2.588150 +v -2.861059 2.566415 -2.816226 +v -2.905797 2.741255 -2.983191 +v -3.512952 2.980090 -2.799595 +v -3.481318 3.218925 -2.744802 +v -3.394891 3.393765 -2.595106 +v -3.276829 3.457761 -2.390617 +v -3.158768 3.393765 -2.186130 +v -3.072341 3.218925 -2.036434 +v -3.040706 2.980090 -1.981642 +v -3.072341 2.741255 -2.036434 +v -3.158768 2.566415 -2.186130 +v -3.276829 2.502419 -2.390618 +v -3.394891 2.566415 -2.595107 +v -3.481317 2.741255 -2.744802 +v -4.020267 2.980090 -2.410318 +v -3.975529 3.218925 -2.365581 +v -3.853302 3.393765 -2.243354 +v -3.686338 3.457761 -2.076391 +v -3.519374 3.393765 -1.909427 +v -3.397148 3.218925 -1.787200 +v -3.352410 2.980090 -1.742463 +v -3.397148 2.741255 -1.787200 +v -3.519374 2.566415 -1.909427 +v -3.686338 2.502419 -2.076390 +v -3.853302 2.566415 -2.243354 +v -3.975528 2.741255 -2.365581 +v -4.409542 2.980090 -1.903005 +v -4.354750 3.218926 -1.871371 +v -4.205054 3.393765 -1.784943 +v -4.000566 3.457761 -1.666882 +v -3.796077 3.393765 -1.548821 +v -3.646381 3.218925 -1.462393 +v -3.591589 2.980090 -1.430759 +v -3.646381 2.741255 -1.462394 +v -3.796077 2.566415 -1.548821 +v -4.000566 2.502419 -1.666882 +v -4.205054 2.566415 -1.784943 +v -4.354750 2.741255 -1.871370 +v -4.654251 2.980090 -1.312225 +v -4.593138 3.218926 -1.295849 +v -4.426174 3.393765 -1.251112 +v -4.198097 3.457761 -1.189999 +v -3.970020 3.393765 -1.128885 +v -3.803056 3.218925 -1.084147 +v -3.741943 2.980090 -1.067772 +v -3.803056 2.741255 -1.084147 +v -3.970020 2.566415 -1.128885 +v -4.198097 2.502419 -1.189998 +v -4.426174 2.566415 -1.251112 +v -4.593138 2.741255 -1.295849 +v -4.737717 2.980090 -0.678240 +v -4.674448 3.218926 -0.678240 +v -4.501594 3.393765 -0.678240 +v -4.265471 3.457761 -0.678240 +v -4.029348 3.393765 -0.678240 +v -3.856495 3.218926 -0.678240 +v -3.793226 2.980090 -0.678240 +v -3.856495 2.741255 -0.678240 +v -4.029348 2.566415 -0.678240 +v -4.265471 2.502419 -0.678240 +v -4.501594 2.566415 -0.678240 +v -4.674448 2.741255 -0.678240 +v -4.654251 2.980090 -0.044255 +v -4.593138 3.218926 -0.060630 +v -4.426174 3.393765 -0.105368 +v -4.198097 3.457761 -0.166481 +v -3.970020 3.393765 -0.227594 +v -3.803056 3.218926 -0.272332 +v -3.741943 2.980090 -0.288707 +v -3.803056 2.741255 -0.272332 +v -3.970020 2.566415 -0.227594 +v -4.198097 2.502419 -0.166481 +v -4.426174 2.566415 -0.105368 +v -4.593138 2.741255 -0.060630 +v -4.409542 2.980090 0.546525 +v -4.354750 3.218926 0.514891 +v -4.205054 3.393765 0.428463 +v -4.000566 3.457761 0.310402 +v -3.796077 3.393765 0.192341 +v -3.646381 3.218926 0.105914 +v -3.591589 2.980090 0.074279 +v -3.646381 2.741255 0.105914 +v -3.796077 2.566415 0.192341 +v -4.000566 2.502419 0.310402 +v -4.205054 2.566415 0.428463 +v -4.354750 2.741255 0.514890 +v -4.020267 2.980090 1.053839 +v -3.975529 3.218926 1.009101 +v -3.853302 3.393765 0.886875 +v -3.686338 3.457761 0.719911 +v -3.519374 3.393765 0.552947 +v -3.397148 3.218925 0.430721 +v -3.352410 2.980090 0.385983 +v -3.397148 2.741255 0.430721 +v -3.519374 2.566415 0.552947 +v -3.686338 2.502419 0.719911 +v -3.853302 2.566415 0.886875 +v -3.975529 2.741255 1.009101 +v -3.512952 2.980090 1.443116 +v -3.481318 3.218925 1.388323 +v -3.394891 3.393765 1.238627 +v -3.276829 3.457761 1.034139 +v -3.158768 3.393765 0.829650 +v -3.072341 3.218925 0.679954 +v -3.040706 2.980090 0.625162 +v -3.072341 2.741255 0.679954 +v -3.158768 2.566415 0.829650 +v -3.276829 2.502419 1.034139 +v -3.394890 2.566415 1.238627 +v -3.481318 2.741255 1.388323 +v -2.922173 2.980090 1.687824 +v -2.905797 3.218925 1.626711 +v -2.861059 3.393765 1.459747 +v -2.799946 3.457761 1.231670 +v -2.738833 3.393765 1.003593 +v -2.694095 3.218925 0.836629 +v -2.677720 2.980090 0.775516 +v -2.694095 2.741255 0.836629 +v -2.738833 2.566415 1.003593 +v -2.799946 2.502419 1.231670 +v -2.861059 2.566415 1.459747 +v -2.905797 2.741255 1.626711 +v -2.288187 2.980090 1.771290 +v -2.288187 3.218925 1.708021 +v -2.288187 3.393765 1.535167 +v -2.288187 3.457761 1.299045 +v -2.288187 3.393765 1.062922 +v -2.288187 3.218925 0.890068 +v -2.288187 2.980090 0.826799 +v -2.288187 2.741255 0.890068 +v -2.288187 2.566415 1.062922 +v -2.288187 2.502419 1.299044 +v -2.288187 2.566415 1.535168 +v -2.288187 2.741255 1.708021 +v -1.654203 2.980090 1.687825 +v -1.670578 3.218925 1.626712 +v -1.715316 3.393765 1.459748 +v -1.776429 3.457761 1.231670 +v -1.837542 3.393765 1.003593 +v -1.882280 3.218925 0.836629 +v -1.898655 2.980090 0.775516 +v -1.882280 2.741255 0.836629 +v -1.837542 2.566415 1.003593 +v -1.776429 2.502419 1.231670 +v -1.715316 2.566415 1.459748 +v -1.670578 2.741255 1.626711 +v -1.063423 2.980090 1.443116 +v -1.095057 3.218925 1.388323 +v -1.181484 3.393765 1.238627 +v -1.299545 3.457761 1.034139 +v -1.417607 3.393765 0.829651 +v -1.504034 3.218925 0.679955 +v -1.535668 2.980090 0.625162 +v -1.504034 2.741255 0.679955 +v -1.417607 2.566415 0.829651 +v -1.299545 2.502419 1.034139 +v -1.181484 2.566415 1.238627 +v -1.095057 2.741255 1.388323 +v -0.556108 2.980090 1.053840 +v -0.600846 3.218925 1.009102 +v -0.723073 3.393765 0.886876 +v -0.890037 3.457761 0.719912 +v -1.057000 3.393765 0.552948 +v -1.179226 3.218925 0.430722 +v -1.223964 2.980090 0.385984 +v -1.179227 2.741255 0.430722 +v -1.057000 2.566415 0.552948 +v -0.890037 2.502419 0.719912 +v -0.723073 2.566415 0.886876 +v -0.600846 2.741255 1.009102 +v -0.166832 2.980090 0.546525 +v -0.221625 3.218925 0.514891 +v -0.371320 3.393765 0.428464 +v -0.575809 3.457761 0.310403 +v -0.780297 3.393765 0.192341 +v -0.929993 3.218925 0.105914 +v -0.984786 2.980090 0.074280 +v -0.929993 2.741255 0.105914 +v -0.780297 2.566415 0.192341 +v -0.575809 2.502419 0.310403 +v -0.371321 2.566415 0.428464 +v -0.221625 2.741255 0.514891 +v 0.077878 2.980090 -0.044255 +v 0.016764 3.218926 -0.060630 +v -0.150200 3.393765 -0.105368 +v -0.378277 3.457761 -0.166481 +v -0.606354 3.393765 -0.227594 +v -0.773318 3.218925 -0.272332 +v -0.834431 2.980090 -0.288707 +v -0.773319 2.741255 -0.272332 +v -0.606354 2.566415 -0.227594 +v -0.378277 2.502419 -0.166481 +v -0.150200 2.566415 -0.105368 +v 0.016764 2.741255 -0.060631 +v 0.145156 3.103695 -0.678240 +v -1.212518 3.103694 0.397430 +v -1.084508 2.502419 0.890426 +v -0.433103 2.518792 -0.678240 +v -0.286679 3.317784 0.477332 +v 0.145156 2.856486 -0.678240 +v 0.140356 2.980090 -0.997964 +v -1.043981 3.218926 0.276474 +v -0.700759 3.317784 -1.103590 +v -0.469980 2.518792 0.371503 +v -0.561943 2.566415 -0.905504 +v -0.083596 3.218926 0.234931 +v -0.180851 3.103694 -1.894911 +v -0.818796 3.103694 -0.284518 +v -0.679584 3.393765 -1.344545 +v -0.461437 2.502419 0.078425 +v -0.681638 2.518792 -1.605781 +v -0.180850 2.856486 -1.894911 +v -0.344869 2.980090 -2.169400 +v -1.126110 3.317784 -1.840317 +v -0.906848 2.566415 -1.738179 +v -1.071516 3.103694 -2.785576 +v -1.228248 3.393765 -2.059579 +v -1.360645 2.518792 -2.284789 +v -1.071516 2.856486 -2.785577 +v -1.350804 2.980090 -2.941282 +v -1.862837 3.317784 -2.265667 +v -1.621882 2.566415 -2.286844 +v -2.288187 3.103694 -3.111582 +v -2.060923 3.393765 -2.404484 +v -2.288187 2.518792 -2.533323 +v -2.288187 2.856486 -3.111582 +v -2.607911 2.980090 -3.106783 +v -2.713537 3.317784 -2.265667 +v -2.515451 2.566415 -2.404483 +v -3.504858 3.103694 -2.785576 +v -2.954492 3.393765 -2.286843 +v -3.215729 2.518792 -2.284789 +v 0.077630 3.218925 -0.366774 +v -3.504858 2.856486 -2.785577 +v -3.779348 2.980090 -2.621558 +v -3.450265 3.317784 -1.840317 +v -3.348126 2.566415 -2.059579 +v -4.395524 3.103695 -1.894911 +v -3.669526 3.393765 -1.738178 +v -3.894736 2.518792 -1.605782 +v -4.395524 2.856486 -1.894912 +v -4.551229 2.980090 -1.615622 +v -3.875615 3.317784 -1.103590 +v -3.896791 2.566415 -1.344545 +v -4.721530 3.103695 -0.678240 +v -4.014431 3.393765 -0.905504 +v -4.143270 2.518792 -0.678240 +v -4.721530 2.856486 -0.678240 +v -4.716731 2.980090 -0.358516 +v -3.875615 3.317784 -0.252890 +v -4.014431 2.566415 -0.450976 +v -4.395524 3.103695 0.538431 +v -3.896791 3.393765 -0.011935 +v -3.894737 2.518792 0.249302 +v -4.395524 2.856486 0.538431 +v -4.231506 2.980090 0.812921 +v -3.450265 3.317784 0.483838 +v -3.669526 2.566415 0.381699 +v -3.504858 3.103695 1.429097 +v -3.348126 3.393765 0.703099 +v -3.215729 2.518792 0.928310 +v -3.504858 2.856486 1.429098 +v -3.225570 2.980090 1.584803 +v -2.713537 3.317784 0.909188 +v -0.327843 2.502419 -0.420156 +v -2.954493 2.566415 0.930364 +v -2.288187 3.103695 1.755103 +v -2.515452 3.393765 1.048005 +v -2.288187 2.518792 1.176844 +v -2.288187 2.856486 1.755103 +v -1.968464 2.980090 1.750304 +v -1.862838 3.317784 0.909188 +v -2.060923 2.566415 1.048005 +v -1.071516 3.103694 1.429097 +v -1.621882 3.393765 0.930364 +v -1.360646 2.518792 0.928310 +v -1.071516 2.856486 1.429098 +v -0.797027 2.980090 1.265079 +v -1.126110 3.317784 0.483839 +v 0.022956 3.317784 -0.678240 +v -1.228249 2.566415 0.703100 +v -0.180851 3.103694 0.538432 +v -0.188702 2.518792 -0.678239 +v -0.906848 3.393765 0.381700 +v 0.077630 3.218925 -0.989705 +v -0.681638 2.518792 0.249303 +v -0.818796 3.103695 -1.071962 +v -0.180850 2.856485 0.538432 +v -0.025145 2.980090 0.259143 +v -0.327843 2.502419 -0.936324 +v -0.700759 3.317784 -0.252890 +v -0.286679 3.317784 -1.833811 +v -0.679584 2.566415 -0.011934 +v -0.839278 3.218926 -1.278397 +v -0.469980 2.518792 -1.727982 +v -0.395062 3.218925 -2.130885 +v -1.212518 3.103694 -1.753909 +v -0.719522 2.502419 -1.881919 +v -1.132616 3.317784 -2.679747 +v -1.333474 3.218925 -1.922446 +v -1.238445 2.518792 -2.496447 +v -1.375016 3.218925 -2.882830 +v -1.894465 3.103694 -2.147631 +v -1.531523 2.502419 -2.504989 +v -2.288187 3.317784 -2.989382 +v -2.083484 3.218925 -2.233110 +v -2.288187 2.518792 -2.777725 +v -2.599653 3.218925 -3.044056 +v -2.681909 3.103695 -2.147631 +v -2.546271 2.502419 -2.638583 +v -3.443758 3.317784 -2.679748 +v -2.888345 3.218925 -2.127149 +v -3.337929 2.518792 -2.496447 +v -3.740833 3.218926 -2.571364 +v -3.363856 3.103695 -1.753908 +v -3.491866 2.502419 -2.246905 +v -4.289695 3.317784 -1.833811 +v -3.532393 3.218926 -1.632953 +v -4.106394 2.518792 -1.727982 +v -4.492777 3.218926 -1.591411 +v -3.757578 3.103695 -1.071962 +v -4.114937 2.502419 -1.434904 +v -4.599329 3.317784 -0.678240 +v -3.843058 3.218925 -0.882942 +v -4.387671 2.518792 -0.678240 +v -4.654004 3.218926 -0.366774 +v -0.561943 3.393765 -0.450975 +v -3.757578 3.103694 -0.284518 +v -4.248531 2.502419 -0.420156 +v -4.289695 3.317784 0.477331 +v -3.737097 3.218925 -0.078082 +v -4.106395 2.518792 0.371502 +v -4.181312 3.218926 0.774405 +v -3.363856 3.103695 0.397429 +v -3.856853 2.502419 0.525439 +v -3.443758 3.317784 1.323268 +v -3.242900 3.218925 0.565966 +v -3.337929 2.518792 1.139967 +v -3.201359 3.218926 1.526350 +v -2.681910 3.103694 0.791152 +v -3.044852 2.502419 1.148510 +v -2.288187 3.317784 1.632903 +v -2.492890 3.218926 0.876631 +v -2.288187 2.518792 1.421245 +v -1.976722 3.218925 1.687577 +v -1.894465 3.103695 0.791152 +v -2.030103 2.502419 1.282104 +v -1.132617 3.317784 1.323268 +v -1.688030 3.218925 0.770670 +v -1.238445 2.518792 1.139968 +v -0.835542 3.218925 1.214885 +v -0.188702 3.441388 -0.678240 +v -1.126110 2.642396 0.483839 +v -0.835542 2.741255 1.214885 +v 0.022955 2.642396 -0.678240 +v -0.681638 3.441388 0.249302 +v -0.093743 3.393765 -0.967144 +v -1.043981 2.741255 0.276474 +v -0.818796 2.856486 -1.071962 +v -0.093743 2.566415 -0.967144 +v -0.461437 3.457761 0.078425 +v -0.469980 3.441388 -1.727983 +v -0.700759 2.642396 -0.252890 +v -0.897730 2.980090 -1.254186 +v -0.083596 2.741255 0.234931 +v -0.286679 2.642396 -1.833811 +v -0.532195 3.393765 -2.025660 +v -1.212518 2.856486 -1.753909 +v -0.532195 2.566415 -2.025660 +v -1.238445 3.441388 -2.496447 +v -1.371989 2.980090 -1.872252 +v -1.132616 2.642396 -2.679747 +v -1.441164 3.393765 -2.723135 +v -1.894465 2.856486 -2.147631 +v -1.441163 2.566415 -2.723136 +v -2.288187 3.441388 -2.777724 +v -2.091743 2.980090 -2.170384 +v -2.288187 2.642396 -2.989382 +v -2.577091 3.393765 -2.872684 +v -2.681909 2.856486 -2.147631 +v -2.577091 2.566415 -2.872684 +v -3.337929 3.441388 -2.496447 +v -2.864133 2.980090 -2.068697 +v -3.443758 2.642396 -2.679747 +v -3.635607 3.393765 -2.434232 +v -3.363856 2.856486 -1.753909 +v -3.635607 2.566415 -2.434232 +v -4.106394 3.441388 -1.727982 +v -3.482200 2.980090 -1.594437 +v -4.289695 2.642396 -1.833811 +v -0.327843 3.457761 -0.420156 +v -4.333083 3.393765 -1.525263 +v -3.757578 2.856486 -1.071962 +v -4.333083 2.566415 -1.525263 +v -4.387672 3.441388 -0.678240 +v -3.780331 2.980090 -0.874684 +v -4.599330 2.642396 -0.678240 +v -4.482631 3.393765 -0.389336 +v -3.757578 2.856486 -0.284518 +v -4.482631 2.566415 -0.389336 +v -4.106395 3.441388 0.371502 +v -3.678644 2.980090 -0.102294 +v -4.289696 2.642396 0.477331 +v -4.044179 3.393765 0.669180 +v -3.363856 2.856486 0.397429 +v -4.044179 2.566415 0.669180 +v -3.337929 3.441388 1.139967 +v -3.204385 2.980090 0.515773 +v -3.443758 2.642396 1.323268 +v -3.135211 3.393765 1.366656 +v -2.681910 2.856486 0.791151 +v -3.135211 2.566415 1.366656 +v -2.288187 3.441388 1.421245 +v -2.484632 2.980090 0.813905 +v -2.288187 2.642396 1.632903 +v -1.999284 3.393765 1.516204 +v -1.894465 2.856486 0.791152 +v 0.077630 2.741255 -0.366774 +v -1.999284 2.566415 1.516204 +v -1.238445 3.441388 1.139968 +v -1.712241 2.980090 0.712218 +v -1.132616 2.642396 1.323268 +v -0.940767 3.393765 1.077753 +v -1.212518 2.856486 0.397430 +v -0.433103 3.441388 -0.678240 +v -0.940768 2.566415 1.077753 +v -0.469980 3.441388 0.371503 +v -1.094175 2.980090 0.237959 +v -0.327843 3.457761 -0.936324 +v -0.286679 2.642396 0.477332 +v -0.700759 2.642396 -1.103590 +v -0.243291 3.393765 0.168784 +v 0.077630 2.741255 -0.989705 +v -0.818796 2.856486 -0.284518 +v -0.681638 3.441388 -1.605782 +v -0.243291 2.566415 0.168784 +v -0.839278 2.741255 -1.278398 +v -0.719522 3.457761 -1.881919 +v -1.126109 2.642396 -1.840318 +v -0.395063 2.741255 -2.130885 +v -1.360645 3.441388 -2.284790 +v -1.333474 2.741255 -1.922446 +v -1.531523 3.457761 -2.504989 +v -1.862837 2.642396 -2.265667 +v -1.375016 2.741255 -2.882830 +v -2.288187 3.441388 -2.533323 +v -2.083484 2.741255 -2.233111 +v -2.546271 3.457761 -2.638584 +v -2.713537 2.642396 -2.265667 +v -2.599653 2.741255 -3.044056 +v -3.215729 3.441388 -2.284790 +v -2.888345 2.741255 -2.127149 +v -3.491867 3.457761 -2.246905 +v -3.450265 2.642396 -1.840317 +v -3.740833 2.741255 -2.571364 +v -3.894737 3.441388 -1.605781 +v -3.532394 2.741255 -1.632953 +v -4.114937 3.457761 -1.434904 +v -3.875615 2.642396 -1.103590 +v -4.492777 2.741255 -1.591411 +v -4.143271 3.441388 -0.678240 +v -3.843058 2.741255 -0.882942 +v -4.248531 3.457761 -0.420156 +v -3.875615 2.642396 -0.252890 +v -4.654004 2.741255 -0.366774 +v -3.894737 3.441388 0.249302 +v -3.737097 2.741255 -0.078082 +v -3.856853 3.457761 0.525439 +v -0.796043 2.980090 -0.481795 +v -3.450265 2.642396 0.483838 +v -4.181312 2.741255 0.774406 +v -3.215729 3.441388 0.928310 +v -3.242900 2.741255 0.565967 +v -3.044852 3.457761 1.148510 +v -2.713537 2.642396 0.909188 +v -3.201359 2.741255 1.526350 +v -2.288187 3.441388 1.176844 +v -2.492890 2.741255 0.876632 +v -2.030103 3.457761 1.282104 +v -1.862838 2.642396 0.909188 +v -1.976722 2.741255 1.687577 +v -1.360646 3.441388 0.928310 +v -1.688030 2.741255 0.770670 +v -1.084508 3.457761 0.890426 +v -1.333474 3.218925 0.565967 +v -0.644761 3.317784 -0.678239 +v -0.803628 2.518792 0.806321 +v -0.395063 3.218925 0.774406 +v 0.062242 3.103694 -1.308035 +v -0.970767 3.103694 0.082373 +v -0.561943 3.393765 -0.905504 +v -0.719522 2.502419 0.525440 +v -0.496314 2.518792 -1.158370 +v -0.055795 3.317784 -0.080072 +v 0.062242 2.856486 -1.308035 +v -0.025145 2.980090 -1.615622 +v -0.839278 3.218925 -0.078082 +v -0.864938 3.317784 -1.499953 +v -0.260241 2.518792 -0.134853 +v -0.679584 2.566415 -1.344545 +v -0.567554 3.103694 -2.398873 +v -0.906848 3.393765 -1.738179 +v -0.976445 2.518792 -1.989982 +v -0.567554 2.856486 -2.398873 +v -0.797027 2.980090 -2.621558 +v -1.466474 3.317784 -2.101489 +v -1.228248 2.566415 -2.059578 +v -1.658391 3.103694 -3.028668 +v -1.621882 3.393765 -2.286843 +v -1.808056 2.518792 -2.470113 +v -1.658391 2.856486 -3.028668 +v -1.968463 2.980090 -3.106782 +v -2.288187 3.317784 -2.321666 +v -2.060923 2.566415 -2.404483 +v -2.917982 3.103694 -3.028668 +v -2.515451 3.393765 -2.404484 +v -2.768318 2.518792 -2.470112 +v -2.917982 2.856486 -3.028668 +v -3.225570 2.980090 -2.941282 +v -3.109900 3.317784 -2.101489 +v -2.954492 2.566415 -2.286843 +v -4.008821 3.103695 -2.398873 +v -3.348126 3.393765 -2.059579 +v -3.599930 2.518792 -1.989982 +v -4.008821 2.856486 -2.398873 +v -4.231505 2.980090 -2.169401 +v -3.711436 3.317784 -1.499953 +v -3.669526 2.566415 -1.738178 +v -4.638616 3.103695 -1.308035 +v -3.896791 3.393765 -1.344545 +v -4.080060 2.518792 -1.158371 +v -4.638616 2.856486 -1.308035 +v -4.716731 2.980090 -0.997964 +v -3.931613 3.317784 -0.678240 +v -4.014431 2.566415 -0.905504 +v -4.638616 3.103695 -0.048444 +v -0.733316 3.218926 -0.473537 +v -4.014431 3.393765 -0.450975 +v -4.080060 2.518792 -0.198109 +v -4.638616 2.856486 -0.048445 +v -4.551229 2.980090 0.259143 +v -3.711436 3.317784 0.143473 +v -3.896791 2.566415 -0.011934 +v -4.008821 3.103695 1.042393 +v -3.669526 3.393765 0.381699 +v -3.599930 2.518792 0.633502 +v -4.008821 2.856486 1.042393 +v -3.779348 2.980090 1.265079 +v -3.109900 3.317784 0.745009 +v -3.348126 2.566415 0.703099 +v -2.917983 3.103694 1.672189 +v -2.954493 3.393765 0.930364 +v -2.768318 2.518792 1.113634 +v -2.917983 2.856486 1.672189 +v -2.607911 2.980090 1.750304 +v -2.288187 3.317784 0.965187 +v -2.515452 2.566415 1.048004 +v -1.658392 3.103694 1.672189 +v -2.060923 3.393765 1.048005 +v -1.808057 2.518792 1.113634 +v -1.658392 2.856486 1.672189 +v -1.350805 2.980090 1.584803 +v -1.466474 3.317784 0.745009 +v -1.621882 2.566415 0.930364 +v -0.567554 3.103694 1.042394 +v -1.228249 3.393765 0.703100 +v -0.976445 2.518792 0.633503 +v -0.766962 3.103694 -0.678240 +v -0.567554 2.856486 1.042394 +v -0.344869 2.980090 0.812922 +v -0.864938 3.317784 0.143474 +v -0.055794 3.317784 -1.276407 +v -0.906848 2.566415 0.381699 +v -0.733316 3.218925 -0.882942 +v 0.062242 3.103694 -0.048445 +v -0.260241 2.518792 -1.221626 +v -0.679584 3.393765 -0.011934 +v -0.083597 3.218925 -1.591411 +v -0.496314 2.518792 -0.198109 +v -0.970767 3.103694 -1.438852 +v 0.062242 2.856486 -0.048445 +v -0.461437 2.502419 -1.434904 +v -0.653963 3.317784 -2.312464 +v -1.043981 3.218926 -1.632953 +v -0.803627 2.518792 -2.162799 +v -0.835541 3.218926 -2.571364 +v -1.527574 3.103694 -1.995660 +v -1.084508 2.502419 -2.246905 +v -1.690020 3.317784 -2.910632 +v -1.688029 3.218925 -2.127149 +v -1.744800 2.518792 -2.706186 +v -1.976721 3.218925 -3.044055 +v -2.288187 3.103694 -2.199465 +v -2.030103 2.502419 -2.638584 +v -2.886354 3.317784 -2.910632 +v -2.492890 3.218925 -2.233111 +v -2.831573 2.518792 -2.706186 +v -3.201358 3.218925 -2.882830 +v -3.048800 3.103694 -1.995660 +v -3.044852 2.502419 -2.504990 +v 0.140357 2.980090 -0.358516 +v -3.922412 3.317784 -2.312464 +v -3.242900 3.218925 -1.922446 +v -3.772747 2.518792 -2.162799 +v -4.181312 3.218926 -2.130886 +v -3.605607 3.103695 -1.438853 +v -3.856853 2.502419 -1.881919 +v -4.520579 3.317784 -1.276407 +v -3.737096 3.218926 -1.278398 +v -4.316133 2.518792 -1.221626 +v -4.654004 3.218926 -0.989706 +v -3.809413 3.103695 -0.678240 +v -4.248531 2.502419 -0.936324 +v -4.520579 3.317784 -0.080072 +v -3.843058 3.218926 -0.473537 +v -4.316133 2.518792 -0.134853 +v -4.492777 3.218926 0.234931 +v -3.605607 3.103695 0.082373 +v -4.114937 2.502419 0.078424 +v -3.922412 3.317784 0.955985 +v -3.532394 3.218926 0.276473 +v -3.772747 2.518792 0.806320 +v -3.740833 3.218925 1.214885 +v -3.048800 3.103694 0.639180 +v -3.491867 2.502419 0.890426 +v -2.886355 3.317784 1.554152 +v -2.888345 3.218925 0.770670 +v -0.561943 2.566415 -0.450976 +v -2.831574 2.518792 1.349707 +v -2.599653 3.218925 1.687577 +v -2.288187 3.103694 0.842986 +v -2.546272 2.502419 1.282104 +v -1.690020 3.317784 1.554152 +v -2.083485 3.218925 0.876632 +v -1.744801 2.518792 1.349707 +v -1.375016 3.218925 1.526350 +v -1.527575 3.103694 0.639181 +v -1.531523 2.502419 1.148510 +v -0.653963 3.317784 0.955985 +v -0.976445 3.441388 0.633503 +v -1.333474 2.741255 0.565967 +v -0.766961 2.856486 -0.678240 +v -0.719522 3.457761 0.525440 +v -0.260240 3.441388 -1.221626 +v -0.864938 2.642396 0.143474 +v -0.796043 2.980090 -0.874684 +v -0.395063 2.741255 0.774406 +v -0.055795 2.642396 -1.276407 +v -0.496314 3.441388 -0.198109 +v -0.243291 3.393765 -1.525263 +v -0.839278 2.741255 -0.078082 +v -0.970767 2.856486 -1.438852 +v -0.243291 2.566415 -1.525264 +v -0.803627 3.441388 -2.162800 +v -1.094175 2.980090 -1.594438 +v -0.653963 2.642396 -2.312464 +v -0.940767 3.393765 -2.434231 +v -1.527574 2.856486 -1.995660 +v -0.940767 2.566415 -2.434231 +v -1.744800 3.441388 -2.706186 +v -1.712241 2.980090 -2.068697 +v -1.690019 2.642396 -2.910632 +v -1.999283 3.393765 -2.872684 +v -2.288187 2.856486 -2.199465 +v -1.999283 2.566415 -2.872683 +v -2.831573 3.441388 -2.706186 +v -2.484632 2.980090 -2.170384 +v -2.886354 2.642396 -2.910632 +v -3.135211 3.393765 -2.723135 +v -3.048800 2.856486 -1.995660 +v -3.135211 2.566415 -2.723135 +v -3.772747 3.441388 -2.162799 +v -3.204385 2.980090 -1.872252 +v -3.922412 2.642396 -2.312464 +v -4.044179 3.393765 -2.025660 +v -3.605607 2.856486 -1.438852 +v -4.044179 2.566415 -2.025660 +v -4.316133 3.441388 -1.221626 +v -3.678644 2.980090 -1.254186 +v -4.520579 2.642396 -1.276407 +v -4.482631 3.393765 -0.967144 +v -3.809413 2.856486 -0.678240 +v -4.482631 2.566415 -0.967144 +v -4.316133 3.441388 -0.134853 +v -3.780332 2.980090 -0.481795 +v -4.520579 2.642396 -0.080072 +v -4.333083 3.393765 0.168784 +v -3.605607 2.856486 0.082373 +v -4.333083 2.566415 0.168784 +v -3.772747 3.441388 0.806320 +v -0.733316 2.741255 -0.473537 +v -3.482200 2.980090 0.237958 +v -3.922412 2.642396 0.955984 +v -3.635607 3.393765 1.077752 +v -3.048800 2.856486 0.639180 +v -3.635607 2.566415 1.077752 +v -2.831574 3.441388 1.349707 +v -2.864133 2.980090 0.712217 +v -2.886355 2.642396 1.554152 +v -2.577091 3.393765 1.516204 +v -2.288187 2.856486 0.842986 +v -2.577091 2.566415 1.516204 +v -1.744801 3.441388 1.349707 +v -2.091743 2.980090 0.813905 +v -1.690020 2.642396 1.554152 +v -1.441164 3.393765 1.366656 +v -1.527575 2.856486 0.639181 +v -1.441164 2.566415 1.366657 +v -0.803628 3.441388 0.806321 +v -1.371989 2.980090 0.515773 +v -0.653963 2.642396 0.955985 +v -0.644761 2.642396 -0.678240 +v -0.532196 3.393765 0.669181 +v -0.970767 2.856486 0.082373 +v -0.496314 3.441388 -1.158371 +v -0.532195 2.566415 0.669181 +v -0.733316 2.741255 -0.882942 +v -0.260241 3.441388 -0.134853 +v -0.897730 2.980090 -0.102294 +v -0.461437 3.457761 -1.434904 +v -0.055795 2.642396 -0.080072 +v -0.864938 2.642396 -1.499953 +v -0.083597 2.741255 -1.591411 +v -0.976445 3.441388 -1.989982 +v -1.043981 2.741255 -1.632953 +v -1.084508 3.457761 -2.246905 +v -1.466474 2.642396 -2.101489 +v -0.835541 2.741255 -2.571364 +v -1.808056 3.441388 -2.470113 +v -1.688029 2.741255 -2.127149 +v -2.030103 3.457761 -2.638584 +v -2.288187 2.642396 -2.321666 +v -1.976721 2.741255 -3.044057 +v -2.768318 3.441388 -2.470113 +v -2.492890 2.741255 -2.233111 +v -3.044851 3.457761 -2.504989 +v -3.109900 2.642396 -2.101489 +v -3.201358 2.741255 -2.882830 +v -3.599930 3.441388 -1.989982 +v -3.242900 2.741255 -1.922446 +v -3.856853 3.457761 -1.881919 +v -3.711436 2.642396 -1.499953 +v -4.181312 2.741255 -2.130886 +v -0.093743 3.393765 -0.389336 +v -4.080060 3.441388 -1.158370 +v -3.737096 2.741255 -1.278397 +v -4.248531 3.457761 -0.936324 +v -3.931613 2.642396 -0.678240 +v -4.654004 2.741255 -0.989705 +v -4.080060 3.441388 -0.198109 +v -3.843058 2.741255 -0.473537 +v -4.114937 3.457761 0.078424 +v -3.711436 2.642396 0.143473 +v -4.492778 2.741255 0.234931 +v -3.599930 3.441388 0.633502 +v -3.532394 2.741255 0.276473 +v -3.491867 3.457761 0.890426 +v -3.109900 2.642396 0.745009 +v -3.740833 2.741255 1.214885 +v -2.768318 3.441388 1.113634 +v -2.888345 2.741255 0.770670 +v -2.546272 3.457761 1.282104 +v -2.288187 2.642396 0.965186 +v -2.599653 2.741255 1.687577 +v -1.808057 3.441388 1.113634 +v -2.083485 2.741255 0.876632 +v -0.093743 2.566415 -0.389336 +v -1.531523 3.457761 1.148510 +v -1.466474 2.642396 0.745009 +v -1.375017 2.741255 1.526350 +v 0.124308 3.103695 -0.995850 +v 0.003155 3.317784 -0.979900 +v -0.206690 3.441388 -0.952274 +v -0.448997 3.441388 -0.920374 +v -0.658841 3.317784 -0.892747 +v -0.779994 3.103694 -0.876797 +v -0.779994 2.856486 -0.876797 +v -0.658841 2.642396 -0.892747 +v -0.448997 2.518792 -0.920374 +v -0.206689 2.518792 -0.952274 +v 0.003155 2.642396 -0.979900 +v 0.124309 2.856486 -0.995850 +v -0.040099 3.103695 -1.609428 +v -0.152997 3.317784 -1.562665 +v -0.348540 3.441388 -1.481668 +v -0.574335 3.441388 -1.388141 +v -0.769878 3.317784 -1.307144 +v -0.882776 3.103694 -1.260380 +v -0.882775 2.856486 -1.260380 +v -0.769878 2.642396 -1.307144 +v -0.574335 2.518792 -1.388141 +v -0.348540 2.518792 -1.481668 +v -0.152996 2.642396 -1.562665 +v -0.040099 2.856486 -1.609428 +v -0.357710 3.103694 -2.159546 +v -0.454658 3.317784 -2.085156 +v -0.622575 3.441388 -1.956309 +v -0.816468 3.441388 -1.807529 +v -0.984386 3.317784 -1.678682 +v -1.081333 3.103694 -1.604292 +v -1.081333 2.856486 -1.604292 +v -0.984385 2.642396 -1.678682 +v -0.816468 2.518792 -1.807529 +v -0.622575 2.518792 -1.956309 +v -0.454657 2.642396 -2.085156 +v -0.357710 2.856486 -2.159547 +v -0.806880 3.103694 -2.608716 +v -0.881270 3.317784 -2.511769 +v -1.010118 3.441388 -2.343853 +v -1.158898 3.441388 -2.149959 +v -1.287745 3.317784 -1.982041 +v -1.362135 3.103694 -1.885094 +v -1.362135 2.856486 -1.885094 +v -1.287745 2.642396 -1.982041 +v -1.158898 2.518792 -2.149958 +v -1.010118 2.518792 -2.343852 +v -0.881270 2.642396 -2.511769 +v -0.806880 2.856486 -2.608716 +v -1.356999 3.103694 -2.926327 +v -1.403762 3.317784 -2.813430 +v -1.484759 3.441388 -2.617886 +v -1.578286 3.441388 -2.392092 +v -1.659283 3.317784 -2.196548 +v -1.706047 3.103694 -2.083652 +v -1.706046 2.856486 -2.083652 +v -1.659283 2.642396 -2.196548 +v -1.578286 2.518792 -2.392092 +v -1.484759 2.518792 -2.617887 +v -1.403762 2.642396 -2.813430 +v -1.356999 2.856486 -2.926328 +v -1.970576 3.103694 -3.090735 +v -1.986526 3.317784 -2.969581 +v -2.014153 3.441388 -2.759737 +v -2.046053 3.441388 -2.517429 +v -2.073679 3.317784 -2.307586 +v -2.089630 3.103694 -2.186432 +v -2.089630 2.856486 -2.186432 +v -2.073679 2.642396 -2.307586 +v -2.046053 2.518792 -2.517430 +v -2.014153 2.518792 -2.759737 +v -1.986526 2.642396 -2.969581 +v -1.970576 2.856486 -3.090735 +v -2.605798 3.103694 -3.090735 +v -2.589848 3.317784 -2.969582 +v -2.562221 3.441388 -2.759737 +v -2.530321 3.441388 -2.517429 +v -2.502694 3.317784 -2.307586 +v -2.486744 3.103694 -2.186432 +v -2.486744 2.856486 -2.186432 +v -2.502694 2.642396 -2.307586 +v -2.530321 2.518792 -2.517430 +v -2.562221 2.518792 -2.759737 +v -2.589848 2.642396 -2.969581 +v -2.605798 2.856486 -3.090735 +v -3.219375 3.103695 -2.926327 +v -3.172612 3.317784 -2.813429 +v -3.091615 3.441388 -2.617887 +v -2.998088 3.441388 -2.392092 +v -2.917091 3.317784 -2.196549 +v -2.870327 3.103694 -2.083652 +v -2.870327 2.856486 -2.083652 +v -2.917091 2.642396 -2.196548 +v -2.998088 2.518792 -2.392092 +v -3.091615 2.518792 -2.617886 +v -3.172612 2.642396 -2.813430 +v -3.219375 2.856486 -2.926328 +v -3.769494 3.103695 -2.608716 +v -3.695104 3.317784 -2.511769 +v -3.566257 3.441388 -2.343852 +v -3.417477 3.441388 -2.149958 +v -3.288629 3.317784 -1.982041 +v -3.214239 3.103694 -1.885094 +v -3.214239 2.856486 -1.885094 +v -3.288629 2.642396 -1.982041 +v -3.417476 2.518792 -2.149958 +v -3.566257 2.518792 -2.343852 +v -3.695104 2.642396 -2.511769 +v -3.769494 2.856486 -2.608716 +v -4.218664 3.103695 -2.159546 +v -4.121717 3.317784 -2.085156 +v -3.953800 3.441388 -1.956309 +v -3.759906 3.441388 -1.807529 +v -3.591988 3.317784 -1.678682 +v -3.495041 3.103694 -1.604291 +v -3.495041 2.856486 -1.604292 +v -3.591988 2.642396 -1.678682 +v -3.759906 2.518792 -1.807529 +v -3.953799 2.518792 -1.956309 +v -4.121717 2.642396 -2.085156 +v -4.218664 2.856486 -2.159546 +v -4.536275 3.103695 -1.609428 +v -4.423378 3.317784 -1.562664 +v -4.227834 3.441388 -1.481668 +v -4.002039 3.441388 -1.388141 +v -3.806496 3.317784 -1.307144 +v -3.693599 3.103695 -1.260380 +v -3.693599 2.856486 -1.260380 +v -3.806496 2.642396 -1.307144 +v -4.002040 2.518792 -1.388141 +v -4.227834 2.518792 -1.481668 +v -4.423378 2.642397 -1.562665 +v -4.536275 2.856486 -1.609428 +v -4.700683 3.103695 -0.995851 +v -4.579529 3.317784 -0.979900 +v -4.369685 3.441388 -0.952274 +v -4.127378 3.441388 -0.920374 +v -3.917533 3.317784 -0.892747 +v -3.796380 3.103695 -0.876797 +v -3.796380 2.856486 -0.876797 +v -3.917533 2.642396 -0.892747 +v -4.127378 2.518792 -0.920374 +v -4.369685 2.518792 -0.952274 +v -4.579529 2.642396 -0.979900 +v -4.700683 2.856486 -0.995851 +v -4.700683 3.103695 -0.360629 +v -4.579529 3.317784 -0.376579 +v -4.369685 3.441388 -0.404206 +v -4.127378 3.441388 -0.436106 +v -3.917533 3.317784 -0.463733 +v -3.796380 3.103694 -0.479683 +v -3.796380 2.856486 -0.479683 +v -3.917533 2.642396 -0.463733 +v -4.127378 2.518792 -0.436106 +v -4.369684 2.518792 -0.404205 +v -4.579529 2.642396 -0.376579 +v -4.700682 2.856486 -0.360629 +v -4.536275 3.103694 0.252948 +v -4.423378 3.317784 0.206185 +v -4.227834 3.441388 0.125188 +v -4.002040 3.441388 0.031661 +v -3.806496 3.317784 -0.049336 +v -3.693599 3.103695 -0.096099 +v -3.693599 2.856486 -0.096099 +v -3.806496 2.642396 -0.049336 +v -4.002040 2.518792 0.031661 +v -4.227834 2.518792 0.125188 +v -4.423378 2.642396 0.206185 +v -4.536275 2.856486 0.252948 +v -4.218664 3.103695 0.803067 +v -4.121717 3.317784 0.728677 +v -3.953800 3.441388 0.599829 +v -3.759906 3.441388 0.451049 +v -3.591989 3.317784 0.322202 +v -3.495042 3.103695 0.247812 +v -3.495042 2.856486 0.247812 +v -3.591989 2.642396 0.322202 +v -3.759906 2.518792 0.451049 +v -3.953800 2.518792 0.599830 +v -4.121717 2.642396 0.728677 +v -4.218664 2.856486 0.803067 +v -3.769494 3.103695 1.252237 +v -3.695104 3.317784 1.155290 +v -3.566257 3.441388 0.987373 +v -3.417477 3.441388 0.793479 +v -3.288629 3.317784 0.625561 +v -3.214239 3.103694 0.528615 +v -3.214239 2.856486 0.528615 +v -3.288629 2.642396 0.625562 +v -3.417476 2.518792 0.793479 +v -3.566257 2.518792 0.987373 +v -3.695104 2.642396 1.155290 +v -3.769494 2.856486 1.252237 +v -3.219376 3.103695 1.569848 +v -3.172612 3.317784 1.456951 +v -3.091615 3.441388 1.261407 +v -2.998088 3.441388 1.035613 +v -2.917091 3.317784 0.840069 +v -2.870328 3.103695 0.727172 +v -2.870328 2.856486 0.727172 +v -2.917091 2.642396 0.840069 +v -2.998088 2.518792 1.035613 +v -3.091615 2.518792 1.261407 +v -3.172612 2.642396 1.456951 +v -3.219376 2.856486 1.569848 +v -2.605798 3.103694 1.734255 +v -2.589848 3.317784 1.613102 +v -2.562222 3.441388 1.403258 +v -2.530321 3.441388 1.160950 +v -2.502695 3.317784 0.951106 +v -2.486745 3.103694 0.829953 +v -2.486744 2.856486 0.829953 +v -2.502695 2.642396 0.951106 +v -2.530321 2.518792 1.160951 +v -2.562222 2.518792 1.403258 +v -2.589848 2.642396 1.613102 +v -2.605798 2.856486 1.734256 +v -1.970577 3.103694 1.734256 +v -1.986527 3.317784 1.613102 +v -2.014153 3.441388 1.403258 +v -2.046053 3.441388 1.160950 +v -2.073680 3.317784 0.951107 +v -2.089630 3.103695 0.829953 +v -2.089630 2.856486 0.829953 +v -2.073680 2.642396 0.951106 +v -2.046053 2.518792 1.160951 +v -2.014153 2.518792 1.403258 +v -1.986527 2.642396 1.613102 +v -1.970577 2.856486 1.734256 +v -1.356999 3.103694 1.569848 +v -1.403763 3.317784 1.456951 +v -1.484759 3.441388 1.261407 +v -1.578287 3.441388 1.035613 +v -1.659283 3.317784 0.840069 +v -1.706047 3.103694 0.727172 +v -1.706047 2.856486 0.727172 +v -1.659283 2.642396 0.840070 +v -1.578287 2.518792 1.035613 +v -1.484760 2.518792 1.261407 +v -1.403763 2.642396 1.456951 +v -1.356999 2.856486 1.569849 +v -0.806881 3.103694 1.252238 +v -0.881271 3.317784 1.155291 +v -1.010118 3.441388 0.987373 +v -1.158898 3.441388 0.793479 +v -1.287746 3.317784 0.625562 +v -1.362135 3.103694 0.528615 +v -1.362135 2.856486 0.528615 +v -1.287745 2.642396 0.625562 +v -1.158898 2.518792 0.793479 +v -1.010118 2.518792 0.987373 +v -0.881271 2.642396 1.155290 +v -0.806880 2.856486 1.252237 +v -0.357711 3.103694 0.803068 +v -0.454658 3.317784 0.728678 +v -0.622575 3.441388 0.599830 +v -0.816469 3.441388 0.451050 +v -0.984386 3.317784 0.322203 +v -1.081333 3.103694 0.247813 +v -1.081333 2.856486 0.247813 +v -0.984386 2.642396 0.322203 +v -0.816469 2.518792 0.451050 +v -0.622575 2.518792 0.599831 +v -0.454658 2.642396 0.728678 +v -0.357711 2.856486 0.803068 +v -0.040099 3.103694 0.252949 +v -0.152997 3.317784 0.206185 +v -0.348540 3.441388 0.125188 +v -0.574335 3.441388 0.031661 +v -0.769878 3.317784 -0.049335 +v -0.882775 3.103694 -0.096099 +v -0.882775 2.856486 -0.096099 +v -0.769878 2.642396 -0.049336 +v -0.574335 2.518792 0.031661 +v -0.348540 2.518792 0.125188 +v -0.152997 2.642396 0.206185 +v -0.040099 2.856486 0.252949 +v 0.124308 3.103694 -0.360629 +v 0.003155 3.317784 -0.376579 +v -0.206690 3.441388 -0.404206 +v -0.448997 3.441388 -0.436106 +v -0.658841 3.317784 -0.463732 +v -0.779994 3.103694 -0.479683 +v -0.779994 2.856486 -0.479683 +v -0.658841 2.642396 -0.463732 +v -0.448997 2.518792 -0.436106 +v -0.206689 2.518792 -0.404205 +v 0.003155 2.642396 -0.376579 +v 0.124308 2.856486 -0.360629 +v -2.265895 3.034201 3.882286 +v -2.207377 3.179999 3.794987 +v -2.240914 3.332677 3.708092 +v -2.357521 3.451325 3.644885 +v -2.525951 3.504153 3.622303 +v -2.701076 3.477004 3.646395 +v -2.835969 3.377153 3.710707 +v -2.894487 3.231355 3.798007 +v -2.860950 3.078677 3.884902 +v -2.744343 2.960029 3.948108 +v -2.575912 2.907202 3.970691 +v -2.400788 2.934350 3.946598 +v -2.335296 2.833436 3.468462 +v -2.274986 2.984420 3.391851 +v -2.303625 3.151265 3.334159 +v -2.413542 3.289266 3.310843 +v -2.575283 3.361446 3.328151 +v -2.745510 3.348464 3.381445 +v -2.878611 3.253799 3.456446 +v -2.938921 3.102816 3.533057 +v -2.910281 2.935971 3.590750 +v -2.800364 2.797969 3.614066 +v -2.638623 2.725789 3.596758 +v -2.468397 2.738771 3.543463 +v -2.500724 2.706967 3.052515 +v -2.436141 2.861217 2.986647 +v -2.453107 3.036987 2.958306 +v -2.547077 3.187179 2.975085 +v -2.692872 3.271550 3.032489 +v -2.851425 3.267492 3.115135 +v -2.980253 3.176094 3.200880 +v -3.044836 3.021844 3.266747 +v -3.027869 2.846075 3.295088 +v -2.933899 2.695882 3.278308 +v -2.788105 2.611511 3.220905 +v -2.629552 2.615569 3.138259 +v -2.750905 2.663413 2.662789 +v -2.679860 2.818787 2.606988 +v -2.679172 2.997631 2.606149 +v -2.749025 3.152021 2.660495 +v -2.870704 3.240591 2.755466 +v -3.011603 3.239607 2.865614 +v -3.133969 3.149333 2.961425 +v -3.205014 2.993958 3.017226 +v -3.205702 2.815115 3.018065 +v -3.135848 2.660725 2.963719 +v -3.014170 2.572155 2.868748 +v -2.873271 2.573139 2.758600 +v -3.068789 2.705741 2.325845 +v -2.989533 2.860022 2.278748 +v -2.966413 3.035878 2.301685 +v -3.005625 3.186189 2.388511 +v -3.096660 3.270678 2.515962 +v -3.215127 3.266707 2.649887 +v -3.329283 3.175340 2.754400 +v -3.408539 3.021059 2.801498 +v -3.431659 2.845203 2.778561 +v -3.392447 2.694892 2.691734 +v -3.301411 2.610403 2.564284 +v -3.182944 2.614374 2.430359 +v -3.432714 2.831067 2.064645 +v -3.344058 2.982111 2.024294 +v -3.295257 3.149123 2.065663 +v -3.299388 3.287353 2.177668 +v -3.355343 3.359761 2.330297 +v -3.448130 3.346947 2.482654 +v -3.552885 3.252343 2.593914 +v -3.641541 3.101299 2.634265 +v -3.690341 2.934286 2.592896 +v -3.686210 2.796057 2.480891 +v -3.630255 2.723648 2.328262 +v -3.537469 2.736463 2.175905 +v -3.817877 3.030850 1.896989 +v -3.719273 3.176734 1.860968 +v -3.643293 3.329648 1.914168 +v -3.610296 3.448620 2.042334 +v -3.629123 3.501770 2.211125 +v -3.694730 3.474858 2.375312 +v -3.789537 3.375093 2.490902 +v -3.888141 3.229209 2.526924 +v -3.964121 3.076295 2.473724 +v -3.997118 2.957324 2.345557 +v -3.978292 2.904173 2.176767 +v -3.912684 2.931086 2.012580 +v -4.198032 3.291475 1.834303 +v -4.089609 3.430628 1.799901 +v -3.986803 3.565151 1.857524 +v -3.917161 3.658999 1.991733 +v -3.899343 3.687027 2.166566 +v -3.938124 3.641723 2.335177 +v -4.023112 3.535227 2.452387 +v -4.131535 3.396075 2.486789 +v -4.234341 3.261551 2.429165 +v -4.303983 3.167703 2.294956 +v -4.321801 3.139676 2.120123 +v -4.283020 3.184979 1.951512 +v -4.547272 3.595182 1.880857 +v -4.429829 3.726490 1.845253 +v -4.302378 3.839582 1.899591 +v -4.199070 3.904154 2.029313 +v -4.147588 3.902906 2.199658 +v -4.161724 3.836171 2.364984 +v -4.237691 3.721830 2.480991 +v -4.355135 3.590522 2.516595 +v -4.482585 3.477431 2.462257 +v -4.585893 3.412858 2.332536 +v -4.637376 3.414107 2.162190 +v -4.623240 3.480842 1.996864 +v -4.841795 3.921273 2.033481 +v -4.716744 4.044158 1.993935 +v -4.568511 4.134239 2.037503 +v -4.436813 4.167378 2.152512 +v -4.356939 4.134696 2.308145 +v -4.350292 4.044950 2.462701 +v -4.418653 3.922187 2.574766 +v -4.543703 3.799302 2.614313 +v -4.691937 3.709221 2.570744 +v -4.823635 3.676082 2.455735 +v -4.903508 3.708764 2.300102 +v -4.910156 3.798510 2.145546 +v -5.061532 4.247525 2.281773 +v -4.930805 4.361984 2.235813 +v -4.767065 4.429042 2.261860 +v -4.614186 4.430732 2.352935 +v -4.513131 4.366601 2.484634 +v -4.490978 4.253832 2.621669 +v -4.553662 4.122643 2.727321 +v -4.684389 4.008184 2.773281 +v -4.848129 3.941126 2.747233 +v -5.001008 3.939436 2.656158 +v -5.102063 4.003567 2.524459 +v -5.124216 4.116336 2.387424 +v -5.191506 4.551706 2.608811 +v -5.057422 4.658308 2.554405 +v -4.884511 4.703901 2.557374 +v -4.719102 4.676270 2.616924 +v -4.605518 4.582817 2.717098 +v -4.574193 4.448584 2.831055 +v -4.633521 4.309537 2.928260 +v -4.767605 4.202935 2.982667 +v -4.940516 4.157341 2.979697 +v -5.105925 4.184973 2.920147 +v -5.219509 4.278426 2.819973 +v -5.250834 4.412660 2.706016 +v -5.222861 4.813085 2.992310 +v -5.087968 4.912935 2.927998 +v -4.912843 4.940084 2.903905 +v -4.744412 4.887257 2.926488 +v -4.627806 4.768609 2.989695 +v -4.594269 4.615931 3.076589 +v -4.652786 4.470133 3.163889 +v -4.787680 4.370282 3.228201 +v -4.962804 4.343133 3.252294 +v -5.131235 4.395961 3.229711 +v -5.247841 4.514609 3.166504 +v -5.281379 4.667287 3.079609 +v -5.153460 5.013849 3.406134 +v -5.020359 5.108515 3.331133 +v -4.850132 5.121496 3.277838 +v -4.688391 5.049316 3.260530 +v -4.578475 4.911315 3.283847 +v -4.549835 4.744470 3.341539 +v -4.610145 4.593487 3.418150 +v -4.743246 4.498821 3.493151 +v -4.913473 4.485840 3.546446 +v -5.075213 4.558020 3.563754 +v -5.185130 4.696021 3.540437 +v -5.213770 4.862866 3.482745 +v -4.988032 5.140318 3.822082 +v -4.859204 5.231717 3.736337 +v -4.700651 5.235775 3.653691 +v -4.554856 5.151403 3.596287 +v -4.460886 5.001211 3.579508 +v -4.443920 4.825441 3.607849 +v -4.508503 4.671192 3.673717 +v -4.637331 4.579793 3.759461 +v -4.795884 4.575736 3.842107 +v -4.941679 4.660107 3.899510 +v -5.035648 4.810299 3.916290 +v -5.052615 4.986069 3.887949 +v -4.737851 5.183873 4.211807 +v -4.615485 5.274147 4.115996 +v -4.474586 5.275131 4.005848 +v -4.352908 5.186561 3.910878 +v -4.283054 5.032170 3.856531 +v -4.283742 4.853327 3.857370 +v -4.354787 4.697953 3.913171 +v -4.477153 4.607679 4.008982 +v -4.618052 4.606695 4.119130 +v -4.739730 4.695265 4.214101 +v -4.809584 4.849655 4.268447 +v -4.808896 5.028499 4.267608 +v -4.419967 5.141545 4.548751 +v -4.305811 5.232912 4.444237 +v -4.187344 5.236883 4.310313 +v -4.096309 5.152393 4.182862 +v -4.057097 5.002083 4.096035 +v -4.080217 4.826227 4.073098 +v -4.159472 4.671946 4.120196 +v -4.273628 4.580579 4.224710 +v -4.392095 4.576608 4.358634 +v -4.483131 4.661097 4.486085 +v -4.522342 4.811408 4.572912 +v -4.499222 4.987264 4.595849 +v -4.056042 5.016219 4.809951 +v -3.951287 5.110823 4.698690 +v -3.858500 5.123638 4.546334 +v -3.802545 5.051229 4.393705 +v -3.798414 4.913000 4.281700 +v -3.847215 4.745987 4.240331 +v -3.935870 4.594943 4.280683 +v -4.040626 4.500339 4.391943 +v -4.133412 4.487525 4.544299 +v -4.189367 4.559933 4.696928 +v -4.193498 4.698163 4.808933 +v -4.144698 4.865175 4.850302 +v -3.670878 4.816436 4.977607 +v -3.576071 4.916200 4.862017 +v -3.510464 4.943113 4.697829 +v -3.491637 4.889962 4.529039 +v -3.524634 4.770991 4.400873 +v -3.600614 4.618076 4.347673 +v -3.699218 4.472192 4.383694 +v -3.794025 4.372428 4.499284 +v -3.859632 4.345515 4.663472 +v -3.878459 4.398666 4.832262 +v -3.845462 4.517637 4.960428 +v -3.769482 4.670552 5.013628 +v -3.290723 4.555811 5.040294 +v -3.205735 4.662307 4.923084 +v -3.166955 4.707611 4.754473 +v -3.184772 4.679584 4.579640 +v -3.254415 4.585734 4.445431 +v -3.357221 4.451211 4.387808 +v -3.465644 4.312059 4.422210 +v -3.550632 4.205564 4.539419 +v -3.589413 4.160259 4.708031 +v -3.571595 4.188287 4.882863 +v -3.501952 4.282135 5.017072 +v -3.399146 4.416658 5.074696 +v -2.941484 4.252104 4.993739 +v -2.865516 4.366444 4.877732 +v -2.851380 4.433179 4.712406 +v -2.902863 4.434428 4.542060 +v -3.006170 4.369855 4.412340 +v -3.133621 4.256763 4.358001 +v -3.251064 4.125456 4.393606 +v -3.327032 4.011116 4.509613 +v -3.341168 3.944380 4.674938 +v -3.289685 3.943131 4.845284 +v -3.186378 4.007704 4.975005 +v -3.058927 4.120796 5.029344 +v -2.646960 3.926013 4.841116 +v -2.578600 4.048776 4.729051 +v -2.585247 4.138522 4.574495 +v -2.665121 4.171205 4.418862 +v -2.796819 4.138065 4.303853 +v -2.945053 4.047985 4.260284 +v -3.070103 3.925099 4.299831 +v -3.138464 3.802336 4.411896 +v -3.131817 3.712590 4.566452 +v -3.051943 3.679908 4.722085 +v -2.920245 3.713047 4.837093 +v -2.772011 3.803128 4.880662 +v -2.427224 3.599761 4.592824 +v -2.364539 3.730950 4.487172 +v -2.386693 3.843719 4.350137 +v -2.487747 3.907850 4.218438 +v -2.640627 3.906160 4.127363 +v -2.804367 3.839102 4.101316 +v -2.935093 3.724643 4.147275 +v -2.997778 3.593454 4.252927 +v -2.975625 3.480685 4.389962 +v -2.874570 3.416554 4.521661 +v -2.721690 3.418244 4.612736 +v -2.557950 3.485302 4.638783 +v -2.297249 3.295580 4.265785 +v -2.237922 3.434626 4.168580 +v -2.269247 3.568860 4.054623 +v -2.382831 3.662313 3.954449 +v -2.548239 3.689944 3.894899 +v -2.721151 3.644351 3.891930 +v -2.855234 3.537749 3.946336 +v -2.914562 3.398703 4.043541 +v -2.883237 3.264469 4.157498 +v -2.769653 3.171016 4.257672 +v -2.604245 3.143384 4.317222 +v -2.431333 3.188978 4.320191 +v -2.225617 3.103644 3.840114 +v -3.012803 3.988680 4.269876 +v -3.164206 3.812670 4.793979 +v -2.811471 3.012820 3.920712 +v -2.364904 3.791722 4.420359 +v -2.325713 2.976514 3.918577 +v -2.288155 2.925290 3.677426 +v -2.868049 3.942657 4.187860 +v -2.662270 3.365870 3.351024 +v -2.802231 3.408816 4.574111 +v -2.876772 3.001262 3.739284 +v -2.289629 3.578793 4.336203 +v -2.458894 2.778573 3.015826 +v -2.795623 3.597164 3.912580 +v -2.625954 3.309433 3.179237 +v -2.812498 3.290474 4.396566 +v -2.989313 2.764999 3.292308 +v -2.558990 2.651442 3.094289 +v -2.616176 2.674519 2.852657 +v -2.941108 3.251799 2.810485 +v -3.109935 2.823010 3.153026 +v -3.023205 2.777354 2.293959 +v -2.978571 3.248045 2.629939 +v -3.419521 2.764070 2.741985 +v -3.123301 2.650223 2.372422 +v -3.246498 2.758450 2.184543 +v -3.398544 3.364280 2.409182 +v -3.557976 2.882669 2.678121 +v -3.767344 3.100315 1.867936 +v -3.491504 3.424686 2.261790 +v -3.986823 3.010283 2.417203 +v -3.867440 2.973184 1.946400 +v -4.010226 3.154593 1.852104 +v -3.912008 3.673175 2.254642 +v -4.100845 3.164253 2.441818 +v -4.491918 3.660918 1.851911 +v -4.027313 3.792025 2.173437 +v -4.539209 3.437664 2.404986 +v -2.210371 3.300944 3.987128 +v -4.592014 3.533787 1.930374 +v -4.702721 3.756803 1.944416 +v -4.343918 4.095716 2.388273 +v -4.593081 3.592313 2.507435 +v -5.002779 4.308950 2.250177 +v -4.442429 4.251633 2.388552 +v -4.928669 3.931698 2.708608 +v -5.102876 4.181820 2.328640 +v -5.138428 4.403717 2.436745 +v -4.578544 4.518683 2.774271 +v -4.902788 4.052149 2.857390 +v -5.163043 4.870772 2.956019 +v -4.625621 4.680360 2.849497 +v -5.050848 4.360008 3.246714 +v -5.263139 4.743642 3.034482 +v -5.200601 4.921996 3.197171 +v -4.553018 4.828742 3.309206 +v -4.946981 4.420549 3.397912 +v -4.929766 5.195844 3.780307 +v -4.527804 4.963327 3.432760 +v -4.873007 4.607830 3.875118 +v -5.029861 5.068713 3.858770 +v -4.872580 5.172767 4.021939 +v -4.274180 4.942813 3.849744 +v -4.713819 4.598801 3.984169 +v -4.365454 5.197062 4.502174 +v -4.175187 5.024715 3.982058 +v -4.442798 4.608759 4.425441 +v -4.465550 5.069932 4.580638 +v -4.242258 5.088836 4.690053 +v -3.816744 4.830332 4.251048 +v -2.746824 3.060245 4.107319 +v -4.265777 4.539142 4.459074 +v -3.621316 4.874102 4.928197 +v -3.662254 4.848075 4.350207 +v -3.875496 4.362547 4.750223 +v -3.721412 4.746971 5.006660 +v -3.478530 4.692693 5.022492 +v -3.303280 4.521437 4.405589 +v -3.722908 4.257558 4.695376 +v -2.896741 4.313498 4.944222 +v -3.126444 4.480737 4.438560 +v -3.323110 3.935165 4.762440 +v -2.996837 4.186368 5.022686 +v -2.786035 4.090484 4.930181 +v -2.871371 4.098897 4.271957 +v -2.212688 3.258114 3.749963 +v -3.230673 3.829498 4.629760 +v -2.385880 3.665466 4.545956 +v -2.663956 2.924077 3.965111 +v -2.711329 4.021129 4.223445 +v -2.229062 3.073901 3.595417 +v -2.933650 3.441131 4.458818 +v -2.819251 3.310160 3.417420 +v -2.485976 3.538336 4.624419 +v -2.350328 3.443569 4.437851 +v -2.762312 2.872114 3.782743 +v -2.636744 3.675929 3.885959 +v -2.434251 2.949367 2.967070 +v -2.920966 3.369662 4.279806 +v -2.791150 3.301615 3.247315 +v -2.865227 2.643606 3.253916 +v -2.548611 2.829607 2.791952 +v -3.077356 3.204570 2.917075 +v -3.027094 2.669690 3.116982 +v -2.970223 2.948210 2.281454 +v -3.108761 3.246321 2.752549 +v -3.352114 2.642554 2.631090 +v -3.162652 2.911370 2.141095 +v -3.500777 3.308688 2.545611 +v -3.535896 2.737439 2.577674 +v -3.676991 3.254952 1.876827 +v -3.570773 3.405426 2.420948 +v -3.994156 2.921204 2.263519 +v -3.906654 3.297281 1.817242 +v -3.976062 3.594615 2.402562 +v -4.152384 3.057210 2.309326 +v -4.365178 3.787402 1.861606 +v -4.053390 3.736297 2.341366 +v -4.619318 3.404892 2.249692 +v -4.581262 3.883936 1.907170 +v -4.375856 3.985736 2.526258 +v -4.711372 3.543319 2.383841 +v -4.850384 4.402891 2.239872 +v -4.427295 4.150278 2.535125 +v -5.060088 3.964013 2.593316 +v -5.005715 4.514141 2.386782 +v -4.593036 4.377253 2.883554 +v -5.063080 4.065515 2.781253 +v -5.002600 4.936498 2.910267 +v -4.592301 4.536443 2.950310 +v -5.198363 4.448752 3.202315 +v -5.066282 5.019033 3.127567 +v -2.528136 3.592401 3.762500 +v -4.569408 4.664256 3.378713 +v -5.113266 4.483875 3.395077 +v -4.781037 5.245245 3.693160 +v -4.504194 4.791319 3.475670 +v -4.997092 4.729224 3.913510 +v -4.746734 5.263328 3.931032 +v -4.311304 4.769846 3.879057 +v -4.848485 4.686299 4.060837 +v -4.245065 5.246402 4.378776 +v -4.186583 4.846612 3.970437 +v -4.510205 4.730275 4.536336 +v -4.132692 5.181565 4.581890 +v -3.887882 4.665728 4.250522 +v -4.339683 4.618550 4.600146 +v -3.538297 4.939660 4.783403 +v -3.724571 4.687508 4.302037 +v -3.868163 4.451625 4.903907 +v -3.388691 4.795653 4.905743 +v -3.412598 4.379802 4.393571 +v -3.723194 4.298779 4.868494 +v -2.850110 4.407210 4.798624 +v -3.241955 4.356637 4.381619 +v -3.243001 3.967937 4.917734 +v -2.714083 4.208999 4.815815 +v -2.290392 3.398533 3.672281 +v -3.144838 3.751570 4.486323 +v -2.907494 3.963350 4.967427 +v -2.486156 2.910788 3.964329 +v -2.560086 3.915588 4.165988 +v -2.261029 3.234264 3.522979 +v -3.061461 3.697008 4.339471 +v -2.919347 3.183030 3.495884 +v -2.596027 2.808789 3.785578 +v -2.425676 3.781771 4.093343 +v -2.491664 3.118062 2.961086 +v -2.910212 3.328603 4.100325 +v -2.922410 3.208840 3.327727 +v -2.483040 3.333145 4.487814 +v -2.707718 2.602041 3.181436 +v -2.557430 3.007666 2.777714 +v -3.177452 3.077440 2.995538 +v -2.892428 2.582191 3.040313 +v -2.978551 3.117011 2.338260 +v -3.227208 3.155777 2.852920 +v -3.243690 2.600883 2.495821 +v -3.126992 3.083506 2.174003 +v -3.600874 3.181558 2.624075 +v -3.461990 2.658031 2.436602 +v -3.620592 3.395661 1.970689 +v -3.670581 3.308463 2.534697 +v -3.950459 2.907625 2.091193 +v -3.817101 3.441463 1.873610 +v -4.076158 3.467484 2.481025 +v -4.152099 3.015988 2.136209 +v -4.245754 3.879349 1.956862 +v -4.133728 3.625986 2.458325 +v -4.638646 3.440076 2.075973 +v -4.442842 3.985623 1.957023 +v -4.475952 3.858606 2.604721 +v -4.777840 3.560148 2.219622 +v -4.686524 4.438470 2.300486 +v -4.492549 4.023266 2.644269 +v -5.123852 4.055564 2.454238 +v -2.360002 3.551542 3.804096 +v -4.836549 4.570177 2.401894 +v -4.693132 4.250122 2.962017 +v -5.171547 4.144702 2.664493 +v -4.824800 4.923209 2.909485 +v -4.650898 4.393852 3.042703 +v -5.276067 4.589172 3.124633 +v -4.892729 5.038497 3.089018 +v -4.669505 4.537126 3.457176 +v -5.227727 4.613022 3.351617 +v -4.623528 5.203680 3.620680 +v -4.566346 4.638446 3.546870 +v -5.054505 4.897919 3.907526 +v -4.596327 5.265095 3.834282 +v -4.411400 4.642715 3.957521 +v -4.931325 4.839620 4.096881 +v -4.136641 5.204732 4.243506 +v -4.261548 4.691509 4.021676 +v -4.518533 4.899076 4.593142 +v -4.026766 5.189255 4.437994 +v -3.987978 4.538598 4.328985 +v -4.361763 4.763780 4.700593 +v -3.494600 4.926082 4.611077 +v -3.818175 4.538823 4.339899 +v -3.811764 4.592334 4.997770 +v -3.336657 4.831298 4.738389 +v -3.512694 4.252671 4.472034 +v -2.403782 3.055295 4.138740 +v -3.671655 4.405823 5.000987 +v -2.869438 4.442394 4.624904 +v -3.355028 4.221300 4.416271 +v -3.123577 4.059884 5.012990 +v -2.710916 4.287139 4.654974 +v -3.112899 3.861550 4.348340 +v -2.437908 3.487277 3.627883 +v -3.045914 3.861664 4.917573 +v -2.428668 3.883273 4.281281 +v -2.996207 3.824020 4.230328 +v -2.375489 3.363411 3.479520 +v -2.638371 3.444395 4.634725 +v -2.935737 3.018544 3.565390 +v -2.317208 3.702584 4.210104 +v -2.422473 2.828252 3.747029 +v -2.895719 3.470033 3.991043 +v -2.615749 3.239455 2.999478 +v -2.652206 3.277108 4.472703 +v -2.984561 3.055967 3.398926 +v -2.640271 3.160986 2.813759 +v -3.214576 2.904473 3.024851 +v -2.742022 2.583958 2.943564 +v -3.045958 3.238527 2.449155 +v -3.302172 3.000673 2.904160 +v -3.149073 3.228736 2.274451 +v -3.672011 3.016954 2.623548 +v -3.356063 2.665721 2.292706 +v -3.613259 3.484739 2.124373 +v -3.764184 3.159778 2.572560 +v -3.765562 3.548506 2.006103 +v -4.185475 3.325849 2.469007 +v -4.100065 3.051632 1.968854 +v -4.165646 3.912121 2.112156 +v -4.246801 3.490649 2.492977 +v -4.324550 4.034616 2.080617 +v -4.617385 3.748390 2.602640 +v -4.774673 3.638288 2.058781 +v -4.555106 4.406155 2.415778 +v -4.620706 3.904630 2.686737 +v -4.676257 4.556811 2.478030 +v -4.852011 4.171356 2.988637 +v -5.199126 4.268493 2.538393 +v -4.677284 4.834466 2.953884 +v -4.785712 4.290794 3.101921 +v -4.726443 4.975171 3.091853 +v -4.826486 4.481416 3.523573 +v -5.259693 4.773385 3.279179 +v -4.499443 5.082287 3.582288 +v -4.697605 4.545671 3.627281 +v -4.461662 5.177596 3.757614 +v -2.837857 3.453434 3.831893 +v -4.547647 4.595487 4.064111 +v -4.940145 5.017679 4.082644 +v -4.069234 5.083216 4.132612 +v -4.379994 4.600965 4.122048 +v -3.952860 5.109847 4.296922 +v -4.090212 4.483006 4.465415 +v -4.326104 4.935916 4.733501 +v -3.501933 4.837004 4.457394 +v -3.917983 4.441860 4.453648 +v -3.336371 4.790076 4.565271 +v -3.576748 4.174110 4.619955 +v -3.582102 4.550005 5.057354 +v -2.949546 4.409622 4.469611 +v -3.435366 4.110989 4.533231 +v -2.777383 4.303967 4.490756 +v -3.034095 4.153287 4.317308 +v -2.615708 3.500566 3.628664 +v -2.990566 3.688446 4.786921 +v -2.461436 3.888514 4.618853 +v -2.294559 2.904206 3.429025 +v -2.876341 3.786068 4.115680 +v -2.541775 3.426737 3.476685 +v -2.954859 3.547113 4.630774 +v -2.864030 2.860777 3.607315 +v -2.242272 3.504726 4.111796 +v -2.394655 2.777076 3.507488 +v -2.406581 2.760263 3.258965 +v -2.755134 3.739100 4.002095 +v -2.773258 3.281020 3.071958 +v -2.690830 3.148104 4.293807 +v -2.960952 2.883958 3.441836 +v -2.707422 2.735306 2.628675 +v -2.774937 3.248485 2.890428 +v -3.178780 2.732014 2.997160 +v -2.807518 2.608176 2.707139 +v -2.902656 2.673901 2.486192 +v -3.154381 3.280197 2.584425 +v -3.313569 2.822570 2.892538 +v -3.384725 2.901852 2.034484 +v -3.222979 3.308144 2.415523 +v -3.695129 2.858982 2.544172 +v -3.484821 2.774721 2.112948 +v -3.624269 2.922405 1.968268 +v -3.656956 3.498318 2.296699 +v -3.826502 2.999211 2.524389 +v -4.144987 3.359218 1.805664 +v -3.765848 3.589729 2.179219 +v -4.274722 3.207660 2.369729 +v -4.245083 3.232088 1.884127 +v -4.378066 3.439190 1.843968 +v -4.146317 3.876937 2.285876 +v -4.362311 3.366549 2.436036 +v -4.784495 3.984854 2.003526 +v -4.258083 4.017788 2.244836 +v -4.762259 3.684620 2.520571 +v -4.884592 3.857724 2.081990 +v -4.962066 4.085784 2.146601 +v -4.491342 4.314603 2.554856 +v -4.777427 3.826158 2.651151 +v -5.131895 4.611121 2.575054 +v -4.567790 4.477624 2.594790 +v -5.027102 4.162061 2.956282 +v -5.231991 4.483990 2.653518 +v -5.219788 4.688933 2.795074 +v -4.599580 4.694046 3.031566 +v -4.960619 4.254885 3.112095 +v -5.094100 5.070210 3.367108 +v -2.703043 3.556491 3.772675 +v -4.611983 4.846024 3.135313 +v -4.998289 4.512053 3.560112 +v -5.194196 4.943080 3.445571 +v -5.082174 5.087023 3.615631 +v -4.442030 4.913592 3.588272 +v -4.862802 4.537852 3.695359 +v -4.681238 5.239111 4.167457 +v -4.378821 5.024276 3.721570 +v -4.683539 4.640815 4.170266 +v -4.781334 5.111980 4.245921 +v -4.586100 5.173386 4.388404 +v -4.060906 4.914415 4.075806 +v -4.510185 4.599240 4.244658 +v -4.003935 5.072564 4.761648 +v -3.930779 4.964617 4.196475 +v -4.167190 4.513847 4.623254 +v -4.104031 4.945435 4.840112 +v -3.864486 4.924881 4.906328 +v -3.558332 4.696294 4.363532 +v -3.997252 4.422600 4.612806 +v -3.243673 4.615199 4.990469 +v -3.387910 4.683033 4.432778 +v -3.587597 4.165170 4.797698 +v -3.343769 4.488068 5.068933 +v -3.110690 4.408096 5.030628 +v -3.068970 4.317676 4.374354 +v -3.461442 4.055262 4.701159 +v -2.604165 3.989563 4.792607 +v -2.895675 4.254973 4.367161 +v -3.100061 3.688210 4.646855 +v -2.776151 3.434840 3.674416 +v -2.704260 3.862432 4.871070 +v -2.526690 3.761502 4.727996 +v -2.723946 3.880009 4.105374 +v -2.278169 3.068691 3.359519 +v -3.046326 3.595653 4.486044 +v -2.715328 3.407273 3.515234 +v -2.256764 3.363296 4.221078 +v -2.723440 2.752002 3.610424 +v -2.585968 3.795137 4.017207 +v -2.344430 2.913136 3.187765 +v -2.835217 3.210768 4.211144 +v -2.921986 3.231619 3.159105 +v -2.356861 3.236165 4.299541 +v -2.857907 2.738903 3.444957 +v -2.670298 2.908273 2.599362 +v -2.925343 3.246717 2.987177 +v -3.079657 2.606275 2.919884 +v -2.827691 2.829004 2.434952 +v -3.274770 3.230857 2.707824 +v -3.258343 2.669190 2.821168 +v -3.313587 3.066455 2.035011 +v -3.328905 3.300454 2.559418 +v -3.664033 2.749971 2.407216 +v -3.530666 3.071090 1.930406 +v -3.739975 3.432759 2.441492 +v -3.840836 2.869786 2.403094 +v -4.035669 3.500853 1.817681 +v -3.817881 3.554084 2.346574 +v -4.319985 3.144586 2.209790 +v -4.264993 3.574527 1.809317 +v -4.192949 3.783225 2.431474 +v -4.449308 3.286940 2.302759 +v -2.268968 3.158353 4.079522 +v -4.643063 4.095070 2.005607 +v -4.261250 3.939648 2.405677 +v -4.871753 3.684383 2.380506 +v -4.833909 4.204421 2.104132 +v -4.512319 4.188348 2.680453 +v -4.920719 3.808877 2.547046 +v -4.973016 4.689886 2.548434 +v -4.540211 4.353834 2.720890 +v -5.171489 4.224726 2.873620 +v -5.084974 4.791990 2.735857 +v -4.612508 4.539576 3.121716 +v -5.128754 4.295744 3.070500 +v -4.937119 5.125921 3.300712 +v -4.580016 4.685661 3.207751 +v -5.138879 4.620828 3.557002 +v -4.950914 5.179797 3.535219 +v -4.466673 4.742797 3.637027 +v -5.017672 4.617086 3.732862 +v -4.544991 5.286339 4.060867 +v -4.370002 4.846217 3.735807 +v -4.782662 4.766554 4.247542 +v -4.467653 5.263930 4.288032 +v -4.113889 4.743559 4.088309 +v -4.617235 4.686799 4.356652 +v -3.901701 5.128157 4.625219 +v -3.966439 4.792480 4.163567 +v -2.863134 3.166926 4.025099 +v -4.198286 4.622859 4.760210 +v -3.764678 5.021844 4.792579 +v -3.648685 4.541657 4.354640 +v -4.034742 4.486204 4.774725 +v -3.179619 4.693759 4.842549 +v -3.477463 4.538850 4.376410 +v -3.542334 4.228244 4.957635 +v -3.030352 4.518407 4.913668 +v -3.195710 4.191192 4.364659 +v -3.426270 4.069050 4.875061 +v -2.572226 4.099543 4.654623 +v -2.726498 4.162666 4.354026 +v -3.227506 3.907639 4.468919 +v -2.876247 3.307710 3.752880 +v -2.568037 4.038409 4.327550 +v -2.349876 3.226459 3.317594 +v -2.997413 3.532682 4.319741 +v -2.849646 3.310236 3.584837 +v -2.654847 3.642866 4.770464 +v -2.551636 2.721365 3.573885 +v -2.461653 3.685225 3.918314 +v -2.368040 3.085145 3.144856 +v -2.948545 3.493452 4.153707 +v -3.022082 3.104489 3.237569 +v -2.703037 2.659670 3.407455 +v -2.706093 3.080732 2.627054 +v -3.051189 3.156157 3.078084 +v -2.943765 2.560947 2.813729 +v -2.816295 3.007107 2.446575 +v -3.374866 3.103727 2.786287 +v -3.151293 2.581632 2.709174 +v -3.290469 3.224427 2.114387 +v -3.438471 3.207726 2.667581 +v -3.587055 2.719129 2.249377 +v -3.468348 3.231657 1.978575 +v -3.840071 3.305629 2.519956 +v -3.803346 2.806182 2.241175 +v -3.946422 3.619042 1.916961 +v -3.907720 3.451123 2.463324 +v -4.309136 3.153527 2.032048 +v -4.149482 3.698627 1.866258 +v -4.293045 3.656095 2.509937 +v -4.484480 3.273151 2.128857 +v -4.498189 4.158840 2.087676 +v -4.333202 3.821133 2.520042 +v -4.916530 3.747744 2.219974 +v -4.677188 4.282892 2.139718 +v -4.612414 4.061218 2.758917 +v -5.012186 3.857417 2.402317 +v -4.797925 4.699182 2.580790 +v -4.600909 4.218610 2.822538 +v -5.246483 4.342560 2.762800 +v -4.910066 4.827900 2.725682 +v -4.712605 4.412446 3.200180 +v -5.245064 4.402425 2.988281 +v -4.765316 5.095284 3.264172 +v -4.639109 4.537050 3.289759 +v -5.210587 4.778594 3.515078 +v -4.785718 5.187616 3.467141 +v -4.566769 4.615667 3.715491 +v -5.120716 4.762141 3.729740 +v -4.409099 5.241011 3.954712 +v -2.896455 3.310843 3.924287 +v -4.437567 4.691129 3.796513 +v -4.818458 4.939013 4.275233 +v -4.337462 5.265654 4.165422 +v -4.213985 4.616429 4.166772 +v -4.672461 4.840179 4.428021 +v -3.824723 5.097316 4.467380 +v -4.050285 4.639560 4.207015 +v -4.175168 4.780830 4.839585 +v -3.685410 5.041104 4.633422 +v -3.748780 4.414527 4.433104 +v -4.020407 4.615629 4.896021 +v -3.168770 4.702701 4.664806 +v -3.581035 4.396163 4.411272 +v -3.453086 4.346433 5.056915 +v -3.004276 4.574134 4.745739 +v -3.295806 4.064061 4.443123 +v -3.339273 4.148660 5.008338 +v -2.617003 4.162903 4.494091 +v -3.155554 4.026154 4.354554 +v -2.845694 3.752216 4.868989 +v -2.889175 3.153240 3.843030 +v -2.476570 3.989869 4.472279 +v -2.976437 3.658938 4.194143 +v -2.490467 3.335234 3.314485 +v -2.811568 3.564394 4.734878 +v -2.908739 3.161625 3.666845 +v -2.317267 3.622561 4.000977 +v -2.887846 3.628676 4.052058 +v -2.471084 3.230200 3.141734 +v -2.515740 3.157400 4.326162 +v -3.046726 2.933694 3.286324 +v -2.537841 2.667488 3.339377 +v -2.805217 3.206470 2.704330 +v -3.118754 3.001069 3.138789 +v -2.871521 3.160487 2.517945 +v -3.427849 2.932871 2.798791 +v -3.021102 2.583356 2.586564 +v -3.321566 3.333439 2.251343 +v -3.522316 3.054806 2.711030 +v -3.454014 3.361082 2.099871 +v -3.930423 3.150992 2.511065 +v -3.724077 2.825442 2.082017 +v -3.901159 3.682117 2.076899 +v -4.011292 3.308436 2.498186 +v -4.062486 3.778236 1.999535 +v -4.419785 3.529611 2.500242 +v -4.458404 3.328879 1.960928 +v -4.388695 4.159077 2.227741 +v -4.454661 3.694000 2.557289 +v -4.533896 4.300174 2.243823 +v -4.764810 3.967277 2.769222 +v -5.027320 3.958772 2.255744 +v -2.243691 3.444860 3.886315 +v -4.653539 4.636518 2.663452 +v -4.733622 4.108185 2.872501 +v -4.741932 4.787041 2.767277 +v -4.873048 4.346719 3.245932 +v -5.278385 4.546342 2.887468 +v -4.624725 4.986509 3.267282 +v -4.773427 4.440012 3.359363 +v -4.630849 5.108383 3.429639 +v -4.715497 4.566266 3.802639 +v -5.144326 4.934150 3.686831 +v -4.309976 5.115272 3.877436 +v -4.563413 4.600568 3.887419 +v -4.230412 5.178096 4.053428 +v -4.334374 4.567089 4.290172 +v -4.661064 5.018282 4.439644 +v -3.793627 4.988304 4.330424 +v -4.159850 4.546832 4.315178 +v -3.647919 4.977500 4.471502 +v -3.831800 4.348968 4.577898 +v -3.958090 4.776196 4.944191 +v -3.214033 4.639626 4.504868 +v -3.670875 4.293202 4.528022 +v -2.578690 3.019386 4.148914 +v -3.039448 4.560347 4.571838 +v -3.342438 3.970349 4.588721 +v -3.223763 4.272758 5.065279 +v -2.247730 2.995453 3.636607 +v -2.233691 3.155356 3.556676 +v -2.309472 3.305186 3.496696 +v -2.454766 3.404796 3.472737 +v -2.630642 3.427496 3.491220 +v -2.789975 3.367203 3.547192 +v -2.890071 3.240073 3.625656 +v -2.904110 3.080170 3.705586 +v -2.828330 2.930340 3.765567 +v -2.683035 2.830729 3.789526 +v -2.507159 2.808029 3.771043 +v -2.347826 2.868322 3.715071 +v -2.365374 2.831516 3.220912 +v -2.345427 2.999652 3.161857 +v -2.410975 3.163742 3.138034 +v -2.544453 3.279818 3.155828 +v -2.710096 3.316777 3.210469 +v -2.863521 3.264717 3.287317 +v -2.963617 3.137587 3.365780 +v -2.983564 2.969451 3.424835 +v -2.918016 2.805361 3.448658 +v -2.784538 2.689286 3.430864 +v -2.618895 2.652326 3.376223 +v -2.465470 2.704386 3.299375 +v -2.573584 2.746339 2.817289 +v -2.543181 2.918752 2.778504 +v -2.590618 3.090251 2.789789 +v -2.703184 3.214882 2.848122 +v -2.850717 3.259250 2.937871 +v -2.993685 3.211468 3.034988 +v -3.093781 3.084337 3.113452 +v -3.124184 2.911924 3.152237 +v -3.076747 2.740425 3.140952 +v -2.964181 2.615794 3.082619 +v -2.816648 2.571426 2.992870 +v -2.673680 2.619208 2.895752 +v -2.858170 2.745724 2.453246 +v -2.813476 2.918169 2.432742 +v -2.836159 3.089720 2.475693 +v -2.920141 3.214413 2.570590 +v -3.042920 3.258835 2.692004 +v -3.171597 3.211083 2.807403 +v -3.271693 3.083953 2.885867 +v -3.316388 2.911509 2.906370 +v -3.293705 2.739957 2.863419 +v -3.209722 2.615264 2.768523 +v -3.086943 2.570842 2.647109 +v -2.958266 2.618594 2.531709 +v -3.199740 2.829715 2.153590 +v -3.137892 2.997941 2.148135 +v -3.130865 3.162188 2.217151 +v -3.180541 3.278444 2.342144 +v -3.273609 3.315561 2.489623 +v -3.385133 3.263591 2.620071 +v -3.485229 3.136461 2.698535 +v -3.547076 2.968234 2.703990 +v -3.554104 2.803988 2.634974 +v -3.504428 2.687731 2.509980 +v -3.411360 2.650615 2.362501 +v -3.299836 2.702584 2.232053 +v -3.575015 2.992586 1.938744 +v -3.494321 3.152634 1.944078 +v -3.454651 3.302713 2.031782 +v -3.466635 3.402611 2.178354 +v -3.527061 3.425560 2.344521 +v -3.619739 3.365412 2.485758 +v -3.719835 3.238281 2.564221 +v -3.800529 3.078234 2.558887 +v -3.840199 2.928155 2.471183 +v -3.828215 2.828256 2.324611 +v -3.767789 2.805307 2.158444 +v -3.675111 2.865456 2.017207 +v -3.958421 3.223240 1.823347 +v -3.858473 3.371704 1.834477 +v -3.785454 3.501721 1.932218 +v -3.758929 3.578452 2.090380 +v -3.786005 3.581339 2.266584 +v -3.859429 3.509607 2.413617 +v -3.959525 3.382476 2.492081 +v -4.059473 3.234013 2.480951 +v -4.132492 3.103996 2.383210 +v -4.159017 3.027264 2.225048 +v -4.131940 3.024377 2.048843 +v -4.058517 3.096110 1.901811 +v -4.323830 3.505957 1.815266 +v -4.205531 3.640223 1.826802 +v -4.100728 3.745648 1.925245 +v -4.037502 3.793984 2.084219 +v -4.032794 3.772280 2.261126 +v -4.087867 3.686349 2.408565 +v -4.187963 3.559219 2.487028 +v -4.306262 3.424953 2.475492 +v -4.411065 3.319528 2.377049 +v -4.474291 3.271192 2.218075 +v -4.478999 3.292896 2.041167 +v -4.423926 3.378826 1.893729 +v -4.646339 3.821470 1.915049 +v -4.511845 3.939891 1.921574 +v -4.378989 4.017873 2.011338 +v -4.283370 4.034519 2.160290 +v -4.250610 3.985370 2.328518 +v -4.289487 3.883595 2.470946 +v -4.389583 3.756465 2.549409 +v -4.524078 3.638044 2.542884 +v -4.656934 3.560062 2.453120 +v -4.752552 3.543416 2.304168 +v -4.785312 3.592565 2.135940 +v -4.746436 3.694340 1.993513 +v -4.903971 4.148278 2.115898 +v -4.756538 4.250288 2.112336 +v -4.601273 4.299842 2.184631 +v -4.479778 4.283665 2.313409 +v -4.424609 4.206089 2.464167 +v -4.450548 4.087903 2.596508 +v -4.550644 3.960772 2.674971 +v -4.698076 3.858763 2.678533 +v -4.853342 3.809208 2.606239 +v -4.974836 3.825386 2.477460 +v -5.030005 3.902961 2.326702 +v -5.004067 4.021148 2.194362 +v -5.079167 4.464109 2.404125 +v -4.922936 4.550258 2.386088 +v -4.752432 4.572341 2.433312 +v -4.613341 4.524442 2.533142 +v -4.542933 4.419394 2.658829 +v -4.560073 4.285347 2.776695 +v -4.660169 4.158217 2.855158 +v -4.816401 4.072068 2.873195 +v -4.986905 4.049985 2.825972 +v -5.125996 4.097885 2.726141 +v -5.196404 4.202931 2.600455 +v -5.179264 4.336979 2.482588 +v -5.159990 4.747441 2.760087 +v -4.999700 4.819361 2.724174 +v -4.822165 4.816799 2.740435 +v -4.674957 4.740442 2.804513 +v -4.597518 4.610751 2.899238 +v -4.610600 4.462474 2.999228 +v -4.710696 4.335344 3.077692 +v -4.870986 4.263424 3.113604 +v -5.048520 4.265985 3.097342 +v -5.195729 4.342342 3.033265 +v -5.273167 4.472034 2.938540 +v -5.260086 4.620311 2.838550 +v -5.140929 4.978963 3.159525 +v -4.981596 5.039256 3.103554 +v -4.805720 5.016557 3.085071 +v -4.660426 4.916946 3.109029 +v -4.584645 4.767116 3.169010 +v -4.598684 4.607213 3.248940 +v -4.698780 4.480083 3.327404 +v -4.858113 4.419789 3.383376 +v -5.033989 4.442490 3.401859 +v -5.179283 4.542100 3.377901 +v -5.255064 4.691930 3.317920 +v -5.241025 4.851833 3.237989 +v -5.023286 5.142900 3.575221 +v -4.869861 5.194960 3.498373 +v -4.704217 5.158000 3.443732 +v -4.570739 5.041924 3.425939 +v -4.505192 4.877835 3.449761 +v -4.525138 4.709699 3.508816 +v -4.625235 4.582569 3.587280 +v -4.778659 4.530509 3.664127 +v -4.944303 4.567468 3.718769 +v -5.077781 4.683544 3.736562 +v -5.143329 4.847633 3.712739 +v -5.123382 5.015769 3.653684 +v -4.815076 5.228078 3.978843 +v -4.672108 5.275860 3.881726 +v -4.524574 5.231492 3.791977 +v -4.412008 5.106861 3.733644 +v -4.364572 4.935362 3.722359 +v -4.394974 4.762949 3.761144 +v -4.495070 4.635818 3.839608 +v -4.638039 4.588036 3.936725 +v -4.785572 4.632404 4.026474 +v -4.898138 4.757035 4.084806 +v -4.945575 4.928534 4.096092 +v -4.915172 5.100947 4.057307 +v -4.530489 5.228692 4.342887 +v -4.401813 5.276443 4.227488 +v -4.279033 5.232022 4.106073 +v -4.195051 5.107329 4.011177 +v -4.172368 4.935777 3.968226 +v -4.217062 4.763332 3.988729 +v -4.317158 4.636202 4.067193 +v -4.445835 4.588451 4.182592 +v -4.568614 4.632873 4.304007 +v -4.652596 4.757565 4.398903 +v -4.675280 4.929117 4.441854 +v -4.630585 5.101562 4.421350 +v -4.188920 5.144702 4.642543 +v -4.077396 5.196671 4.512094 +v -3.984327 5.159555 4.364615 +v -3.934652 5.043298 4.239623 +v -3.941679 4.879052 4.170607 +v -4.003527 4.710825 4.176062 +v -4.103623 4.583695 4.254525 +v -4.215147 4.531725 4.384973 +v -4.308215 4.568841 4.532453 +v -4.357891 4.685099 4.657445 +v -4.350863 4.849345 4.726461 +v -4.289016 5.017571 4.721006 +v -3.813644 4.981830 4.857389 +v -3.720967 5.041979 4.716152 +v -3.660541 5.019030 4.549985 +v -3.648557 4.919131 4.403413 +v -3.688227 4.769052 4.315710 +v -3.768920 4.609005 4.310375 +v -3.869016 4.481874 4.388838 +v -3.961694 4.421725 4.530076 +v -4.022120 4.444674 4.696243 +v -4.034104 4.544573 4.842814 +v -3.994434 4.694653 4.930518 +v -3.913741 4.854700 4.935853 +v -3.430238 4.751176 4.972785 +v -3.356815 4.822908 4.825753 +v -3.329738 4.820022 4.649549 +v -3.356263 4.743290 4.491386 +v -3.429283 4.613274 4.393646 +v -3.529231 4.464809 4.382516 +v -3.629327 4.337679 4.460979 +v -3.702750 4.265947 4.608012 +v -3.729827 4.268833 4.784216 +v -3.703302 4.345566 4.942379 +v -3.630283 4.475582 5.040119 +v -3.530334 4.624046 5.051249 +v -3.064830 4.468460 4.980867 +v -3.009757 4.554389 4.833428 +v -3.014464 4.576094 4.656521 +v -3.077690 4.527759 4.497548 +v -3.182493 4.422333 4.399104 +v -3.300792 4.288067 4.387568 +v -3.400888 4.160936 4.466032 +v -3.455961 4.075006 4.613470 +v -3.451254 4.053302 4.790377 +v -3.388028 4.101638 4.949351 +v -3.283224 4.207064 5.047795 +v -3.164926 4.341330 5.059331 +v -2.742320 4.152946 4.881083 +v -2.703444 4.254721 4.738657 +v -2.736204 4.303870 4.570428 +v -2.831822 4.287224 4.421477 +v -2.964678 4.209242 4.331712 +v -3.099173 4.090821 4.325188 +v -3.199269 3.963691 4.403651 +v -3.238145 3.861916 4.546079 +v -3.205385 3.812767 4.714306 +v -3.109767 3.829413 4.863258 +v -2.976911 3.907395 4.953022 +v -2.842416 4.025816 4.959548 +v -2.484689 3.826138 4.680235 +v -2.458750 3.944325 4.547894 +v -2.513919 4.021901 4.397136 +v -2.635414 4.038078 4.268358 +v -2.790679 3.988523 4.196064 +v -2.938112 3.886514 4.199625 +v -3.038208 3.759384 4.278089 +v -3.064147 3.641197 4.410429 +v -3.008977 3.563622 4.561187 +v -2.887483 3.547444 4.689966 +v -2.732217 3.596999 4.762260 +v -2.584785 3.699008 4.758698 +v -2.309492 3.510307 4.392008 +v -2.292352 3.644354 4.274142 +v -2.362760 3.749401 4.148455 +v -2.501851 3.797300 4.048625 +v -2.672355 3.775218 4.001401 +v -2.828586 3.689069 4.019438 +v -2.928682 3.561939 4.097901 +v -2.945822 3.427891 4.215767 +v -2.875414 3.322844 4.341455 +v -2.736323 3.274945 4.441285 +v -2.565819 3.297028 4.488508 +v -2.409588 3.383176 4.470472 +v -2.228670 3.226975 4.036046 +v -2.215588 3.375252 3.936056 +v -2.293027 3.504943 3.841331 +v -2.440235 3.581300 3.777254 +v -2.617769 3.583862 3.760993 +v -2.778059 3.511942 3.796905 +v -2.878156 3.384812 3.875369 +v -2.891237 3.236535 3.975359 +v -2.813799 3.106843 4.070083 +v -2.666590 3.030487 4.134161 +v -2.489056 3.027925 4.150422 +v -2.328766 3.099845 4.114510 +v -4.885655 -0.004460 3.185549 +v -4.885655 4.535810 3.185549 +v -4.744234 -0.004460 3.244127 +v -4.744234 4.535810 3.244127 +v -4.685656 -0.004460 3.385549 +v -4.685656 4.535810 3.385549 +v -4.744234 -0.004460 3.526970 +v -4.744234 4.535810 3.526970 +v -4.885655 -0.004460 3.585549 +v -4.885655 4.535810 3.585549 +v -5.027077 -0.004460 3.526970 +v -5.027077 4.535810 3.526970 +v -5.085655 -0.004460 3.385549 +v -5.085656 4.535810 3.385549 +v -5.027077 -0.004460 3.244127 +v -5.027077 4.535810 3.244127 +v -2.367983 -0.004460 1.521488 +v -2.367983 0.985540 1.521488 +v -2.226562 -0.004460 1.580067 +v -2.226562 0.985540 1.580067 +v -2.167984 -0.004460 1.721488 +v -2.167984 0.985540 1.721488 +v -2.226562 -0.004460 1.862909 +v -2.226562 0.985540 1.862909 +v -2.367983 -0.004460 1.921488 +v -2.367984 0.985540 1.921488 +v -2.509405 -0.004460 1.862909 +v -2.509405 0.985540 1.862909 +v -2.567983 -0.004460 1.721488 +v -2.567983 0.985540 1.721488 +v -2.509405 -0.004460 1.580067 +v -2.509405 0.985540 1.580066 +v -0.346361 -0.004460 -1.075261 +v -0.346361 2.679184 -1.075261 +v -0.204940 -0.004460 -1.016682 +v -0.204940 2.679184 -1.016683 +v -0.146361 -0.004460 -0.875261 +v -0.146361 2.679184 -0.875261 +v -0.204940 -0.004460 -0.733840 +v -0.204940 2.679184 -0.733840 +v -0.346361 -0.004460 -0.675262 +v -0.346361 2.679184 -0.675261 +v -0.487782 -0.004460 -0.733840 +v -0.487782 2.679184 -0.733840 +v -0.546361 -0.004460 -0.875261 +v -0.546361 2.679184 -0.875261 +v -0.487782 -0.004460 -1.016683 +v -0.487782 2.679184 -1.016683 +v -4.814945 -0.004460 3.214838 +v -4.814945 4.535810 3.214838 +v -4.885655 2.265675 3.185549 +v -4.744234 2.265675 3.244127 +v -4.714945 -0.004460 3.314838 +v -4.714945 4.535810 3.314838 +v -4.685656 2.265675 3.385549 +v -4.714945 -0.004460 3.456259 +v -4.714945 4.535810 3.456259 +v -4.744234 2.265675 3.526970 +v -4.814945 -0.004460 3.556260 +v -4.814945 4.535810 3.556259 +v -4.885655 2.265675 3.585549 +v -4.956366 -0.004460 3.556260 +v -4.956367 4.535810 3.556259 +v -5.027077 2.265675 3.526970 +v -5.056366 -0.004460 3.456259 +v -5.056366 4.535810 3.456259 +v -5.085656 2.265675 3.385549 +v -5.056366 -0.004460 3.314838 +v -5.056366 4.535810 3.314838 +v -5.027077 2.265676 3.244127 +v -4.956366 -0.004460 3.214838 +v -4.956367 4.535810 3.214838 +v -2.297272 -0.004460 1.550777 +v -2.297273 0.985540 1.550777 +v -2.367983 0.490540 1.521488 +v -2.226562 0.490540 1.580066 +v -2.197273 -0.004460 1.650777 +v -2.197273 0.985540 1.650777 +v -2.167984 0.490540 1.721488 +v -2.197273 -0.004460 1.792199 +v -2.197273 0.985540 1.792199 +v -2.226562 0.490540 1.862909 +v -2.297272 -0.004460 1.892199 +v -2.297273 0.985540 1.892199 +v -2.367983 0.490540 1.921488 +v -2.438694 -0.004459 1.892199 +v -2.438694 0.985540 1.892199 +v -2.509405 0.490540 1.862909 +v -2.538694 -0.004460 1.792199 +v -2.538694 0.985540 1.792198 +v -2.567983 0.490540 1.721488 +v -2.538694 -0.004460 1.650777 +v -2.538694 0.985540 1.650777 +v -2.509405 0.490540 1.580067 +v -2.438694 -0.004460 1.550777 +v -2.438694 0.985540 1.550777 +v -0.275651 -0.004460 -1.045972 +v -0.275651 2.679184 -1.045972 +v -0.346361 1.337362 -1.075261 +v -0.204940 1.337363 -1.016682 +v -0.175651 -0.004460 -0.945972 +v -0.175651 2.679184 -0.945972 +v -0.146362 1.337362 -0.875261 +v -0.175651 -0.004460 -0.804550 +v -0.175651 2.679184 -0.804550 +v -0.204940 1.337362 -0.733839 +v -0.275651 -0.004460 -0.704551 +v -0.275651 2.679184 -0.704551 +v -0.346361 1.337363 -0.675261 +v -0.417072 -0.004460 -0.704551 +v -0.417072 2.679184 -0.704551 +v -0.487782 1.337362 -0.733840 +v -0.517072 -0.004460 -0.804550 +v -0.517072 2.679184 -0.804550 +v -0.546361 1.337362 -0.875261 +v -0.517072 -0.004460 -0.945972 +v -0.517072 2.679185 -0.945972 +v -0.487782 1.337363 -1.016683 +v -0.417072 -0.004460 -1.045972 +v -0.417072 2.679184 -1.045972 +v -0.417072 1.337362 -1.045971 +v -0.517072 1.337362 -0.945971 +v -0.517072 1.337362 -0.804550 +v -0.417072 1.337363 -0.704550 +v -0.275651 1.337362 -0.704550 +v -0.175651 1.337362 -0.804550 +v -0.175651 1.337362 -0.945971 +v -0.275651 1.337362 -1.045971 +v -2.438694 0.490540 1.550777 +v -2.538694 0.490540 1.650777 +v -2.538694 0.490541 1.792199 +v -2.438694 0.490540 1.892199 +v -2.297273 0.490541 1.892199 +v -2.197273 0.490540 1.792199 +v -2.197273 0.490541 1.650777 +v -2.297273 0.490541 1.550777 +v -4.956366 2.265675 3.214838 +v -5.056366 2.265675 3.314838 +v -5.056366 2.265675 3.456259 +v -4.956366 2.265675 3.556259 +v -4.814945 2.265675 3.556259 +v -4.714945 2.265675 3.456259 +v -4.714945 2.265675 3.314838 +v -4.814945 2.265675 3.214838 +v -4.885655 -0.004460 3.385549 +v -4.885655 4.535810 3.385549 +v -4.885655 -0.004460 3.185549 +v -4.885655 4.535810 3.185549 +v -4.744234 -0.004460 3.244127 +v -4.744234 4.535810 3.244127 +v -4.685656 -0.004460 3.385549 +v -4.685656 4.535810 3.385549 +v -4.744234 -0.004460 3.526970 +v -4.744234 4.535810 3.526970 +v -4.885655 -0.004460 3.585549 +v -4.885655 4.535810 3.585549 +v -5.027077 -0.004460 3.526970 +v -5.027077 4.535810 3.526970 +v -5.085655 -0.004460 3.385549 +v -5.085656 4.535810 3.385549 +v -5.027077 -0.004460 3.244127 +v -5.027077 4.535810 3.244127 +v -2.367984 -0.004460 1.721488 +v -2.367983 0.985540 1.721488 +v -2.367983 -0.004460 1.521488 +v -2.367983 0.985540 1.521488 +v -2.226562 -0.004460 1.580067 +v -2.226562 0.985540 1.580067 +v -2.167984 -0.004460 1.721488 +v -2.167984 0.985540 1.721488 +v -2.226562 -0.004460 1.862909 +v -2.226562 0.985540 1.862909 +v -2.367983 -0.004460 1.921488 +v -2.367984 0.985540 1.921488 +v -2.509405 -0.004460 1.862909 +v -2.509405 0.985540 1.862909 +v -2.567983 -0.004460 1.721488 +v -2.567983 0.985540 1.721488 +v -2.509405 -0.004460 1.580067 +v -2.509405 0.985540 1.580066 +v -0.346361 -0.004460 -0.875261 +v -0.346361 2.679184 -0.875261 +v -0.346361 -0.004460 -1.075261 +v -0.346361 2.679184 -1.075261 +v -0.204940 -0.004460 -1.016682 +v -0.204940 2.679184 -1.016683 +v -0.146361 -0.004460 -0.875261 +v -0.146361 2.679184 -0.875261 +v -0.204940 -0.004460 -0.733840 +v -0.204940 2.679184 -0.733840 +v -0.346361 -0.004460 -0.675262 +v -0.346361 2.679184 -0.675261 +v -0.487782 -0.004460 -0.733840 +v -0.487782 2.679184 -0.733840 +v -0.546361 -0.004460 -0.875261 +v -0.546361 2.679184 -0.875261 +v -0.487782 -0.004460 -1.016683 +v -0.487782 2.679184 -1.016683 +v -4.814945 -0.004460 3.214838 +v -4.814945 4.535810 3.214838 +v -4.714945 -0.004460 3.314838 +v -4.714945 4.535810 3.314838 +v -4.714945 -0.004460 3.456259 +v -4.714945 4.535810 3.456259 +v -4.814945 -0.004460 3.556260 +v -4.814945 4.535810 3.556259 +v -4.956366 -0.004460 3.556260 +v -4.956367 4.535810 3.556259 +v -5.056366 -0.004460 3.456259 +v -5.056366 4.535810 3.456259 +v -5.056366 -0.004460 3.314838 +v -5.056366 4.535810 3.314838 +v -4.956366 -0.004460 3.214838 +v -4.956367 4.535810 3.214838 +v -2.297272 -0.004460 1.550777 +v -2.297273 0.985540 1.550777 +v -2.197273 -0.004460 1.650777 +v -2.197273 0.985540 1.650777 +v -2.197273 -0.004460 1.792199 +v -2.197273 0.985540 1.792199 +v -2.297272 -0.004460 1.892199 +v -2.297273 0.985540 1.892199 +v -2.438694 -0.004459 1.892199 +v -2.438694 0.985540 1.892199 +v -2.538694 -0.004460 1.792199 +v -2.538694 0.985540 1.792198 +v -2.538694 -0.004460 1.650777 +v -2.538694 0.985540 1.650777 +v -2.438694 -0.004460 1.550777 +v -2.438694 0.985540 1.550777 +v -0.275651 -0.004460 -1.045972 +v -0.275651 2.679184 -1.045972 +v -0.175651 -0.004460 -0.945972 +v -0.175651 2.679184 -0.945972 +v -0.175651 -0.004460 -0.804550 +v -0.175651 2.679184 -0.804550 +v -0.275651 -0.004460 -0.704551 +v -0.275651 2.679184 -0.704551 +v -0.417072 -0.004460 -0.704551 +v -0.417072 2.679184 -0.704551 +v -0.517072 -0.004460 -0.804550 +v -0.517072 2.679184 -0.804550 +v -0.517072 -0.004460 -0.945972 +v -0.517072 2.679185 -0.945972 +v -0.417072 -0.004460 -1.045972 +v -0.417072 2.679184 -1.045972 +vt 0.520833 0.500000 +vt 0.500000 0.541667 +vt 0.500000 0.500000 +vt 0.541667 0.541667 +vt 0.520833 0.541667 +vt 0.541667 0.583333 +vt 0.520833 0.583333 +vt 0.500000 0.583333 +vt 0.500000 0.625000 +vt 0.541667 0.625000 +vt 0.520833 0.625000 +vt 0.541667 0.666667 +vt 0.520833 0.666667 +vt 0.500000 0.666667 +vt 0.500000 0.708333 +vt 0.541667 0.708333 +vt 0.520833 0.708333 +vt 0.541667 0.750000 +vt 0.520833 0.750000 +vt 0.500000 0.750000 +vt 0.500000 0.791667 +vt 0.541667 0.791667 +vt 0.520833 0.791667 +vt 0.541667 0.833333 +vt 0.520833 0.833333 +vt 0.500000 0.833333 +vt 0.500000 0.875000 +vt 0.541667 0.875000 +vt 0.520833 0.875000 +vt 0.541667 0.916667 +vt 0.520833 0.916667 +vt 0.500000 0.916667 +vt 0.500000 0.958333 +vt 0.541667 0.958333 +vt 0.520833 0.958333 +vt 0.541667 1.000000 +vt 0.520833 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.000000 +vt 0.520833 0.041667 +vt 0.500000 0.041667 +vt 0.541667 0.000000 +vt 0.520833 0.000000 +vt 0.541667 0.041667 +vt 0.520833 0.083333 +vt 0.500000 0.083333 +vt 0.520833 0.125000 +vt 0.500000 0.125000 +vt 0.541667 0.083333 +vt 0.541667 0.125000 +vt 0.520833 0.166667 +vt 0.500000 0.166667 +vt 0.520833 0.208333 +vt 0.500000 0.208333 +vt 0.541667 0.166667 +vt 0.541667 0.208333 +vt 0.520833 0.250000 +vt 0.500000 0.250000 +vt 0.520833 0.291667 +vt 0.500000 0.291667 +vt 0.541667 0.250000 +vt 0.541667 0.291667 +vt 0.520833 0.333333 +vt 0.500000 0.333333 +vt 0.520833 0.375000 +vt 0.500000 0.375000 +vt 0.541667 0.333333 +vt 0.541667 0.375000 +vt 0.520833 0.416667 +vt 0.500000 0.416667 +vt 0.520833 0.458333 +vt 0.500000 0.458333 +vt 0.541667 0.416667 +vt 0.541667 0.458333 +vt 0.562500 0.500000 +vt 0.541667 0.500000 +vt 0.583333 0.541667 +vt 0.562500 0.541667 +vt 0.583333 0.583333 +vt 0.562500 0.583333 +vt 0.583333 0.625000 +vt 0.562500 0.625000 +vt 0.583333 0.666667 +vt 0.562500 0.666667 +vt 0.583333 0.708333 +vt 0.562500 0.708333 +vt 0.583333 0.750000 +vt 0.562500 0.750000 +vt 0.583333 0.791667 +vt 0.562500 0.791667 +vt 0.583333 0.833333 +vt 0.562500 0.833333 +vt 0.583333 0.875000 +vt 0.562500 0.875000 +vt 0.583333 0.916667 +vt 0.562500 0.916667 +vt 0.583333 0.958333 +vt 0.562500 0.958333 +vt 0.583333 1.000000 +vt 0.562500 1.000000 +vt 0.562500 0.041667 +vt 0.583333 0.000000 +vt 0.562500 0.000000 +vt 0.583333 0.041667 +vt 0.562500 0.083333 +vt 0.562500 0.125000 +vt 0.583333 0.083333 +vt 0.583333 0.125000 +vt 0.562500 0.166667 +vt 0.562500 0.208333 +vt 0.583333 0.166667 +vt 0.583333 0.208333 +vt 0.562500 0.250000 +vt 0.562500 0.291667 +vt 0.583333 0.250000 +vt 0.583333 0.291667 +vt 0.562500 0.333333 +vt 0.562500 0.375000 +vt 0.583333 0.333333 +vt 0.583333 0.375000 +vt 0.562500 0.416667 +vt 0.562500 0.458333 +vt 0.583333 0.416667 +vt 0.583333 0.458333 +vt 0.604167 0.500000 +vt 0.583333 0.500000 +vt 0.625000 0.541667 +vt 0.604167 0.541667 +vt 0.625000 0.583333 +vt 0.604167 0.583333 +vt 0.625000 0.625000 +vt 0.604167 0.625000 +vt 0.625000 0.666667 +vt 0.604167 0.666667 +vt 0.625000 0.708333 +vt 0.604167 0.708333 +vt 0.625000 0.750000 +vt 0.604167 0.750000 +vt 0.625000 0.791667 +vt 0.604167 0.791667 +vt 0.625000 0.833333 +vt 0.604167 0.833333 +vt 0.625000 0.875000 +vt 0.604167 0.875000 +vt 0.625000 0.916667 +vt 0.604167 0.916667 +vt 0.625000 0.958333 +vt 0.604167 0.958333 +vt 0.625000 1.000000 +vt 0.604167 1.000000 +vt 0.604167 0.041667 +vt 0.625000 0.000000 +vt 0.604167 0.000000 +vt 0.625000 0.041667 +vt 0.604167 0.083333 +vt 0.604167 0.125000 +vt 0.625000 0.083333 +vt 0.625000 0.125000 +vt 0.604167 0.166667 +vt 0.604167 0.208333 +vt 0.625000 0.166667 +vt 0.625000 0.208333 +vt 0.604167 0.250000 +vt 0.604167 0.291667 +vt 0.625000 0.250000 +vt 0.625000 0.291667 +vt 0.604167 0.333333 +vt 0.604167 0.375000 +vt 0.625000 0.333333 +vt 0.625000 0.375000 +vt 0.604167 0.416667 +vt 0.604167 0.458333 +vt 0.625000 0.416667 +vt 0.625000 0.458333 +vt 0.645833 0.500000 +vt 0.625000 0.500000 +vt 0.666667 0.541667 +vt 0.645833 0.541667 +vt 0.666667 0.583333 +vt 0.645833 0.583333 +vt 0.666667 0.625000 +vt 0.645833 0.625000 +vt 0.666667 0.666667 +vt 0.645833 0.666667 +vt 0.666667 0.708333 +vt 0.645833 0.708333 +vt 0.666667 0.750000 +vt 0.645833 0.750000 +vt 0.666667 0.791667 +vt 0.645833 0.791667 +vt 0.666667 0.833333 +vt 0.645833 0.833333 +vt 0.666667 0.875000 +vt 0.645833 0.875000 +vt 0.666667 0.916667 +vt 0.645833 0.916667 +vt 0.666667 0.958333 +vt 0.645833 0.958333 +vt 0.666667 1.000000 +vt 0.645833 1.000000 +vt 0.645833 0.041667 +vt 0.666667 0.000000 +vt 0.645833 0.000000 +vt 0.666667 0.041667 +vt 0.645833 0.083333 +vt 0.645833 0.125000 +vt 0.666667 0.083333 +vt 0.666667 0.125000 +vt 0.645833 0.166667 +vt 0.645833 0.208333 +vt 0.666667 0.166667 +vt 0.666667 0.208333 +vt 0.645833 0.250000 +vt 0.645833 0.291667 +vt 0.666667 0.250000 +vt 0.666667 0.291667 +vt 0.645833 0.333333 +vt 0.645833 0.375000 +vt 0.666667 0.333333 +vt 0.666667 0.375000 +vt 0.645833 0.416667 +vt 0.645833 0.458333 +vt 0.666667 0.416667 +vt 0.666667 0.458333 +vt 0.687500 0.500000 +vt 0.666667 0.500000 +vt 0.708333 0.541667 +vt 0.687500 0.541667 +vt 0.708333 0.583333 +vt 0.687500 0.583333 +vt 0.708333 0.625000 +vt 0.687500 0.625000 +vt 0.708333 0.666667 +vt 0.687500 0.666667 +vt 0.708333 0.708333 +vt 0.687500 0.708333 +vt 0.708333 0.750000 +vt 0.687500 0.750000 +vt 0.708333 0.791667 +vt 0.687500 0.791667 +vt 0.708333 0.833333 +vt 0.687500 0.833333 +vt 0.708333 0.875000 +vt 0.687500 0.875000 +vt 0.708333 0.916667 +vt 0.687500 0.916667 +vt 0.708333 0.958333 +vt 0.687500 0.958333 +vt 0.708333 1.000000 +vt 0.687500 1.000000 +vt 0.687500 0.041667 +vt 0.708333 0.000000 +vt 0.687500 0.000000 +vt 0.708333 0.041667 +vt 0.687500 0.083333 +vt 0.687500 0.125000 +vt 0.708333 0.083333 +vt 0.708333 0.125000 +vt 0.687500 0.166667 +vt 0.687500 0.208333 +vt 0.708333 0.166667 +vt 0.708333 0.208333 +vt 0.687500 0.250000 +vt 0.687500 0.291667 +vt 0.708333 0.250000 +vt 0.708333 0.291667 +vt 0.687500 0.333333 +vt 0.687500 0.375000 +vt 0.708333 0.333333 +vt 0.708333 0.375000 +vt 0.687500 0.416667 +vt 0.687500 0.458333 +vt 0.708333 0.416667 +vt 0.708333 0.458333 +vt 0.729167 0.500000 +vt 0.708333 0.500000 +vt 0.750000 0.541667 +vt 0.729167 0.541667 +vt 0.750000 0.583333 +vt 0.729167 0.583333 +vt 0.750000 0.625000 +vt 0.729167 0.625000 +vt 0.750000 0.666667 +vt 0.729167 0.666667 +vt 0.750000 0.708333 +vt 0.729167 0.708333 +vt 0.750000 0.750000 +vt 0.729167 0.750000 +vt 0.750000 0.791667 +vt 0.729167 0.791667 +vt 0.750000 0.833333 +vt 0.729167 0.833333 +vt 0.750000 0.875000 +vt 0.729167 0.875000 +vt 0.750000 0.916667 +vt 0.729167 0.916667 +vt 0.750000 0.958333 +vt 0.729167 0.958333 +vt 0.750000 1.000000 +vt 0.729167 1.000000 +vt 0.729167 0.041667 +vt 0.750000 0.000000 +vt 0.729167 0.000000 +vt 0.750000 0.041667 +vt 0.729167 0.083333 +vt 0.729167 0.125000 +vt 0.750000 0.083333 +vt 0.750000 0.125000 +vt 0.729167 0.166667 +vt 0.729167 0.208333 +vt 0.750000 0.166667 +vt 0.750000 0.208333 +vt 0.729167 0.250000 +vt 0.729167 0.291667 +vt 0.750000 0.250000 +vt 0.750000 0.291667 +vt 0.729167 0.333333 +vt 0.729167 0.375000 +vt 0.750000 0.333333 +vt 0.750000 0.375000 +vt 0.729167 0.416667 +vt 0.729167 0.458333 +vt 0.750000 0.416667 +vt 0.750000 0.458333 +vt 0.770833 0.500000 +vt 0.750000 0.500000 +vt 0.791667 0.541667 +vt 0.770833 0.541667 +vt 0.791667 0.583333 +vt 0.770833 0.583333 +vt 0.791667 0.625000 +vt 0.770833 0.625000 +vt 0.791667 0.666667 +vt 0.770833 0.666667 +vt 0.791667 0.708333 +vt 0.770833 0.708333 +vt 0.791667 0.750000 +vt 0.770833 0.750000 +vt 0.791667 0.791667 +vt 0.770833 0.791667 +vt 0.791667 0.833333 +vt 0.770833 0.833333 +vt 0.791667 0.875000 +vt 0.770833 0.875000 +vt 0.791667 0.916667 +vt 0.770833 0.916667 +vt 0.791667 0.958333 +vt 0.770833 0.958333 +vt 0.791667 1.000000 +vt 0.770833 1.000000 +vt 0.770833 0.041667 +vt 0.791667 0.000000 +vt 0.770833 0.000000 +vt 0.791667 0.041667 +vt 0.770833 0.083333 +vt 0.770833 0.125000 +vt 0.791667 0.083333 +vt 0.791667 0.125000 +vt 0.770833 0.166667 +vt 0.770833 0.208333 +vt 0.791667 0.166667 +vt 0.791667 0.208333 +vt 0.770833 0.250000 +vt 0.770833 0.291667 +vt 0.791667 0.250000 +vt 0.791667 0.291667 +vt 0.770833 0.333333 +vt 0.770833 0.375000 +vt 0.791667 0.333333 +vt 0.791667 0.375000 +vt 0.770833 0.416667 +vt 0.770833 0.458333 +vt 0.791667 0.416667 +vt 0.791667 0.458333 +vt 0.812500 0.500000 +vt 0.791667 0.500000 +vt 0.833333 0.541667 +vt 0.812500 0.541667 +vt 0.833333 0.583333 +vt 0.812500 0.583333 +vt 0.833333 0.625000 +vt 0.812500 0.625000 +vt 0.833333 0.666667 +vt 0.812500 0.666667 +vt 0.833333 0.708333 +vt 0.812500 0.708333 +vt 0.833333 0.750000 +vt 0.812500 0.750000 +vt 0.833333 0.791667 +vt 0.812500 0.791667 +vt 0.833333 0.833333 +vt 0.812500 0.833333 +vt 0.833333 0.875000 +vt 0.812500 0.875000 +vt 0.833333 0.916667 +vt 0.812500 0.916667 +vt 0.833333 0.958333 +vt 0.812500 0.958333 +vt 0.833333 1.000000 +vt 0.812500 1.000000 +vt 0.812500 0.041667 +vt 0.833333 0.000000 +vt 0.812500 0.000000 +vt 0.833333 0.041667 +vt 0.812500 0.083333 +vt 0.812500 0.125000 +vt 0.833333 0.083333 +vt 0.833333 0.125000 +vt 0.812500 0.166667 +vt 0.812500 0.208333 +vt 0.833333 0.166667 +vt 0.833333 0.208333 +vt 0.812500 0.250000 +vt 0.812500 0.291667 +vt 0.833333 0.250000 +vt 0.833333 0.291667 +vt 0.812500 0.333333 +vt 0.812500 0.375000 +vt 0.833333 0.333333 +vt 0.833333 0.375000 +vt 0.812500 0.416667 +vt 0.812500 0.458333 +vt 0.833333 0.416667 +vt 0.833333 0.458333 +vt 0.854167 0.500000 +vt 0.833333 0.500000 +vt 0.875000 0.541667 +vt 0.854167 0.541667 +vt 0.875000 0.583333 +vt 0.854167 0.583333 +vt 0.875000 0.625000 +vt 0.854167 0.625000 +vt 0.875000 0.666667 +vt 0.854167 0.666667 +vt 0.875000 0.708333 +vt 0.854167 0.708333 +vt 0.875000 0.750000 +vt 0.854167 0.750000 +vt 0.875000 0.791667 +vt 0.854167 0.791667 +vt 0.875000 0.833333 +vt 0.854167 0.833333 +vt 0.875000 0.875000 +vt 0.854167 0.875000 +vt 0.875000 0.916667 +vt 0.854167 0.916667 +vt 0.875000 0.958333 +vt 0.854167 0.958333 +vt 0.875000 1.000000 +vt 0.854167 1.000000 +vt 0.854167 0.041667 +vt 0.875000 0.000000 +vt 0.854167 0.000000 +vt 0.875000 0.041667 +vt 0.854167 0.083333 +vt 0.854167 0.125000 +vt 0.875000 0.083333 +vt 0.875000 0.125000 +vt 0.854167 0.166667 +vt 0.854167 0.208333 +vt 0.875000 0.166667 +vt 0.875000 0.208333 +vt 0.854167 0.250000 +vt 0.854167 0.291667 +vt 0.875000 0.250000 +vt 0.875000 0.291667 +vt 0.854167 0.333333 +vt 0.854167 0.375000 +vt 0.875000 0.333333 +vt 0.875000 0.375000 +vt 0.854167 0.416667 +vt 0.854167 0.458333 +vt 0.875000 0.416667 +vt 0.875000 0.458333 +vt 0.895833 0.500000 +vt 0.875000 0.500000 +vt 0.916667 0.541667 +vt 0.895833 0.541667 +vt 0.916667 0.583333 +vt 0.895833 0.583333 +vt 0.916667 0.625000 +vt 0.895833 0.625000 +vt 0.916667 0.666667 +vt 0.895833 0.666667 +vt 0.916667 0.708333 +vt 0.895833 0.708333 +vt 0.916667 0.750000 +vt 0.895833 0.750000 +vt 0.916667 0.791667 +vt 0.895833 0.791667 +vt 0.916667 0.833333 +vt 0.895833 0.833333 +vt 0.916667 0.875000 +vt 0.895833 0.875000 +vt 0.916667 0.916667 +vt 0.895833 0.916667 +vt 0.916667 0.958333 +vt 0.895833 0.958333 +vt 0.916667 1.000000 +vt 0.895833 1.000000 +vt 0.895834 0.041667 +vt 0.916667 0.000000 +vt 0.895833 0.000000 +vt 0.916667 0.041667 +vt 0.895834 0.083333 +vt 0.895833 0.125000 +vt 0.916667 0.083333 +vt 0.916667 0.125000 +vt 0.895833 0.166667 +vt 0.895833 0.208333 +vt 0.916667 0.166667 +vt 0.916667 0.208333 +vt 0.895833 0.250000 +vt 0.895833 0.291667 +vt 0.916667 0.250000 +vt 0.916667 0.291667 +vt 0.895833 0.333333 +vt 0.895833 0.375000 +vt 0.916667 0.333333 +vt 0.916667 0.375000 +vt 0.895833 0.416667 +vt 0.895833 0.458333 +vt 0.916667 0.416667 +vt 0.916667 0.458333 +vt 0.937500 0.500000 +vt 0.916667 0.500000 +vt 0.958333 0.541667 +vt 0.937500 0.541667 +vt 0.958333 0.583333 +vt 0.937500 0.583333 +vt 0.958333 0.625000 +vt 0.937500 0.625000 +vt 0.958333 0.666667 +vt 0.937500 0.666667 +vt 0.958333 0.708333 +vt 0.937500 0.708333 +vt 0.958333 0.750000 +vt 0.937500 0.750000 +vt 0.958333 0.791667 +vt 0.937500 0.791667 +vt 0.958333 0.833333 +vt 0.937500 0.833333 +vt 0.958333 0.875000 +vt 0.937500 0.875000 +vt 0.958333 0.916667 +vt 0.937500 0.916667 +vt 0.958333 0.958333 +vt 0.937500 0.958333 +vt 0.958333 1.000000 +vt 0.937500 1.000000 +vt 0.937500 0.041667 +vt 0.958333 0.000000 +vt 0.937500 0.000000 +vt 0.958333 0.041667 +vt 0.937500 0.083333 +vt 0.937500 0.125000 +vt 0.958333 0.083333 +vt 0.958333 0.125000 +vt 0.937500 0.166667 +vt 0.937500 0.208333 +vt 0.958333 0.166667 +vt 0.958333 0.208333 +vt 0.937500 0.250000 +vt 0.937500 0.291667 +vt 0.958333 0.250000 +vt 0.958333 0.291667 +vt 0.937500 0.333333 +vt 0.937500 0.375000 +vt 0.958333 0.333333 +vt 0.958333 0.375000 +vt 0.937500 0.416667 +vt 0.937500 0.458333 +vt 0.958333 0.416667 +vt 0.958333 0.458333 +vt 0.979167 0.500000 +vt 0.958333 0.500000 +vt 1.000000 0.541667 +vt 0.979167 0.541667 +vt 1.000000 0.583333 +vt 0.979167 0.583333 +vt 1.000000 0.625000 +vt 0.979167 0.625000 +vt 1.000000 0.666667 +vt 0.979167 0.666667 +vt 1.000000 0.708333 +vt 0.979167 0.708333 +vt 1.000000 0.750000 +vt 0.979167 0.750000 +vt 1.000000 0.791667 +vt 0.979167 0.791667 +vt 1.000000 0.833333 +vt 0.979167 0.833333 +vt 1.000000 0.875000 +vt 0.979167 0.875000 +vt 1.000000 0.916667 +vt 0.979167 0.916667 +vt 1.000000 0.958333 +vt 0.979167 0.958333 +vt 1.000000 1.000000 +vt 0.979167 1.000000 +vt 0.979167 0.041667 +vt 1.000000 0.000000 +vt 0.979167 0.000000 +vt 1.000000 0.041667 +vt 0.979167 0.083333 +vt 0.979167 0.125000 +vt 1.000000 0.083333 +vt 1.000000 0.125000 +vt 0.979167 0.166667 +vt 0.979167 0.208333 +vt 1.000000 0.166667 +vt 1.000000 0.208333 +vt 0.979167 0.250000 +vt 0.979167 0.291667 +vt 1.000000 0.250000 +vt 1.000000 0.291667 +vt 0.979167 0.333333 +vt 0.979167 0.375000 +vt 1.000000 0.333333 +vt 1.000000 0.375000 +vt 0.979167 0.416667 +vt 0.979167 0.458333 +vt 1.000000 0.416667 +vt 1.000000 0.458333 +vt 0.020833 0.500000 +vt -0.000000 0.541667 +vt -0.000000 0.500000 +vt 0.041667 0.541667 +vt 0.020833 0.541667 +vt 0.041667 0.583333 +vt 0.020833 0.583333 +vt -0.000000 0.583333 +vt -0.000000 0.625000 +vt 0.041667 0.625000 +vt 0.020833 0.625000 +vt 0.041667 0.666667 +vt 0.020833 0.666667 +vt -0.000000 0.666667 +vt -0.000000 0.708333 +vt 0.041667 0.708333 +vt 0.020833 0.708333 +vt 0.041667 0.750000 +vt 0.020833 0.750000 +vt -0.000000 0.750000 +vt -0.000000 0.791667 +vt 0.041667 0.791667 +vt 0.020833 0.791667 +vt 0.041667 0.833333 +vt 0.020833 0.833333 +vt -0.000000 0.833333 +vt -0.000000 0.875000 +vt 0.041667 0.875000 +vt 0.020833 0.875000 +vt 0.041667 0.916667 +vt 0.020833 0.916667 +vt -0.000000 0.916667 +vt -0.000000 0.958333 +vt 0.041667 0.958333 +vt 0.020833 0.958333 +vt 0.041667 1.000000 +vt 0.020833 1.000000 +vt -0.000000 1.000000 +vt -0.000000 0.000000 +vt 0.020833 0.041667 +vt -0.000000 0.041667 +vt 0.041667 0.000000 +vt 0.020833 0.000000 +vt 0.041667 0.041667 +vt 0.020833 0.083333 +vt -0.000000 0.083333 +vt 0.020833 0.125000 +vt -0.000000 0.125000 +vt 0.041667 0.083333 +vt 0.041667 0.125000 +vt 0.020833 0.166667 +vt -0.000000 0.166667 +vt 0.020833 0.208333 +vt -0.000000 0.208333 +vt 0.041667 0.166667 +vt 0.041667 0.208333 +vt 0.020833 0.250000 +vt -0.000000 0.250000 +vt 0.020833 0.291667 +vt -0.000000 0.291667 +vt 0.041667 0.250000 +vt 0.041667 0.291667 +vt 0.020833 0.333333 +vt -0.000000 0.333333 +vt 0.020833 0.375000 +vt -0.000000 0.375000 +vt 0.041667 0.333333 +vt 0.041667 0.375000 +vt 0.020833 0.416667 +vt -0.000000 0.416667 +vt 0.020833 0.458333 +vt -0.000000 0.458333 +vt 0.041667 0.416667 +vt 0.041667 0.458333 +vt 0.062500 0.500000 +vt 0.041667 0.500000 +vt 0.083333 0.541667 +vt 0.062500 0.541667 +vt 0.083333 0.583333 +vt 0.062500 0.583333 +vt 0.083333 0.625000 +vt 0.062500 0.625000 +vt 0.083333 0.666667 +vt 0.062500 0.666667 +vt 0.083333 0.708333 +vt 0.062500 0.708333 +vt 0.083333 0.750000 +vt 0.062500 0.750000 +vt 0.083333 0.791667 +vt 0.062500 0.791667 +vt 0.083333 0.833333 +vt 0.062500 0.833333 +vt 0.083333 0.875000 +vt 0.062500 0.875000 +vt 0.083333 0.916667 +vt 0.062500 0.916667 +vt 0.083333 0.958333 +vt 0.062500 0.958333 +vt 0.083333 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.041667 +vt 0.083333 0.000000 +vt 0.062500 0.000000 +vt 0.083333 0.041667 +vt 0.062500 0.083333 +vt 0.062500 0.125000 +vt 0.083333 0.083333 +vt 0.083333 0.125000 +vt 0.062500 0.166667 +vt 0.062500 0.208333 +vt 0.083333 0.166667 +vt 0.083333 0.208333 +vt 0.062500 0.250000 +vt 0.062500 0.291667 +vt 0.083333 0.250000 +vt 0.083333 0.291667 +vt 0.062500 0.333333 +vt 0.062500 0.375000 +vt 0.083333 0.333333 +vt 0.083333 0.375000 +vt 0.062500 0.416667 +vt 0.062500 0.458333 +vt 0.083333 0.416667 +vt 0.083333 0.458333 +vt 0.104167 0.500000 +vt 0.083333 0.500000 +vt 0.125000 0.541667 +vt 0.104167 0.541667 +vt 0.125000 0.583333 +vt 0.104167 0.583333 +vt 0.125000 0.625000 +vt 0.104167 0.625000 +vt 0.125000 0.666667 +vt 0.104167 0.666667 +vt 0.125000 0.708333 +vt 0.104167 0.708333 +vt 0.125000 0.750000 +vt 0.104167 0.750000 +vt 0.125000 0.791667 +vt 0.104167 0.791667 +vt 0.125000 0.833333 +vt 0.104167 0.833333 +vt 0.125000 0.875000 +vt 0.104167 0.875000 +vt 0.125000 0.916667 +vt 0.104167 0.916667 +vt 0.125000 0.958333 +vt 0.104167 0.958333 +vt 0.125000 1.000000 +vt 0.104167 1.000000 +vt 0.104167 0.041667 +vt 0.125000 0.000000 +vt 0.104167 0.000000 +vt 0.125000 0.041667 +vt 0.104167 0.083333 +vt 0.104167 0.125000 +vt 0.125000 0.083333 +vt 0.125000 0.125000 +vt 0.104167 0.166667 +vt 0.104167 0.208333 +vt 0.125000 0.166667 +vt 0.125000 0.208333 +vt 0.104167 0.250000 +vt 0.104167 0.291667 +vt 0.125000 0.250000 +vt 0.125000 0.291667 +vt 0.104167 0.333333 +vt 0.104167 0.375000 +vt 0.125000 0.333333 +vt 0.125000 0.375000 +vt 0.104167 0.416667 +vt 0.104167 0.458333 +vt 0.125000 0.416667 +vt 0.125000 0.458333 +vt 0.145833 0.500000 +vt 0.125000 0.500000 +vt 0.166667 0.541667 +vt 0.145833 0.541667 +vt 0.166667 0.583333 +vt 0.145833 0.583333 +vt 0.166667 0.625000 +vt 0.145833 0.625000 +vt 0.166667 0.666667 +vt 0.145833 0.666667 +vt 0.166667 0.708333 +vt 0.145833 0.708333 +vt 0.166667 0.750000 +vt 0.145833 0.750000 +vt 0.166667 0.791667 +vt 0.145833 0.791667 +vt 0.166667 0.833333 +vt 0.145833 0.833333 +vt 0.166667 0.875000 +vt 0.145833 0.875000 +vt 0.166667 0.916667 +vt 0.145833 0.916667 +vt 0.166667 0.958333 +vt 0.145833 0.958333 +vt 0.166667 1.000000 +vt 0.145833 1.000000 +vt 0.145833 0.041667 +vt 0.166667 0.000000 +vt 0.145833 0.000000 +vt 0.166667 0.041667 +vt 0.145833 0.083333 +vt 0.145833 0.125000 +vt 0.166667 0.083333 +vt 0.166667 0.125000 +vt 0.145833 0.166667 +vt 0.145833 0.208333 +vt 0.166667 0.166667 +vt 0.166667 0.208333 +vt 0.145833 0.250000 +vt 0.145833 0.291667 +vt 0.166667 0.250000 +vt 0.166667 0.291667 +vt 0.145833 0.333333 +vt 0.145833 0.375000 +vt 0.166667 0.333333 +vt 0.166667 0.375000 +vt 0.145833 0.416667 +vt 0.145833 0.458333 +vt 0.166667 0.416667 +vt 0.166667 0.458333 +vt 0.187500 0.500000 +vt 0.166667 0.500000 +vt 0.208333 0.541667 +vt 0.187500 0.541667 +vt 0.208333 0.583333 +vt 0.187500 0.583333 +vt 0.208333 0.625000 +vt 0.187500 0.625000 +vt 0.208333 0.666667 +vt 0.187500 0.666667 +vt 0.208333 0.708333 +vt 0.187500 0.708333 +vt 0.208333 0.750000 +vt 0.187500 0.750000 +vt 0.208333 0.791667 +vt 0.187500 0.791667 +vt 0.208333 0.833333 +vt 0.187500 0.833333 +vt 0.208333 0.875000 +vt 0.187500 0.875000 +vt 0.208333 0.916667 +vt 0.187500 0.916667 +vt 0.208333 0.958333 +vt 0.187500 0.958333 +vt 0.208333 1.000000 +vt 0.187500 1.000000 +vt 0.187500 0.041667 +vt 0.208333 0.000000 +vt 0.187500 0.000000 +vt 0.208333 0.041667 +vt 0.187500 0.083333 +vt 0.187500 0.125000 +vt 0.208333 0.083333 +vt 0.208333 0.125000 +vt 0.187500 0.166667 +vt 0.187500 0.208333 +vt 0.208333 0.166667 +vt 0.208333 0.208333 +vt 0.187500 0.250000 +vt 0.187500 0.291667 +vt 0.208333 0.250000 +vt 0.208333 0.291667 +vt 0.187500 0.333333 +vt 0.187500 0.375000 +vt 0.208333 0.333333 +vt 0.208333 0.375000 +vt 0.187500 0.416667 +vt 0.187500 0.458333 +vt 0.208333 0.416667 +vt 0.208333 0.458333 +vt 0.229167 0.500000 +vt 0.208333 0.500000 +vt 0.250000 0.541667 +vt 0.229167 0.541667 +vt 0.250000 0.583333 +vt 0.229167 0.583333 +vt 0.250000 0.625000 +vt 0.229167 0.625000 +vt 0.250000 0.666667 +vt 0.229167 0.666667 +vt 0.250000 0.708333 +vt 0.229167 0.708333 +vt 0.250000 0.750000 +vt 0.229167 0.750000 +vt 0.250000 0.791667 +vt 0.229167 0.791667 +vt 0.250000 0.833333 +vt 0.229167 0.833333 +vt 0.250000 0.875000 +vt 0.229167 0.875000 +vt 0.250000 0.916667 +vt 0.229167 0.916667 +vt 0.250000 0.958333 +vt 0.229167 0.958333 +vt 0.250000 1.000000 +vt 0.229167 1.000000 +vt 0.229167 0.041667 +vt 0.250000 0.000000 +vt 0.229167 0.000000 +vt 0.250000 0.041667 +vt 0.229167 0.083333 +vt 0.229167 0.125000 +vt 0.250000 0.083333 +vt 0.250000 0.125000 +vt 0.229167 0.166667 +vt 0.229167 0.208333 +vt 0.250000 0.166667 +vt 0.250000 0.208333 +vt 0.229167 0.250000 +vt 0.229167 0.291667 +vt 0.250000 0.250000 +vt 0.250000 0.291667 +vt 0.229167 0.333333 +vt 0.229167 0.375000 +vt 0.250000 0.333333 +vt 0.250000 0.375000 +vt 0.229167 0.416667 +vt 0.229167 0.458333 +vt 0.250000 0.416667 +vt 0.250000 0.458333 +vt 0.270833 0.500000 +vt 0.250000 0.500000 +vt 0.291667 0.541667 +vt 0.270833 0.541667 +vt 0.291667 0.583333 +vt 0.270833 0.583333 +vt 0.291667 0.625000 +vt 0.270833 0.625000 +vt 0.291667 0.666667 +vt 0.270833 0.666667 +vt 0.291667 0.708333 +vt 0.270833 0.708333 +vt 0.291667 0.750000 +vt 0.270833 0.750000 +vt 0.291667 0.791667 +vt 0.270833 0.791667 +vt 0.291667 0.833333 +vt 0.270833 0.833333 +vt 0.291667 0.875000 +vt 0.270833 0.875000 +vt 0.291667 0.916667 +vt 0.270833 0.916667 +vt 0.291667 0.958333 +vt 0.270833 0.958333 +vt 0.291667 1.000000 +vt 0.270833 1.000000 +vt 0.270833 0.041667 +vt 0.291667 0.000000 +vt 0.270833 0.000000 +vt 0.291667 0.041667 +vt 0.270833 0.083333 +vt 0.270833 0.125000 +vt 0.291667 0.083333 +vt 0.291667 0.125000 +vt 0.270833 0.166667 +vt 0.270833 0.208333 +vt 0.291667 0.166667 +vt 0.291667 0.208333 +vt 0.270833 0.250000 +vt 0.270833 0.291667 +vt 0.291667 0.250000 +vt 0.291667 0.291667 +vt 0.270833 0.333333 +vt 0.270833 0.375000 +vt 0.291667 0.333333 +vt 0.291667 0.375000 +vt 0.270833 0.416667 +vt 0.270833 0.458333 +vt 0.291667 0.416667 +vt 0.291667 0.458333 +vt 0.312500 0.500000 +vt 0.291667 0.500000 +vt 0.333333 0.541667 +vt 0.312500 0.541667 +vt 0.333333 0.583333 +vt 0.312500 0.583333 +vt 0.333333 0.625000 +vt 0.312500 0.625000 +vt 0.333333 0.666667 +vt 0.312500 0.666667 +vt 0.333333 0.708333 +vt 0.312500 0.708333 +vt 0.333333 0.750000 +vt 0.312500 0.750000 +vt 0.333333 0.791667 +vt 0.312500 0.791667 +vt 0.333333 0.833333 +vt 0.312500 0.833333 +vt 0.333333 0.875000 +vt 0.312500 0.875000 +vt 0.333333 0.916667 +vt 0.312500 0.916667 +vt 0.333333 0.958333 +vt 0.312500 0.958333 +vt 0.333333 1.000000 +vt 0.312500 1.000000 +vt 0.312500 0.041667 +vt 0.333333 0.000000 +vt 0.312500 0.000000 +vt 0.333333 0.041667 +vt 0.312500 0.083333 +vt 0.312500 0.125000 +vt 0.333333 0.083333 +vt 0.333333 0.125000 +vt 0.312500 0.166667 +vt 0.312500 0.208333 +vt 0.333333 0.166667 +vt 0.333333 0.208333 +vt 0.312500 0.250000 +vt 0.312500 0.291667 +vt 0.333333 0.250000 +vt 0.333333 0.291667 +vt 0.312500 0.333333 +vt 0.312500 0.375000 +vt 0.333333 0.333333 +vt 0.333333 0.375000 +vt 0.312500 0.416667 +vt 0.312500 0.458333 +vt 0.333333 0.416667 +vt 0.333333 0.458333 +vt 0.354167 0.500000 +vt 0.333333 0.500000 +vt 0.375000 0.541667 +vt 0.354167 0.541667 +vt 0.375000 0.583333 +vt 0.354167 0.583333 +vt 0.375000 0.625000 +vt 0.354167 0.625000 +vt 0.375000 0.666667 +vt 0.354167 0.666667 +vt 0.375000 0.708333 +vt 0.354167 0.708333 +vt 0.375000 0.750000 +vt 0.354167 0.750000 +vt 0.375000 0.791667 +vt 0.354167 0.791667 +vt 0.375000 0.833333 +vt 0.354167 0.833333 +vt 0.375000 0.875000 +vt 0.354167 0.875000 +vt 0.375000 0.916667 +vt 0.354167 0.916667 +vt 0.375000 0.958333 +vt 0.354167 0.958333 +vt 0.375000 1.000000 +vt 0.354167 1.000000 +vt 0.354167 0.041667 +vt 0.375000 0.000000 +vt 0.354167 0.000000 +vt 0.375000 0.041667 +vt 0.354167 0.083333 +vt 0.354167 0.125000 +vt 0.375000 0.083333 +vt 0.375000 0.125000 +vt 0.354167 0.166667 +vt 0.354167 0.208333 +vt 0.375000 0.166667 +vt 0.375000 0.208333 +vt 0.354167 0.250000 +vt 0.354167 0.291667 +vt 0.375000 0.250000 +vt 0.375000 0.291667 +vt 0.354167 0.333333 +vt 0.354167 0.375000 +vt 0.375000 0.333333 +vt 0.375000 0.375000 +vt 0.354167 0.416667 +vt 0.354167 0.458333 +vt 0.375000 0.416667 +vt 0.375000 0.458333 +vt 0.395833 0.500000 +vt 0.375000 0.500000 +vt 0.416667 0.541667 +vt 0.395833 0.541667 +vt 0.416667 0.583333 +vt 0.395833 0.583333 +vt 0.416667 0.625000 +vt 0.395833 0.625000 +vt 0.416667 0.666667 +vt 0.395833 0.666667 +vt 0.416667 0.708333 +vt 0.395833 0.708333 +vt 0.416667 0.750000 +vt 0.395833 0.750000 +vt 0.416667 0.791667 +vt 0.395833 0.791667 +vt 0.416667 0.833333 +vt 0.395833 0.833333 +vt 0.416667 0.875000 +vt 0.395833 0.875000 +vt 0.416667 0.916667 +vt 0.395833 0.916667 +vt 0.416667 0.958333 +vt 0.395833 0.958333 +vt 0.416667 1.000000 +vt 0.395833 1.000000 +vt 0.395833 0.041667 +vt 0.416667 0.000000 +vt 0.395833 0.000000 +vt 0.416667 0.041667 +vt 0.395833 0.083333 +vt 0.395833 0.125000 +vt 0.416667 0.083333 +vt 0.416667 0.125000 +vt 0.395833 0.166667 +vt 0.395833 0.208333 +vt 0.416667 0.166667 +vt 0.416667 0.208333 +vt 0.395833 0.250000 +vt 0.395833 0.291667 +vt 0.416667 0.250000 +vt 0.416667 0.291667 +vt 0.395833 0.333333 +vt 0.395833 0.375000 +vt 0.416667 0.333333 +vt 0.416667 0.375000 +vt 0.395833 0.416667 +vt 0.395833 0.458333 +vt 0.416667 0.416667 +vt 0.416667 0.458333 +vt 0.437500 0.500000 +vt 0.416667 0.500000 +vt 0.458333 0.541667 +vt 0.437500 0.541667 +vt 0.458333 0.583333 +vt 0.437500 0.583333 +vt 0.458333 0.625000 +vt 0.437500 0.625000 +vt 0.458333 0.666667 +vt 0.437500 0.666667 +vt 0.458333 0.708333 +vt 0.437500 0.708333 +vt 0.458333 0.750000 +vt 0.437500 0.750000 +vt 0.458333 0.791667 +vt 0.437500 0.791667 +vt 0.458333 0.833333 +vt 0.437500 0.833333 +vt 0.458333 0.875000 +vt 0.437500 0.875000 +vt 0.458333 0.916667 +vt 0.437500 0.916667 +vt 0.458333 0.958333 +vt 0.437500 0.958333 +vt 0.458333 1.000000 +vt 0.437500 1.000000 +vt 0.437500 0.041667 +vt 0.458333 0.000000 +vt 0.437500 0.000000 +vt 0.458333 0.041667 +vt 0.437500 0.083333 +vt 0.437500 0.125000 +vt 0.458333 0.083333 +vt 0.458333 0.125000 +vt 0.437500 0.166667 +vt 0.437500 0.208333 +vt 0.458333 0.166667 +vt 0.458333 0.208333 +vt 0.437500 0.250000 +vt 0.437500 0.291667 +vt 0.458333 0.250000 +vt 0.458333 0.291667 +vt 0.437500 0.333333 +vt 0.437500 0.375000 +vt 0.458333 0.333333 +vt 0.458333 0.375000 +vt 0.437500 0.416667 +vt 0.437500 0.458333 +vt 0.458333 0.416667 +vt 0.458333 0.458333 +vt 0.479167 0.500000 +vt 0.458333 0.500000 +vt 0.479167 0.541667 +vt 0.479167 0.583333 +vt 0.479167 0.625000 +vt 0.479167 0.666667 +vt 0.479167 0.708333 +vt 0.479167 0.750000 +vt 0.479167 0.791667 +vt 0.479167 0.833333 +vt 0.479167 0.875000 +vt 0.479167 0.916667 +vt 0.479167 0.958333 +vt 0.479167 1.000000 +vt 0.479167 0.041667 +vt 0.479167 0.000000 +vt 0.479167 0.083333 +vt 0.479167 0.125000 +vt 0.479167 0.166667 +vt 0.479167 0.208333 +vt 0.479167 0.250000 +vt 0.479167 0.291667 +vt 0.479167 0.333333 +vt 0.479167 0.375000 +vt 0.479167 0.416667 +vt 0.479167 0.458333 +vt 1.000000 0.500000 +vt 0.520833 0.500000 +vt 0.500000 0.541667 +vt 0.500000 0.500000 +vt 0.541667 0.541667 +vt 0.520833 0.541667 +vt 0.541667 0.583333 +vt 0.520833 0.583333 +vt 0.500000 0.583333 +vt 0.500000 0.625000 +vt 0.541667 0.625000 +vt 0.520833 0.625000 +vt 0.541667 0.666667 +vt 0.520833 0.666667 +vt 0.500000 0.666667 +vt 0.500000 0.708333 +vt 0.541667 0.708333 +vt 0.520833 0.708333 +vt 0.541667 0.750000 +vt 0.520833 0.750000 +vt 0.500000 0.750000 +vt 0.500000 0.791667 +vt 0.541667 0.791667 +vt 0.520833 0.791667 +vt 0.541667 0.833333 +vt 0.520833 0.833333 +vt 0.500000 0.833333 +vt 0.500000 0.875000 +vt 0.541667 0.875000 +vt 0.520833 0.875000 +vt 0.541667 0.916667 +vt 0.520833 0.916667 +vt 0.500000 0.916667 +vt 0.500000 0.958333 +vt 0.541667 0.958333 +vt 0.520833 0.958333 +vt 0.541667 1.000000 +vt 0.520833 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.000000 +vt 0.520833 0.041667 +vt 0.500000 0.041667 +vt 0.541667 0.000000 +vt 0.520833 0.000000 +vt 0.541667 0.041667 +vt 0.520833 0.083333 +vt 0.500000 0.083333 +vt 0.520833 0.125000 +vt 0.500000 0.125000 +vt 0.541667 0.083333 +vt 0.541667 0.125000 +vt 0.520833 0.166667 +vt 0.500000 0.166667 +vt 0.520833 0.208333 +vt 0.500000 0.208333 +vt 0.541667 0.166667 +vt 0.541667 0.208333 +vt 0.520833 0.250000 +vt 0.500000 0.250000 +vt 0.520833 0.291667 +vt 0.500000 0.291667 +vt 0.541667 0.250000 +vt 0.541667 0.291667 +vt 0.520833 0.333333 +vt 0.500000 0.333333 +vt 0.520833 0.375000 +vt 0.500000 0.375000 +vt 0.541667 0.333333 +vt 0.541667 0.375000 +vt 0.520833 0.416667 +vt 0.500000 0.416667 +vt 0.520833 0.458333 +vt 0.500000 0.458333 +vt 0.541667 0.416667 +vt 0.541667 0.458333 +vt 0.562500 0.500000 +vt 0.541667 0.500000 +vt 0.583333 0.541667 +vt 0.562500 0.541667 +vt 0.583333 0.583333 +vt 0.562500 0.583333 +vt 0.583333 0.625000 +vt 0.562500 0.625000 +vt 0.583333 0.666667 +vt 0.562500 0.666667 +vt 0.583333 0.708333 +vt 0.562500 0.708333 +vt 0.583333 0.750000 +vt 0.562500 0.750000 +vt 0.583333 0.791667 +vt 0.562500 0.791667 +vt 0.583333 0.833333 +vt 0.562500 0.833333 +vt 0.583333 0.875000 +vt 0.562500 0.875000 +vt 0.583333 0.916667 +vt 0.562500 0.916667 +vt 0.583333 0.958333 +vt 0.562500 0.958333 +vt 0.583333 1.000000 +vt 0.562500 1.000000 +vt 0.562500 0.041667 +vt 0.583333 0.000000 +vt 0.562500 0.000000 +vt 0.583333 0.041667 +vt 0.562500 0.083333 +vt 0.562500 0.125000 +vt 0.583333 0.083333 +vt 0.583333 0.125000 +vt 0.562500 0.166667 +vt 0.562500 0.208333 +vt 0.583333 0.166667 +vt 0.583333 0.208333 +vt 0.562500 0.250000 +vt 0.562500 0.291667 +vt 0.583333 0.250000 +vt 0.583333 0.291667 +vt 0.562500 0.333333 +vt 0.562500 0.375000 +vt 0.583333 0.333333 +vt 0.583333 0.375000 +vt 0.562500 0.416667 +vt 0.562500 0.458333 +vt 0.583333 0.416667 +vt 0.583333 0.458333 +vt 0.604167 0.500000 +vt 0.583333 0.500000 +vt 0.625000 0.541667 +vt 0.604167 0.541667 +vt 0.625000 0.583333 +vt 0.604167 0.583333 +vt 0.625000 0.625000 +vt 0.604167 0.625000 +vt 0.625000 0.666667 +vt 0.604167 0.666667 +vt 0.625000 0.708333 +vt 0.604167 0.708333 +vt 0.625000 0.750000 +vt 0.604167 0.750000 +vt 0.625000 0.791667 +vt 0.604167 0.791667 +vt 0.625000 0.833333 +vt 0.604167 0.833333 +vt 0.625000 0.875000 +vt 0.604167 0.875000 +vt 0.625000 0.916667 +vt 0.604167 0.916667 +vt 0.625000 0.958333 +vt 0.604167 0.958333 +vt 0.625000 1.000000 +vt 0.604167 1.000000 +vt 0.604167 0.041667 +vt 0.625000 0.000000 +vt 0.604167 0.000000 +vt 0.625000 0.041667 +vt 0.604167 0.083333 +vt 0.604167 0.125000 +vt 0.625000 0.083333 +vt 0.625000 0.125000 +vt 0.604167 0.166667 +vt 0.604167 0.208333 +vt 0.625000 0.166667 +vt 0.625000 0.208333 +vt 0.604167 0.250000 +vt 0.604167 0.291667 +vt 0.625000 0.250000 +vt 0.625000 0.291667 +vt 0.604167 0.333333 +vt 0.604167 0.375000 +vt 0.625000 0.333333 +vt 0.625000 0.375000 +vt 0.604167 0.416667 +vt 0.604167 0.458333 +vt 0.625000 0.416667 +vt 0.625000 0.458333 +vt 0.645833 0.500000 +vt 0.625000 0.500000 +vt 0.666667 0.541667 +vt 0.645833 0.541667 +vt 0.666667 0.583333 +vt 0.645833 0.583333 +vt 0.666667 0.625000 +vt 0.645833 0.625000 +vt 0.666667 0.666667 +vt 0.645833 0.666667 +vt 0.666667 0.708333 +vt 0.645833 0.708333 +vt 0.666667 0.750000 +vt 0.645833 0.750000 +vt 0.666667 0.791667 +vt 0.645833 0.791667 +vt 0.666667 0.833333 +vt 0.645833 0.833333 +vt 0.666667 0.875000 +vt 0.645833 0.875000 +vt 0.666667 0.916667 +vt 0.645833 0.916667 +vt 0.666667 0.958333 +vt 0.645833 0.958333 +vt 0.666667 1.000000 +vt 0.645833 1.000000 +vt 0.645833 0.041667 +vt 0.666667 0.000000 +vt 0.645833 0.000000 +vt 0.666667 0.041667 +vt 0.645833 0.083333 +vt 0.645833 0.125000 +vt 0.666667 0.083333 +vt 0.666667 0.125000 +vt 0.645833 0.166667 +vt 0.645833 0.208333 +vt 0.666667 0.166667 +vt 0.666667 0.208333 +vt 0.645833 0.250000 +vt 0.645833 0.291667 +vt 0.666667 0.250000 +vt 0.666667 0.291667 +vt 0.645833 0.333333 +vt 0.645833 0.375000 +vt 0.666667 0.333333 +vt 0.666667 0.375000 +vt 0.645833 0.416667 +vt 0.645833 0.458333 +vt 0.666667 0.416667 +vt 0.666667 0.458333 +vt 0.687500 0.500000 +vt 0.666667 0.500000 +vt 0.708333 0.541667 +vt 0.687500 0.541667 +vt 0.708333 0.583333 +vt 0.687500 0.583333 +vt 0.708333 0.625000 +vt 0.687500 0.625000 +vt 0.708333 0.666667 +vt 0.687500 0.666667 +vt 0.708333 0.708333 +vt 0.687500 0.708333 +vt 0.708333 0.750000 +vt 0.687500 0.750000 +vt 0.708333 0.791667 +vt 0.687500 0.791667 +vt 0.708333 0.833333 +vt 0.687500 0.833333 +vt 0.708333 0.875000 +vt 0.687500 0.875000 +vt 0.708333 0.916667 +vt 0.687500 0.916667 +vt 0.708333 0.958333 +vt 0.687500 0.958333 +vt 0.708333 1.000000 +vt 0.687500 1.000000 +vt 0.687500 0.041667 +vt 0.708333 0.000000 +vt 0.687500 0.000000 +vt 0.708333 0.041667 +vt 0.687500 0.083333 +vt 0.687500 0.125000 +vt 0.708333 0.083333 +vt 0.708333 0.125000 +vt 0.687500 0.166667 +vt 0.687500 0.208333 +vt 0.708333 0.166667 +vt 0.708333 0.208333 +vt 0.687500 0.250000 +vt 0.687500 0.291667 +vt 0.708333 0.250000 +vt 0.708333 0.291667 +vt 0.687500 0.333333 +vt 0.687500 0.375000 +vt 0.708333 0.333333 +vt 0.708333 0.375000 +vt 0.687500 0.416667 +vt 0.687500 0.458333 +vt 0.708333 0.416667 +vt 0.708333 0.458333 +vt 0.729167 0.500000 +vt 0.708333 0.500000 +vt 0.750000 0.541667 +vt 0.729167 0.541667 +vt 0.750000 0.583333 +vt 0.729167 0.583333 +vt 0.750000 0.625000 +vt 0.729167 0.625000 +vt 0.750000 0.666667 +vt 0.729167 0.666667 +vt 0.750000 0.708333 +vt 0.729167 0.708333 +vt 0.750000 0.750000 +vt 0.729167 0.750000 +vt 0.750000 0.791667 +vt 0.729167 0.791667 +vt 0.750000 0.833333 +vt 0.729167 0.833333 +vt 0.750000 0.875000 +vt 0.729167 0.875000 +vt 0.750000 0.916667 +vt 0.729167 0.916667 +vt 0.750000 0.958333 +vt 0.729167 0.958333 +vt 0.750000 1.000000 +vt 0.729167 1.000000 +vt 0.729167 0.041667 +vt 0.750000 0.000000 +vt 0.729167 0.000000 +vt 0.750000 0.041667 +vt 0.729167 0.083333 +vt 0.729167 0.125000 +vt 0.750000 0.083333 +vt 0.750000 0.125000 +vt 0.729167 0.166667 +vt 0.729167 0.208333 +vt 0.750000 0.166667 +vt 0.750000 0.208333 +vt 0.729167 0.250000 +vt 0.729167 0.291667 +vt 0.750000 0.250000 +vt 0.750000 0.291667 +vt 0.729167 0.333333 +vt 0.729167 0.375000 +vt 0.750000 0.333333 +vt 0.750000 0.375000 +vt 0.729167 0.416667 +vt 0.729167 0.458333 +vt 0.750000 0.416667 +vt 0.750000 0.458333 +vt 0.770833 0.500000 +vt 0.750000 0.500000 +vt 0.791667 0.541667 +vt 0.770833 0.541667 +vt 0.791667 0.583333 +vt 0.770833 0.583333 +vt 0.791667 0.625000 +vt 0.770833 0.625000 +vt 0.791667 0.666667 +vt 0.770833 0.666667 +vt 0.791667 0.708333 +vt 0.770833 0.708333 +vt 0.791667 0.750000 +vt 0.770833 0.750000 +vt 0.791667 0.791667 +vt 0.770833 0.791667 +vt 0.791667 0.833333 +vt 0.770833 0.833333 +vt 0.791667 0.875000 +vt 0.770833 0.875000 +vt 0.791667 0.916667 +vt 0.770833 0.916667 +vt 0.791667 0.958333 +vt 0.770833 0.958333 +vt 0.791667 1.000000 +vt 0.770833 1.000000 +vt 0.770833 0.041667 +vt 0.791667 0.000000 +vt 0.770833 0.000000 +vt 0.791667 0.041667 +vt 0.770833 0.083333 +vt 0.770833 0.125000 +vt 0.791667 0.083333 +vt 0.791667 0.125000 +vt 0.770833 0.166667 +vt 0.770833 0.208333 +vt 0.791667 0.166667 +vt 0.791667 0.208333 +vt 0.770833 0.250000 +vt 0.770833 0.291667 +vt 0.791667 0.250000 +vt 0.791667 0.291667 +vt 0.770833 0.333333 +vt 0.770833 0.375000 +vt 0.791667 0.333333 +vt 0.791667 0.375000 +vt 0.770833 0.416667 +vt 0.770833 0.458333 +vt 0.791667 0.416667 +vt 0.791667 0.458333 +vt 0.812500 0.500000 +vt 0.791667 0.500000 +vt 0.833333 0.541667 +vt 0.812500 0.541667 +vt 0.833333 0.583333 +vt 0.812500 0.583333 +vt 0.833333 0.625000 +vt 0.812500 0.625000 +vt 0.833333 0.666667 +vt 0.812500 0.666667 +vt 0.833333 0.708333 +vt 0.812500 0.708333 +vt 0.833333 0.750000 +vt 0.812500 0.750000 +vt 0.833333 0.791667 +vt 0.812500 0.791667 +vt 0.833333 0.833333 +vt 0.812500 0.833333 +vt 0.833333 0.875000 +vt 0.812500 0.875000 +vt 0.833333 0.916667 +vt 0.812500 0.916667 +vt 0.833333 0.958333 +vt 0.812500 0.958333 +vt 0.833333 1.000000 +vt 0.812500 1.000000 +vt 0.812500 0.041667 +vt 0.833333 0.000000 +vt 0.812500 0.000000 +vt 0.833333 0.041667 +vt 0.812500 0.083333 +vt 0.812500 0.125000 +vt 0.833333 0.083333 +vt 0.833333 0.125000 +vt 0.812500 0.166667 +vt 0.812500 0.208333 +vt 0.833333 0.166667 +vt 0.833333 0.208333 +vt 0.812500 0.250000 +vt 0.812500 0.291667 +vt 0.833333 0.250000 +vt 0.833333 0.291667 +vt 0.812500 0.333333 +vt 0.812500 0.375000 +vt 0.833333 0.333333 +vt 0.833333 0.375000 +vt 0.812500 0.416667 +vt 0.812500 0.458333 +vt 0.833333 0.416667 +vt 0.833333 0.458333 +vt 0.854167 0.500000 +vt 0.833333 0.500000 +vt 0.875000 0.541667 +vt 0.854167 0.541667 +vt 0.875000 0.583333 +vt 0.854167 0.583333 +vt 0.875000 0.625000 +vt 0.854167 0.625000 +vt 0.875000 0.666667 +vt 0.854167 0.666667 +vt 0.875000 0.708333 +vt 0.854167 0.708333 +vt 0.875000 0.750000 +vt 0.854167 0.750000 +vt 0.875000 0.791667 +vt 0.854167 0.791667 +vt 0.875000 0.833333 +vt 0.854167 0.833333 +vt 0.875000 0.875000 +vt 0.854167 0.875000 +vt 0.875000 0.916667 +vt 0.854167 0.916667 +vt 0.875000 0.958333 +vt 0.854167 0.958333 +vt 0.875000 1.000000 +vt 0.854167 1.000000 +vt 0.854167 0.041667 +vt 0.875000 0.000000 +vt 0.854167 0.000000 +vt 0.875000 0.041667 +vt 0.854167 0.083333 +vt 0.854167 0.125000 +vt 0.875000 0.083333 +vt 0.875000 0.125000 +vt 0.854167 0.166667 +vt 0.854167 0.208333 +vt 0.875000 0.166667 +vt 0.875000 0.208333 +vt 0.854167 0.250000 +vt 0.854167 0.291667 +vt 0.875000 0.250000 +vt 0.875000 0.291667 +vt 0.854167 0.333333 +vt 0.854167 0.375000 +vt 0.875000 0.333333 +vt 0.875000 0.375000 +vt 0.854167 0.416667 +vt 0.854167 0.458333 +vt 0.875000 0.416667 +vt 0.875000 0.458333 +vt 0.895833 0.500000 +vt 0.875000 0.500000 +vt 0.916667 0.541667 +vt 0.895833 0.541667 +vt 0.916667 0.583333 +vt 0.895833 0.583333 +vt 0.916667 0.625000 +vt 0.895833 0.625000 +vt 0.916667 0.666667 +vt 0.895833 0.666667 +vt 0.916667 0.708333 +vt 0.895833 0.708333 +vt 0.916667 0.750000 +vt 0.895833 0.750000 +vt 0.916667 0.791667 +vt 0.895833 0.791667 +vt 0.916667 0.833333 +vt 0.895833 0.833333 +vt 0.916667 0.875000 +vt 0.895833 0.875000 +vt 0.916667 0.916667 +vt 0.895833 0.916667 +vt 0.916667 0.958333 +vt 0.895833 0.958333 +vt 0.916667 1.000000 +vt 0.895833 1.000000 +vt 0.895834 0.041667 +vt 0.916667 0.000000 +vt 0.895833 0.000000 +vt 0.916667 0.041667 +vt 0.895834 0.083333 +vt 0.895833 0.125000 +vt 0.916667 0.083333 +vt 0.916667 0.125000 +vt 0.895833 0.166667 +vt 0.895833 0.208333 +vt 0.916667 0.166667 +vt 0.916667 0.208333 +vt 0.895833 0.250000 +vt 0.895833 0.291667 +vt 0.916667 0.250000 +vt 0.916667 0.291667 +vt 0.895833 0.333333 +vt 0.895833 0.375000 +vt 0.916667 0.333333 +vt 0.916667 0.375000 +vt 0.895833 0.416667 +vt 0.895833 0.458333 +vt 0.916667 0.416667 +vt 0.916667 0.458333 +vt 0.937500 0.500000 +vt 0.916667 0.500000 +vt 0.958333 0.541667 +vt 0.937500 0.541667 +vt 0.958333 0.583333 +vt 0.937500 0.583333 +vt 0.958333 0.625000 +vt 0.937500 0.625000 +vt 0.958333 0.666667 +vt 0.937500 0.666667 +vt 0.958333 0.708333 +vt 0.937500 0.708333 +vt 0.958333 0.750000 +vt 0.937500 0.750000 +vt 0.958333 0.791667 +vt 0.937500 0.791667 +vt 0.958333 0.833333 +vt 0.937500 0.833333 +vt 0.958333 0.875000 +vt 0.937500 0.875000 +vt 0.958333 0.916667 +vt 0.937500 0.916667 +vt 0.958333 0.958333 +vt 0.937500 0.958333 +vt 0.958333 1.000000 +vt 0.937500 1.000000 +vt 0.937500 0.041667 +vt 0.958333 0.000000 +vt 0.937500 0.000000 +vt 0.958333 0.041667 +vt 0.937500 0.083333 +vt 0.937500 0.125000 +vt 0.958333 0.083333 +vt 0.958333 0.125000 +vt 0.937500 0.166667 +vt 0.937500 0.208333 +vt 0.958333 0.166667 +vt 0.958333 0.208333 +vt 0.937500 0.250000 +vt 0.937500 0.291667 +vt 0.958333 0.250000 +vt 0.958333 0.291667 +vt 0.937500 0.333333 +vt 0.937500 0.375000 +vt 0.958333 0.333333 +vt 0.958333 0.375000 +vt 0.937500 0.416667 +vt 0.937500 0.458333 +vt 0.958333 0.416667 +vt 0.958333 0.458333 +vt 0.979167 0.500000 +vt 0.958333 0.500000 +vt 1.000000 0.541667 +vt 0.979167 0.541667 +vt 1.000000 0.583333 +vt 0.979167 0.583333 +vt 1.000000 0.625000 +vt 0.979167 0.625000 +vt 1.000000 0.666667 +vt 0.979167 0.666667 +vt 1.000000 0.708333 +vt 0.979167 0.708333 +vt 1.000000 0.750000 +vt 0.979167 0.750000 +vt 1.000000 0.791667 +vt 0.979167 0.791667 +vt 1.000000 0.833333 +vt 0.979167 0.833333 +vt 1.000000 0.875000 +vt 0.979167 0.875000 +vt 1.000000 0.916667 +vt 0.979167 0.916667 +vt 1.000000 0.958333 +vt 0.979167 0.958333 +vt 1.000000 1.000000 +vt 0.979167 1.000000 +vt 0.979167 0.041667 +vt 1.000000 0.000000 +vt 0.979167 0.000000 +vt 1.000000 0.041667 +vt 0.979167 0.083333 +vt 0.979167 0.125000 +vt 1.000000 0.083333 +vt 1.000000 0.125000 +vt 0.979167 0.166667 +vt 0.979167 0.208333 +vt 1.000000 0.166667 +vt 1.000000 0.208333 +vt 0.979167 0.250000 +vt 0.979167 0.291667 +vt 1.000000 0.250000 +vt 1.000000 0.291667 +vt 0.979167 0.333333 +vt 0.979167 0.375000 +vt 1.000000 0.333333 +vt 1.000000 0.375000 +vt 0.979167 0.416667 +vt 0.979167 0.458333 +vt 1.000000 0.416667 +vt 1.000000 0.458333 +vt 0.020833 0.500000 +vt -0.000000 0.541667 +vt -0.000000 0.500000 +vt 0.041667 0.541667 +vt 0.020833 0.541667 +vt 0.041667 0.583333 +vt 0.020833 0.583333 +vt -0.000000 0.583333 +vt -0.000000 0.625000 +vt 0.041667 0.625000 +vt 0.020833 0.625000 +vt 0.041667 0.666667 +vt 0.020833 0.666667 +vt -0.000000 0.666667 +vt -0.000000 0.708333 +vt 0.041667 0.708333 +vt 0.020833 0.708333 +vt 0.041667 0.750000 +vt 0.020833 0.750000 +vt -0.000000 0.750000 +vt -0.000000 0.791667 +vt 0.041667 0.791667 +vt 0.020833 0.791667 +vt 0.041667 0.833333 +vt 0.020833 0.833333 +vt -0.000000 0.833333 +vt -0.000000 0.875000 +vt 0.041667 0.875000 +vt 0.020833 0.875000 +vt 0.041667 0.916667 +vt 0.020833 0.916667 +vt -0.000000 0.916667 +vt -0.000000 0.958333 +vt 0.041667 0.958333 +vt 0.020833 0.958333 +vt 0.041667 1.000000 +vt 0.020833 1.000000 +vt -0.000000 1.000000 +vt -0.000000 0.000000 +vt 0.020833 0.041667 +vt -0.000000 0.041667 +vt 0.041667 0.000000 +vt 0.020833 0.000000 +vt 0.041667 0.041667 +vt 0.020833 0.083333 +vt -0.000000 0.083333 +vt 0.020833 0.125000 +vt -0.000000 0.125000 +vt 0.041667 0.083333 +vt 0.041667 0.125000 +vt 0.020833 0.166667 +vt -0.000000 0.166667 +vt 0.020833 0.208333 +vt -0.000000 0.208333 +vt 0.041667 0.166667 +vt 0.041667 0.208333 +vt 0.020833 0.250000 +vt -0.000000 0.250000 +vt 0.020833 0.291667 +vt -0.000000 0.291667 +vt 0.041667 0.250000 +vt 0.041667 0.291667 +vt 0.020833 0.333333 +vt -0.000000 0.333333 +vt 0.020833 0.375000 +vt -0.000000 0.375000 +vt 0.041667 0.333333 +vt 0.041667 0.375000 +vt 0.020833 0.416667 +vt -0.000000 0.416667 +vt 0.020833 0.458333 +vt -0.000000 0.458333 +vt 0.041667 0.416667 +vt 0.041667 0.458333 +vt 0.062500 0.500000 +vt 0.041667 0.500000 +vt 0.083333 0.541667 +vt 0.062500 0.541667 +vt 0.083333 0.583333 +vt 0.062500 0.583333 +vt 0.083333 0.625000 +vt 0.062500 0.625000 +vt 0.083333 0.666667 +vt 0.062500 0.666667 +vt 0.083333 0.708333 +vt 0.062500 0.708333 +vt 0.083333 0.750000 +vt 0.062500 0.750000 +vt 0.083333 0.791667 +vt 0.062500 0.791667 +vt 0.083333 0.833333 +vt 0.062500 0.833333 +vt 0.083333 0.875000 +vt 0.062500 0.875000 +vt 0.083333 0.916667 +vt 0.062500 0.916667 +vt 0.083333 0.958333 +vt 0.062500 0.958333 +vt 0.083333 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.041667 +vt 0.083333 0.000000 +vt 0.062500 0.000000 +vt 0.083333 0.041667 +vt 0.062500 0.083333 +vt 0.062500 0.125000 +vt 0.083333 0.083333 +vt 0.083333 0.125000 +vt 0.062500 0.166667 +vt 0.062500 0.208333 +vt 0.083333 0.166667 +vt 0.083333 0.208333 +vt 0.062500 0.250000 +vt 0.062500 0.291667 +vt 0.083333 0.250000 +vt 0.083333 0.291667 +vt 0.062500 0.333333 +vt 0.062500 0.375000 +vt 0.083333 0.333333 +vt 0.083333 0.375000 +vt 0.062500 0.416667 +vt 0.062500 0.458333 +vt 0.083333 0.416667 +vt 0.083333 0.458333 +vt 0.104167 0.500000 +vt 0.083333 0.500000 +vt 0.125000 0.541667 +vt 0.104167 0.541667 +vt 0.125000 0.583333 +vt 0.104167 0.583333 +vt 0.125000 0.625000 +vt 0.104167 0.625000 +vt 0.125000 0.666667 +vt 0.104167 0.666667 +vt 0.125000 0.708333 +vt 0.104167 0.708333 +vt 0.125000 0.750000 +vt 0.104167 0.750000 +vt 0.125000 0.791667 +vt 0.104167 0.791667 +vt 0.125000 0.833333 +vt 0.104167 0.833333 +vt 0.125000 0.875000 +vt 0.104167 0.875000 +vt 0.125000 0.916667 +vt 0.104167 0.916667 +vt 0.125000 0.958333 +vt 0.104167 0.958333 +vt 0.125000 1.000000 +vt 0.104167 1.000000 +vt 0.104167 0.041667 +vt 0.125000 0.000000 +vt 0.104167 0.000000 +vt 0.125000 0.041667 +vt 0.104167 0.083333 +vt 0.104167 0.125000 +vt 0.125000 0.083333 +vt 0.125000 0.125000 +vt 0.104167 0.166667 +vt 0.104167 0.208333 +vt 0.125000 0.166667 +vt 0.125000 0.208333 +vt 0.104167 0.250000 +vt 0.104167 0.291667 +vt 0.125000 0.250000 +vt 0.125000 0.291667 +vt 0.104167 0.333333 +vt 0.104167 0.375000 +vt 0.125000 0.333333 +vt 0.125000 0.375000 +vt 0.104167 0.416667 +vt 0.104167 0.458333 +vt 0.125000 0.416667 +vt 0.125000 0.458333 +vt 0.145833 0.500000 +vt 0.125000 0.500000 +vt 0.166667 0.541667 +vt 0.145833 0.541667 +vt 0.166667 0.583333 +vt 0.145833 0.583333 +vt 0.166667 0.625000 +vt 0.145833 0.625000 +vt 0.166667 0.666667 +vt 0.145833 0.666667 +vt 0.166667 0.708333 +vt 0.145833 0.708333 +vt 0.166667 0.750000 +vt 0.145833 0.750000 +vt 0.166667 0.791667 +vt 0.145833 0.791667 +vt 0.166667 0.833333 +vt 0.145833 0.833333 +vt 0.166667 0.875000 +vt 0.145833 0.875000 +vt 0.166667 0.916667 +vt 0.145833 0.916667 +vt 0.166667 0.958333 +vt 0.145833 0.958333 +vt 0.166667 1.000000 +vt 0.145833 1.000000 +vt 0.145833 0.041667 +vt 0.166667 0.000000 +vt 0.145833 0.000000 +vt 0.166667 0.041667 +vt 0.145833 0.083333 +vt 0.145833 0.125000 +vt 0.166667 0.083333 +vt 0.166667 0.125000 +vt 0.145833 0.166667 +vt 0.145833 0.208333 +vt 0.166667 0.166667 +vt 0.166667 0.208333 +vt 0.145833 0.250000 +vt 0.145833 0.291667 +vt 0.166667 0.250000 +vt 0.166667 0.291667 +vt 0.145833 0.333333 +vt 0.145833 0.375000 +vt 0.166667 0.333333 +vt 0.166667 0.375000 +vt 0.145833 0.416667 +vt 0.145833 0.458333 +vt 0.166667 0.416667 +vt 0.166667 0.458333 +vt 0.187500 0.500000 +vt 0.166667 0.500000 +vt 0.208333 0.541667 +vt 0.187500 0.541667 +vt 0.208333 0.583333 +vt 0.187500 0.583333 +vt 0.208333 0.625000 +vt 0.187500 0.625000 +vt 0.208333 0.666667 +vt 0.187500 0.666667 +vt 0.208333 0.708333 +vt 0.187500 0.708333 +vt 0.208333 0.750000 +vt 0.187500 0.750000 +vt 0.208333 0.791667 +vt 0.187500 0.791667 +vt 0.208333 0.833333 +vt 0.187500 0.833333 +vt 0.208333 0.875000 +vt 0.187500 0.875000 +vt 0.208333 0.916667 +vt 0.187500 0.916667 +vt 0.208333 0.958333 +vt 0.187500 0.958333 +vt 0.208333 1.000000 +vt 0.187500 1.000000 +vt 0.187500 0.041667 +vt 0.208333 0.000000 +vt 0.187500 0.000000 +vt 0.208333 0.041667 +vt 0.187500 0.083333 +vt 0.187500 0.125000 +vt 0.208333 0.083333 +vt 0.208333 0.125000 +vt 0.187500 0.166667 +vt 0.187500 0.208333 +vt 0.208333 0.166667 +vt 0.208333 0.208333 +vt 0.187500 0.250000 +vt 0.187500 0.291667 +vt 0.208333 0.250000 +vt 0.208333 0.291667 +vt 0.187500 0.333333 +vt 0.187500 0.375000 +vt 0.208333 0.333333 +vt 0.208333 0.375000 +vt 0.187500 0.416667 +vt 0.187500 0.458333 +vt 0.208333 0.416667 +vt 0.208333 0.458333 +vt 0.229167 0.500000 +vt 0.208333 0.500000 +vt 0.250000 0.541667 +vt 0.229167 0.541667 +vt 0.250000 0.583333 +vt 0.229167 0.583333 +vt 0.250000 0.625000 +vt 0.229167 0.625000 +vt 0.250000 0.666667 +vt 0.229167 0.666667 +vt 0.250000 0.708333 +vt 0.229167 0.708333 +vt 0.250000 0.750000 +vt 0.229167 0.750000 +vt 0.250000 0.791667 +vt 0.229167 0.791667 +vt 0.250000 0.833333 +vt 0.229167 0.833333 +vt 0.250000 0.875000 +vt 0.229167 0.875000 +vt 0.250000 0.916667 +vt 0.229167 0.916667 +vt 0.250000 0.958333 +vt 0.229167 0.958333 +vt 0.250000 1.000000 +vt 0.229167 1.000000 +vt 0.229167 0.041667 +vt 0.250000 0.000000 +vt 0.229167 0.000000 +vt 0.250000 0.041667 +vt 0.229167 0.083333 +vt 0.229167 0.125000 +vt 0.250000 0.083333 +vt 0.250000 0.125000 +vt 0.229167 0.166667 +vt 0.229167 0.208333 +vt 0.250000 0.166667 +vt 0.250000 0.208333 +vt 0.229167 0.250000 +vt 0.229167 0.291667 +vt 0.250000 0.250000 +vt 0.250000 0.291667 +vt 0.229167 0.333333 +vt 0.229167 0.375000 +vt 0.250000 0.333333 +vt 0.250000 0.375000 +vt 0.229167 0.416667 +vt 0.229167 0.458333 +vt 0.250000 0.416667 +vt 0.250000 0.458333 +vt 0.270833 0.500000 +vt 0.250000 0.500000 +vt 0.291667 0.541667 +vt 0.270833 0.541667 +vt 0.291667 0.583333 +vt 0.270833 0.583333 +vt 0.291667 0.625000 +vt 0.270833 0.625000 +vt 0.291667 0.666667 +vt 0.270833 0.666667 +vt 0.291667 0.708333 +vt 0.270833 0.708333 +vt 0.291667 0.750000 +vt 0.270833 0.750000 +vt 0.291667 0.791667 +vt 0.270833 0.791667 +vt 0.291667 0.833333 +vt 0.270833 0.833333 +vt 0.291667 0.875000 +vt 0.270833 0.875000 +vt 0.291667 0.916667 +vt 0.270833 0.916667 +vt 0.291667 0.958333 +vt 0.270833 0.958333 +vt 0.291667 1.000000 +vt 0.270833 1.000000 +vt 0.270833 0.041667 +vt 0.291667 0.000000 +vt 0.270833 0.000000 +vt 0.291667 0.041667 +vt 0.270833 0.083333 +vt 0.270833 0.125000 +vt 0.291667 0.083333 +vt 0.291667 0.125000 +vt 0.270833 0.166667 +vt 0.270833 0.208333 +vt 0.291667 0.166667 +vt 0.291667 0.208333 +vt 0.270833 0.250000 +vt 0.270833 0.291667 +vt 0.291667 0.250000 +vt 0.291667 0.291667 +vt 0.270833 0.333333 +vt 0.270833 0.375000 +vt 0.291667 0.333333 +vt 0.291667 0.375000 +vt 0.270833 0.416667 +vt 0.270833 0.458333 +vt 0.291667 0.416667 +vt 0.291667 0.458333 +vt 0.312500 0.500000 +vt 0.291667 0.500000 +vt 0.333333 0.541667 +vt 0.312500 0.541667 +vt 0.333333 0.583333 +vt 0.312500 0.583333 +vt 0.333333 0.625000 +vt 0.312500 0.625000 +vt 0.333333 0.666667 +vt 0.312500 0.666667 +vt 0.333333 0.708333 +vt 0.312500 0.708333 +vt 0.333333 0.750000 +vt 0.312500 0.750000 +vt 0.333333 0.791667 +vt 0.312500 0.791667 +vt 0.333333 0.833333 +vt 0.312500 0.833333 +vt 0.333333 0.875000 +vt 0.312500 0.875000 +vt 0.333333 0.916667 +vt 0.312500 0.916667 +vt 0.333333 0.958333 +vt 0.312500 0.958333 +vt 0.333333 1.000000 +vt 0.312500 1.000000 +vt 0.312500 0.041667 +vt 0.333333 0.000000 +vt 0.312500 0.000000 +vt 0.333333 0.041667 +vt 0.312500 0.083333 +vt 0.312500 0.125000 +vt 0.333333 0.083333 +vt 0.333333 0.125000 +vt 0.312500 0.166667 +vt 0.312500 0.208333 +vt 0.333333 0.166667 +vt 0.333333 0.208333 +vt 0.312500 0.250000 +vt 0.312500 0.291667 +vt 0.333333 0.250000 +vt 0.333333 0.291667 +vt 0.312500 0.333333 +vt 0.312500 0.375000 +vt 0.333333 0.333333 +vt 0.333333 0.375000 +vt 0.312500 0.416667 +vt 0.312500 0.458333 +vt 0.333333 0.416667 +vt 0.333333 0.458333 +vt 0.354167 0.500000 +vt 0.333333 0.500000 +vt 0.375000 0.541667 +vt 0.354167 0.541667 +vt 0.375000 0.583333 +vt 0.354167 0.583333 +vt 0.375000 0.625000 +vt 0.354167 0.625000 +vt 0.375000 0.666667 +vt 0.354167 0.666667 +vt 0.375000 0.708333 +vt 0.354167 0.708333 +vt 0.375000 0.750000 +vt 0.354167 0.750000 +vt 0.375000 0.791667 +vt 0.354167 0.791667 +vt 0.375000 0.833333 +vt 0.354167 0.833333 +vt 0.375000 0.875000 +vt 0.354167 0.875000 +vt 0.375000 0.916667 +vt 0.354167 0.916667 +vt 0.375000 0.958333 +vt 0.354167 0.958333 +vt 0.375000 1.000000 +vt 0.354167 1.000000 +vt 0.354167 0.041667 +vt 0.375000 0.000000 +vt 0.354167 0.000000 +vt 0.375000 0.041667 +vt 0.354167 0.083333 +vt 0.354167 0.125000 +vt 0.375000 0.083333 +vt 0.375000 0.125000 +vt 0.354167 0.166667 +vt 0.354167 0.208333 +vt 0.375000 0.166667 +vt 0.375000 0.208333 +vt 0.354167 0.250000 +vt 0.354167 0.291667 +vt 0.375000 0.250000 +vt 0.375000 0.291667 +vt 0.354167 0.333333 +vt 0.354167 0.375000 +vt 0.375000 0.333333 +vt 0.375000 0.375000 +vt 0.354167 0.416667 +vt 0.354167 0.458333 +vt 0.375000 0.416667 +vt 0.375000 0.458333 +vt 0.395833 0.500000 +vt 0.375000 0.500000 +vt 0.416667 0.541667 +vt 0.395833 0.541667 +vt 0.416667 0.583333 +vt 0.395833 0.583333 +vt 0.416667 0.625000 +vt 0.395833 0.625000 +vt 0.416667 0.666667 +vt 0.395833 0.666667 +vt 0.416667 0.708333 +vt 0.395833 0.708333 +vt 0.416667 0.750000 +vt 0.395833 0.750000 +vt 0.416667 0.791667 +vt 0.395833 0.791667 +vt 0.416667 0.833333 +vt 0.395833 0.833333 +vt 0.416667 0.875000 +vt 0.395833 0.875000 +vt 0.416667 0.916667 +vt 0.395833 0.916667 +vt 0.416667 0.958333 +vt 0.395833 0.958333 +vt 0.416667 1.000000 +vt 0.395833 1.000000 +vt 0.395833 0.041667 +vt 0.416667 0.000000 +vt 0.395833 0.000000 +vt 0.416667 0.041667 +vt 0.395833 0.083333 +vt 0.395833 0.125000 +vt 0.416667 0.083333 +vt 0.416667 0.125000 +vt 0.395833 0.166667 +vt 0.395833 0.208333 +vt 0.416667 0.166667 +vt 0.416667 0.208333 +vt 0.395833 0.250000 +vt 0.395833 0.291667 +vt 0.416667 0.250000 +vt 0.416667 0.291667 +vt 0.395833 0.333333 +vt 0.395833 0.375000 +vt 0.416667 0.333333 +vt 0.416667 0.375000 +vt 0.395833 0.416667 +vt 0.395833 0.458333 +vt 0.416667 0.416667 +vt 0.416667 0.458333 +vt 0.437500 0.500000 +vt 0.416667 0.500000 +vt 0.458333 0.541667 +vt 0.437500 0.541667 +vt 0.458333 0.583333 +vt 0.437500 0.583333 +vt 0.458333 0.625000 +vt 0.437500 0.625000 +vt 0.458333 0.666667 +vt 0.437500 0.666667 +vt 0.458333 0.708333 +vt 0.437500 0.708333 +vt 0.458333 0.750000 +vt 0.437500 0.750000 +vt 0.458333 0.791667 +vt 0.437500 0.791667 +vt 0.458333 0.833333 +vt 0.437500 0.833333 +vt 0.458333 0.875000 +vt 0.437500 0.875000 +vt 0.458333 0.916667 +vt 0.437500 0.916667 +vt 0.458333 0.958333 +vt 0.437500 0.958333 +vt 0.458333 1.000000 +vt 0.437500 1.000000 +vt 0.437500 0.041667 +vt 0.458333 0.000000 +vt 0.437500 0.000000 +vt 0.458333 0.041667 +vt 0.437500 0.083333 +vt 0.437500 0.125000 +vt 0.458333 0.083333 +vt 0.458333 0.125000 +vt 0.437500 0.166667 +vt 0.437500 0.208333 +vt 0.458333 0.166667 +vt 0.458333 0.208333 +vt 0.437500 0.250000 +vt 0.437500 0.291667 +vt 0.458333 0.250000 +vt 0.458333 0.291667 +vt 0.437500 0.333333 +vt 0.437500 0.375000 +vt 0.458333 0.333333 +vt 0.458333 0.375000 +vt 0.437500 0.416667 +vt 0.437500 0.458333 +vt 0.458333 0.416667 +vt 0.458333 0.458333 +vt 0.479167 0.500000 +vt 0.458333 0.500000 +vt 0.479167 0.541667 +vt 0.479167 0.583333 +vt 0.479167 0.625000 +vt 0.479167 0.666667 +vt 0.479167 0.708333 +vt 0.479167 0.750000 +vt 0.479167 0.791667 +vt 0.479167 0.833333 +vt 0.479167 0.875000 +vt 0.479167 0.916667 +vt 0.479167 0.958333 +vt 0.479167 1.000000 +vt 0.479167 0.041667 +vt 0.479167 0.000000 +vt 0.479167 0.083333 +vt 0.479167 0.125000 +vt 0.479167 0.166667 +vt 0.479167 0.208333 +vt 0.479167 0.250000 +vt 0.479167 0.291667 +vt 0.479167 0.333333 +vt 0.479167 0.375000 +vt 0.479167 0.416667 +vt 0.479167 0.458333 +vt 1.000000 0.500000 +vt 0.520833 0.500000 +vt 0.500000 0.541667 +vt 0.500000 0.500000 +vt 0.541667 0.541667 +vt 0.520833 0.541667 +vt 0.541667 0.583333 +vt 0.520833 0.583333 +vt 0.500000 0.583333 +vt 0.500000 0.625000 +vt 0.541667 0.625000 +vt 0.520833 0.625000 +vt 0.541667 0.666667 +vt 0.520833 0.666667 +vt 0.500000 0.666667 +vt 0.500000 0.708333 +vt 0.541667 0.708333 +vt 0.520833 0.708333 +vt 0.541667 0.750000 +vt 0.520833 0.750000 +vt 0.500000 0.750000 +vt 0.500000 0.791667 +vt 0.541667 0.791667 +vt 0.520833 0.791667 +vt 0.541667 0.833333 +vt 0.520833 0.833333 +vt 0.500000 0.833333 +vt 0.500000 0.875000 +vt 0.541667 0.875000 +vt 0.520833 0.875000 +vt 0.541667 0.916667 +vt 0.520833 0.916667 +vt 0.500000 0.916667 +vt 0.500000 0.958333 +vt 0.541667 0.958333 +vt 0.520833 0.958333 +vt 0.541667 1.000000 +vt 0.520833 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.000000 +vt 0.520833 0.041667 +vt 0.500000 0.041667 +vt 0.541667 0.000000 +vt 0.520833 0.000000 +vt 0.541667 0.041667 +vt 0.520833 0.083333 +vt 0.500000 0.083333 +vt 0.520833 0.125000 +vt 0.500000 0.125000 +vt 0.541667 0.083333 +vt 0.541667 0.125000 +vt 0.520833 0.166667 +vt 0.500000 0.166667 +vt 0.520833 0.208333 +vt 0.500000 0.208333 +vt 0.541667 0.166667 +vt 0.541667 0.208333 +vt 0.520833 0.250000 +vt 0.500000 0.250000 +vt 0.520833 0.291667 +vt 0.500000 0.291667 +vt 0.541667 0.250000 +vt 0.541667 0.291667 +vt 0.520833 0.333333 +vt 0.500000 0.333333 +vt 0.520833 0.375000 +vt 0.500000 0.375000 +vt 0.541667 0.333333 +vt 0.541667 0.375000 +vt 0.520833 0.416667 +vt 0.500000 0.416667 +vt 0.520833 0.458333 +vt 0.500000 0.458333 +vt 0.541667 0.416667 +vt 0.541667 0.458333 +vt 0.562500 0.500000 +vt 0.541667 0.500000 +vt 0.583333 0.541667 +vt 0.562500 0.541667 +vt 0.583333 0.583333 +vt 0.562500 0.583333 +vt 0.583333 0.625000 +vt 0.562500 0.625000 +vt 0.583333 0.666667 +vt 0.562500 0.666667 +vt 0.583333 0.708333 +vt 0.562500 0.708333 +vt 0.583333 0.750000 +vt 0.562500 0.750000 +vt 0.583333 0.791667 +vt 0.562500 0.791667 +vt 0.583333 0.833333 +vt 0.562500 0.833333 +vt 0.583333 0.875000 +vt 0.562500 0.875000 +vt 0.583333 0.916667 +vt 0.562500 0.916667 +vt 0.583333 0.958333 +vt 0.562500 0.958333 +vt 0.583333 1.000000 +vt 0.562500 1.000000 +vt 0.562500 0.041667 +vt 0.583333 0.000000 +vt 0.562500 0.000000 +vt 0.583333 0.041667 +vt 0.562500 0.083333 +vt 0.562500 0.125000 +vt 0.583333 0.083333 +vt 0.583333 0.125000 +vt 0.562500 0.166667 +vt 0.562500 0.208333 +vt 0.583333 0.166667 +vt 0.583333 0.208333 +vt 0.562500 0.250000 +vt 0.562500 0.291667 +vt 0.583333 0.250000 +vt 0.583333 0.291667 +vt 0.562500 0.333333 +vt 0.562500 0.375000 +vt 0.583333 0.333333 +vt 0.583333 0.375000 +vt 0.562500 0.416667 +vt 0.562500 0.458333 +vt 0.583333 0.416667 +vt 0.583333 0.458333 +vt 0.604167 0.500000 +vt 0.583333 0.500000 +vt 0.625000 0.541667 +vt 0.604167 0.541667 +vt 0.625000 0.583333 +vt 0.604167 0.583333 +vt 0.625000 0.625000 +vt 0.604167 0.625000 +vt 0.625000 0.666667 +vt 0.604167 0.666667 +vt 0.625000 0.708333 +vt 0.604167 0.708333 +vt 0.625000 0.750000 +vt 0.604167 0.750000 +vt 0.625000 0.791667 +vt 0.604167 0.791667 +vt 0.625000 0.833333 +vt 0.604167 0.833333 +vt 0.625000 0.875000 +vt 0.604167 0.875000 +vt 0.625000 0.916667 +vt 0.604167 0.916667 +vt 0.625000 0.958333 +vt 0.604167 0.958333 +vt 0.625000 1.000000 +vt 0.604167 1.000000 +vt 0.604167 0.041667 +vt 0.625000 0.000000 +vt 0.604167 0.000000 +vt 0.625000 0.041667 +vt 0.604167 0.083333 +vt 0.604167 0.125000 +vt 0.625000 0.083333 +vt 0.625000 0.125000 +vt 0.604167 0.166667 +vt 0.604167 0.208333 +vt 0.625000 0.166667 +vt 0.625000 0.208333 +vt 0.604167 0.250000 +vt 0.604167 0.291667 +vt 0.625000 0.250000 +vt 0.625000 0.291667 +vt 0.604167 0.333333 +vt 0.604167 0.375000 +vt 0.625000 0.333333 +vt 0.625000 0.375000 +vt 0.604167 0.416667 +vt 0.604167 0.458333 +vt 0.625000 0.416667 +vt 0.625000 0.458333 +vt 0.645833 0.500000 +vt 0.625000 0.500000 +vt 0.666667 0.541667 +vt 0.645833 0.541667 +vt 0.666667 0.583333 +vt 0.645833 0.583333 +vt 0.666667 0.625000 +vt 0.645833 0.625000 +vt 0.666667 0.666667 +vt 0.645833 0.666667 +vt 0.666667 0.708333 +vt 0.645833 0.708333 +vt 0.666667 0.750000 +vt 0.645833 0.750000 +vt 0.666667 0.791667 +vt 0.645833 0.791667 +vt 0.666667 0.833333 +vt 0.645833 0.833333 +vt 0.666667 0.875000 +vt 0.645833 0.875000 +vt 0.666667 0.916667 +vt 0.645833 0.916667 +vt 0.666667 0.958333 +vt 0.645833 0.958333 +vt 0.666667 1.000000 +vt 0.645833 1.000000 +vt 0.645833 0.041667 +vt 0.666667 0.000000 +vt 0.645833 0.000000 +vt 0.666667 0.041667 +vt 0.645833 0.083333 +vt 0.645833 0.125000 +vt 0.666667 0.083333 +vt 0.666667 0.125000 +vt 0.645833 0.166667 +vt 0.645833 0.208333 +vt 0.666667 0.166667 +vt 0.666667 0.208333 +vt 0.645833 0.250000 +vt 0.645833 0.291667 +vt 0.666667 0.250000 +vt 0.666667 0.291667 +vt 0.645833 0.333333 +vt 0.645833 0.375000 +vt 0.666667 0.333333 +vt 0.666667 0.375000 +vt 0.645833 0.416667 +vt 0.645833 0.458333 +vt 0.666667 0.416667 +vt 0.666667 0.458333 +vt 0.687500 0.500000 +vt 0.666667 0.500000 +vt 0.708333 0.541667 +vt 0.687500 0.541667 +vt 0.708333 0.583333 +vt 0.687500 0.583333 +vt 0.708333 0.625000 +vt 0.687500 0.625000 +vt 0.708333 0.666667 +vt 0.687500 0.666667 +vt 0.708333 0.708333 +vt 0.687500 0.708333 +vt 0.708333 0.750000 +vt 0.687500 0.750000 +vt 0.708333 0.791667 +vt 0.687500 0.791667 +vt 0.708333 0.833333 +vt 0.687500 0.833333 +vt 0.708333 0.875000 +vt 0.687500 0.875000 +vt 0.708333 0.916667 +vt 0.687500 0.916667 +vt 0.708333 0.958333 +vt 0.687500 0.958333 +vt 0.708333 1.000000 +vt 0.687500 1.000000 +vt 0.687500 0.041667 +vt 0.708333 0.000000 +vt 0.687500 0.000000 +vt 0.708333 0.041667 +vt 0.687500 0.083333 +vt 0.687500 0.125000 +vt 0.708333 0.083333 +vt 0.708333 0.125000 +vt 0.687500 0.166667 +vt 0.687500 0.208333 +vt 0.708333 0.166667 +vt 0.708333 0.208333 +vt 0.687500 0.250000 +vt 0.687500 0.291667 +vt 0.708333 0.250000 +vt 0.708333 0.291667 +vt 0.687500 0.333333 +vt 0.687500 0.375000 +vt 0.708333 0.333333 +vt 0.708333 0.375000 +vt 0.687500 0.416667 +vt 0.687500 0.458333 +vt 0.708333 0.416667 +vt 0.708333 0.458333 +vt 0.729167 0.500000 +vt 0.708333 0.500000 +vt 0.750000 0.541667 +vt 0.729167 0.541667 +vt 0.750000 0.583333 +vt 0.729167 0.583333 +vt 0.750000 0.625000 +vt 0.729167 0.625000 +vt 0.750000 0.666667 +vt 0.729167 0.666667 +vt 0.750000 0.708333 +vt 0.729167 0.708333 +vt 0.750000 0.750000 +vt 0.729167 0.750000 +vt 0.750000 0.791667 +vt 0.729167 0.791667 +vt 0.750000 0.833333 +vt 0.729167 0.833333 +vt 0.750000 0.875000 +vt 0.729167 0.875000 +vt 0.750000 0.916667 +vt 0.729167 0.916667 +vt 0.750000 0.958333 +vt 0.729167 0.958333 +vt 0.750000 1.000000 +vt 0.729167 1.000000 +vt 0.729167 0.041667 +vt 0.750000 0.000000 +vt 0.729167 0.000000 +vt 0.750000 0.041667 +vt 0.729167 0.083333 +vt 0.729167 0.125000 +vt 0.750000 0.083333 +vt 0.750000 0.125000 +vt 0.729167 0.166667 +vt 0.729167 0.208333 +vt 0.750000 0.166667 +vt 0.750000 0.208333 +vt 0.729167 0.250000 +vt 0.729167 0.291667 +vt 0.750000 0.250000 +vt 0.750000 0.291667 +vt 0.729167 0.333333 +vt 0.729167 0.375000 +vt 0.750000 0.333333 +vt 0.750000 0.375000 +vt 0.729167 0.416667 +vt 0.729167 0.458333 +vt 0.750000 0.416667 +vt 0.750000 0.458333 +vt 0.770833 0.500000 +vt 0.750000 0.500000 +vt 0.791667 0.541667 +vt 0.770833 0.541667 +vt 0.791667 0.583333 +vt 0.770833 0.583333 +vt 0.791667 0.625000 +vt 0.770833 0.625000 +vt 0.791667 0.666667 +vt 0.770833 0.666667 +vt 0.791667 0.708333 +vt 0.770833 0.708333 +vt 0.791667 0.750000 +vt 0.770833 0.750000 +vt 0.791667 0.791667 +vt 0.770833 0.791667 +vt 0.791667 0.833333 +vt 0.770833 0.833333 +vt 0.791667 0.875000 +vt 0.770833 0.875000 +vt 0.791667 0.916667 +vt 0.770833 0.916667 +vt 0.791667 0.958333 +vt 0.770833 0.958333 +vt 0.791667 1.000000 +vt 0.770833 1.000000 +vt 0.770833 0.041667 +vt 0.791667 0.000000 +vt 0.770833 0.000000 +vt 0.791667 0.041667 +vt 0.770833 0.083333 +vt 0.770833 0.125000 +vt 0.791667 0.083333 +vt 0.791667 0.125000 +vt 0.770833 0.166667 +vt 0.770833 0.208333 +vt 0.791667 0.166667 +vt 0.791667 0.208333 +vt 0.770833 0.250000 +vt 0.770833 0.291667 +vt 0.791667 0.250000 +vt 0.791667 0.291667 +vt 0.770833 0.333333 +vt 0.770833 0.375000 +vt 0.791667 0.333333 +vt 0.791667 0.375000 +vt 0.770833 0.416667 +vt 0.770833 0.458333 +vt 0.791667 0.416667 +vt 0.791667 0.458333 +vt 0.812500 0.500000 +vt 0.791667 0.500000 +vt 0.833333 0.541667 +vt 0.812500 0.541667 +vt 0.833333 0.583333 +vt 0.812500 0.583333 +vt 0.833333 0.625000 +vt 0.812500 0.625000 +vt 0.833333 0.666667 +vt 0.812500 0.666667 +vt 0.833333 0.708333 +vt 0.812500 0.708333 +vt 0.833333 0.750000 +vt 0.812500 0.750000 +vt 0.833333 0.791667 +vt 0.812500 0.791667 +vt 0.833333 0.833333 +vt 0.812500 0.833333 +vt 0.833333 0.875000 +vt 0.812500 0.875000 +vt 0.833333 0.916667 +vt 0.812500 0.916667 +vt 0.833333 0.958333 +vt 0.812500 0.958333 +vt 0.833333 1.000000 +vt 0.812500 1.000000 +vt 0.812500 0.041667 +vt 0.833333 0.000000 +vt 0.812500 0.000000 +vt 0.833333 0.041667 +vt 0.812500 0.083333 +vt 0.812500 0.125000 +vt 0.833333 0.083333 +vt 0.833333 0.125000 +vt 0.812500 0.166667 +vt 0.812500 0.208333 +vt 0.833333 0.166667 +vt 0.833333 0.208333 +vt 0.812500 0.250000 +vt 0.812500 0.291667 +vt 0.833333 0.250000 +vt 0.833333 0.291667 +vt 0.812500 0.333333 +vt 0.812500 0.375000 +vt 0.833333 0.333333 +vt 0.833333 0.375000 +vt 0.812500 0.416667 +vt 0.812500 0.458333 +vt 0.833333 0.416667 +vt 0.833333 0.458333 +vt 0.854167 0.500000 +vt 0.833333 0.500000 +vt 0.875000 0.541667 +vt 0.854167 0.541667 +vt 0.875000 0.583333 +vt 0.854167 0.583333 +vt 0.875000 0.625000 +vt 0.854167 0.625000 +vt 0.875000 0.666667 +vt 0.854167 0.666667 +vt 0.875000 0.708333 +vt 0.854167 0.708333 +vt 0.875000 0.750000 +vt 0.854167 0.750000 +vt 0.875000 0.791667 +vt 0.854167 0.791667 +vt 0.875000 0.833333 +vt 0.854167 0.833333 +vt 0.875000 0.875000 +vt 0.854167 0.875000 +vt 0.875000 0.916667 +vt 0.854167 0.916667 +vt 0.875000 0.958333 +vt 0.854167 0.958333 +vt 0.875000 1.000000 +vt 0.854167 1.000000 +vt 0.854167 0.041667 +vt 0.875000 0.000000 +vt 0.854167 0.000000 +vt 0.875000 0.041667 +vt 0.854167 0.083333 +vt 0.854167 0.125000 +vt 0.875000 0.083333 +vt 0.875000 0.125000 +vt 0.854167 0.166667 +vt 0.854167 0.208333 +vt 0.875000 0.166667 +vt 0.875000 0.208333 +vt 0.854167 0.250000 +vt 0.854167 0.291667 +vt 0.875000 0.250000 +vt 0.875000 0.291667 +vt 0.854167 0.333333 +vt 0.854167 0.375000 +vt 0.875000 0.333333 +vt 0.875000 0.375000 +vt 0.854167 0.416667 +vt 0.854167 0.458333 +vt 0.875000 0.416667 +vt 0.875000 0.458333 +vt 0.895833 0.500000 +vt 0.875000 0.500000 +vt 0.916667 0.541667 +vt 0.895833 0.541667 +vt 0.916667 0.583333 +vt 0.895833 0.583333 +vt 0.916667 0.625000 +vt 0.895833 0.625000 +vt 0.916667 0.666667 +vt 0.895833 0.666667 +vt 0.916667 0.708333 +vt 0.895833 0.708333 +vt 0.916667 0.750000 +vt 0.895833 0.750000 +vt 0.916667 0.791667 +vt 0.895833 0.791667 +vt 0.916667 0.833333 +vt 0.895833 0.833333 +vt 0.916667 0.875000 +vt 0.895833 0.875000 +vt 0.916667 0.916667 +vt 0.895833 0.916667 +vt 0.916667 0.958333 +vt 0.895833 0.958333 +vt 0.916667 1.000000 +vt 0.895833 1.000000 +vt 0.895834 0.041667 +vt 0.916667 0.000000 +vt 0.895833 0.000000 +vt 0.916667 0.041667 +vt 0.895834 0.083333 +vt 0.895833 0.125000 +vt 0.916667 0.083333 +vt 0.916667 0.125000 +vt 0.895833 0.166667 +vt 0.895833 0.208333 +vt 0.916667 0.166667 +vt 0.916667 0.208333 +vt 0.895833 0.250000 +vt 0.895833 0.291667 +vt 0.916667 0.250000 +vt 0.916667 0.291667 +vt 0.895833 0.333333 +vt 0.895833 0.375000 +vt 0.916667 0.333333 +vt 0.916667 0.375000 +vt 0.895833 0.416667 +vt 0.895833 0.458333 +vt 0.916667 0.416667 +vt 0.916667 0.458333 +vt 0.937500 0.500000 +vt 0.916667 0.500000 +vt 0.958333 0.541667 +vt 0.937500 0.541667 +vt 0.958333 0.583333 +vt 0.937500 0.583333 +vt 0.958333 0.625000 +vt 0.937500 0.625000 +vt 0.958333 0.666667 +vt 0.937500 0.666667 +vt 0.958333 0.708333 +vt 0.937500 0.708333 +vt 0.958333 0.750000 +vt 0.937500 0.750000 +vt 0.958333 0.791667 +vt 0.937500 0.791667 +vt 0.958333 0.833333 +vt 0.937500 0.833333 +vt 0.958333 0.875000 +vt 0.937500 0.875000 +vt 0.958333 0.916667 +vt 0.937500 0.916667 +vt 0.958333 0.958333 +vt 0.937500 0.958333 +vt 0.958333 1.000000 +vt 0.937500 1.000000 +vt 0.937500 0.041667 +vt 0.958333 0.000000 +vt 0.937500 0.000000 +vt 0.958333 0.041667 +vt 0.937500 0.083333 +vt 0.937500 0.125000 +vt 0.958333 0.083333 +vt 0.958333 0.125000 +vt 0.937500 0.166667 +vt 0.937500 0.208333 +vt 0.958333 0.166667 +vt 0.958333 0.208333 +vt 0.937500 0.250000 +vt 0.937500 0.291667 +vt 0.958333 0.250000 +vt 0.958333 0.291667 +vt 0.937500 0.333333 +vt 0.937500 0.375000 +vt 0.958333 0.333333 +vt 0.958333 0.375000 +vt 0.937500 0.416667 +vt 0.937500 0.458333 +vt 0.958333 0.416667 +vt 0.958333 0.458333 +vt 0.979167 0.500000 +vt 0.958333 0.500000 +vt 1.000000 0.541667 +vt 0.979167 0.541667 +vt 1.000000 0.583333 +vt 0.979167 0.583333 +vt 1.000000 0.625000 +vt 0.979167 0.625000 +vt 1.000000 0.666667 +vt 0.979167 0.666667 +vt 1.000000 0.708333 +vt 0.979167 0.708333 +vt 1.000000 0.750000 +vt 0.979167 0.750000 +vt 1.000000 0.791667 +vt 0.979167 0.791667 +vt 1.000000 0.833333 +vt 0.979167 0.833333 +vt 1.000000 0.875000 +vt 0.979167 0.875000 +vt 1.000000 0.916667 +vt 0.979167 0.916667 +vt 1.000000 0.958333 +vt 0.979167 0.958333 +vt 1.000000 1.000000 +vt 0.979167 1.000000 +vt 0.979167 0.041667 +vt 1.000000 0.000000 +vt 0.979167 0.000000 +vt 1.000000 0.041667 +vt 0.979167 0.083333 +vt 0.979167 0.125000 +vt 1.000000 0.083333 +vt 1.000000 0.125000 +vt 0.979167 0.166667 +vt 0.979167 0.208333 +vt 1.000000 0.166667 +vt 1.000000 0.208333 +vt 0.979167 0.250000 +vt 0.979167 0.291667 +vt 1.000000 0.250000 +vt 1.000000 0.291667 +vt 0.979167 0.333333 +vt 0.979167 0.375000 +vt 1.000000 0.333333 +vt 1.000000 0.375000 +vt 0.979167 0.416667 +vt 0.979167 0.458333 +vt 1.000000 0.416667 +vt 1.000000 0.458333 +vt 0.020833 0.500000 +vt -0.000000 0.541667 +vt -0.000000 0.500000 +vt 0.041667 0.541667 +vt 0.020833 0.541667 +vt 0.041667 0.583333 +vt 0.020833 0.583333 +vt -0.000000 0.583333 +vt -0.000000 0.625000 +vt 0.041667 0.625000 +vt 0.020833 0.625000 +vt 0.041667 0.666667 +vt 0.020833 0.666667 +vt -0.000000 0.666667 +vt -0.000000 0.708333 +vt 0.041667 0.708333 +vt 0.020833 0.708333 +vt 0.041667 0.750000 +vt 0.020833 0.750000 +vt -0.000000 0.750000 +vt -0.000000 0.791667 +vt 0.041667 0.791667 +vt 0.020833 0.791667 +vt 0.041667 0.833333 +vt 0.020833 0.833333 +vt -0.000000 0.833333 +vt -0.000000 0.875000 +vt 0.041667 0.875000 +vt 0.020833 0.875000 +vt 0.041667 0.916667 +vt 0.020833 0.916667 +vt -0.000000 0.916667 +vt -0.000000 0.958333 +vt 0.041667 0.958333 +vt 0.020833 0.958333 +vt 0.041667 1.000000 +vt 0.020833 1.000000 +vt -0.000000 1.000000 +vt -0.000000 0.000000 +vt 0.020833 0.041667 +vt -0.000000 0.041667 +vt 0.041667 0.000000 +vt 0.020833 0.000000 +vt 0.041667 0.041667 +vt 0.020833 0.083333 +vt -0.000000 0.083333 +vt 0.020833 0.125000 +vt -0.000000 0.125000 +vt 0.041667 0.083333 +vt 0.041667 0.125000 +vt 0.020833 0.166667 +vt -0.000000 0.166667 +vt 0.020833 0.208333 +vt -0.000000 0.208333 +vt 0.041667 0.166667 +vt 0.041667 0.208333 +vt 0.020833 0.250000 +vt -0.000000 0.250000 +vt 0.020833 0.291667 +vt -0.000000 0.291667 +vt 0.041667 0.250000 +vt 0.041667 0.291667 +vt 0.020833 0.333333 +vt -0.000000 0.333333 +vt 0.020833 0.375000 +vt -0.000000 0.375000 +vt 0.041667 0.333333 +vt 0.041667 0.375000 +vt 0.020833 0.416667 +vt -0.000000 0.416667 +vt 0.020833 0.458333 +vt -0.000000 0.458333 +vt 0.041667 0.416667 +vt 0.041667 0.458333 +vt 0.062500 0.500000 +vt 0.041667 0.500000 +vt 0.083333 0.541667 +vt 0.062500 0.541667 +vt 0.083333 0.583333 +vt 0.062500 0.583333 +vt 0.083333 0.625000 +vt 0.062500 0.625000 +vt 0.083333 0.666667 +vt 0.062500 0.666667 +vt 0.083333 0.708333 +vt 0.062500 0.708333 +vt 0.083333 0.750000 +vt 0.062500 0.750000 +vt 0.083333 0.791667 +vt 0.062500 0.791667 +vt 0.083333 0.833333 +vt 0.062500 0.833333 +vt 0.083333 0.875000 +vt 0.062500 0.875000 +vt 0.083333 0.916667 +vt 0.062500 0.916667 +vt 0.083333 0.958333 +vt 0.062500 0.958333 +vt 0.083333 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.041667 +vt 0.083333 0.000000 +vt 0.062500 0.000000 +vt 0.083333 0.041667 +vt 0.062500 0.083333 +vt 0.062500 0.125000 +vt 0.083333 0.083333 +vt 0.083333 0.125000 +vt 0.062500 0.166667 +vt 0.062500 0.208333 +vt 0.083333 0.166667 +vt 0.083333 0.208333 +vt 0.062500 0.250000 +vt 0.062500 0.291667 +vt 0.083333 0.250000 +vt 0.083333 0.291667 +vt 0.062500 0.333333 +vt 0.062500 0.375000 +vt 0.083333 0.333333 +vt 0.083333 0.375000 +vt 0.062500 0.416667 +vt 0.062500 0.458333 +vt 0.083333 0.416667 +vt 0.083333 0.458333 +vt 0.104167 0.500000 +vt 0.083333 0.500000 +vt 0.125000 0.541667 +vt 0.104167 0.541667 +vt 0.125000 0.583333 +vt 0.104167 0.583333 +vt 0.125000 0.625000 +vt 0.104167 0.625000 +vt 0.125000 0.666667 +vt 0.104167 0.666667 +vt 0.125000 0.708333 +vt 0.104167 0.708333 +vt 0.125000 0.750000 +vt 0.104167 0.750000 +vt 0.125000 0.791667 +vt 0.104167 0.791667 +vt 0.125000 0.833333 +vt 0.104167 0.833333 +vt 0.125000 0.875000 +vt 0.104167 0.875000 +vt 0.125000 0.916667 +vt 0.104167 0.916667 +vt 0.125000 0.958333 +vt 0.104167 0.958333 +vt 0.125000 1.000000 +vt 0.104167 1.000000 +vt 0.104167 0.041667 +vt 0.125000 0.000000 +vt 0.104167 0.000000 +vt 0.125000 0.041667 +vt 0.104167 0.083333 +vt 0.104167 0.125000 +vt 0.125000 0.083333 +vt 0.125000 0.125000 +vt 0.104167 0.166667 +vt 0.104167 0.208333 +vt 0.125000 0.166667 +vt 0.125000 0.208333 +vt 0.104167 0.250000 +vt 0.104167 0.291667 +vt 0.125000 0.250000 +vt 0.125000 0.291667 +vt 0.104167 0.333333 +vt 0.104167 0.375000 +vt 0.125000 0.333333 +vt 0.125000 0.375000 +vt 0.104167 0.416667 +vt 0.104167 0.458333 +vt 0.125000 0.416667 +vt 0.125000 0.458333 +vt 0.145833 0.500000 +vt 0.125000 0.500000 +vt 0.166667 0.541667 +vt 0.145833 0.541667 +vt 0.166667 0.583333 +vt 0.145833 0.583333 +vt 0.166667 0.625000 +vt 0.145833 0.625000 +vt 0.166667 0.666667 +vt 0.145833 0.666667 +vt 0.166667 0.708333 +vt 0.145833 0.708333 +vt 0.166667 0.750000 +vt 0.145833 0.750000 +vt 0.166667 0.791667 +vt 0.145833 0.791667 +vt 0.166667 0.833333 +vt 0.145833 0.833333 +vt 0.166667 0.875000 +vt 0.145833 0.875000 +vt 0.166667 0.916667 +vt 0.145833 0.916667 +vt 0.166667 0.958333 +vt 0.145833 0.958333 +vt 0.166667 1.000000 +vt 0.145833 1.000000 +vt 0.145833 0.041667 +vt 0.166667 0.000000 +vt 0.145833 0.000000 +vt 0.166667 0.041667 +vt 0.145833 0.083333 +vt 0.145833 0.125000 +vt 0.166667 0.083333 +vt 0.166667 0.125000 +vt 0.145833 0.166667 +vt 0.145833 0.208333 +vt 0.166667 0.166667 +vt 0.166667 0.208333 +vt 0.145833 0.250000 +vt 0.145833 0.291667 +vt 0.166667 0.250000 +vt 0.166667 0.291667 +vt 0.145833 0.333333 +vt 0.145833 0.375000 +vt 0.166667 0.333333 +vt 0.166667 0.375000 +vt 0.145833 0.416667 +vt 0.145833 0.458333 +vt 0.166667 0.416667 +vt 0.166667 0.458333 +vt 0.187500 0.500000 +vt 0.166667 0.500000 +vt 0.208333 0.541667 +vt 0.187500 0.541667 +vt 0.208333 0.583333 +vt 0.187500 0.583333 +vt 0.208333 0.625000 +vt 0.187500 0.625000 +vt 0.208333 0.666667 +vt 0.187500 0.666667 +vt 0.208333 0.708333 +vt 0.187500 0.708333 +vt 0.208333 0.750000 +vt 0.187500 0.750000 +vt 0.208333 0.791667 +vt 0.187500 0.791667 +vt 0.208333 0.833333 +vt 0.187500 0.833333 +vt 0.208333 0.875000 +vt 0.187500 0.875000 +vt 0.208333 0.916667 +vt 0.187500 0.916667 +vt 0.208333 0.958333 +vt 0.187500 0.958333 +vt 0.208333 1.000000 +vt 0.187500 1.000000 +vt 0.187500 0.041667 +vt 0.208333 0.000000 +vt 0.187500 0.000000 +vt 0.208333 0.041667 +vt 0.187500 0.083333 +vt 0.187500 0.125000 +vt 0.208333 0.083333 +vt 0.208333 0.125000 +vt 0.187500 0.166667 +vt 0.187500 0.208333 +vt 0.208333 0.166667 +vt 0.208333 0.208333 +vt 0.187500 0.250000 +vt 0.187500 0.291667 +vt 0.208333 0.250000 +vt 0.208333 0.291667 +vt 0.187500 0.333333 +vt 0.187500 0.375000 +vt 0.208333 0.333333 +vt 0.208333 0.375000 +vt 0.187500 0.416667 +vt 0.187500 0.458333 +vt 0.208333 0.416667 +vt 0.208333 0.458333 +vt 0.229167 0.500000 +vt 0.208333 0.500000 +vt 0.250000 0.541667 +vt 0.229167 0.541667 +vt 0.250000 0.583333 +vt 0.229167 0.583333 +vt 0.250000 0.625000 +vt 0.229167 0.625000 +vt 0.250000 0.666667 +vt 0.229167 0.666667 +vt 0.250000 0.708333 +vt 0.229167 0.708333 +vt 0.250000 0.750000 +vt 0.229167 0.750000 +vt 0.250000 0.791667 +vt 0.229167 0.791667 +vt 0.250000 0.833333 +vt 0.229167 0.833333 +vt 0.250000 0.875000 +vt 0.229167 0.875000 +vt 0.250000 0.916667 +vt 0.229167 0.916667 +vt 0.250000 0.958333 +vt 0.229167 0.958333 +vt 0.250000 1.000000 +vt 0.229167 1.000000 +vt 0.229167 0.041667 +vt 0.250000 0.000000 +vt 0.229167 0.000000 +vt 0.250000 0.041667 +vt 0.229167 0.083333 +vt 0.229167 0.125000 +vt 0.250000 0.083333 +vt 0.250000 0.125000 +vt 0.229167 0.166667 +vt 0.229167 0.208333 +vt 0.250000 0.166667 +vt 0.250000 0.208333 +vt 0.229167 0.250000 +vt 0.229167 0.291667 +vt 0.250000 0.250000 +vt 0.250000 0.291667 +vt 0.229167 0.333333 +vt 0.229167 0.375000 +vt 0.250000 0.333333 +vt 0.250000 0.375000 +vt 0.229167 0.416667 +vt 0.229167 0.458333 +vt 0.250000 0.416667 +vt 0.250000 0.458333 +vt 0.270833 0.500000 +vt 0.250000 0.500000 +vt 0.291667 0.541667 +vt 0.270833 0.541667 +vt 0.291667 0.583333 +vt 0.270833 0.583333 +vt 0.291667 0.625000 +vt 0.270833 0.625000 +vt 0.291667 0.666667 +vt 0.270833 0.666667 +vt 0.291667 0.708333 +vt 0.270833 0.708333 +vt 0.291667 0.750000 +vt 0.270833 0.750000 +vt 0.291667 0.791667 +vt 0.270833 0.791667 +vt 0.291667 0.833333 +vt 0.270833 0.833333 +vt 0.291667 0.875000 +vt 0.270833 0.875000 +vt 0.291667 0.916667 +vt 0.270833 0.916667 +vt 0.291667 0.958333 +vt 0.270833 0.958333 +vt 0.291667 1.000000 +vt 0.270833 1.000000 +vt 0.270833 0.041667 +vt 0.291667 0.000000 +vt 0.270833 0.000000 +vt 0.291667 0.041667 +vt 0.270833 0.083333 +vt 0.270833 0.125000 +vt 0.291667 0.083333 +vt 0.291667 0.125000 +vt 0.270833 0.166667 +vt 0.270833 0.208333 +vt 0.291667 0.166667 +vt 0.291667 0.208333 +vt 0.270833 0.250000 +vt 0.270833 0.291667 +vt 0.291667 0.250000 +vt 0.291667 0.291667 +vt 0.270833 0.333333 +vt 0.270833 0.375000 +vt 0.291667 0.333333 +vt 0.291667 0.375000 +vt 0.270833 0.416667 +vt 0.270833 0.458333 +vt 0.291667 0.416667 +vt 0.291667 0.458333 +vt 0.312500 0.500000 +vt 0.291667 0.500000 +vt 0.333333 0.541667 +vt 0.312500 0.541667 +vt 0.333333 0.583333 +vt 0.312500 0.583333 +vt 0.333333 0.625000 +vt 0.312500 0.625000 +vt 0.333333 0.666667 +vt 0.312500 0.666667 +vt 0.333333 0.708333 +vt 0.312500 0.708333 +vt 0.333333 0.750000 +vt 0.312500 0.750000 +vt 0.333333 0.791667 +vt 0.312500 0.791667 +vt 0.333333 0.833333 +vt 0.312500 0.833333 +vt 0.333333 0.875000 +vt 0.312500 0.875000 +vt 0.333333 0.916667 +vt 0.312500 0.916667 +vt 0.333333 0.958333 +vt 0.312500 0.958333 +vt 0.333333 1.000000 +vt 0.312500 1.000000 +vt 0.312500 0.041667 +vt 0.333333 0.000000 +vt 0.312500 0.000000 +vt 0.333333 0.041667 +vt 0.312500 0.083333 +vt 0.312500 0.125000 +vt 0.333333 0.083333 +vt 0.333333 0.125000 +vt 0.312500 0.166667 +vt 0.312500 0.208333 +vt 0.333333 0.166667 +vt 0.333333 0.208333 +vt 0.312500 0.250000 +vt 0.312500 0.291667 +vt 0.333333 0.250000 +vt 0.333333 0.291667 +vt 0.312500 0.333333 +vt 0.312500 0.375000 +vt 0.333333 0.333333 +vt 0.333333 0.375000 +vt 0.312500 0.416667 +vt 0.312500 0.458333 +vt 0.333333 0.416667 +vt 0.333333 0.458333 +vt 0.354167 0.500000 +vt 0.333333 0.500000 +vt 0.375000 0.541667 +vt 0.354167 0.541667 +vt 0.375000 0.583333 +vt 0.354167 0.583333 +vt 0.375000 0.625000 +vt 0.354167 0.625000 +vt 0.375000 0.666667 +vt 0.354167 0.666667 +vt 0.375000 0.708333 +vt 0.354167 0.708333 +vt 0.375000 0.750000 +vt 0.354167 0.750000 +vt 0.375000 0.791667 +vt 0.354167 0.791667 +vt 0.375000 0.833333 +vt 0.354167 0.833333 +vt 0.375000 0.875000 +vt 0.354167 0.875000 +vt 0.375000 0.916667 +vt 0.354167 0.916667 +vt 0.375000 0.958333 +vt 0.354167 0.958333 +vt 0.375000 1.000000 +vt 0.354167 1.000000 +vt 0.354167 0.041667 +vt 0.375000 0.000000 +vt 0.354167 0.000000 +vt 0.375000 0.041667 +vt 0.354167 0.083333 +vt 0.354167 0.125000 +vt 0.375000 0.083333 +vt 0.375000 0.125000 +vt 0.354167 0.166667 +vt 0.354167 0.208333 +vt 0.375000 0.166667 +vt 0.375000 0.208333 +vt 0.354167 0.250000 +vt 0.354167 0.291667 +vt 0.375000 0.250000 +vt 0.375000 0.291667 +vt 0.354167 0.333333 +vt 0.354167 0.375000 +vt 0.375000 0.333333 +vt 0.375000 0.375000 +vt 0.354167 0.416667 +vt 0.354167 0.458333 +vt 0.375000 0.416667 +vt 0.375000 0.458333 +vt 0.395833 0.500000 +vt 0.375000 0.500000 +vt 0.416667 0.541667 +vt 0.395833 0.541667 +vt 0.416667 0.583333 +vt 0.395833 0.583333 +vt 0.416667 0.625000 +vt 0.395833 0.625000 +vt 0.416667 0.666667 +vt 0.395833 0.666667 +vt 0.416667 0.708333 +vt 0.395833 0.708333 +vt 0.416667 0.750000 +vt 0.395833 0.750000 +vt 0.416667 0.791667 +vt 0.395833 0.791667 +vt 0.416667 0.833333 +vt 0.395833 0.833333 +vt 0.416667 0.875000 +vt 0.395833 0.875000 +vt 0.416667 0.916667 +vt 0.395833 0.916667 +vt 0.416667 0.958333 +vt 0.395833 0.958333 +vt 0.416667 1.000000 +vt 0.395833 1.000000 +vt 0.395833 0.041667 +vt 0.416667 0.000000 +vt 0.395833 0.000000 +vt 0.416667 0.041667 +vt 0.395833 0.083333 +vt 0.395833 0.125000 +vt 0.416667 0.083333 +vt 0.416667 0.125000 +vt 0.395833 0.166667 +vt 0.395833 0.208333 +vt 0.416667 0.166667 +vt 0.416667 0.208333 +vt 0.395833 0.250000 +vt 0.395833 0.291667 +vt 0.416667 0.250000 +vt 0.416667 0.291667 +vt 0.395833 0.333333 +vt 0.395833 0.375000 +vt 0.416667 0.333333 +vt 0.416667 0.375000 +vt 0.395833 0.416667 +vt 0.395833 0.458333 +vt 0.416667 0.416667 +vt 0.416667 0.458333 +vt 0.437500 0.500000 +vt 0.416667 0.500000 +vt 0.458333 0.541667 +vt 0.437500 0.541667 +vt 0.458333 0.583333 +vt 0.437500 0.583333 +vt 0.458333 0.625000 +vt 0.437500 0.625000 +vt 0.458333 0.666667 +vt 0.437500 0.666667 +vt 0.458333 0.708333 +vt 0.437500 0.708333 +vt 0.458333 0.750000 +vt 0.437500 0.750000 +vt 0.458333 0.791667 +vt 0.437500 0.791667 +vt 0.458333 0.833333 +vt 0.437500 0.833333 +vt 0.458333 0.875000 +vt 0.437500 0.875000 +vt 0.458333 0.916667 +vt 0.437500 0.916667 +vt 0.458333 0.958333 +vt 0.437500 0.958333 +vt 0.458333 1.000000 +vt 0.437500 1.000000 +vt 0.437500 0.041667 +vt 0.458333 0.000000 +vt 0.437500 0.000000 +vt 0.458333 0.041667 +vt 0.437500 0.083333 +vt 0.437500 0.125000 +vt 0.458333 0.083333 +vt 0.458333 0.125000 +vt 0.437500 0.166667 +vt 0.437500 0.208333 +vt 0.458333 0.166667 +vt 0.458333 0.208333 +vt 0.437500 0.250000 +vt 0.437500 0.291667 +vt 0.458333 0.250000 +vt 0.458333 0.291667 +vt 0.437500 0.333333 +vt 0.437500 0.375000 +vt 0.458333 0.333333 +vt 0.458333 0.375000 +vt 0.437500 0.416667 +vt 0.437500 0.458333 +vt 0.458333 0.416667 +vt 0.458333 0.458333 +vt 0.479167 0.500000 +vt 0.458333 0.500000 +vt 0.479167 0.541667 +vt 0.479167 0.583333 +vt 0.479167 0.625000 +vt 0.479167 0.666667 +vt 0.479167 0.708333 +vt 0.479167 0.750000 +vt 0.479167 0.791667 +vt 0.479167 0.833333 +vt 0.479167 0.875000 +vt 0.479167 0.916667 +vt 0.479167 0.958333 +vt 0.479167 1.000000 +vt 0.479167 0.041667 +vt 0.479167 0.000000 +vt 0.479167 0.083333 +vt 0.479167 0.125000 +vt 0.479167 0.166667 +vt 0.479167 0.208333 +vt 0.479167 0.250000 +vt 0.479167 0.291667 +vt 0.479167 0.333333 +vt 0.479167 0.375000 +vt 0.479167 0.416667 +vt 0.479167 0.458333 +vt 1.000000 0.500000 +vt 0.750000 0.250000 +vt 0.834853 0.454853 +vt 0.919706 0.419706 +vt 0.250000 0.250000 +vt 0.334853 0.454853 +vt 0.250000 0.490000 +vt 0.954853 0.334853 +vt 0.990000 0.250000 +vt 0.454853 0.334853 +vt 0.419706 0.419706 +vt 0.954853 0.165147 +vt 0.919706 0.080294 +vt 0.454853 0.165147 +vt 0.490000 0.250000 +vt 0.834853 0.045147 +vt 0.750000 0.010000 +vt 0.334853 0.045147 +vt 0.419706 0.080294 +vt 0.665147 0.045147 +vt 0.580294 0.080294 +vt 0.165147 0.045147 +vt 0.250000 0.010000 +vt 0.545147 0.165147 +vt 0.510000 0.250000 +vt 0.045147 0.165147 +vt 0.080294 0.080294 +vt 0.545147 0.334853 +vt 0.580294 0.419706 +vt 0.045147 0.334853 +vt 0.010000 0.250000 +vt 0.665147 0.454853 +vt 0.750000 0.490000 +vt 0.165147 0.454853 +vt 0.080294 0.419706 +vt 0.750000 0.250000 +vt 0.834853 0.454853 +vt 0.919706 0.419706 +vt 0.250000 0.250000 +vt 0.334853 0.454853 +vt 0.250000 0.490000 +vt 0.954853 0.334853 +vt 0.990000 0.250000 +vt 0.454853 0.334853 +vt 0.419706 0.419706 +vt 0.954853 0.165147 +vt 0.919706 0.080294 +vt 0.454853 0.165147 +vt 0.490000 0.250000 +vt 0.834853 0.045147 +vt 0.750000 0.010000 +vt 0.334853 0.045147 +vt 0.419706 0.080294 +vt 0.665147 0.045147 +vt 0.580294 0.080294 +vt 0.165147 0.045147 +vt 0.250000 0.010000 +vt 0.545147 0.165147 +vt 0.510000 0.250000 +vt 0.045147 0.165147 +vt 0.080294 0.080294 +vt 0.545147 0.334853 +vt 0.580294 0.419706 +vt 0.045147 0.334853 +vt 0.010000 0.250000 +vt 0.665147 0.454853 +vt 0.750000 0.490000 +vt 0.165147 0.454853 +vt 0.080294 0.419706 +vt 0.750000 0.250000 +vt 0.834853 0.454853 +vt 0.919706 0.419706 +vt 0.250000 0.250000 +vt 0.334853 0.454853 +vt 0.250000 0.490000 +vt 0.954853 0.334853 +vt 0.990000 0.250000 +vt 0.454853 0.334853 +vt 0.419706 0.419706 +vt 0.954853 0.165147 +vt 0.919706 0.080294 +vt 0.454853 0.165147 +vt 0.490000 0.250000 +vt 0.834853 0.045147 +vt 0.750000 0.010000 +vt 0.334853 0.045147 +vt 0.419706 0.080294 +vt 0.665147 0.045147 +vt 0.580294 0.080294 +vt 0.165147 0.045147 +vt 0.250000 0.010000 +vt 0.545147 0.165147 +vt 0.510000 0.250000 +vt 0.045147 0.165147 +vt 0.080294 0.080294 +vt 0.545147 0.334853 +vt 0.580294 0.419706 +vt 0.045147 0.334853 +vt 0.010000 0.250000 +vt 0.665147 0.454853 +vt 0.750000 0.490000 +vt 0.165147 0.454853 +vt 0.080294 0.419706 +vt 0.937500 0.750000 +vt 0.875000 1.000000 +vt 0.875000 0.750000 +vt 0.812500 1.000000 +vt 0.750000 0.750000 +vt 0.812500 0.750000 +vt 0.687500 1.000000 +vt 0.625000 0.750000 +vt 0.687500 0.750000 +vt 0.562500 0.750000 +vt 0.500000 1.000000 +vt 0.500000 0.750000 +vt 0.437500 0.750000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.312500 0.750000 +vt 0.250000 1.000000 +vt 0.250000 0.750000 +vt 0.187500 0.750000 +vt 0.125000 1.000000 +vt 0.125000 0.750000 +vt 0.062500 1.000000 +vt 0.000000 0.750000 +vt 0.062500 0.750000 +vt 0.937500 0.750000 +vt 0.875000 1.000000 +vt 0.875000 0.750000 +vt 0.812500 0.750000 +vt 0.750000 1.000000 +vt 0.750000 0.750000 +vt 0.687500 1.000000 +vt 0.625000 0.750000 +vt 0.687500 0.750000 +vt 0.562500 0.750000 +vt 0.500000 1.000000 +vt 0.500000 0.750000 +vt 0.437500 0.750000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.312500 1.000000 +vt 0.250000 0.750000 +vt 0.312500 0.750000 +vt 0.187500 1.000000 +vt 0.125000 0.750000 +vt 0.187500 0.750000 +vt 0.062500 0.750000 +vt 0.000000 1.000000 +vt 0.000000 0.750000 +vt 0.937500 1.000000 +vt 0.875000 0.750000 +vt 0.937500 0.750000 +vt 0.812500 1.000000 +vt 0.750000 0.750000 +vt 0.812500 0.750000 +vt 0.687500 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.750000 +vt 0.562500 1.000000 +vt 0.500000 0.750000 +vt 0.562500 0.750000 +vt 0.437500 0.750000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.312500 1.000000 +vt 0.250000 0.750000 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 1.000000 +vt 0.125000 0.750000 +vt 0.062500 0.750000 +vt 0.000000 1.000000 +vt 0.000000 0.750000 +vt 0.000000 0.500000 +vt 0.062500 0.500000 +vt 0.125000 0.500000 +vt 0.062500 1.000000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.187500 1.000000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.437500 0.500000 +vt 0.500000 0.500000 +vt 0.500000 1.000000 +vt 0.562500 0.500000 +vt 0.625000 0.500000 +vt 0.687500 0.500000 +vt 0.750000 0.500000 +vt 0.687500 1.000000 +vt 0.812500 0.500000 +vt 0.875000 0.500000 +vt 0.875000 1.000000 +vt 0.937500 0.500000 +vt 1.000000 0.500000 +vt 1.000000 0.750000 +vt 0.000000 0.500000 +vt 0.062500 0.500000 +vt 0.125000 0.500000 +vt 0.125000 1.000000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.250000 1.000000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.437500 0.500000 +vt 0.500000 0.500000 +vt 0.562500 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.687500 0.500000 +vt 0.750000 0.500000 +vt 0.812500 0.500000 +vt 0.875000 0.500000 +vt 0.937500 0.500000 +vt 1.000000 0.500000 +vt 1.000000 1.000000 +vt 1.000000 0.750000 +vt 0.000000 0.500000 +vt 0.062500 0.500000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.187500 1.000000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.312500 1.000000 +vt 0.437500 0.500000 +vt 0.500000 0.500000 +vt 0.437500 1.000000 +vt 0.562500 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.687500 0.500000 +vt 0.750000 0.500000 +vt 0.812500 0.500000 +vt 0.875000 0.500000 +vt 0.937500 0.500000 +vt 1.000000 0.500000 +vt 1.000000 0.750000 +vt 0.937500 1.000000 +vt 0.750000 1.000000 +vt 0.562500 1.000000 +vt 0.000000 1.000000 +vt 0.937500 1.000000 +vt 0.812500 1.000000 +vt 0.562500 1.000000 +vt 0.437500 1.000000 +vt 0.062500 1.000000 +vt 0.750000 1.000000 +vt 0.437500 1.000000 +vt 0.250000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +vn 0.4108 -0.9039 -0.1187 +vn 0.6230 -0.7815 0.0315 +vn 0.4041 -0.9146 0.0115 +vn 0.6292 -0.7459 -0.2183 +vn 0.6295 -0.7712 -0.0943 +vn 0.8068 -0.5642 -0.1751 +vn 0.8071 -0.5869 -0.0637 +vn 0.8013 -0.5962 0.0495 +vn 0.9268 -0.3699 0.0643 +vn 0.9314 -0.3436 -0.1200 +vn 0.9316 -0.3623 -0.0285 +vn 0.9935 -0.0984 -0.0564 +vn 0.9937 -0.1117 0.0087 +vn 0.9903 -0.1171 0.0749 +vn 0.9861 0.1453 0.0803 +vn 0.9878 0.1551 0.0114 +vn 0.9879 0.1481 0.0456 +vn 0.9136 0.3988 0.0788 +vn 0.9136 0.3987 0.0795 +vn 0.9136 0.3986 0.0802 +vn 0.7773 0.6247 0.0745 +vn 0.7756 0.6153 0.1408 +vn 0.7755 0.6220 0.1079 +vn 0.5840 0.7885 0.1928 +vn 0.5838 0.8016 0.1288 +vn 0.5872 0.8069 0.0637 +vn 0.3571 0.9328 0.0484 +vn 0.3525 0.9067 0.2314 +vn 0.3523 0.9252 0.1407 +vn 0.0981 0.9622 0.2540 +vn 0.0978 0.9849 0.1429 +vn 0.1036 0.9941 0.0300 +vn -0.1558 0.9877 0.0095 +vn -0.1620 0.9521 0.2592 +vn -0.1623 0.9774 0.1353 +vn -0.4105 0.8778 0.2469 +vn -0.4108 0.9039 0.1187 +vn -0.4041 0.9146 -0.0115 +vn -0.6317 0.7695 0.0941 +vn -0.6252 0.7798 -0.0317 +vn -0.6314 0.7442 0.2179 +vn -0.8103 0.5826 0.0630 +vn -0.8045 0.5919 -0.0499 +vn -0.9343 0.3553 0.0275 +vn -0.9296 0.3628 -0.0647 +vn -0.8100 0.5599 0.1741 +vn -0.9341 0.3367 0.1183 +vn -0.9947 0.1024 -0.0100 +vn -0.9913 0.1077 -0.0751 +vn -0.9862 -0.1584 -0.0470 +vn -0.9845 -0.1557 -0.0804 +vn -0.9945 0.0893 0.0540 +vn -0.9861 -0.1651 -0.0142 +vn -0.9091 -0.4087 -0.0808 +vn -0.9091 -0.4088 -0.0801 +vn -0.7689 -0.6301 -0.1089 +vn -0.7707 -0.6329 -0.0742 +vn -0.9091 -0.4086 -0.0815 +vn -0.7689 -0.6231 -0.1430 +vn -0.5761 -0.8071 -0.1293 +vn -0.5795 -0.8125 -0.0632 +vn -0.3452 -0.9279 -0.1408 +vn -0.3500 -0.9355 -0.0479 +vn -0.5762 -0.7938 -0.1945 +vn -0.3454 -0.9092 -0.2323 +vn -0.0924 -0.9854 -0.1428 +vn -0.0983 -0.9947 -0.0295 +vn 0.1650 -0.9770 -0.1352 +vn 0.1585 -0.9873 -0.0093 +vn -0.0927 -0.9627 -0.2542 +vn 0.1647 -0.9517 -0.2591 +vn 0.4032 -0.8366 -0.3708 +vn 0.4105 -0.8778 -0.2469 +vn 0.6084 -0.6524 -0.4518 +vn 0.6222 -0.7061 -0.3381 +vn 0.7881 -0.4801 -0.3852 +vn 0.8005 -0.5284 -0.2829 +vn 0.9160 -0.2746 -0.2924 +vn 0.9261 -0.3142 -0.2085 +vn 0.9826 -0.0493 -0.1792 +vn 0.9898 -0.0775 -0.1194 +vn 0.9821 0.1809 -0.0529 +vn 0.9859 0.1661 -0.0216 +vn 0.9135 0.3994 0.0774 +vn 0.9136 0.3991 0.0781 +vn 0.7812 0.5905 0.2027 +vn 0.7775 0.6047 0.1726 +vn 0.5947 0.7402 0.3136 +vn 0.5876 0.7679 0.2548 +vn 0.3678 0.8383 0.4025 +vn 0.3577 0.8776 0.3192 +vn 0.1168 0.8784 0.4634 +vn 0.1044 0.9265 0.3614 +vn -0.1411 0.8587 0.4926 +vn -0.1549 0.9124 0.3789 +vn -0.3890 0.7811 0.4884 +vn -0.4032 0.8366 0.3708 +vn -0.6243 0.7044 0.3377 +vn -0.6105 0.6508 0.4513 +vn -0.8036 0.5242 0.2816 +vn -0.9289 0.3076 0.2061 +vn -0.7913 0.4761 0.3835 +vn -0.9189 0.2683 0.2893 +vn -0.9908 0.0687 0.1160 +vn -0.9843 -0.1757 0.0176 +vn -0.9837 0.0409 0.1748 +vn -0.9806 -0.1899 0.0477 +vn -0.9091 -0.4083 -0.0822 +vn -0.7709 -0.6121 -0.1761 +vn -0.9092 -0.4080 -0.0829 +vn -0.7747 -0.5973 -0.2074 +vn -0.5800 -0.7729 -0.2575 +vn -0.3507 -0.8798 -0.3208 +vn -0.5872 -0.7447 -0.3172 +vn -0.3608 -0.8402 -0.4047 +vn -0.0991 -0.9268 -0.3620 +vn 0.1576 -0.9119 -0.3790 +vn -0.1115 -0.8786 -0.4643 +vn 0.1439 -0.8582 -0.4927 +vn 0.3681 -0.7123 -0.5976 +vn 0.3890 -0.7811 -0.4884 +vn 0.5619 -0.5075 -0.6532 +vn 0.5882 -0.5859 -0.5575 +vn 0.7463 -0.3497 -0.5663 +vn 0.7699 -0.4202 -0.4802 +vn 0.8817 -0.1677 -0.4410 +vn 0.9011 -0.2255 -0.3703 +vn 0.9581 0.0269 -0.2850 +vn 0.9720 -0.0143 -0.2347 +vn 0.9692 0.2208 -0.1084 +vn 0.9765 0.1992 -0.0820 +vn 0.9132 0.4002 0.0763 +vn 0.9134 0.3998 0.0768 +vn 0.7935 0.5520 0.2561 +vn 0.7865 0.5728 0.2307 +vn 0.6188 0.6652 0.4177 +vn 0.6052 0.7057 0.3682 +vn 0.4019 0.7321 0.5500 +vn 0.3826 0.7895 0.4799 +vn 0.1585 0.7484 0.6440 +vn 0.1349 0.8187 0.5581 +vn -0.0947 0.7139 0.6938 +vn -0.1210 0.7922 0.5981 +vn -0.3409 0.6312 0.6966 +vn -0.3681 0.7123 0.5976 +vn -0.5903 0.5843 0.5568 +vn -0.5641 0.5060 0.6525 +vn -0.7732 0.4164 0.4782 +vn -0.9040 0.2195 0.3667 +vn -0.7496 0.3461 0.5641 +vn -0.8848 0.1621 0.4368 +vn -0.9733 0.0065 0.2294 +vn -0.9753 -0.2076 0.0757 +vn -0.9597 -0.0340 0.2789 +vn -0.9683 -0.2284 0.1011 +vn -0.9093 -0.4076 -0.0834 +vn -0.7803 -0.5789 -0.2365 +vn -0.9095 -0.4072 -0.0840 +vn -0.7875 -0.5574 -0.2629 +vn -0.5978 -0.7096 -0.3728 +vn -0.3757 -0.7911 -0.4827 +vn -0.6116 -0.6685 -0.4231 +vn -0.3951 -0.7333 -0.5533 +vn -0.1296 -0.8187 -0.5593 +vn 0.1237 -0.7916 -0.5983 +vn -0.1533 -0.7482 -0.6454 +vn 0.0974 -0.7132 -0.6941 +vn 0.3079 -0.5394 -0.7837 +vn 0.3409 -0.6312 -0.6966 +vn 0.4929 -0.3210 -0.8087 +vn 0.5300 -0.4187 -0.7374 +vn 0.6843 -0.1820 -0.7062 +vn 0.7176 -0.2699 -0.6421 +vn 0.8308 -0.0300 -0.5557 +vn 0.8581 -0.1021 -0.5032 +vn 0.9219 0.1249 -0.3667 +vn 0.9413 0.0735 -0.3293 +vn 0.9502 0.2722 -0.1513 +vn 0.9604 0.2453 -0.1317 +vn 0.9128 0.4013 0.0754 +vn 0.9131 0.4007 0.0758 +vn 0.8118 0.5026 0.2973 +vn 0.8019 0.5285 0.2784 +vn 0.6545 0.5688 0.4981 +vn 0.6353 0.6193 0.4613 +vn 0.4524 0.5954 0.6639 +vn 0.4252 0.6670 0.6117 +vn 0.2203 0.5812 0.7833 +vn 0.1871 0.6688 0.7195 +vn -0.0258 0.5275 0.8491 +vn -0.0628 0.6251 0.7779 +vn -0.2696 0.4383 0.8574 +vn -0.3078 0.5394 0.7837 +vn -0.5322 0.4172 0.7367 +vn -0.4952 0.3196 0.8079 +vn -0.7210 0.2665 0.6396 +vn -0.8614 0.0971 0.4986 +vn -0.6878 0.1789 0.7035 +vn -0.8343 0.0255 0.5507 +vn -0.9432 -0.0799 0.3225 +vn -0.9598 -0.2519 0.1234 +vn -0.9240 -0.1304 0.3593 +vn -0.9500 -0.2778 0.1423 +vn -0.9096 -0.4067 -0.0845 +vn -0.7963 -0.5329 -0.2862 +vn -0.9098 -0.4061 -0.0849 +vn -0.8065 -0.5059 -0.3058 +vn -0.6284 -0.6218 -0.4673 +vn -0.4187 -0.6677 -0.6155 +vn -0.6479 -0.5704 -0.5048 +vn -0.4460 -0.5956 -0.6681 +vn -0.1820 -0.6684 -0.7212 +vn 0.0654 -0.6244 -0.7783 +vn -0.2153 -0.5805 -0.7853 +vn 0.0284 -0.5267 -0.8495 +vn 0.2267 -0.3298 -0.9164 +vn 0.2696 -0.4383 -0.8574 +vn 0.4062 -0.1055 -0.9077 +vn 0.4514 -0.2160 -0.8657 +vn 0.6063 0.0118 -0.7952 +vn 0.6469 -0.0875 -0.7575 +vn 0.7668 0.1290 -0.6288 +vn 0.8002 0.0475 -0.5979 +vn 0.8763 0.2381 -0.4187 +vn 0.9001 0.1801 -0.3967 +vn 0.9263 0.3316 -0.1786 +vn 0.9388 0.3012 -0.1670 +vn 0.9124 0.4025 0.0748 +vn 0.9126 0.4019 0.0751 +vn 0.8348 0.4454 0.3236 +vn 0.8228 0.4747 0.3124 +vn 0.6993 0.4574 0.5493 +vn 0.6759 0.5145 0.5277 +vn 0.5159 0.4376 0.7364 +vn 0.4827 0.5185 0.7057 +vn 0.2981 0.3880 0.8721 +vn 0.2575 0.4870 0.8345 +vn 0.0608 0.3122 0.9480 +vn 0.0156 0.4226 0.9062 +vn -0.1799 0.2155 0.9598 +vn -0.2267 0.3298 0.9164 +vn -0.4537 0.2147 0.8649 +vn -0.4085 0.1043 0.9068 +vn -0.6506 0.0847 0.7547 +vn -0.8039 -0.0514 0.5925 +vn -0.6100 -0.0143 0.7922 +vn -0.7707 -0.1323 0.6232 +vn -0.9026 -0.1847 0.3888 +vn -0.9390 -0.3056 0.1575 +vn -0.8792 -0.2418 0.4105 +vn -0.9270 -0.3349 0.1686 +vn -0.9101 -0.4055 -0.0852 +vn -0.8180 -0.4770 -0.3215 +vn -0.9103 -0.4049 -0.0855 +vn -0.8304 -0.4465 -0.3331 +vn -0.6697 -0.5152 -0.5348 +vn -0.4766 -0.5181 -0.7102 +vn -0.6934 -0.4572 -0.5568 +vn -0.5100 -0.4366 -0.7411 +vn -0.2526 -0.4860 -0.8366 +vn -0.0131 -0.4217 -0.9066 +vn -0.2933 -0.3867 -0.8743 +vn -0.0583 -0.3113 -0.9485 +vn 0.1300 -0.0976 -0.9867 +vn 0.1799 -0.2155 -0.9598 +vn 0.3076 0.1241 -0.9434 +vn 0.3580 0.0085 -0.9337 +vn 0.5176 0.2183 -0.8273 +vn 0.5629 0.1143 -0.8186 +vn 0.6940 0.2984 -0.6551 +vn 0.7312 0.2131 -0.6480 +vn 0.8245 0.3588 -0.4375 +vn 0.8510 0.2980 -0.4324 +vn 0.8992 0.3949 -0.1884 +vn 0.9131 0.3630 -0.1857 +vn 0.9118 0.4038 0.0746 +vn 0.9120 0.4031 0.0747 +vn 0.8609 0.3846 0.3330 +vn 0.8475 0.4152 0.3305 +vn 0.7503 0.3386 0.5678 +vn 0.7242 0.3984 0.5628 +vn 0.5881 0.2694 0.7625 +vn 0.5512 0.3541 0.7555 +vn 0.3865 0.1821 0.9041 +vn 0.3413 0.2858 0.8954 +vn 0.1593 0.0828 0.9837 +vn 0.1090 0.1983 0.9741 +vn -0.0779 -0.0219 0.9967 +vn -0.1300 0.0976 0.9867 +vn -0.3603 -0.0096 0.9328 +vn -0.3100 -0.1251 0.9424 +vn -0.5668 -0.1165 0.8155 +vn -0.7354 -0.2158 0.6423 +vn -0.5217 -0.2201 0.8242 +vn -0.6985 -0.3005 0.6494 +vn -0.8543 -0.3008 0.4239 +vn -0.9142 -0.3652 0.1755 +vn -0.8282 -0.3606 0.4289 +vn -0.9009 -0.3958 0.1780 +vn -0.9106 -0.4042 -0.0856 +vn -0.8437 -0.4151 -0.3403 +vn -0.9109 -0.4036 -0.0857 +vn -0.8576 -0.3833 -0.3429 +vn -0.7188 -0.3973 -0.5705 +vn -0.5456 -0.3525 -0.7603 +vn -0.7453 -0.3365 -0.5756 +vn -0.5828 -0.2671 -0.7674 +vn -0.3367 -0.2842 -0.8977 +vn -0.1065 -0.1973 -0.9745 +vn -0.3820 -0.1802 -0.9064 +vn -0.1569 -0.0817 -0.9842 +vn 0.0245 0.1411 -0.9897 +vn 0.0779 0.0219 -0.9967 +vn 0.2039 0.3522 -0.9134 +vn 0.2560 0.2393 -0.9366 +vn 0.4243 0.4235 -0.8003 +vn 0.4711 0.3220 -0.8212 +vn 0.6175 0.4668 -0.6330 +vn 0.6559 0.3835 -0.6501 +vn 0.7700 0.4787 -0.4218 +vn 0.7974 0.4194 -0.4339 +vn 0.8706 0.4578 -0.1802 +vn 0.8849 0.4267 -0.1865 +vn 0.9112 0.4051 0.0748 +vn 0.9115 0.4045 0.0747 +vn 0.8884 0.3241 0.3251 +vn 0.8746 0.3540 0.3312 +vn 0.8039 0.2206 0.5523 +vn 0.7770 0.2790 0.5643 +vn 0.6641 0.1023 0.7406 +vn 0.6259 0.1850 0.7576 +vn 0.4794 -0.0225 0.8773 +vn 0.4328 0.0788 0.8980 +vn 0.2630 -0.1452 0.9538 +vn 0.2109 -0.0324 0.9769 +vn 0.0293 -0.2579 0.9657 +vn -0.0245 -0.1411 0.9897 +vn -0.2584 -0.2403 0.9357 +vn -0.2064 -0.3532 0.9125 +vn -0.4753 -0.3235 0.8182 +vn -0.6607 -0.3849 0.6444 +vn -0.4287 -0.4247 0.7974 +vn -0.6226 -0.4676 0.6274 +vn -0.8015 -0.4202 0.4254 +vn -0.8872 -0.4264 0.1763 +vn -0.7746 -0.4786 0.4134 +vn -0.8734 -0.4563 0.1701 +vn -0.9112 -0.4029 -0.0856 +vn -0.8719 -0.3515 -0.3411 +vn -0.9115 -0.4023 -0.0855 +vn -0.8862 -0.3203 -0.3347 +vn -0.7724 -0.2759 -0.5720 +vn -0.6209 -0.1821 -0.7624 +vn -0.7998 -0.2166 -0.5598 +vn -0.6593 -0.0987 -0.7453 +vn -0.4284 -0.0765 -0.9003 +vn -0.2085 0.0336 -0.9774 +vn -0.4753 0.0251 -0.8795 +vn -0.2606 0.1465 -0.9543 +vn -0.0826 0.3703 -0.9252 +vn -0.0293 0.2579 -0.9657 +vn 0.1021 0.5634 -0.8198 +vn 0.1523 0.4609 -0.8742 +vn 0.3327 0.6135 -0.7161 +vn 0.3779 0.5213 -0.7651 +vn 0.5424 0.6227 -0.5640 +vn 0.5794 0.5470 -0.6041 +vn 0.7165 0.5897 -0.3726 +vn 0.7429 0.5358 -0.4012 +vn 0.8425 0.5161 -0.1544 +vn 0.8563 0.4878 -0.1693 +vn 0.9106 0.4063 0.0753 +vn 0.9109 0.4057 0.0750 +vn 0.9154 0.2681 0.3002 +vn 0.9021 0.2953 0.3147 +vn 0.8565 0.1115 0.5039 +vn 0.8306 0.1645 0.5321 +vn 0.7386 -0.0524 0.6720 +vn 0.7019 0.0227 0.7119 +vn 0.5707 -0.2118 0.7933 +vn 0.5257 -0.1199 0.8422 +vn 0.3647 -0.3563 0.8603 +vn 0.3145 -0.2538 0.9147 +vn 0.1346 -0.4763 0.8689 +vn 0.0826 -0.3703 0.9252 +vn -0.1548 -0.4617 0.8734 +vn -0.1046 -0.5642 0.8190 +vn -0.3824 -0.5222 0.7623 +vn -0.5848 -0.5472 0.5988 +vn -0.3374 -0.6141 0.7134 +vn -0.5480 -0.6223 0.5589 +vn -0.7479 -0.5347 0.3932 +vn -0.8597 -0.4851 0.1597 +vn -0.7220 -0.5878 0.3650 +vn -0.8464 -0.5123 0.1453 +vn -0.9118 -0.4017 -0.0853 +vn -0.9004 -0.2904 -0.3239 +vn -0.9121 -0.4010 -0.0850 +vn -0.9142 -0.2621 -0.3089 +vn -0.8269 -0.1595 -0.5393 +vn -0.6974 -0.0185 -0.7165 +vn -0.8533 -0.1056 -0.5106 +vn -0.7344 0.0571 -0.6763 +vn -0.5217 0.1228 -0.8443 +vn -0.3121 0.2551 -0.9151 +vn -0.5668 0.2150 -0.7953 +vn -0.3623 0.3577 -0.8607 +vn -0.1841 0.5742 -0.7977 +vn -0.1346 0.4763 -0.8689 +vn 0.0092 0.7432 -0.6689 +vn 0.0541 0.6581 -0.7510 +vn 0.2492 0.7752 -0.5805 +vn 0.2896 0.6986 -0.6542 +vn 0.4738 0.7554 -0.4526 +vn 0.5070 0.6926 -0.5131 +vn 0.6677 0.6842 -0.2933 +vn 0.6913 0.6395 -0.3364 +vn 0.8169 0.5656 -0.1128 +vn 0.8293 0.5421 -0.1354 +vn 0.9101 0.4074 0.0762 +vn 0.9103 0.4069 0.0757 +vn 0.9400 0.2204 0.2603 +vn 0.9281 0.2430 0.2820 +vn 0.9046 0.0185 0.4259 +vn 0.8813 0.0625 0.4683 +vn 0.8067 -0.1841 0.5615 +vn 0.7738 -0.1217 0.6216 +vn 0.6540 -0.3730 0.6580 +vn 0.6137 -0.2967 0.7316 +vn 0.4575 -0.5359 0.7095 +vn 0.4126 -0.4508 0.7915 +vn 0.2306 -0.6622 0.7129 +vn 0.1841 -0.5742 0.7977 +vn -0.0567 -0.6588 0.7502 +vn -0.0118 -0.7439 0.6682 +vn -0.2944 -0.6990 0.6517 +vn -0.5129 -0.6917 0.5084 +vn -0.2541 -0.7753 0.5782 +vn -0.4800 -0.7540 0.4483 +vn -0.6971 -0.6367 0.3294 +vn -0.8337 -0.5374 0.1270 +vn -0.6739 -0.6807 0.2870 +vn -0.8217 -0.5600 0.1053 +vn -0.9124 -0.4005 -0.0846 +vn -0.9275 -0.2360 -0.2899 +vn -0.9126 -0.4000 -0.0841 +vn -0.9398 -0.2126 -0.2673 +vn -0.8785 -0.0558 -0.4744 +vn -0.7698 0.1270 -0.6254 +vn -0.9021 -0.0111 -0.4313 +vn -0.8030 0.1898 -0.5649 +vn -0.6100 0.3001 -0.7334 +vn -0.4104 0.4523 -0.7918 +vn -0.6504 0.3767 -0.6596 +vn -0.4553 0.5375 -0.7098 +vn -0.2731 0.7389 -0.6159 +vn -0.2306 0.6622 -0.7129 +vn -0.0685 0.8794 -0.4711 +vn -0.0319 0.8174 -0.5751 +vn 0.1793 0.8977 -0.4025 +vn 0.2122 0.8419 -0.4960 +vn 0.4164 0.8559 -0.3066 +vn 0.4435 0.8101 -0.3833 +vn 0.6268 0.7558 -0.1893 +vn 0.6460 0.7232 -0.2439 +vn 0.7955 0.6032 -0.0582 +vn 0.8056 0.5861 -0.0869 +vn 0.9096 0.4081 0.0773 +vn 0.9098 0.4078 0.0768 +vn 0.9606 0.1843 0.2078 +vn 0.9509 0.2007 0.2354 +vn 0.9448 -0.0519 0.3236 +vn 0.9258 -0.0199 0.3774 +vn 0.8636 -0.2838 0.4166 +vn 0.8368 -0.2384 0.4928 +vn 0.7237 -0.4951 0.4806 +vn 0.6909 -0.4396 0.5739 +vn 0.5352 -0.6720 0.5118 +vn 0.4986 -0.6101 0.6157 +vn 0.3110 -0.8030 0.5083 +vn 0.2731 -0.7389 0.6159 +vn 0.0293 -0.8180 0.5744 +vn 0.0658 -0.8799 0.4705 +vn -0.2172 -0.8419 0.4940 +vn -0.4498 -0.8084 0.3796 +vn -0.1844 -0.8974 0.4008 +vn -0.4230 -0.8538 0.3034 +vn -0.6526 -0.7191 0.2385 +vn -0.8108 -0.5797 0.0804 +vn -0.6337 -0.7512 0.1847 +vn -0.8011 -0.5961 0.0528 +vn -0.9128 -0.3996 -0.0836 +vn -0.9512 -0.1921 -0.2414 +vn -0.9131 -0.3992 -0.0829 +vn -0.9613 -0.1750 -0.2127 +vn -0.9237 0.0279 -0.3820 +vn -0.8333 0.2445 -0.4957 +vn -0.9429 0.0604 -0.3274 +vn -0.8603 0.2903 -0.4189 +vn -0.6874 0.4434 -0.5752 +vn -0.4964 0.6117 -0.6160 +vn -0.7203 0.4992 -0.4816 +vn -0.5330 0.6736 -0.5119 +vn -0.3435 0.8534 -0.3920 +vn -0.3110 0.8030 -0.5083 +vn -0.1257 0.9626 -0.2397 +vn -0.0999 0.9281 -0.3587 +vn 0.1278 0.9725 -0.1944 +vn 0.1510 0.9414 -0.3014 +vn 0.3742 0.9173 -0.1358 +vn 0.3932 0.8918 -0.2236 +vn 0.5967 0.7996 -0.0677 +vn 0.6103 0.7814 -0.1302 +vn 0.7797 0.6261 0.0055 +vn 0.7868 0.6166 -0.0272 +vn 0.9093 0.4086 0.0786 +vn 0.9095 0.4084 0.0780 +vn 0.9758 0.1622 0.1465 +vn 0.9690 0.1714 0.1780 +vn 0.9743 -0.0949 0.2040 +vn 0.9610 -0.0771 0.2655 +vn 0.9055 -0.3448 0.2471 +vn 0.8867 -0.3195 0.3343 +vn 0.7750 -0.5698 0.2732 +vn 0.7519 -0.5388 0.3798 +vn 0.5924 -0.7552 0.2806 +vn 0.5666 -0.7207 0.3995 +vn 0.3702 -0.8891 0.2691 +vn 0.3435 -0.8534 0.3920 +vn 0.0973 -0.9286 0.3582 +vn 0.1230 -0.9631 0.2393 +vn -0.1562 -0.9411 0.3000 +vn -0.4000 -0.8894 0.2211 +vn -0.1331 -0.9720 0.1933 +vn -0.3811 -0.9147 0.1340 +vn -0.6175 -0.7763 0.1266 +vn -0.7928 -0.6090 0.0230 +vn -0.6041 -0.7942 0.0651 +vn -0.7860 -0.6182 -0.0085 +vn -0.9132 -0.3990 -0.0823 +vn -0.9699 -0.1616 -0.1817 +vn -0.9134 -0.3988 -0.0816 +vn -0.9771 -0.1521 -0.1490 +vn -0.9595 0.0860 -0.2683 +vn -0.8836 0.3262 -0.3359 +vn -0.9730 0.1042 -0.2058 +vn -0.9026 0.3517 -0.2481 +vn -0.7486 0.5430 -0.3805 +vn -0.5644 0.7223 -0.3995 +vn -0.7718 0.5741 -0.2736 +vn -0.5902 0.7569 -0.2806 +vn -0.3905 0.9096 -0.1415 +vn -0.3702 0.8891 -0.2691 +vn -0.1585 0.9873 0.0093 +vn -0.1453 0.9825 -0.1164 +vn 0.0983 0.9947 0.0295 +vn 0.1101 0.9904 -0.0835 +vn 0.3500 0.9355 0.0479 +vn 0.3597 0.9320 -0.0448 +vn 0.5795 0.8125 0.0632 +vn 0.5864 0.8100 -0.0028 +vn 0.7707 0.6329 0.0742 +vn 0.7743 0.6316 0.0395 +vn 0.9091 0.4088 0.0801 +vn 0.9092 0.4087 0.0794 +vn 0.9845 0.1557 0.0804 +vn 0.9810 0.1570 0.1137 +vn 0.9913 -0.1077 0.0751 +vn 0.9845 -0.1052 0.1401 +vn 0.9296 -0.3628 0.0647 +vn 0.9199 -0.3593 0.1568 +vn 0.8045 -0.5919 0.0499 +vn 0.7926 -0.5876 0.1626 +vn 0.6252 -0.7798 0.0317 +vn 0.6120 -0.7750 0.1574 +vn 0.3905 -0.9096 0.1415 +vn 0.1426 -0.9829 0.1161 +vn 0.1558 -0.9877 -0.0095 +vn -0.1155 -0.9898 0.0827 +vn -0.3667 -0.9293 0.0436 +vn -0.1036 -0.9941 -0.0300 +vn -0.3571 -0.9328 -0.0484 +vn -0.5940 -0.8045 0.0013 +vn -0.7808 -0.6234 -0.0412 +vn -0.5872 -0.8069 -0.0637 +vn -0.7773 -0.6247 -0.0745 +vn -0.9135 -0.3987 -0.0809 +vn -0.9825 -0.1466 -0.1150 +vn -0.9136 -0.3986 -0.0802 +vn -0.9861 -0.1453 -0.0803 +vn -0.9833 0.1146 -0.1409 +vn -0.9171 0.3664 -0.1571 +vn -0.9903 0.1171 -0.0749 +vn -0.9268 0.3699 -0.0643 +vn -0.7894 0.5919 -0.1626 +vn -0.6099 0.7767 -0.1572 +vn -0.8013 0.5962 -0.0495 +vn -0.6230 0.7815 -0.0315 +vn -0.1647 0.9517 0.2591 +vn -0.1650 0.9770 0.1352 +vn 0.0927 0.9627 0.2542 +vn 0.0924 0.9854 0.1428 +vn 0.3454 0.9092 0.2323 +vn 0.3452 0.9279 0.1408 +vn 0.5762 0.7938 0.1945 +vn 0.5761 0.8071 0.1293 +vn 0.7689 0.6231 0.1431 +vn 0.7689 0.6301 0.1089 +vn 0.9091 0.4086 0.0815 +vn 0.9091 0.4087 0.0808 +vn 0.9861 0.1651 0.0142 +vn 0.9862 0.1584 0.0470 +vn 0.9945 -0.0893 -0.0540 +vn 0.9947 -0.1024 0.0100 +vn 0.9341 -0.3367 -0.1183 +vn 0.9343 -0.3553 -0.0275 +vn 0.8100 -0.5599 -0.1741 +vn 0.8103 -0.5826 -0.0630 +vn 0.6314 -0.7442 -0.2179 +vn 0.6317 -0.7695 -0.0941 +vn 0.1623 -0.9774 -0.1353 +vn 0.1620 -0.9521 -0.2592 +vn -0.0978 -0.9849 -0.1429 +vn -0.3523 -0.9252 -0.1407 +vn -0.0981 -0.9622 -0.2540 +vn -0.3525 -0.9067 -0.2314 +vn -0.5838 -0.8016 -0.1288 +vn -0.7755 -0.6220 -0.1079 +vn -0.5840 -0.7885 -0.1928 +vn -0.7756 -0.6153 -0.1408 +vn -0.9136 -0.3987 -0.0795 +vn -0.9879 -0.1481 -0.0456 +vn -0.9136 -0.3988 -0.0788 +vn -0.9878 -0.1551 -0.0114 +vn -0.9937 0.1117 -0.0087 +vn -0.9316 0.3623 0.0285 +vn -0.9935 0.0984 0.0564 +vn -0.9314 0.3436 0.1200 +vn -0.8071 0.5869 0.0637 +vn -0.6295 0.7712 0.0943 +vn -0.8068 0.5642 0.1751 +vn -0.6292 0.7459 0.2183 +vn -0.1439 0.8582 0.4927 +vn -0.1576 0.9119 0.3790 +vn 0.1115 0.8786 0.4643 +vn 0.0991 0.9268 0.3620 +vn 0.3608 0.8402 0.4047 +vn 0.3507 0.8798 0.3208 +vn 0.5872 0.7447 0.3172 +vn 0.5800 0.7729 0.2575 +vn 0.7747 0.5973 0.2074 +vn 0.7709 0.6121 0.1761 +vn 0.9092 0.4080 0.0829 +vn 0.9091 0.4083 0.0822 +vn 0.9806 0.1899 -0.0477 +vn 0.9843 0.1757 -0.0176 +vn 0.9837 -0.0409 -0.1748 +vn 0.9908 -0.0687 -0.1160 +vn 0.9189 -0.2683 -0.2893 +vn 0.9289 -0.3076 -0.2061 +vn 0.7913 -0.4761 -0.3835 +vn 0.8036 -0.5242 -0.2816 +vn 0.6105 -0.6508 -0.4513 +vn 0.6243 -0.7044 -0.3377 +vn 0.1549 -0.9124 -0.3789 +vn 0.1411 -0.8587 -0.4926 +vn -0.1044 -0.9265 -0.3614 +vn -0.3577 -0.8776 -0.3192 +vn -0.1168 -0.8784 -0.4634 +vn -0.3678 -0.8383 -0.4025 +vn -0.5876 -0.7679 -0.2548 +vn -0.7775 -0.6047 -0.1726 +vn -0.5947 -0.7402 -0.3136 +vn -0.7812 -0.5905 -0.2027 +vn -0.9136 -0.3991 -0.0781 +vn -0.9859 -0.1661 0.0216 +vn -0.9135 -0.3994 -0.0774 +vn -0.9821 -0.1809 0.0529 +vn -0.9898 0.0775 0.1194 +vn -0.9261 0.3142 0.2085 +vn -0.9826 0.0493 0.1792 +vn -0.9160 0.2746 0.2924 +vn -0.8005 0.5284 0.2829 +vn -0.6222 0.7061 0.3381 +vn -0.7881 0.4801 0.3852 +vn -0.6084 0.6524 0.4518 +vn -0.0974 0.7132 0.6941 +vn -0.1237 0.7916 0.5983 +vn 0.1533 0.7482 0.6454 +vn 0.1296 0.8187 0.5593 +vn 0.3951 0.7333 0.5533 +vn 0.3757 0.7911 0.4827 +vn 0.6116 0.6685 0.4231 +vn 0.5978 0.7096 0.3728 +vn 0.7875 0.5574 0.2629 +vn 0.7803 0.5789 0.2365 +vn 0.9095 0.4072 0.0840 +vn 0.9093 0.4076 0.0834 +vn 0.9683 0.2284 -0.1011 +vn 0.9753 0.2076 -0.0757 +vn 0.9597 0.0340 -0.2789 +vn 0.9733 -0.0065 -0.2294 +vn 0.8848 -0.1621 -0.4368 +vn 0.9040 -0.2195 -0.3667 +vn 0.7496 -0.3461 -0.5641 +vn 0.7732 -0.4164 -0.4782 +vn 0.5641 -0.5060 -0.6525 +vn 0.5903 -0.5843 -0.5568 +vn 0.1210 -0.7922 -0.5981 +vn 0.0947 -0.7139 -0.6938 +vn -0.1349 -0.8187 -0.5581 +vn -0.3826 -0.7895 -0.4799 +vn -0.1585 -0.7484 -0.6440 +vn -0.4019 -0.7321 -0.5500 +vn -0.6052 -0.7058 -0.3682 +vn -0.7865 -0.5728 -0.2307 +vn -0.6188 -0.6652 -0.4177 +vn -0.7935 -0.5520 -0.2561 +vn -0.9134 -0.3998 -0.0768 +vn -0.9765 -0.1992 0.0820 +vn -0.9132 -0.4002 -0.0763 +vn -0.9692 -0.2208 0.1084 +vn -0.9720 0.0143 0.2347 +vn -0.9011 0.2255 0.3703 +vn -0.9581 -0.0269 0.2850 +vn -0.8817 0.1677 0.4410 +vn -0.7699 0.4202 0.4802 +vn -0.5882 0.5859 0.5575 +vn -0.7463 0.3497 0.5663 +vn -0.5619 0.5075 0.6532 +vn -0.0284 0.5267 0.8495 +vn -0.0654 0.6244 0.7783 +vn 0.2153 0.5805 0.7853 +vn 0.1820 0.6684 0.7212 +vn 0.4460 0.5956 0.6681 +vn 0.4187 0.6677 0.6155 +vn 0.6479 0.5704 0.5048 +vn 0.6284 0.6218 0.4673 +vn 0.8065 0.5059 0.3058 +vn 0.7963 0.5329 0.2862 +vn 0.9098 0.4061 0.0849 +vn 0.9096 0.4067 0.0845 +vn 0.9500 0.2778 -0.1423 +vn 0.9598 0.2519 -0.1234 +vn 0.9240 0.1304 -0.3593 +vn 0.9432 0.0799 -0.3225 +vn 0.8343 -0.0255 -0.5507 +vn 0.8614 -0.0971 -0.4986 +vn 0.6878 -0.1789 -0.7035 +vn 0.7210 -0.2665 -0.6396 +vn 0.4952 -0.3196 -0.8079 +vn 0.5322 -0.4172 -0.7367 +vn 0.0628 -0.6251 -0.7779 +vn 0.0258 -0.5275 -0.8491 +vn -0.1871 -0.6688 -0.7195 +vn -0.4252 -0.6670 -0.6117 +vn -0.2203 -0.5812 -0.7833 +vn -0.4524 -0.5954 -0.6639 +vn -0.6353 -0.6193 -0.4613 +vn -0.8019 -0.5285 -0.2784 +vn -0.6545 -0.5688 -0.4981 +vn -0.8118 -0.5026 -0.2973 +vn -0.9131 -0.4007 -0.0758 +vn -0.9604 -0.2453 0.1317 +vn -0.9128 -0.4013 -0.0754 +vn -0.9502 -0.2722 0.1513 +vn -0.9413 -0.0735 0.3293 +vn -0.8581 0.1021 0.5032 +vn -0.9219 -0.1249 0.3667 +vn -0.8308 0.0300 0.5557 +vn -0.7176 0.2699 0.6421 +vn -0.5300 0.4187 0.7374 +vn -0.6843 0.1820 0.7062 +vn -0.4929 0.3210 0.8087 +vn 0.0583 0.3113 0.9485 +vn 0.0131 0.4217 0.9066 +vn 0.2933 0.3867 0.8743 +vn 0.2526 0.4860 0.8366 +vn 0.5100 0.4366 0.7411 +vn 0.4766 0.5181 0.7102 +vn 0.6934 0.4572 0.5568 +vn 0.6697 0.5152 0.5348 +vn 0.8304 0.4465 0.3331 +vn 0.8180 0.4770 0.3215 +vn 0.9103 0.4049 0.0855 +vn 0.9101 0.4055 0.0852 +vn 0.9270 0.3349 -0.1686 +vn 0.9390 0.3056 -0.1575 +vn 0.8792 0.2418 -0.4105 +vn 0.9026 0.1847 -0.3888 +vn 0.7707 0.1323 -0.6232 +vn 0.8039 0.0514 -0.5925 +vn 0.6100 0.0143 -0.7922 +vn 0.6506 -0.0847 -0.7547 +vn 0.4085 -0.1043 -0.9068 +vn 0.4537 -0.2147 -0.8649 +vn -0.0156 -0.4226 -0.9062 +vn -0.0608 -0.3122 -0.9480 +vn -0.2575 -0.4870 -0.8345 +vn -0.4827 -0.5185 -0.7057 +vn -0.2981 -0.3880 -0.8721 +vn -0.5159 -0.4376 -0.7364 +vn -0.6759 -0.5145 -0.5277 +vn -0.8228 -0.4747 -0.3124 +vn -0.6993 -0.4574 -0.5493 +vn -0.8348 -0.4454 -0.3236 +vn -0.9126 -0.4019 -0.0751 +vn -0.9388 -0.3012 0.1670 +vn -0.9124 -0.4025 -0.0748 +vn -0.9263 -0.3316 0.1786 +vn -0.9001 -0.1801 0.3967 +vn -0.8002 -0.0475 0.5979 +vn -0.8763 -0.2381 0.4187 +vn -0.7668 -0.1290 0.6288 +vn -0.6469 0.0875 0.7575 +vn -0.4514 0.2160 0.8657 +vn -0.6063 -0.0118 0.7952 +vn -0.4062 0.1055 0.9077 +vn 0.1569 0.0817 0.9842 +vn 0.1065 0.1973 0.9745 +vn 0.3820 0.1802 0.9064 +vn 0.3367 0.2842 0.8977 +vn 0.5828 0.2671 0.7674 +vn 0.5456 0.3525 0.7603 +vn 0.7453 0.3365 0.5756 +vn 0.7188 0.3973 0.5705 +vn 0.8576 0.3833 0.3429 +vn 0.8437 0.4151 0.3403 +vn 0.9109 0.4036 0.0857 +vn 0.9106 0.4042 0.0856 +vn 0.9009 0.3958 -0.1780 +vn 0.9142 0.3652 -0.1755 +vn 0.8282 0.3606 -0.4289 +vn 0.8543 0.3008 -0.4239 +vn 0.6985 0.3005 -0.6494 +vn 0.7354 0.2158 -0.6423 +vn 0.5217 0.2201 -0.8242 +vn 0.5668 0.1165 -0.8155 +vn 0.3100 0.1251 -0.9424 +vn 0.3603 0.0096 -0.9328 +vn -0.1090 -0.1983 -0.9740 +vn -0.1593 -0.0828 -0.9837 +vn -0.3413 -0.2858 -0.8954 +vn -0.5512 -0.3541 -0.7555 +vn -0.3865 -0.1821 -0.9041 +vn -0.5881 -0.2694 -0.7625 +vn -0.7242 -0.3984 -0.5628 +vn -0.8475 -0.4152 -0.3305 +vn -0.7503 -0.3386 -0.5678 +vn -0.8609 -0.3846 -0.3330 +vn -0.9120 -0.4031 -0.0747 +vn -0.9131 -0.3630 0.1857 +vn -0.9118 -0.4038 -0.0746 +vn -0.8992 -0.3949 0.1884 +vn -0.8510 -0.2980 0.4324 +vn -0.7312 -0.2131 0.6480 +vn -0.8245 -0.3588 0.4375 +vn -0.6940 -0.2984 0.6551 +vn -0.5629 -0.1143 0.8186 +vn -0.3580 -0.0085 0.9337 +vn -0.5176 -0.2183 0.8273 +vn -0.3076 -0.1241 0.9434 +vn 0.2606 -0.1465 0.9543 +vn 0.2085 -0.0336 0.9774 +vn 0.4753 -0.0251 0.8795 +vn 0.4284 0.0765 0.9003 +vn 0.6593 0.0987 0.7453 +vn 0.6209 0.1821 0.7624 +vn 0.7998 0.2166 0.5598 +vn 0.7724 0.2759 0.5720 +vn 0.8862 0.3203 0.3347 +vn 0.8719 0.3515 0.3411 +vn 0.9115 0.4023 0.0855 +vn 0.9112 0.4029 0.0856 +vn 0.8734 0.4563 -0.1701 +vn 0.8872 0.4264 -0.1763 +vn 0.7746 0.4786 -0.4134 +vn 0.8015 0.4202 -0.4254 +vn 0.6226 0.4676 -0.6274 +vn 0.6607 0.3849 -0.6444 +vn 0.4287 0.4247 -0.7974 +vn 0.4753 0.3235 -0.8182 +vn 0.2063 0.3532 -0.9125 +vn 0.2584 0.2403 -0.9357 +vn -0.2109 0.0324 -0.9769 +vn -0.2630 0.1452 -0.9538 +vn -0.4328 -0.0788 -0.8980 +vn -0.6259 -0.1850 -0.7576 +vn -0.4794 0.0225 -0.8773 +vn -0.6641 -0.1023 -0.7406 +vn -0.7770 -0.2790 -0.5643 +vn -0.8746 -0.3540 -0.3312 +vn -0.8039 -0.2206 -0.5523 +vn -0.8884 -0.3241 -0.3251 +vn -0.9115 -0.4045 -0.0747 +vn -0.8849 -0.4267 0.1865 +vn -0.9112 -0.4051 -0.0748 +vn -0.8706 -0.4578 0.1802 +vn -0.7974 -0.4194 0.4339 +vn -0.6559 -0.3835 0.6501 +vn -0.7700 -0.4787 0.4218 +vn -0.6175 -0.4668 0.6330 +vn -0.4711 -0.3220 0.8212 +vn -0.2560 -0.2393 0.9366 +vn -0.4243 -0.4235 0.8003 +vn -0.2039 -0.3522 0.9134 +vn 0.3623 -0.3577 0.8607 +vn 0.3121 -0.2551 0.9151 +vn 0.5668 -0.2150 0.7953 +vn 0.5217 -0.1228 0.8443 +vn 0.7344 -0.0571 0.6763 +vn 0.6974 0.0185 0.7165 +vn 0.8533 0.1056 0.5106 +vn 0.8269 0.1595 0.5393 +vn 0.9142 0.2621 0.3089 +vn 0.9004 0.2904 0.3239 +vn 0.9121 0.4010 0.0850 +vn 0.9118 0.4017 0.0853 +vn 0.8464 0.5123 -0.1453 +vn 0.8597 0.4851 -0.1597 +vn 0.7220 0.5878 -0.3650 +vn 0.7479 0.5347 -0.3932 +vn 0.5480 0.6223 -0.5589 +vn 0.5848 0.5472 -0.5988 +vn 0.3374 0.6141 -0.7134 +vn 0.3824 0.5222 -0.7623 +vn 0.1046 0.5642 -0.8190 +vn 0.1548 0.4617 -0.8734 +vn -0.3145 0.2538 -0.9147 +vn -0.3647 0.3563 -0.8603 +vn -0.5257 0.1199 -0.8422 +vn -0.7018 -0.0227 -0.7119 +vn -0.5707 0.2118 -0.7933 +vn -0.7386 0.0524 -0.6720 +vn -0.8306 -0.1645 -0.5321 +vn -0.9021 -0.2953 -0.3147 +vn -0.8565 -0.1115 -0.5039 +vn -0.9154 -0.2681 -0.3002 +vn -0.9109 -0.4057 -0.0750 +vn -0.8563 -0.4878 0.1693 +vn -0.9106 -0.4063 -0.0753 +vn -0.8425 -0.5161 0.1544 +vn -0.7429 -0.5358 0.4012 +vn -0.5794 -0.5470 0.6041 +vn -0.7165 -0.5897 0.3726 +vn -0.5424 -0.6227 0.5640 +vn -0.3779 -0.5213 0.7651 +vn -0.1523 -0.4609 0.8742 +vn -0.3327 -0.6135 0.7161 +vn -0.1021 -0.5634 0.8198 +vn 0.1842 -0.5742 0.7977 +vn 0.4553 -0.5375 0.7098 +vn 0.4104 -0.4523 0.7918 +vn 0.6504 -0.3767 0.6596 +vn 0.6100 -0.3001 0.7334 +vn 0.8030 -0.1898 0.5649 +vn 0.7698 -0.1270 0.6254 +vn 0.9021 0.0111 0.4313 +vn 0.8785 0.0558 0.4744 +vn 0.9398 0.2126 0.2673 +vn 0.9275 0.2360 0.2899 +vn 0.9126 0.4000 0.0841 +vn 0.9124 0.4005 0.0846 +vn 0.8217 0.5600 -0.1053 +vn 0.8337 0.5374 -0.1270 +vn 0.6739 0.6807 -0.2870 +vn 0.6971 0.6367 -0.3294 +vn 0.4800 0.7540 -0.4483 +vn 0.5129 0.6917 -0.5084 +vn 0.2541 0.7753 -0.5782 +vn 0.2944 0.6990 -0.6517 +vn 0.0118 0.7439 -0.6682 +vn 0.0567 0.6588 -0.7502 +vn -0.4126 0.4508 -0.7915 +vn -0.4575 0.5359 -0.7095 +vn -0.6137 0.2967 -0.7316 +vn -0.7738 0.1217 -0.6216 +vn -0.6540 0.3730 -0.6580 +vn -0.8067 0.1841 -0.5615 +vn -0.8813 -0.0625 -0.4683 +vn -0.9281 -0.2430 -0.2820 +vn -0.9046 -0.0185 -0.4259 +vn -0.9400 -0.2204 -0.2603 +vn -0.9103 -0.4069 -0.0757 +vn -0.8293 -0.5421 0.1354 +vn -0.9101 -0.4074 -0.0762 +vn -0.8169 -0.5656 0.1128 +vn -0.6913 -0.6395 0.3364 +vn -0.5070 -0.6926 0.5131 +vn -0.6677 -0.6842 0.2933 +vn -0.4738 -0.7554 0.4526 +vn -0.2896 -0.6986 0.6542 +vn -0.0541 -0.6581 0.7510 +vn -0.2492 -0.7752 0.5805 +vn -0.0092 -0.7432 0.6689 +vn 0.5330 -0.6736 0.5119 +vn 0.4964 -0.6117 0.6160 +vn 0.7203 -0.4992 0.4816 +vn 0.6874 -0.4434 0.5752 +vn 0.8603 -0.2903 0.4189 +vn 0.8333 -0.2445 0.4957 +vn 0.9429 -0.0604 0.3274 +vn 0.9237 -0.0279 0.3820 +vn 0.9613 0.1750 0.2127 +vn 0.9512 0.1921 0.2414 +vn 0.9131 0.3992 0.0829 +vn 0.9128 0.3996 0.0836 +vn 0.8011 0.5961 -0.0528 +vn 0.8108 0.5797 -0.0804 +vn 0.6337 0.7512 -0.1847 +vn 0.6526 0.7191 -0.2385 +vn 0.4230 0.8538 -0.3034 +vn 0.4498 0.8084 -0.3796 +vn 0.1844 0.8974 -0.4008 +vn 0.2172 0.8419 -0.4940 +vn -0.0658 0.8799 -0.4705 +vn -0.0293 0.8180 -0.5744 +vn -0.4986 0.6101 -0.6157 +vn -0.5352 0.6720 -0.5118 +vn -0.6909 0.4396 -0.5739 +vn -0.8368 0.2384 -0.4928 +vn -0.7237 0.4951 -0.4806 +vn -0.8636 0.2838 -0.4166 +vn -0.9258 0.0199 -0.3774 +vn -0.9509 -0.2007 -0.2354 +vn -0.9448 0.0519 -0.3236 +vn -0.9606 -0.1843 -0.2078 +vn -0.9098 -0.4078 -0.0768 +vn -0.8056 -0.5861 0.0869 +vn -0.9096 -0.4081 -0.0773 +vn -0.7955 -0.6032 0.0582 +vn -0.6460 -0.7232 0.2439 +vn -0.4435 -0.8101 0.3833 +vn -0.6268 -0.7558 0.1893 +vn -0.4164 -0.8559 0.3066 +vn -0.2122 -0.8419 0.4961 +vn 0.0319 -0.8174 0.5751 +vn -0.1793 -0.8977 0.4025 +vn 0.0685 -0.8794 0.4711 +vn 0.5902 -0.7569 0.2806 +vn 0.5644 -0.7223 0.3995 +vn 0.7718 -0.5741 0.2736 +vn 0.7486 -0.5430 0.3805 +vn 0.9026 -0.3517 0.2481 +vn 0.8836 -0.3262 0.3359 +vn 0.9730 -0.1042 0.2058 +vn 0.9595 -0.0860 0.2683 +vn 0.9771 0.1521 0.1490 +vn 0.9700 0.1616 0.1817 +vn 0.9134 0.3988 0.0816 +vn 0.9132 0.3990 0.0823 +vn 0.7860 0.6182 0.0085 +vn 0.7928 0.6090 -0.0230 +vn 0.6041 0.7942 -0.0651 +vn 0.6175 0.7763 -0.1266 +vn 0.3811 0.9147 -0.1340 +vn 0.4000 0.8894 -0.2211 +vn 0.1331 0.9720 -0.1933 +vn 0.1562 0.9411 -0.3000 +vn -0.1230 0.9631 -0.2393 +vn -0.0973 0.9286 -0.3582 +vn -0.5666 0.7207 -0.3995 +vn -0.5924 0.7552 -0.2806 +vn -0.7519 0.5388 -0.3798 +vn -0.8867 0.3195 -0.3343 +vn -0.7750 0.5698 -0.2732 +vn -0.9055 0.3448 -0.2471 +vn -0.9610 0.0771 -0.2655 +vn -0.9690 -0.1714 -0.1780 +vn -0.9743 0.0949 -0.2040 +vn -0.9758 -0.1622 -0.1465 +vn -0.9095 -0.4084 -0.0780 +vn -0.7868 -0.6166 0.0272 +vn -0.9093 -0.4086 -0.0786 +vn -0.7797 -0.6261 -0.0055 +vn -0.6103 -0.7814 0.1302 +vn -0.3932 -0.8918 0.2236 +vn -0.5967 -0.7996 0.0677 +vn -0.3742 -0.9173 0.1358 +vn -0.1510 -0.9414 0.3014 +vn 0.0999 -0.9281 0.3587 +vn -0.1278 -0.9725 0.1944 +vn 0.1257 -0.9626 0.2397 +vn 0.6099 -0.7767 0.1572 +vn 0.7894 -0.5919 0.1626 +vn 0.9171 -0.3664 0.1571 +vn 0.9833 -0.1146 0.1409 +vn 0.9825 0.1466 0.1150 +vn 0.9135 0.3987 0.0809 +vn 0.7808 0.6234 0.0412 +vn 0.5940 0.8045 -0.0013 +vn 0.3667 0.9293 -0.0436 +vn 0.1155 0.9898 -0.0827 +vn -0.1426 0.9829 -0.1161 +vn -0.6120 0.7750 -0.1574 +vn -0.7926 0.5876 -0.1626 +vn -0.9199 0.3593 -0.1568 +vn -0.9845 0.1052 -0.1401 +vn -0.9810 -0.1570 -0.1137 +vn -0.9092 -0.4087 -0.0794 +vn -0.7743 -0.6316 -0.0395 +vn -0.5864 -0.8100 0.0029 +vn -0.3597 -0.9320 0.0448 +vn -0.1101 -0.9904 0.0835 +vn 0.1453 -0.9825 0.1164 +vn 0.9914 0.0000 -0.1305 +vn 0.9670 0.2548 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.9340 0.2548 -0.2503 +vn 0.9587 0.2548 -0.1262 +vn 0.8401 0.4935 -0.2251 +vn 0.8623 0.4935 -0.1135 +vn 0.8697 0.4935 0.0000 +vn 0.7136 0.7005 0.0000 +vn 0.6893 0.7005 -0.1847 +vn 0.7075 0.7005 -0.0931 +vn 0.4909 0.8612 -0.1315 +vn 0.5039 0.8612 -0.0663 +vn 0.5082 0.8612 0.0000 +vn 0.2665 0.9638 0.0000 +vn 0.2575 0.9638 -0.0690 +vn 0.2643 0.9638 -0.0348 +vn 0.0053 1.0000 -0.0014 +vn 0.0055 1.0000 -0.0007 +vn 0.0055 1.0000 0.0000 +vn -0.2564 0.9666 0.0000 +vn -0.2476 0.9666 0.0663 +vn -0.2542 0.9666 0.0334 +vn -0.4830 0.8660 0.1294 +vn -0.4957 0.8660 0.0652 +vn -0.5000 0.8660 0.0000 +vn -0.7083 0.7059 0.0000 +vn -0.6842 0.7059 0.1833 +vn -0.7022 0.7059 0.0924 +vn -0.8375 0.4982 0.2244 +vn -0.8596 0.4982 0.1132 +vn -0.8670 0.4982 0.0000 +vn -0.9663 0.2575 0.0000 +vn -0.9333 0.2575 0.2501 +vn -0.9580 0.2575 0.1261 +vn -0.9659 0.0000 0.2588 +vn -0.9914 0.0000 0.1305 +vn -1.0000 0.0000 0.0000 +vn -0.9580 -0.2575 0.1261 +vn -0.9663 -0.2575 0.0000 +vn -0.9333 -0.2575 0.2501 +vn -0.8596 -0.4982 0.1132 +vn -0.8670 -0.4982 0.0000 +vn -0.7022 -0.7059 0.0924 +vn -0.7083 -0.7059 0.0000 +vn -0.8375 -0.4982 0.2244 +vn -0.6842 -0.7059 0.1833 +vn -0.4957 -0.8660 0.0652 +vn -0.5000 -0.8660 0.0000 +vn -0.2542 -0.9666 0.0334 +vn -0.2564 -0.9666 0.0000 +vn -0.4830 -0.8660 0.1294 +vn -0.2476 -0.9666 0.0663 +vn 0.0055 -1.0000 -0.0007 +vn 0.0055 -1.0000 0.0000 +vn 0.2643 -0.9638 -0.0348 +vn 0.2665 -0.9638 0.0000 +vn 0.0053 -1.0000 -0.0014 +vn 0.2575 -0.9638 -0.0690 +vn 0.5039 -0.8612 -0.0663 +vn 0.5082 -0.8612 0.0000 +vn 0.7075 -0.7005 -0.0931 +vn 0.7136 -0.7005 0.0000 +vn 0.4909 -0.8612 -0.1315 +vn 0.6893 -0.7005 -0.1847 +vn 0.8623 -0.4935 -0.1135 +vn 0.8697 -0.4935 0.0000 +vn 0.9587 -0.2548 -0.1262 +vn 0.9670 -0.2548 0.0000 +vn 0.8401 -0.4935 -0.2251 +vn 0.9340 -0.2548 -0.2503 +vn 0.9239 0.0000 -0.3827 +vn 0.9659 0.0000 -0.2588 +vn 0.8374 0.2548 -0.4835 +vn 0.8934 0.2548 -0.3700 +vn 0.7532 0.4935 -0.4349 +vn 0.8035 0.4935 -0.3328 +vn 0.6180 0.7005 -0.3568 +vn 0.6593 0.7005 -0.2731 +vn 0.4401 0.8612 -0.2541 +vn 0.4695 0.8612 -0.1945 +vn 0.2308 0.9638 -0.1333 +vn 0.2463 0.9638 -0.1020 +vn 0.0048 1.0000 -0.0027 +vn 0.0051 1.0000 -0.0021 +vn -0.2220 0.9666 0.1282 +vn -0.2369 0.9666 0.0981 +vn -0.4330 0.8660 0.2500 +vn -0.4620 0.8660 0.1914 +vn -0.6134 0.7059 0.3541 +vn -0.6544 0.7059 0.2710 +vn -0.7509 0.4982 0.4335 +vn -0.8010 0.4982 0.3318 +vn -0.8368 0.2575 0.4831 +vn -0.8927 0.2575 0.3698 +vn -0.8660 0.0000 0.5000 +vn -0.9239 0.0000 0.3827 +vn -0.8927 -0.2575 0.3698 +vn -0.8368 -0.2575 0.4831 +vn -0.8010 -0.4982 0.3318 +vn -0.6544 -0.7059 0.2710 +vn -0.7509 -0.4982 0.4335 +vn -0.6134 -0.7059 0.3541 +vn -0.4620 -0.8660 0.1914 +vn -0.2369 -0.9666 0.0981 +vn -0.4330 -0.8660 0.2500 +vn -0.2220 -0.9666 0.1282 +vn 0.0051 -1.0000 -0.0021 +vn 0.2463 -0.9638 -0.1020 +vn 0.0048 -1.0000 -0.0027 +vn 0.2308 -0.9638 -0.1333 +vn 0.4695 -0.8612 -0.1945 +vn 0.6593 -0.7005 -0.2731 +vn 0.4401 -0.8612 -0.2541 +vn 0.6180 -0.7005 -0.3568 +vn 0.8035 -0.4935 -0.3328 +vn 0.8934 -0.2548 -0.3700 +vn 0.7532 -0.4935 -0.4349 +vn 0.8374 -0.2548 -0.4835 +vn 0.7933 0.0000 -0.6088 +vn 0.8660 0.0000 -0.5000 +vn 0.6837 0.2548 -0.6837 +vn 0.7671 0.2548 -0.5886 +vn 0.6150 0.4935 -0.6150 +vn 0.6900 0.4935 -0.5294 +vn 0.5046 0.7005 -0.5046 +vn 0.5661 0.7005 -0.4344 +vn 0.3594 0.8612 -0.3594 +vn 0.4032 0.8612 -0.3094 +vn 0.1885 0.9638 -0.1885 +vn 0.2115 0.9638 -0.1623 +vn 0.0039 1.0000 -0.0039 +vn 0.0044 1.0000 -0.0034 +vn -0.1813 0.9666 0.1813 +vn -0.2034 0.9666 0.1561 +vn -0.3536 0.8660 0.3536 +vn -0.3967 0.8660 0.3044 +vn -0.5008 0.7059 0.5008 +vn -0.5619 0.7059 0.4312 +vn -0.6131 0.4982 0.6131 +vn -0.6879 0.4982 0.5278 +vn -0.6832 0.2575 0.6832 +vn -0.7666 0.2575 0.5882 +vn -0.7071 0.0000 0.7071 +vn -0.7933 0.0000 0.6088 +vn -0.7666 -0.2575 0.5882 +vn -0.6832 -0.2575 0.6832 +vn -0.6879 -0.4982 0.5278 +vn -0.5619 -0.7059 0.4312 +vn -0.6131 -0.4982 0.6131 +vn -0.5008 -0.7059 0.5008 +vn -0.3967 -0.8660 0.3044 +vn -0.2034 -0.9666 0.1561 +vn -0.3536 -0.8660 0.3536 +vn -0.1813 -0.9666 0.1813 +vn 0.0044 -1.0000 -0.0034 +vn 0.2115 -0.9638 -0.1623 +vn 0.0039 -1.0000 -0.0039 +vn 0.1885 -0.9638 -0.1885 +vn 0.4032 -0.8612 -0.3094 +vn 0.5661 -0.7005 -0.4344 +vn 0.3594 -0.8612 -0.3594 +vn 0.5046 -0.7005 -0.5046 +vn 0.6900 -0.4935 -0.5294 +vn 0.7671 -0.2548 -0.5886 +vn 0.6150 -0.4935 -0.6150 +vn 0.6837 -0.2548 -0.6837 +vn 0.6088 0.0000 -0.7933 +vn 0.7071 0.0000 -0.7071 +vn 0.4835 0.2548 -0.8374 +vn 0.5886 0.2548 -0.7671 +vn 0.4349 0.4935 -0.7532 +vn 0.5294 0.4935 -0.6900 +vn 0.3568 0.7005 -0.6180 +vn 0.4344 0.7005 -0.5661 +vn 0.2541 0.8612 -0.4401 +vn 0.3094 0.8612 -0.4032 +vn 0.1333 0.9638 -0.2308 +vn 0.1623 0.9638 -0.2115 +vn 0.0027 1.0000 -0.0048 +vn 0.0034 1.0000 -0.0044 +vn -0.1282 0.9666 0.2220 +vn -0.1561 0.9666 0.2034 +vn -0.2500 0.8660 0.4330 +vn -0.3044 0.8660 0.3967 +vn -0.3541 0.7059 0.6134 +vn -0.4312 0.7059 0.5619 +vn -0.4335 0.4982 0.7509 +vn -0.5278 0.4982 0.6879 +vn -0.4831 0.2575 0.8368 +vn -0.5882 0.2575 0.7666 +vn -0.5000 0.0000 0.8660 +vn -0.6088 0.0000 0.7933 +vn -0.5882 -0.2575 0.7666 +vn -0.4831 -0.2575 0.8368 +vn -0.5278 -0.4982 0.6879 +vn -0.4312 -0.7059 0.5619 +vn -0.4335 -0.4982 0.7509 +vn -0.3541 -0.7059 0.6134 +vn -0.3044 -0.8660 0.3967 +vn -0.1561 -0.9666 0.2034 +vn -0.2500 -0.8660 0.4330 +vn -0.1282 -0.9666 0.2220 +vn 0.0034 -1.0000 -0.0044 +vn 0.1623 -0.9638 -0.2115 +vn 0.0027 -1.0000 -0.0048 +vn 0.1333 -0.9638 -0.2308 +vn 0.3094 -0.8612 -0.4032 +vn 0.4344 -0.7005 -0.5661 +vn 0.2541 -0.8612 -0.4401 +vn 0.3568 -0.7005 -0.6180 +vn 0.5294 -0.4935 -0.6900 +vn 0.5886 -0.2548 -0.7671 +vn 0.4349 -0.4935 -0.7532 +vn 0.4835 -0.2548 -0.8374 +vn 0.3827 0.0000 -0.9239 +vn 0.5000 0.0000 -0.8660 +vn 0.2503 0.2548 -0.9340 +vn 0.3700 0.2548 -0.8934 +vn 0.2251 0.4935 -0.8401 +vn 0.3328 0.4935 -0.8035 +vn 0.1847 0.7005 -0.6893 +vn 0.2731 0.7005 -0.6593 +vn 0.1315 0.8612 -0.4909 +vn 0.1945 0.8612 -0.4695 +vn 0.0690 0.9638 -0.2575 +vn 0.1020 0.9638 -0.2463 +vn 0.0014 1.0000 -0.0053 +vn 0.0021 1.0000 -0.0051 +vn -0.0663 0.9666 0.2476 +vn -0.0981 0.9666 0.2369 +vn -0.1294 0.8660 0.4830 +vn -0.1913 0.8660 0.4620 +vn -0.1833 0.7059 0.6842 +vn -0.2710 0.7059 0.6544 +vn -0.2244 0.4982 0.8375 +vn -0.3318 0.4982 0.8010 +vn -0.2501 0.2575 0.9333 +vn -0.3698 0.2575 0.8927 +vn -0.2588 0.0000 0.9659 +vn -0.3827 0.0000 0.9239 +vn -0.3698 -0.2575 0.8927 +vn -0.2501 -0.2575 0.9333 +vn -0.3318 -0.4982 0.8010 +vn -0.2710 -0.7059 0.6544 +vn -0.2244 -0.4982 0.8375 +vn -0.1833 -0.7059 0.6842 +vn -0.1914 -0.8660 0.4620 +vn -0.0981 -0.9666 0.2369 +vn -0.1294 -0.8660 0.4830 +vn -0.0663 -0.9666 0.2476 +vn 0.0021 -1.0000 -0.0051 +vn 0.1020 -0.9638 -0.2463 +vn 0.0014 -1.0000 -0.0053 +vn 0.0690 -0.9638 -0.2575 +vn 0.1945 -0.8612 -0.4695 +vn 0.2731 -0.7005 -0.6593 +vn 0.1315 -0.8612 -0.4909 +vn 0.1847 -0.7005 -0.6893 +vn 0.3328 -0.4935 -0.8035 +vn 0.3700 -0.2548 -0.8934 +vn 0.2251 -0.4935 -0.8401 +vn 0.2503 -0.2548 -0.9340 +vn 0.1305 0.0000 -0.9914 +vn 0.2588 0.0000 -0.9659 +vn 0.0000 0.2548 -0.9670 +vn 0.1262 0.2548 -0.9587 +vn 0.0000 0.4935 -0.8697 +vn 0.1135 0.4935 -0.8623 +vn 0.0000 0.7005 -0.7136 +vn 0.0931 0.7005 -0.7075 +vn 0.0000 0.8612 -0.5082 +vn 0.0663 0.8612 -0.5039 +vn 0.0000 0.9638 -0.2665 +vn 0.0348 0.9638 -0.2643 +vn 0.0000 1.0000 -0.0055 +vn 0.0007 1.0000 -0.0055 +vn 0.0000 0.9666 0.2564 +vn -0.0334 0.9666 0.2542 +vn 0.0000 0.8660 0.5000 +vn -0.0652 0.8660 0.4957 +vn 0.0000 0.7059 0.7083 +vn -0.0924 0.7059 0.7022 +vn 0.0000 0.4982 0.8670 +vn -0.1132 0.4982 0.8596 +vn 0.0000 0.2575 0.9663 +vn -0.1261 0.2575 0.9580 +vn 0.0000 0.0000 1.0000 +vn -0.1305 0.0000 0.9914 +vn -0.1261 -0.2575 0.9580 +vn 0.0000 -0.2575 0.9663 +vn -0.1132 -0.4982 0.8596 +vn -0.0924 -0.7059 0.7022 +vn 0.0000 -0.4982 0.8670 +vn 0.0000 -0.7059 0.7083 +vn -0.0652 -0.8660 0.4957 +vn -0.0334 -0.9666 0.2542 +vn 0.0000 -0.8660 0.5000 +vn 0.0000 -0.9666 0.2564 +vn 0.0007 -1.0000 -0.0055 +vn 0.0348 -0.9638 -0.2643 +vn 0.0000 -1.0000 -0.0055 +vn 0.0000 -0.9638 -0.2665 +vn 0.0663 -0.8612 -0.5039 +vn 0.0931 -0.7005 -0.7075 +vn 0.0000 -0.8612 -0.5082 +vn 0.0000 -0.7005 -0.7136 +vn 0.1135 -0.4935 -0.8623 +vn 0.1262 -0.2548 -0.9587 +vn 0.0000 -0.4935 -0.8697 +vn 0.0000 -0.2548 -0.9670 +vn -0.1305 0.0000 -0.9914 +vn 0.0000 0.0000 -1.0000 +vn -0.2503 0.2548 -0.9340 +vn -0.1262 0.2548 -0.9587 +vn -0.2251 0.4935 -0.8401 +vn -0.1135 0.4935 -0.8623 +vn -0.1847 0.7005 -0.6893 +vn -0.0931 0.7005 -0.7075 +vn -0.1315 0.8612 -0.4909 +vn -0.0663 0.8612 -0.5039 +vn -0.0690 0.9638 -0.2575 +vn -0.0348 0.9638 -0.2643 +vn -0.0014 1.0000 -0.0053 +vn -0.0007 1.0000 -0.0055 +vn 0.0663 0.9666 0.2476 +vn 0.0334 0.9666 0.2542 +vn 0.1294 0.8660 0.4830 +vn 0.0652 0.8660 0.4957 +vn 0.1833 0.7059 0.6842 +vn 0.0924 0.7059 0.7022 +vn 0.2244 0.4982 0.8375 +vn 0.1132 0.4982 0.8596 +vn 0.2501 0.2575 0.9333 +vn 0.1261 0.2575 0.9580 +vn 0.2588 0.0000 0.9659 +vn 0.1305 0.0000 0.9914 +vn 0.1261 -0.2575 0.9580 +vn 0.2501 -0.2575 0.9333 +vn 0.1132 -0.4982 0.8596 +vn 0.0924 -0.7059 0.7022 +vn 0.2244 -0.4982 0.8375 +vn 0.1833 -0.7059 0.6842 +vn 0.0652 -0.8660 0.4957 +vn 0.0334 -0.9666 0.2542 +vn 0.1294 -0.8660 0.4830 +vn 0.0663 -0.9666 0.2476 +vn -0.0007 -1.0000 -0.0055 +vn -0.0348 -0.9638 -0.2643 +vn -0.0014 -1.0000 -0.0053 +vn -0.0690 -0.9638 -0.2575 +vn -0.0663 -0.8612 -0.5039 +vn -0.0931 -0.7005 -0.7075 +vn -0.1315 -0.8612 -0.4909 +vn -0.1847 -0.7005 -0.6893 +vn -0.1135 -0.4935 -0.8623 +vn -0.1262 -0.2548 -0.9587 +vn -0.2251 -0.4935 -0.8401 +vn -0.2503 -0.2548 -0.9340 +vn -0.3827 0.0000 -0.9239 +vn -0.2588 0.0000 -0.9659 +vn -0.4835 0.2548 -0.8374 +vn -0.3700 0.2548 -0.8934 +vn -0.4349 0.4935 -0.7532 +vn -0.3328 0.4935 -0.8035 +vn -0.3568 0.7005 -0.6180 +vn -0.2731 0.7005 -0.6593 +vn -0.2541 0.8612 -0.4401 +vn -0.1945 0.8612 -0.4695 +vn -0.1333 0.9638 -0.2308 +vn -0.1020 0.9638 -0.2463 +vn -0.0027 1.0000 -0.0048 +vn -0.0021 1.0000 -0.0051 +vn 0.1282 0.9666 0.2220 +vn 0.0981 0.9666 0.2369 +vn 0.2500 0.8660 0.4330 +vn 0.1914 0.8660 0.4620 +vn 0.3541 0.7059 0.6134 +vn 0.2710 0.7059 0.6544 +vn 0.4335 0.4982 0.7509 +vn 0.3318 0.4982 0.8010 +vn 0.4831 0.2575 0.8368 +vn 0.3698 0.2575 0.8927 +vn 0.5000 0.0000 0.8660 +vn 0.3827 0.0000 0.9239 +vn 0.3698 -0.2575 0.8927 +vn 0.4831 -0.2575 0.8368 +vn 0.3318 -0.4982 0.8010 +vn 0.2710 -0.7059 0.6544 +vn 0.4335 -0.4982 0.7509 +vn 0.3541 -0.7059 0.6134 +vn 0.1914 -0.8660 0.4620 +vn 0.0981 -0.9666 0.2369 +vn 0.2500 -0.8660 0.4330 +vn 0.1282 -0.9666 0.2220 +vn -0.0021 -1.0000 -0.0051 +vn -0.1020 -0.9638 -0.2463 +vn -0.0027 -1.0000 -0.0048 +vn -0.1333 -0.9638 -0.2308 +vn -0.1945 -0.8612 -0.4695 +vn -0.2731 -0.7005 -0.6593 +vn -0.2541 -0.8612 -0.4401 +vn -0.3568 -0.7005 -0.6180 +vn -0.3328 -0.4935 -0.8035 +vn -0.3700 -0.2548 -0.8934 +vn -0.4349 -0.4935 -0.7532 +vn -0.4835 -0.2548 -0.8374 +vn -0.6088 0.0000 -0.7933 +vn -0.5000 0.0000 -0.8660 +vn -0.6837 0.2548 -0.6837 +vn -0.5886 0.2548 -0.7671 +vn -0.6150 0.4935 -0.6150 +vn -0.5294 0.4935 -0.6900 +vn -0.5046 0.7005 -0.5046 +vn -0.4344 0.7005 -0.5661 +vn -0.3594 0.8612 -0.3594 +vn -0.3094 0.8612 -0.4032 +vn -0.1885 0.9638 -0.1885 +vn -0.1623 0.9638 -0.2115 +vn -0.0039 1.0000 -0.0039 +vn -0.0034 1.0000 -0.0044 +vn 0.1813 0.9666 0.1813 +vn 0.1561 0.9666 0.2034 +vn 0.3536 0.8660 0.3536 +vn 0.3044 0.8660 0.3967 +vn 0.5008 0.7059 0.5008 +vn 0.4312 0.7059 0.5619 +vn 0.6131 0.4982 0.6131 +vn 0.5278 0.4982 0.6879 +vn 0.6832 0.2575 0.6832 +vn 0.5882 0.2575 0.7666 +vn 0.7071 0.0000 0.7071 +vn 0.6088 0.0000 0.7933 +vn 0.5882 -0.2575 0.7666 +vn 0.6832 -0.2575 0.6832 +vn 0.5278 -0.4982 0.6879 +vn 0.4312 -0.7059 0.5619 +vn 0.6131 -0.4982 0.6131 +vn 0.5008 -0.7059 0.5008 +vn 0.3044 -0.8660 0.3967 +vn 0.1561 -0.9666 0.2034 +vn 0.3536 -0.8660 0.3536 +vn 0.1813 -0.9666 0.1813 +vn -0.0034 -1.0000 -0.0044 +vn -0.1623 -0.9638 -0.2115 +vn -0.0039 -1.0000 -0.0039 +vn -0.1885 -0.9638 -0.1885 +vn -0.3094 -0.8612 -0.4032 +vn -0.4344 -0.7005 -0.5661 +vn -0.3594 -0.8612 -0.3594 +vn -0.5046 -0.7005 -0.5046 +vn -0.5294 -0.4935 -0.6900 +vn -0.5886 -0.2548 -0.7671 +vn -0.6150 -0.4935 -0.6150 +vn -0.6837 -0.2548 -0.6837 +vn -0.7933 0.0000 -0.6088 +vn -0.7071 0.0000 -0.7071 +vn -0.8374 0.2548 -0.4835 +vn -0.7671 0.2548 -0.5886 +vn -0.7532 0.4935 -0.4349 +vn -0.6900 0.4935 -0.5294 +vn -0.6180 0.7005 -0.3568 +vn -0.5661 0.7005 -0.4344 +vn -0.4401 0.8612 -0.2541 +vn -0.4032 0.8612 -0.3094 +vn -0.2308 0.9638 -0.1333 +vn -0.2115 0.9638 -0.1623 +vn -0.0048 1.0000 -0.0027 +vn -0.0044 1.0000 -0.0034 +vn 0.2220 0.9666 0.1282 +vn 0.2034 0.9666 0.1561 +vn 0.4330 0.8660 0.2500 +vn 0.3967 0.8660 0.3044 +vn 0.6134 0.7059 0.3541 +vn 0.5619 0.7059 0.4312 +vn 0.7509 0.4982 0.4335 +vn 0.6879 0.4982 0.5278 +vn 0.8368 0.2575 0.4831 +vn 0.7666 0.2575 0.5882 +vn 0.8660 0.0000 0.5000 +vn 0.7933 0.0000 0.6088 +vn 0.7666 -0.2575 0.5882 +vn 0.8368 -0.2575 0.4831 +vn 0.6879 -0.4982 0.5278 +vn 0.5619 -0.7059 0.4312 +vn 0.7509 -0.4982 0.4335 +vn 0.6134 -0.7059 0.3541 +vn 0.3967 -0.8660 0.3044 +vn 0.2034 -0.9666 0.1561 +vn 0.4330 -0.8660 0.2500 +vn 0.2220 -0.9666 0.1282 +vn -0.0044 -1.0000 -0.0034 +vn -0.2115 -0.9638 -0.1623 +vn -0.0048 -1.0000 -0.0027 +vn -0.2308 -0.9638 -0.1333 +vn -0.4032 -0.8612 -0.3094 +vn -0.5661 -0.7005 -0.4344 +vn -0.4401 -0.8612 -0.2541 +vn -0.6180 -0.7005 -0.3568 +vn -0.6900 -0.4935 -0.5294 +vn -0.7671 -0.2548 -0.5886 +vn -0.7532 -0.4935 -0.4349 +vn -0.8374 -0.2548 -0.4835 +vn -0.9239 0.0000 -0.3827 +vn -0.8660 0.0000 -0.5000 +vn -0.9340 0.2548 -0.2503 +vn -0.8934 0.2548 -0.3700 +vn -0.8401 0.4935 -0.2251 +vn -0.8035 0.4935 -0.3328 +vn -0.6893 0.7005 -0.1847 +vn -0.6593 0.7005 -0.2731 +vn -0.4909 0.8612 -0.1315 +vn -0.4695 0.8612 -0.1945 +vn -0.2575 0.9638 -0.0690 +vn -0.2463 0.9638 -0.1020 +vn -0.0053 1.0000 -0.0014 +vn -0.0051 1.0000 -0.0021 +vn 0.2476 0.9666 0.0663 +vn 0.2369 0.9666 0.0981 +vn 0.4830 0.8660 0.1294 +vn 0.4620 0.8660 0.1913 +vn 0.6842 0.7059 0.1833 +vn 0.6544 0.7059 0.2710 +vn 0.8375 0.4982 0.2244 +vn 0.8010 0.4982 0.3318 +vn 0.9333 0.2575 0.2501 +vn 0.8927 0.2575 0.3698 +vn 0.9659 0.0000 0.2588 +vn 0.9239 0.0000 0.3827 +vn 0.8927 -0.2575 0.3698 +vn 0.9333 -0.2575 0.2501 +vn 0.8010 -0.4982 0.3318 +vn 0.6544 -0.7059 0.2710 +vn 0.8375 -0.4982 0.2244 +vn 0.6842 -0.7059 0.1833 +vn 0.4620 -0.8660 0.1913 +vn 0.2369 -0.9666 0.0981 +vn 0.4830 -0.8660 0.1294 +vn 0.2476 -0.9666 0.0663 +vn -0.0051 -1.0000 -0.0021 +vn -0.2463 -0.9638 -0.1020 +vn -0.0053 -1.0000 -0.0014 +vn -0.2575 -0.9638 -0.0690 +vn -0.4695 -0.8612 -0.1945 +vn -0.6593 -0.7005 -0.2731 +vn -0.4909 -0.8612 -0.1315 +vn -0.6893 -0.7005 -0.1847 +vn -0.8035 -0.4935 -0.3328 +vn -0.8934 -0.2548 -0.3700 +vn -0.8401 -0.4935 -0.2251 +vn -0.9340 -0.2548 -0.2503 +vn -0.9914 0.0000 -0.1305 +vn -0.9659 0.0000 -0.2588 +vn -0.9670 0.2548 0.0000 +vn -0.9587 0.2548 -0.1262 +vn -0.8697 0.4935 0.0000 +vn -0.8623 0.4935 -0.1135 +vn -0.7136 0.7005 0.0000 +vn -0.7075 0.7005 -0.0931 +vn -0.5082 0.8612 0.0000 +vn -0.5039 0.8612 -0.0663 +vn -0.2665 0.9638 0.0000 +vn -0.2643 0.9638 -0.0348 +vn -0.0055 1.0000 0.0000 +vn -0.0055 1.0000 -0.0007 +vn 0.2564 0.9666 0.0000 +vn 0.2542 0.9666 0.0334 +vn 0.5000 0.8660 0.0000 +vn 0.4957 0.8660 0.0652 +vn 0.7083 0.7059 0.0000 +vn 0.7022 0.7059 0.0924 +vn 0.8670 0.4982 0.0000 +vn 0.8596 0.4982 0.1132 +vn 0.9663 0.2575 0.0000 +vn 0.9580 0.2575 0.1261 +vn 0.9914 0.0000 0.1305 +vn 0.9580 -0.2575 0.1261 +vn 0.9663 -0.2575 0.0000 +vn 0.8596 -0.4982 0.1132 +vn 0.7022 -0.7059 0.0924 +vn 0.8670 -0.4982 0.0000 +vn 0.7083 -0.7059 0.0000 +vn 0.4957 -0.8660 0.0652 +vn 0.2542 -0.9666 0.0334 +vn 0.5000 -0.8660 0.0000 +vn 0.2564 -0.9666 0.0000 +vn -0.0055 -1.0000 -0.0007 +vn -0.2643 -0.9638 -0.0348 +vn -0.0055 -1.0000 0.0000 +vn -0.2665 -0.9638 0.0000 +vn -0.5039 -0.8612 -0.0663 +vn -0.7075 -0.7005 -0.0931 +vn -0.5082 -0.8612 0.0000 +vn -0.7136 -0.7005 0.0000 +vn -0.8623 -0.4935 -0.1135 +vn -0.9587 -0.2548 -0.1262 +vn -0.8697 -0.4935 0.0000 +vn -0.9670 -0.2548 0.0000 +vn -0.9340 0.2548 0.2503 +vn -0.9587 0.2548 0.1262 +vn -0.8401 0.4935 0.2251 +vn -0.8623 0.4935 0.1135 +vn -0.6893 0.7005 0.1847 +vn -0.7075 0.7005 0.0931 +vn -0.4909 0.8612 0.1315 +vn -0.5039 0.8612 0.0663 +vn -0.2575 0.9638 0.0690 +vn -0.2643 0.9638 0.0348 +vn -0.0053 1.0000 0.0014 +vn -0.0055 1.0000 0.0007 +vn 0.2476 0.9666 -0.0663 +vn 0.2542 0.9666 -0.0334 +vn 0.4830 0.8660 -0.1294 +vn 0.4957 0.8660 -0.0652 +vn 0.6842 0.7059 -0.1833 +vn 0.7022 0.7059 -0.0924 +vn 0.8375 0.4982 -0.2244 +vn 0.8596 0.4982 -0.1132 +vn 0.9333 0.2575 -0.2501 +vn 0.9580 0.2575 -0.1261 +vn 0.9580 -0.2575 -0.1261 +vn 0.9333 -0.2575 -0.2501 +vn 0.8596 -0.4982 -0.1132 +vn 0.7022 -0.7059 -0.0924 +vn 0.8375 -0.4982 -0.2244 +vn 0.6842 -0.7059 -0.1833 +vn 0.4957 -0.8660 -0.0652 +vn 0.2542 -0.9666 -0.0334 +vn 0.4830 -0.8660 -0.1294 +vn 0.2476 -0.9666 -0.0663 +vn -0.0055 -1.0000 0.0007 +vn -0.2643 -0.9638 0.0348 +vn -0.0053 -1.0000 0.0014 +vn -0.2575 -0.9638 0.0690 +vn -0.5039 -0.8612 0.0663 +vn -0.7075 -0.7005 0.0931 +vn -0.4909 -0.8612 0.1315 +vn -0.6893 -0.7005 0.1847 +vn -0.8623 -0.4935 0.1135 +vn -0.9587 -0.2548 0.1262 +vn -0.8401 -0.4935 0.2251 +vn -0.9340 -0.2548 0.2503 +vn -0.8374 0.2548 0.4835 +vn -0.8934 0.2548 0.3700 +vn -0.7532 0.4935 0.4349 +vn -0.8035 0.4935 0.3328 +vn -0.6180 0.7005 0.3568 +vn -0.6593 0.7005 0.2731 +vn -0.4401 0.8612 0.2541 +vn -0.4695 0.8612 0.1945 +vn -0.2308 0.9638 0.1333 +vn -0.2463 0.9638 0.1020 +vn -0.0048 1.0000 0.0027 +vn -0.0051 1.0000 0.0021 +vn 0.2220 0.9666 -0.1282 +vn 0.2369 0.9666 -0.0981 +vn 0.4330 0.8660 -0.2500 +vn 0.4620 0.8660 -0.1913 +vn 0.6134 0.7059 -0.3541 +vn 0.6544 0.7059 -0.2710 +vn 0.7509 0.4982 -0.4335 +vn 0.8010 0.4982 -0.3318 +vn 0.8368 0.2575 -0.4831 +vn 0.8927 0.2575 -0.3698 +vn 0.8927 -0.2575 -0.3698 +vn 0.8368 -0.2575 -0.4831 +vn 0.8010 -0.4982 -0.3318 +vn 0.6544 -0.7059 -0.2710 +vn 0.7509 -0.4982 -0.4335 +vn 0.6134 -0.7059 -0.3541 +vn 0.4620 -0.8660 -0.1913 +vn 0.2369 -0.9666 -0.0981 +vn 0.4330 -0.8660 -0.2500 +vn 0.2220 -0.9666 -0.1282 +vn -0.0051 -1.0000 0.0021 +vn -0.2463 -0.9638 0.1020 +vn -0.0048 -1.0000 0.0027 +vn -0.2308 -0.9638 0.1333 +vn -0.4695 -0.8612 0.1945 +vn -0.6593 -0.7005 0.2731 +vn -0.4401 -0.8612 0.2541 +vn -0.6180 -0.7005 0.3568 +vn -0.8035 -0.4935 0.3328 +vn -0.8934 -0.2548 0.3700 +vn -0.7532 -0.4935 0.4349 +vn -0.8374 -0.2548 0.4835 +vn -0.6837 0.2548 0.6837 +vn -0.7671 0.2548 0.5886 +vn -0.6150 0.4935 0.6150 +vn -0.6900 0.4935 0.5294 +vn -0.5046 0.7005 0.5046 +vn -0.5661 0.7005 0.4344 +vn -0.3594 0.8612 0.3594 +vn -0.4032 0.8612 0.3094 +vn -0.1885 0.9638 0.1885 +vn -0.2115 0.9638 0.1623 +vn -0.0039 1.0000 0.0039 +vn -0.0044 1.0000 0.0034 +vn 0.1813 0.9666 -0.1813 +vn 0.2034 0.9666 -0.1561 +vn 0.3536 0.8660 -0.3536 +vn 0.3967 0.8660 -0.3044 +vn 0.5008 0.7059 -0.5008 +vn 0.5619 0.7059 -0.4312 +vn 0.6131 0.4982 -0.6131 +vn 0.6879 0.4982 -0.5278 +vn 0.6832 0.2575 -0.6832 +vn 0.7666 0.2575 -0.5882 +vn 0.7666 -0.2575 -0.5882 +vn 0.6832 -0.2575 -0.6832 +vn 0.6879 -0.4982 -0.5278 +vn 0.5619 -0.7059 -0.4312 +vn 0.6131 -0.4982 -0.6131 +vn 0.5008 -0.7059 -0.5008 +vn 0.3967 -0.8660 -0.3044 +vn 0.2034 -0.9666 -0.1561 +vn 0.3536 -0.8660 -0.3536 +vn 0.1813 -0.9666 -0.1813 +vn -0.0044 -1.0000 0.0034 +vn -0.2115 -0.9638 0.1623 +vn -0.0039 -1.0000 0.0039 +vn -0.1885 -0.9638 0.1885 +vn -0.4032 -0.8612 0.3094 +vn -0.5661 -0.7005 0.4344 +vn -0.3594 -0.8612 0.3594 +vn -0.5046 -0.7005 0.5046 +vn -0.6900 -0.4935 0.5294 +vn -0.7671 -0.2548 0.5886 +vn -0.6150 -0.4935 0.6150 +vn -0.6837 -0.2548 0.6837 +vn -0.4835 0.2548 0.8374 +vn -0.5886 0.2548 0.7671 +vn -0.4349 0.4935 0.7532 +vn -0.5294 0.4935 0.6900 +vn -0.3568 0.7005 0.6180 +vn -0.4344 0.7005 0.5661 +vn -0.2541 0.8612 0.4401 +vn -0.3094 0.8612 0.4032 +vn -0.1333 0.9638 0.2308 +vn -0.1623 0.9638 0.2115 +vn -0.0027 1.0000 0.0048 +vn -0.0034 1.0000 0.0044 +vn 0.1282 0.9666 -0.2220 +vn 0.1561 0.9666 -0.2034 +vn 0.2500 0.8660 -0.4330 +vn 0.3044 0.8660 -0.3967 +vn 0.3541 0.7059 -0.6134 +vn 0.4312 0.7059 -0.5619 +vn 0.4335 0.4982 -0.7509 +vn 0.5278 0.4982 -0.6879 +vn 0.4831 0.2575 -0.8368 +vn 0.5882 0.2575 -0.7666 +vn 0.5882 -0.2575 -0.7666 +vn 0.4831 -0.2575 -0.8368 +vn 0.5278 -0.4982 -0.6879 +vn 0.4312 -0.7059 -0.5619 +vn 0.4335 -0.4982 -0.7509 +vn 0.3541 -0.7059 -0.6134 +vn 0.3044 -0.8660 -0.3967 +vn 0.1561 -0.9666 -0.2034 +vn 0.2500 -0.8660 -0.4330 +vn 0.1282 -0.9666 -0.2220 +vn -0.0034 -1.0000 0.0044 +vn -0.1623 -0.9638 0.2115 +vn -0.0027 -1.0000 0.0048 +vn -0.1333 -0.9638 0.2308 +vn -0.3094 -0.8612 0.4032 +vn -0.4344 -0.7005 0.5661 +vn -0.2541 -0.8612 0.4401 +vn -0.3568 -0.7005 0.6180 +vn -0.5294 -0.4935 0.6900 +vn -0.5886 -0.2548 0.7671 +vn -0.4349 -0.4935 0.7532 +vn -0.4835 -0.2548 0.8374 +vn -0.2503 0.2548 0.9340 +vn -0.3700 0.2548 0.8934 +vn -0.2251 0.4935 0.8401 +vn -0.3328 0.4935 0.8035 +vn -0.1847 0.7005 0.6893 +vn -0.2731 0.7005 0.6593 +vn -0.1315 0.8612 0.4909 +vn -0.1945 0.8612 0.4695 +vn -0.0690 0.9638 0.2575 +vn -0.1020 0.9638 0.2463 +vn -0.0014 1.0000 0.0053 +vn -0.0021 1.0000 0.0051 +vn 0.0663 0.9666 -0.2476 +vn 0.0981 0.9666 -0.2369 +vn 0.1294 0.8660 -0.4830 +vn 0.1914 0.8660 -0.4620 +vn 0.1833 0.7059 -0.6842 +vn 0.2710 0.7059 -0.6544 +vn 0.2244 0.4982 -0.8375 +vn 0.3318 0.4982 -0.8010 +vn 0.2501 0.2575 -0.9333 +vn 0.3698 0.2575 -0.8927 +vn 0.3698 -0.2575 -0.8927 +vn 0.2501 -0.2575 -0.9333 +vn 0.3318 -0.4982 -0.8010 +vn 0.2710 -0.7059 -0.6544 +vn 0.2244 -0.4982 -0.8375 +vn 0.1833 -0.7059 -0.6842 +vn 0.1914 -0.8660 -0.4620 +vn 0.0981 -0.9666 -0.2369 +vn 0.1294 -0.8660 -0.4830 +vn 0.0663 -0.9666 -0.2476 +vn -0.0021 -1.0000 0.0051 +vn -0.1020 -0.9638 0.2463 +vn -0.0014 -1.0000 0.0053 +vn -0.0690 -0.9638 0.2575 +vn -0.1945 -0.8612 0.4695 +vn -0.2731 -0.7005 0.6593 +vn -0.1315 -0.8612 0.4909 +vn -0.1847 -0.7005 0.6893 +vn -0.3328 -0.4935 0.8035 +vn -0.3700 -0.2548 0.8934 +vn -0.2251 -0.4935 0.8401 +vn -0.2503 -0.2548 0.9340 +vn 0.0000 0.2548 0.9670 +vn -0.1262 0.2548 0.9587 +vn 0.0000 0.4935 0.8697 +vn -0.1135 0.4935 0.8623 +vn 0.0000 0.7005 0.7136 +vn -0.0931 0.7005 0.7075 +vn 0.0000 0.8612 0.5082 +vn -0.0663 0.8612 0.5039 +vn 0.0000 0.9638 0.2665 +vn -0.0348 0.9638 0.2643 +vn 0.0000 1.0000 0.0055 +vn -0.0007 1.0000 0.0055 +vn 0.0000 0.9666 -0.2564 +vn 0.0334 0.9666 -0.2542 +vn 0.0000 0.8660 -0.5000 +vn 0.0652 0.8660 -0.4957 +vn 0.0000 0.7059 -0.7083 +vn 0.0924 0.7059 -0.7022 +vn 0.0000 0.4982 -0.8670 +vn 0.1132 0.4982 -0.8596 +vn 0.0000 0.2575 -0.9663 +vn 0.1261 0.2575 -0.9580 +vn 0.1261 -0.2575 -0.9580 +vn 0.0000 -0.2575 -0.9663 +vn 0.1132 -0.4982 -0.8596 +vn 0.0924 -0.7059 -0.7022 +vn 0.0000 -0.4982 -0.8670 +vn 0.0000 -0.7059 -0.7083 +vn 0.0652 -0.8660 -0.4957 +vn 0.0334 -0.9666 -0.2542 +vn 0.0000 -0.8660 -0.5000 +vn 0.0000 -0.9666 -0.2564 +vn -0.0007 -1.0000 0.0055 +vn -0.0348 -0.9638 0.2643 +vn 0.0000 -1.0000 0.0055 +vn 0.0000 -0.9638 0.2665 +vn -0.0663 -0.8612 0.5039 +vn -0.0931 -0.7005 0.7075 +vn 0.0000 -0.8612 0.5082 +vn 0.0000 -0.7005 0.7136 +vn -0.1135 -0.4935 0.8623 +vn -0.1262 -0.2548 0.9587 +vn 0.0000 -0.4935 0.8697 +vn 0.0000 -0.2548 0.9670 +vn 0.2503 0.2548 0.9340 +vn 0.1262 0.2548 0.9587 +vn 0.2251 0.4935 0.8401 +vn 0.1135 0.4935 0.8623 +vn 0.1847 0.7005 0.6893 +vn 0.0931 0.7005 0.7075 +vn 0.1315 0.8612 0.4909 +vn 0.0663 0.8612 0.5039 +vn 0.0690 0.9638 0.2575 +vn 0.0348 0.9638 0.2643 +vn 0.0014 1.0000 0.0053 +vn 0.0007 1.0000 0.0055 +vn -0.0663 0.9666 -0.2476 +vn -0.0334 0.9666 -0.2542 +vn -0.1294 0.8660 -0.4830 +vn -0.0652 0.8660 -0.4957 +vn -0.1833 0.7059 -0.6842 +vn -0.0924 0.7059 -0.7022 +vn -0.2244 0.4982 -0.8375 +vn -0.1132 0.4982 -0.8596 +vn -0.2501 0.2575 -0.9333 +vn -0.1261 0.2575 -0.9580 +vn -0.1261 -0.2575 -0.9580 +vn -0.2501 -0.2575 -0.9333 +vn -0.1132 -0.4982 -0.8596 +vn -0.0924 -0.7059 -0.7022 +vn -0.2244 -0.4982 -0.8375 +vn -0.1833 -0.7059 -0.6842 +vn -0.0652 -0.8660 -0.4957 +vn -0.0334 -0.9666 -0.2542 +vn -0.1294 -0.8660 -0.4830 +vn -0.0663 -0.9666 -0.2476 +vn 0.0007 -1.0000 0.0055 +vn 0.0348 -0.9638 0.2643 +vn 0.0014 -1.0000 0.0053 +vn 0.0690 -0.9638 0.2575 +vn 0.0663 -0.8612 0.5039 +vn 0.0931 -0.7005 0.7075 +vn 0.1315 -0.8612 0.4909 +vn 0.1847 -0.7005 0.6893 +vn 0.1135 -0.4935 0.8623 +vn 0.1262 -0.2548 0.9587 +vn 0.2251 -0.4935 0.8401 +vn 0.2503 -0.2548 0.9340 +vn 0.4835 0.2548 0.8374 +vn 0.3700 0.2548 0.8934 +vn 0.4349 0.4935 0.7532 +vn 0.3328 0.4935 0.8035 +vn 0.3568 0.7005 0.6180 +vn 0.2731 0.7005 0.6593 +vn 0.2541 0.8612 0.4401 +vn 0.1945 0.8612 0.4695 +vn 0.1333 0.9638 0.2308 +vn 0.1020 0.9638 0.2463 +vn 0.0027 1.0000 0.0048 +vn 0.0021 1.0000 0.0051 +vn -0.1282 0.9666 -0.2220 +vn -0.0981 0.9666 -0.2369 +vn -0.2500 0.8660 -0.4330 +vn -0.1914 0.8660 -0.4620 +vn -0.3541 0.7059 -0.6134 +vn -0.2710 0.7059 -0.6544 +vn -0.4335 0.4982 -0.7509 +vn -0.3318 0.4982 -0.8010 +vn -0.4831 0.2575 -0.8368 +vn -0.3698 0.2575 -0.8927 +vn -0.3698 -0.2575 -0.8927 +vn -0.4831 -0.2575 -0.8368 +vn -0.3318 -0.4982 -0.8010 +vn -0.2710 -0.7059 -0.6544 +vn -0.4335 -0.4982 -0.7509 +vn -0.3541 -0.7059 -0.6134 +vn -0.1914 -0.8660 -0.4620 +vn -0.0981 -0.9666 -0.2369 +vn -0.2500 -0.8660 -0.4330 +vn -0.1282 -0.9666 -0.2220 +vn 0.0021 -1.0000 0.0051 +vn 0.1020 -0.9638 0.2463 +vn 0.0027 -1.0000 0.0048 +vn 0.1333 -0.9638 0.2308 +vn 0.1945 -0.8612 0.4695 +vn 0.2731 -0.7005 0.6593 +vn 0.2541 -0.8612 0.4401 +vn 0.3568 -0.7005 0.6180 +vn 0.3328 -0.4935 0.8035 +vn 0.3700 -0.2548 0.8934 +vn 0.4349 -0.4935 0.7532 +vn 0.4835 -0.2548 0.8374 +vn 0.6837 0.2548 0.6837 +vn 0.5886 0.2548 0.7671 +vn 0.6150 0.4935 0.6150 +vn 0.5294 0.4935 0.6900 +vn 0.5046 0.7005 0.5046 +vn 0.4344 0.7005 0.5661 +vn 0.3594 0.8612 0.3594 +vn 0.3094 0.8612 0.4032 +vn 0.1885 0.9638 0.1885 +vn 0.1623 0.9638 0.2115 +vn 0.0039 1.0000 0.0039 +vn 0.0034 1.0000 0.0044 +vn -0.1813 0.9666 -0.1813 +vn -0.1561 0.9666 -0.2034 +vn -0.3536 0.8660 -0.3536 +vn -0.3044 0.8660 -0.3967 +vn -0.5008 0.7059 -0.5008 +vn -0.4312 0.7059 -0.5619 +vn -0.6131 0.4982 -0.6131 +vn -0.5278 0.4982 -0.6879 +vn -0.6832 0.2575 -0.6832 +vn -0.5882 0.2575 -0.7666 +vn -0.5882 -0.2575 -0.7666 +vn -0.6832 -0.2575 -0.6832 +vn -0.5278 -0.4982 -0.6879 +vn -0.4312 -0.7059 -0.5619 +vn -0.6131 -0.4982 -0.6131 +vn -0.5008 -0.7059 -0.5008 +vn -0.3044 -0.8660 -0.3967 +vn -0.1561 -0.9666 -0.2034 +vn -0.3536 -0.8660 -0.3536 +vn -0.1813 -0.9666 -0.1813 +vn 0.0034 -1.0000 0.0044 +vn 0.1623 -0.9638 0.2115 +vn 0.0039 -1.0000 0.0039 +vn 0.1885 -0.9638 0.1885 +vn 0.3094 -0.8612 0.4032 +vn 0.4344 -0.7005 0.5661 +vn 0.3594 -0.8612 0.3594 +vn 0.5046 -0.7005 0.5046 +vn 0.5294 -0.4935 0.6900 +vn 0.5886 -0.2548 0.7671 +vn 0.6150 -0.4935 0.6150 +vn 0.6837 -0.2548 0.6837 +vn 0.8374 0.2548 0.4835 +vn 0.7671 0.2548 0.5886 +vn 0.7532 0.4935 0.4349 +vn 0.6900 0.4935 0.5294 +vn 0.6180 0.7005 0.3568 +vn 0.5661 0.7005 0.4344 +vn 0.4401 0.8612 0.2541 +vn 0.4032 0.8612 0.3094 +vn 0.2308 0.9638 0.1333 +vn 0.2115 0.9638 0.1623 +vn 0.0048 1.0000 0.0027 +vn 0.0044 1.0000 0.0034 +vn -0.2220 0.9666 -0.1282 +vn -0.2034 0.9666 -0.1561 +vn -0.4330 0.8660 -0.2500 +vn -0.3967 0.8660 -0.3044 +vn -0.6134 0.7059 -0.3541 +vn -0.5619 0.7059 -0.4312 +vn -0.7509 0.4982 -0.4335 +vn -0.6879 0.4982 -0.5278 +vn -0.8368 0.2575 -0.4831 +vn -0.7666 0.2575 -0.5882 +vn -0.7666 -0.2575 -0.5882 +vn -0.8368 -0.2575 -0.4831 +vn -0.6879 -0.4982 -0.5278 +vn -0.5619 -0.7059 -0.4312 +vn -0.7509 -0.4982 -0.4335 +vn -0.6134 -0.7059 -0.3541 +vn -0.3967 -0.8660 -0.3044 +vn -0.2034 -0.9666 -0.1561 +vn -0.4330 -0.8660 -0.2500 +vn -0.2220 -0.9666 -0.1282 +vn 0.0044 -1.0000 0.0034 +vn 0.2115 -0.9638 0.1623 +vn 0.0048 -1.0000 0.0027 +vn 0.2308 -0.9638 0.1333 +vn 0.4032 -0.8612 0.3094 +vn 0.5661 -0.7005 0.4344 +vn 0.4401 -0.8612 0.2541 +vn 0.6180 -0.7005 0.3568 +vn 0.6900 -0.4935 0.5294 +vn 0.7671 -0.2548 0.5886 +vn 0.7532 -0.4935 0.4349 +vn 0.8374 -0.2548 0.4835 +vn 0.9340 0.2548 0.2503 +vn 0.8934 0.2548 0.3700 +vn 0.8401 0.4935 0.2251 +vn 0.8035 0.4935 0.3328 +vn 0.6893 0.7005 0.1847 +vn 0.6593 0.7005 0.2731 +vn 0.4909 0.8612 0.1315 +vn 0.4695 0.8612 0.1945 +vn 0.2575 0.9638 0.0690 +vn 0.2463 0.9638 0.1020 +vn 0.0053 1.0000 0.0014 +vn 0.0051 1.0000 0.0021 +vn -0.2476 0.9666 -0.0663 +vn -0.2369 0.9666 -0.0981 +vn -0.4830 0.8660 -0.1294 +vn -0.4620 0.8660 -0.1913 +vn -0.6842 0.7059 -0.1833 +vn -0.6544 0.7059 -0.2710 +vn -0.8375 0.4982 -0.2244 +vn -0.8010 0.4982 -0.3318 +vn -0.9333 0.2575 -0.2501 +vn -0.8927 0.2575 -0.3698 +vn -0.8927 -0.2575 -0.3698 +vn -0.9333 -0.2575 -0.2501 +vn -0.8010 -0.4982 -0.3318 +vn -0.6544 -0.7059 -0.2710 +vn -0.8375 -0.4982 -0.2244 +vn -0.6842 -0.7059 -0.1833 +vn -0.4620 -0.8660 -0.1914 +vn -0.2369 -0.9666 -0.0981 +vn -0.4830 -0.8660 -0.1294 +vn -0.2476 -0.9666 -0.0663 +vn 0.0051 -1.0000 0.0021 +vn 0.2463 -0.9638 0.1020 +vn 0.0053 -1.0000 0.0014 +vn 0.2575 -0.9638 0.0690 +vn 0.4695 -0.8612 0.1945 +vn 0.6593 -0.7005 0.2731 +vn 0.4909 -0.8612 0.1315 +vn 0.6893 -0.7005 0.1847 +vn 0.8035 -0.4935 0.3328 +vn 0.8934 -0.2548 0.3700 +vn 0.8401 -0.4935 0.2251 +vn 0.9340 -0.2548 0.2503 +vn 0.9587 0.2548 0.1262 +vn 0.8623 0.4935 0.1135 +vn 0.7075 0.7005 0.0931 +vn 0.5039 0.8612 0.0663 +vn 0.2643 0.9638 0.0348 +vn 0.0055 1.0000 0.0007 +vn -0.2542 0.9666 -0.0334 +vn -0.4957 0.8660 -0.0652 +vn -0.7022 0.7059 -0.0924 +vn -0.8596 0.4982 -0.1132 +vn -0.9580 0.2575 -0.1261 +vn -0.9580 -0.2575 -0.1261 +vn -0.8596 -0.4982 -0.1132 +vn -0.7022 -0.7059 -0.0924 +vn -0.4957 -0.8660 -0.0652 +vn -0.2542 -0.9666 -0.0334 +vn 0.0055 -1.0000 0.0007 +vn 0.2643 -0.9638 0.0348 +vn 0.5039 -0.8612 0.0663 +vn 0.7075 -0.7005 0.0931 +vn 0.8623 -0.4935 0.1135 +vn 0.9587 -0.2548 0.1262 +vn 0.8173 -0.5603 0.1347 +vn 0.9442 -0.3025 0.1303 +vn 0.8297 -0.4992 0.2497 +vn 0.9065 -0.4115 -0.0943 +vn 0.9321 -0.3616 0.0191 +vn 0.9625 -0.1832 -0.2001 +vn 0.9855 -0.1384 -0.0981 +vn 0.9963 -0.0852 0.0018 +vn 0.9821 0.1390 -0.1274 +vn 0.9543 0.0586 -0.2932 +vn 0.9731 0.0954 -0.2094 +vn 0.8813 0.2979 -0.3669 +vn 0.8947 0.3241 -0.3073 +vn 0.9011 0.3551 -0.2488 +vn 0.7577 0.5483 -0.3540 +vn 0.7473 0.5183 -0.4159 +vn 0.7543 0.5320 -0.3846 +vn 0.5610 0.7035 -0.4362 +vn 0.5611 0.7038 -0.4356 +vn 0.5612 0.7042 -0.4349 +vn 0.3253 0.8113 -0.4858 +vn 0.3352 0.8402 -0.4262 +vn 0.3284 0.8270 -0.4563 +vn 0.0866 0.9181 -0.3866 +vn 0.0734 0.8924 -0.4452 +vn 0.0671 0.8618 -0.5027 +vn -0.1948 0.8526 -0.4849 +vn -0.1672 0.9324 -0.3204 +vn -0.1859 0.8959 -0.4035 +vn -0.4083 0.8827 -0.2326 +vn -0.4313 0.8380 -0.3342 +vn -0.4421 0.7850 -0.4339 +vn -0.6584 0.6644 -0.3536 +vn -0.6208 0.7732 -0.1292 +vn -0.6464 0.7234 -0.2426 +vn -0.7908 0.6118 -0.0175 +vn -0.8173 0.5603 -0.1347 +vn -0.8297 0.4992 -0.2497 +vn -0.9330 0.3594 -0.0179 +vn -0.9451 0.3003 -0.1289 +vn -0.9074 0.4091 0.0954 +vn -0.9859 0.1336 0.1005 +vn -0.9967 0.0806 0.0009 +vn -0.9718 -0.1022 0.2125 +vn -0.9806 -0.1455 0.1311 +vn -0.9630 0.1783 0.2022 +vn -0.9530 -0.0657 0.2956 +vn -0.8907 -0.3321 0.3105 +vn -0.8969 -0.3626 0.2530 +vn -0.7476 -0.5397 0.3872 +vn -0.7507 -0.5553 0.3577 +vn -0.8774 -0.3063 0.3691 +vn -0.7407 -0.5264 0.4172 +vn -0.5521 -0.7100 0.4371 +vn -0.5520 -0.7097 0.4377 +vn -0.3186 -0.8307 0.4564 +vn -0.3153 -0.8144 0.4871 +vn -0.5522 -0.7103 0.4364 +vn -0.3257 -0.8444 0.4252 +vn -0.0640 -0.8936 0.4443 +vn -0.0576 -0.8625 0.5027 +vn 0.1933 -0.8951 0.4018 +vn 0.2022 -0.8514 0.4838 +vn -0.0775 -0.9198 0.3847 +vn 0.1744 -0.9319 0.3181 +vn 0.4360 -0.8362 0.3325 +vn 0.4469 -0.7830 0.4325 +vn 0.6484 -0.7219 0.2415 +vn 0.6605 -0.6628 0.3527 +vn 0.4130 -0.8810 0.2305 +vn 0.6228 -0.7718 0.1281 +vn 0.7508 -0.6529 -0.1001 +vn 0.7908 -0.6118 0.0175 +vn 0.8167 -0.4801 -0.3200 +vn 0.8679 -0.4512 -0.2080 +vn 0.8817 -0.2449 -0.4031 +vn 0.9277 -0.2189 -0.3024 +vn 0.8880 0.0079 -0.4597 +vn 0.9257 0.0293 -0.3771 +vn 0.8341 0.2618 -0.4855 +vn 0.8609 0.2770 -0.4266 +vn 0.7225 0.4993 -0.4781 +vn 0.7366 0.5073 -0.4472 +vn 0.5605 0.7031 -0.4375 +vn 0.5607 0.7033 -0.4369 +vn 0.3591 0.8584 -0.3664 +vn 0.3455 0.8507 -0.3961 +vn 0.1331 0.9536 -0.2699 +vn 0.1066 0.9387 -0.3278 +vn -0.1014 0.9827 -0.1550 +vn -0.1389 0.9615 -0.2371 +vn -0.3278 0.9442 -0.0302 +vn -0.3736 0.9183 -0.1306 +vn -0.5311 0.8418 0.0963 +vn -0.5821 0.8129 -0.0156 +vn -0.6979 0.6828 0.2159 +vn -0.7508 0.6529 0.1001 +vn -0.8688 0.4488 0.2091 +vn -0.8177 0.4777 0.3210 +vn -0.9283 0.2139 0.3041 +vn -0.9247 -0.0366 0.3789 +vn -0.8825 0.2398 0.4046 +vn -0.8873 -0.0154 0.4610 +vn -0.8574 -0.2857 0.4279 +vn -0.7305 -0.5159 0.4474 +vn -0.8310 -0.2708 0.4858 +vn -0.7169 -0.5083 0.4771 +vn -0.5524 -0.7105 0.4357 +vn -0.3363 -0.8554 0.3938 +vn -0.5527 -0.7107 0.4351 +vn -0.3504 -0.8634 0.3630 +vn -0.0978 -0.9407 0.3249 +vn 0.1459 -0.9611 0.2342 +vn -0.1246 -0.9559 0.2660 +vn 0.1082 -0.9825 0.1515 +vn 0.3782 -0.9167 0.1283 +vn 0.5841 -0.8115 0.0144 +vn 0.3323 -0.9427 0.0275 +vn 0.5330 -0.8404 -0.0976 +vn 0.6331 -0.7010 -0.3281 +vn 0.6979 -0.6828 -0.2159 +vn 0.6810 -0.5037 -0.5315 +vn 0.7541 -0.4977 -0.4284 +vn 0.7596 -0.2662 -0.5934 +vn 0.8254 -0.2608 -0.5007 +vn 0.7878 -0.0095 -0.6158 +vn 0.8418 -0.0051 -0.5398 +vn 0.7627 0.2494 -0.5967 +vn 0.8011 0.2526 -0.5425 +vn 0.6851 0.4928 -0.5364 +vn 0.7053 0.4945 -0.5080 +vn 0.5597 0.7030 -0.4387 +vn 0.5601 0.7031 -0.4381 +vn 0.3951 0.8647 -0.3103 +vn 0.3757 0.8631 -0.3376 +vn 0.2033 0.9658 -0.1605 +vn 0.1654 0.9627 -0.2138 +vn -0.0020 1.0000 -0.0001 +vn -0.0555 0.9956 -0.0756 +vn -0.2061 0.9654 0.1595 +vn -0.2716 0.9600 0.0671 +vn -0.3954 0.8654 0.3076 +vn -0.4685 0.8594 0.2047 +vn -0.5575 0.7072 0.4346 +vn -0.6331 0.7010 0.3281 +vn -0.7551 0.4953 0.4294 +vn -0.6821 0.5014 0.5323 +vn -0.8263 0.2556 0.5018 +vn -0.8414 -0.0025 0.5404 +vn -0.7607 0.2610 0.5943 +vn -0.7878 0.0019 0.6159 +vn -0.7986 -0.2617 0.5419 +vn -0.7003 -0.5036 0.5058 +vn -0.7608 -0.2586 0.5952 +vn -0.6810 -0.5020 0.5332 +vn -0.5531 -0.7108 0.4345 +vn -0.3677 -0.8682 0.3330 +vn -0.5535 -0.7108 0.4339 +vn -0.3878 -0.8699 0.3047 +vn -0.1576 -0.9651 0.2090 +vn 0.0619 -0.9955 0.0715 +vn -0.1960 -0.9683 0.1549 +vn 0.0080 -0.9999 -0.0045 +vn 0.2759 -0.9586 -0.0700 +vn 0.4704 -0.8580 -0.2061 +vn 0.2102 -0.9640 -0.1627 +vn 0.3973 -0.8640 -0.3091 +vn 0.4724 -0.7014 -0.5338 +vn 0.5575 -0.7072 -0.4346 +vn 0.5085 -0.4808 -0.7143 +vn 0.5986 -0.4980 -0.6273 +vn 0.6044 -0.2455 -0.7578 +vn 0.6855 -0.2611 -0.6796 +vn 0.6605 0.0074 -0.7508 +vn 0.7270 -0.0053 -0.6866 +vn 0.6720 0.2615 -0.6928 +vn 0.7194 0.2524 -0.6470 +vn 0.6375 0.4992 -0.5868 +vn 0.6624 0.4944 -0.5628 +vn 0.5587 0.7031 -0.4398 +vn 0.5592 0.7031 -0.4393 +vn 0.4408 0.8585 -0.2618 +vn 0.4169 0.8632 -0.2849 +vn 0.2925 0.9540 -0.0660 +vn 0.2458 0.9629 -0.1109 +vn 0.1244 0.9832 0.1338 +vn 0.0583 0.9958 0.0701 +vn -0.0514 0.9448 0.3234 +vn -0.1323 0.9603 0.2454 +vn -0.2230 0.8425 0.4903 +vn -0.3131 0.8597 0.4034 +vn -0.3791 0.6835 0.6237 +vn -0.4724 0.7014 0.5338 +vn -0.5998 0.4957 0.6281 +vn -0.5097 0.4784 0.7150 +vn -0.6869 0.2559 0.6802 +vn -0.7275 -0.0022 0.6861 +vn -0.6060 0.2404 0.7582 +vn -0.6615 -0.0149 0.7498 +vn -0.7182 -0.2615 0.6448 +vn -0.6591 -0.5035 0.5586 +vn -0.6716 -0.2705 0.6897 +vn -0.6352 -0.5081 0.5817 +vn -0.5540 -0.7108 0.4334 +vn -0.4105 -0.8683 0.2782 +vn -0.5545 -0.7107 0.4328 +vn -0.4354 -0.8636 0.2542 +vn -0.2393 -0.9653 0.1045 +vn -0.0528 -0.9958 -0.0753 +vn -0.2867 -0.9562 0.0587 +vn -0.1193 -0.9830 -0.1395 +vn 0.1361 -0.9589 -0.2489 +vn 0.3149 -0.8584 -0.4050 +vn 0.0550 -0.9434 -0.3271 +vn 0.2248 -0.8411 -0.4920 +vn 0.2794 -0.6539 -0.7031 +vn 0.3791 -0.6835 -0.6237 +vn 0.3110 -0.4127 -0.8561 +vn 0.4120 -0.4522 -0.7910 +vn 0.4268 -0.1844 -0.8853 +vn 0.5177 -0.2198 -0.8268 +vn 0.5147 0.0576 -0.8554 +vn 0.5893 0.0285 -0.8074 +vn 0.5683 0.2972 -0.7673 +vn 0.6214 0.2765 -0.7331 +vn 0.5831 0.5179 -0.6259 +vn 0.6110 0.5071 -0.6079 +vn 0.5576 0.7035 -0.4406 +vn 0.5582 0.7033 -0.4402 +vn 0.4931 0.8405 -0.2242 +vn 0.4664 0.8510 -0.2415 +vn 0.3946 0.9188 0.0073 +vn 0.3423 0.9392 -0.0263 +vn 0.2690 0.9333 0.2376 +vn 0.1950 0.9622 0.1900 +vn 0.1256 0.8838 0.4505 +vn 0.0350 0.9192 0.3922 +vn -0.0257 0.7745 0.6320 +vn -0.1267 0.8139 0.5670 +vn -0.1749 0.6131 0.7703 +vn -0.2794 0.6539 0.7031 +vn -0.4133 0.4498 0.7917 +vn -0.3123 0.4104 0.8567 +vn -0.5196 0.2148 0.8270 +vn -0.5908 -0.0358 0.8060 +vn -0.4290 0.1794 0.8853 +vn -0.5168 -0.0647 0.8536 +vn -0.6218 -0.2852 0.7294 +vn -0.6096 -0.5156 0.6020 +vn -0.5695 -0.3056 0.7630 +vn -0.5828 -0.5261 0.6192 +vn -0.5551 -0.7105 0.4324 +vn -0.4620 -0.8557 0.2331 +vn -0.5556 -0.7103 0.4321 +vn -0.4899 -0.8448 0.2152 +vn -0.3374 -0.9412 0.0185 +vn -0.1905 -0.9619 -0.1961 +vn -0.3905 -0.9205 -0.0157 +vn -0.2651 -0.9328 -0.2441 +vn -0.0317 -0.9176 -0.3961 +vn 0.1283 -0.8125 -0.5687 +vn -0.1226 -0.8822 -0.4546 +vn 0.0273 -0.7731 -0.6337 +vn 0.0674 -0.5619 -0.8244 +vn 0.1749 -0.6131 -0.7703 +vn 0.1020 -0.3043 -0.9471 +vn 0.2070 -0.3632 -0.9084 +vn 0.2388 -0.0869 -0.9672 +vn 0.3333 -0.1398 -0.9324 +vn 0.3605 0.1376 -0.9225 +vn 0.4380 0.0942 -0.8940 +vn 0.4584 0.3542 -0.8151 +vn 0.5136 0.3233 -0.7948 +vn 0.5255 0.5478 -0.6510 +vn 0.5544 0.5316 -0.6403 +vn 0.5564 0.7042 -0.4411 +vn 0.5570 0.7038 -0.4409 +vn 0.5486 0.8118 -0.2001 +vn 0.5207 0.8274 -0.2103 +vn 0.5027 0.8628 0.0544 +vn 0.4483 0.8932 0.0344 +vn 0.4221 0.8539 0.3043 +vn 0.3452 0.8970 0.2759 +vn 0.3131 0.7866 0.5321 +vn 0.2188 0.8394 0.4975 +vn 0.1832 0.6662 0.7229 +vn 0.0782 0.7250 0.6843 +vn 0.0412 0.5010 0.8644 +vn -0.0674 0.5619 0.8244 +vn -0.2084 0.3609 0.9090 +vn -0.1035 0.3021 0.9476 +vn -0.3358 0.1350 0.9322 +vn -0.4407 -0.1010 0.8920 +vn -0.2416 0.0822 0.9669 +vn -0.3637 -0.1441 0.9203 +vn -0.5157 -0.3312 0.7901 +vn -0.5553 -0.5392 0.6331 +vn -0.4614 -0.3617 0.8101 +vn -0.5274 -0.5549 0.6434 +vn -0.5562 -0.7100 0.4317 +vn -0.5185 -0.8311 0.2008 +vn -0.5568 -0.7097 0.4315 +vn -0.5475 -0.8149 0.1901 +vn -0.4451 -0.8944 -0.0432 +vn -0.3418 -0.8962 -0.2827 +vn -0.5003 -0.8635 -0.0635 +vn -0.4193 -0.8528 -0.3113 +vn -0.2161 -0.8376 -0.5017 +vn -0.0767 -0.7235 -0.6860 +vn -0.3106 -0.7847 -0.5365 +vn -0.1817 -0.6647 -0.7247 +vn -0.1492 -0.4316 -0.8896 +vn -0.0412 -0.5010 -0.8644 +vn -0.1043 -0.1629 -0.9811 +vn -0.0024 -0.2372 -0.9714 +vn 0.0533 0.0403 -0.9977 +vn 0.1449 -0.0265 -0.9891 +vn 0.2082 0.2420 -0.9477 +vn 0.2834 0.1872 -0.9405 +vn 0.3500 0.4285 -0.8330 +vn 0.4035 0.3895 -0.8279 +vn 0.4686 0.5868 -0.6603 +vn 0.4967 0.5663 -0.6577 +vn 0.5552 0.7050 -0.4413 +vn 0.5558 0.7046 -0.4412 +vn 0.6033 0.7743 -0.1911 +vn 0.5763 0.7940 -0.1936 +vn 0.6093 0.7896 0.0719 +vn 0.5566 0.8280 0.0670 +vn 0.5732 0.7503 0.3292 +vn 0.4986 0.8047 0.3221 +vn 0.4981 0.6598 0.5626 +vn 0.4067 0.7264 0.5540 +vn 0.3893 0.5248 0.7569 +vn 0.2875 0.5991 0.7473 +vn 0.2546 0.3548 0.8996 +vn 0.1492 0.4316 0.8896 +vn 0.0008 0.2350 0.9720 +vn 0.1027 0.1608 0.9816 +vn -0.1480 0.0220 0.9887 +vn -0.2872 -0.1933 0.9381 +vn -0.0566 -0.0446 0.9974 +vn -0.2126 -0.2477 0.9452 +vn -0.4074 -0.3964 0.8227 +vn -0.4997 -0.5726 0.6498 +vn -0.3547 -0.4348 0.8277 +vn -0.4727 -0.5924 0.6524 +vn -0.5574 -0.7093 0.4314 +vn -0.5763 -0.7964 0.1834 +vn -0.5580 -0.7089 0.4313 +vn -0.6043 -0.7759 0.1807 +vn -0.5552 -0.8282 -0.0763 +vn -0.4964 -0.8032 -0.3292 +vn -0.6088 -0.7891 -0.0814 +vn -0.5716 -0.7484 -0.3363 +vn -0.4045 -0.7243 -0.5584 +vn -0.2861 -0.5975 -0.7490 +vn -0.4961 -0.6575 -0.5671 +vn -0.3880 -0.5232 -0.7587 +vn -0.3556 -0.2719 -0.8942 +vn -0.2546 -0.3548 -0.8996 +vn -0.2938 0.0019 -0.9558 +vn -0.2020 -0.0827 -0.9759 +vn -0.1172 0.1886 -0.9750 +vn -0.0346 0.1124 -0.9930 +vn 0.0683 0.3637 -0.9290 +vn 0.1361 0.3012 -0.9438 +vn 0.2503 0.5152 -0.8197 +vn 0.2986 0.4707 -0.8302 +vn 0.4164 0.6322 -0.6534 +vn 0.4417 0.6089 -0.6589 +vn 0.5541 0.7059 -0.4411 +vn 0.5546 0.7054 -0.4412 +vn 0.6535 0.7306 -0.1978 +vn 0.6292 0.7530 -0.1924 +vn 0.7073 0.7044 0.0589 +vn 0.6598 0.7482 0.0692 +vn 0.7121 0.6296 0.3107 +vn 0.6448 0.6916 0.3254 +vn 0.6680 0.5120 0.5400 +vn 0.5857 0.5879 0.5579 +vn 0.5787 0.3601 0.7317 +vn 0.4870 0.4447 0.7517 +vn 0.4506 0.1843 0.8735 +vn 0.3556 0.2719 0.8942 +vn 0.2003 0.0807 0.9764 +vn 0.2921 -0.0039 0.9564 +vn 0.0310 -0.1165 0.9927 +vn -0.1410 -0.3064 0.9414 +vn 0.1133 -0.1924 0.9747 +vn -0.0738 -0.3685 0.9267 +vn -0.3042 -0.4763 0.8250 +vn -0.4468 -0.6136 0.6510 +vn -0.2567 -0.5201 0.8146 +vn -0.4225 -0.6360 0.6457 +vn -0.5585 -0.7084 0.4314 +vn -0.6313 -0.7538 0.1822 +vn -0.5591 -0.7079 0.4315 +vn -0.6566 -0.7305 0.1877 +vn -0.6601 -0.7470 -0.0786 +vn -0.6437 -0.6892 -0.3325 +vn -0.7084 -0.7025 -0.0681 +vn -0.7115 -0.6268 -0.3177 +vn -0.5840 -0.5854 -0.5623 +vn -0.4857 -0.4431 -0.7535 +vn -0.6666 -0.5092 -0.5443 +vn -0.5776 -0.3584 -0.7335 +vn -0.5378 -0.0936 -0.8378 +vn -0.4506 -0.1843 -0.8735 +vn -0.4537 0.1789 -0.8730 +vn -0.3782 0.0896 -0.9214 +vn -0.2609 0.3477 -0.9005 +vn -0.1930 0.2675 -0.9440 +vn -0.0496 0.4942 -0.8679 +vn 0.0061 0.4284 -0.9036 +vn 0.1664 0.6081 -0.7761 +vn 0.2060 0.5613 -0.8016 +vn 0.3723 0.6810 -0.6305 +vn 0.3931 0.6564 -0.6438 +vn 0.5532 0.7069 -0.4407 +vn 0.5536 0.7064 -0.4409 +vn 0.6959 0.6836 -0.2197 +vn 0.6759 0.7073 -0.2069 +vn 0.7900 0.6129 0.0161 +vn 0.7510 0.6590 0.0410 +vn 0.8291 0.5000 0.2500 +vn 0.7739 0.5654 0.2854 +vn 0.8113 0.3534 0.4657 +vn 0.7436 0.4334 0.5090 +vn 0.7384 0.1833 0.6489 +vn 0.6630 0.2725 0.6972 +vn 0.6159 0.0013 0.7878 +vn 0.5378 0.0936 0.8378 +vn 0.3764 -0.0916 0.9219 +vn 0.4518 -0.1807 0.8736 +vn 0.1890 -0.2710 0.9438 +vn -0.0119 -0.4327 0.9014 +vn 0.2567 -0.3511 0.9005 +vn 0.0433 -0.4981 0.8660 +vn -0.2131 -0.5654 0.7968 +vn -0.4001 -0.6593 0.6366 +vn -0.1741 -0.6116 0.7718 +vn -0.3801 -0.6830 0.6237 +vn -0.5596 -0.7074 0.4317 +vn -0.6798 -0.7063 0.1972 +vn -0.5600 -0.7069 0.4319 +vn -0.7006 -0.6817 0.2105 +vn -0.7527 -0.6564 -0.0500 +vn -0.7737 -0.5620 -0.2922 +vn -0.7924 -0.6095 -0.0246 +vn -0.8294 -0.4962 -0.2566 +vn -0.7425 -0.4303 -0.5133 +vn -0.6619 -0.2707 -0.6990 +vn -0.8104 -0.3500 -0.4698 +vn -0.7374 -0.1814 -0.6506 +vn -0.6834 0.0910 -0.7244 +vn -0.6159 -0.0013 -0.7878 +vn -0.5729 0.3559 -0.7383 +vn -0.5190 0.2681 -0.8116 +vn -0.3682 0.5070 -0.7794 +vn -0.3196 0.4281 -0.8453 +vn -0.1376 0.6249 -0.7684 +vn -0.0978 0.5601 -0.8226 +vn 0.1037 0.7012 -0.7053 +vn 0.1321 0.6551 -0.7439 +vn 0.3394 0.7298 -0.5934 +vn 0.3543 0.7056 -0.6136 +vn 0.5525 0.7079 -0.4399 +vn 0.5528 0.7074 -0.4403 +vn 0.7275 0.6367 -0.2555 +vn 0.7132 0.6600 -0.2360 +vn 0.8516 0.5213 -0.0536 +vn 0.8237 0.5667 -0.0157 +vn 0.9165 0.3703 0.1513 +vn 0.8769 0.4346 0.2051 +vn 0.9182 0.1946 0.3449 +vn 0.8698 0.2733 0.4107 +vn 0.8576 0.0064 0.5143 +vn 0.8036 0.0941 0.5876 +vn 0.7392 -0.1817 0.6485 +vn 0.6834 -0.0910 0.7244 +vn 0.5170 -0.2699 0.8123 +vn 0.5709 -0.3577 0.7390 +vn 0.3152 -0.4311 0.8454 +vn 0.0911 -0.5635 0.8211 +vn 0.3636 -0.5098 0.7797 +vn 0.1306 -0.6278 0.7673 +vn -0.1403 -0.6577 0.7400 +vn -0.3628 -0.7067 0.6074 +vn -0.1124 -0.7031 0.7021 +vn -0.3485 -0.7299 0.5880 +vn -0.5604 -0.7064 0.4323 +vn -0.7186 -0.6571 0.2274 +vn -0.5607 -0.7059 0.4327 +vn -0.7335 -0.6329 0.2477 +vn -0.8267 -0.5626 0.0076 +vn -0.8776 -0.4303 -0.2113 +vn -0.8550 -0.5165 0.0462 +vn -0.9174 -0.3655 -0.1571 +vn -0.8690 -0.2698 -0.4146 +vn -0.8027 -0.0922 -0.5892 +vn -0.9176 -0.1908 -0.3486 +vn -0.8566 -0.0044 -0.5159 +vn -0.7823 0.2694 -0.5615 +vn -0.7392 0.1817 -0.6485 +vn -0.6435 0.5210 -0.5608 +vn -0.6147 0.4407 -0.6542 +vn -0.4316 0.6554 -0.6197 +vn -0.4057 0.5832 -0.7037 +vn -0.1897 0.7468 -0.6374 +vn -0.1684 0.6875 -0.7064 +vn 0.0666 0.7880 -0.6120 +vn 0.0818 0.7458 -0.6612 +vn 0.3200 0.7753 -0.5445 +vn 0.3279 0.7532 -0.5702 +vn 0.5521 0.7089 -0.4389 +vn 0.5523 0.7084 -0.4394 +vn 0.7462 0.5929 -0.3025 +vn 0.7386 0.6142 -0.2777 +vn 0.8881 0.4360 -0.1454 +vn 0.8732 0.4775 -0.0971 +vn 0.9681 0.2494 0.0213 +vn 0.9471 0.3082 0.0897 +vn 0.9815 0.0466 0.1857 +vn 0.9557 0.1186 0.2695 +vn 0.9281 -0.1585 0.3369 +vn 0.8993 -0.0783 0.4302 +vn 0.8121 -0.3525 0.4649 +vn 0.7823 -0.2694 0.5615 +vn 0.6127 -0.4424 0.6549 +vn 0.6414 -0.5226 0.5616 +vn 0.4010 -0.5858 0.7042 +vn 0.1612 -0.6899 0.7057 +vn 0.4268 -0.6578 0.6205 +vn 0.1823 -0.7487 0.6373 +vn -0.0908 -0.7469 0.6586 +vn -0.3374 -0.7524 0.5657 +vn -0.0760 -0.7885 0.6103 +vn -0.3298 -0.7737 0.5409 +vn -0.5609 -0.7054 0.4332 +vn -0.7450 -0.6095 0.2709 +vn -0.5611 -0.7050 0.4337 +vn -0.7530 -0.5874 0.2966 +vn -0.8770 -0.4719 0.0904 +vn -0.9482 -0.3029 -0.0951 +vn -0.8921 -0.4297 0.1395 +vn -0.9695 -0.2437 -0.0262 +vn -0.9551 -0.1146 -0.2730 +vn -0.8984 0.0804 -0.4318 +vn -0.9810 -0.0423 -0.1890 +vn -0.9272 0.1606 -0.3384 +vn -0.8280 0.4295 -0.3604 +vn -0.8121 0.3525 -0.4649 +vn -0.6605 0.6628 -0.3527 +vn -0.6588 0.5955 -0.4597 +vn -0.4469 0.7830 -0.4325 +vn -0.4454 0.7224 -0.5288 +vn -0.2022 0.8514 -0.4838 +vn -0.2010 0.8017 -0.5629 +vn 0.0576 0.8625 -0.5027 +vn 0.0585 0.8271 -0.5589 +vn 0.3153 0.8144 -0.4871 +vn 0.3157 0.7959 -0.5166 +vn 0.5520 0.7097 -0.4377 +vn 0.5520 0.7093 -0.4383 +vn 0.7507 0.5553 -0.3577 +vn 0.7503 0.5732 -0.3293 +vn 0.8969 0.3627 -0.2530 +vn 0.8961 0.3975 -0.1976 +vn 0.9806 0.1455 -0.1311 +vn 0.9794 0.1948 -0.0527 +vn 0.9967 -0.0806 -0.0009 +vn 0.9952 -0.0202 0.0951 +vn 0.9451 -0.3003 0.1289 +vn 0.9434 -0.2329 0.2359 +vn 0.8280 -0.4295 0.3604 +vn 0.6568 -0.5970 0.4606 +vn 0.6584 -0.6644 0.3536 +vn 0.4406 -0.7246 0.5299 +vn 0.1936 -0.8032 0.5633 +vn 0.4421 -0.7850 0.4339 +vn 0.1948 -0.8526 0.4849 +vn -0.0680 -0.8270 0.5581 +vn -0.3257 -0.7934 0.5141 +vn -0.0671 -0.8618 0.5027 +vn -0.3253 -0.8113 0.4858 +vn -0.5612 -0.7046 0.4343 +vn -0.7572 -0.5669 0.3244 +vn -0.5612 -0.7042 0.4349 +vn -0.7577 -0.5483 0.3540 +vn -0.9002 -0.3906 0.1926 +vn -0.9808 -0.1887 0.0484 +vn -0.9011 -0.3551 0.2488 +vn -0.9821 -0.1390 0.1274 +vn -0.9948 0.0246 -0.0981 +vn -0.9425 0.2351 -0.2373 +vn -0.9963 0.0852 -0.0018 +vn -0.9442 0.3025 -0.1303 +vn -0.6228 0.7718 -0.1281 +vn -0.6484 0.7219 -0.2415 +vn -0.4130 0.8810 -0.2305 +vn -0.4360 0.8362 -0.3325 +vn -0.1744 0.9319 -0.3181 +vn -0.1933 0.8951 -0.4018 +vn 0.0775 0.9198 -0.3847 +vn 0.0640 0.8936 -0.4443 +vn 0.3257 0.8444 -0.4252 +vn 0.3186 0.8307 -0.4564 +vn 0.5522 0.7103 -0.4364 +vn 0.5521 0.7100 -0.4371 +vn 0.7407 0.5264 -0.4172 +vn 0.7476 0.5397 -0.3872 +vn 0.8774 0.3063 -0.3691 +vn 0.8907 0.3321 -0.3105 +vn 0.9530 0.0657 -0.2956 +vn 0.9718 0.1022 -0.2125 +vn 0.9630 -0.1783 -0.2022 +vn 0.9859 -0.1336 -0.1005 +vn 0.9074 -0.4091 -0.0954 +vn 0.9330 -0.3594 0.0179 +vn 0.6464 -0.7234 0.2426 +vn 0.6208 -0.7732 0.1292 +vn 0.4313 -0.8380 0.3342 +vn 0.1859 -0.8959 0.4035 +vn 0.4083 -0.8827 0.2326 +vn 0.1672 -0.9324 0.3204 +vn -0.0734 -0.8924 0.4452 +vn -0.3284 -0.8270 0.4563 +vn -0.0866 -0.9181 0.3866 +vn -0.3352 -0.8402 0.4262 +vn -0.5611 -0.7038 0.4356 +vn -0.7543 -0.5320 0.3846 +vn -0.5610 -0.7035 0.4362 +vn -0.7473 -0.5183 0.4159 +vn -0.8947 -0.3241 0.3073 +vn -0.9731 -0.0953 0.2094 +vn -0.8813 -0.2979 0.3669 +vn -0.9543 -0.0586 0.2932 +vn -0.9855 0.1384 0.0981 +vn -0.9321 0.3616 -0.0191 +vn -0.9625 0.1832 0.2001 +vn -0.9065 0.4115 0.0943 +vn -0.5330 0.8404 0.0976 +vn -0.5841 0.8115 -0.0144 +vn -0.3323 0.9427 -0.0275 +vn -0.3782 0.9167 -0.1283 +vn -0.1082 0.9825 -0.1515 +vn -0.1459 0.9611 -0.2342 +vn 0.1246 0.9559 -0.2660 +vn 0.0978 0.9407 -0.3249 +vn 0.3504 0.8634 -0.3630 +vn 0.3363 0.8554 -0.3938 +vn 0.5527 0.7107 -0.4351 +vn 0.5524 0.7105 -0.4357 +vn 0.7169 0.5083 -0.4771 +vn 0.7305 0.5159 -0.4474 +vn 0.8310 0.2708 -0.4858 +vn 0.8574 0.2857 -0.4279 +vn 0.8873 0.0154 -0.4610 +vn 0.9247 0.0366 -0.3789 +vn 0.8825 -0.2398 -0.4046 +vn 0.9283 -0.2139 -0.3041 +vn 0.8177 -0.4777 -0.3210 +vn 0.8688 -0.4488 -0.2091 +vn 0.5821 -0.8129 0.0156 +vn 0.5311 -0.8418 -0.0963 +vn 0.3736 -0.9183 0.1306 +vn 0.1389 -0.9615 0.2371 +vn 0.3278 -0.9442 0.0302 +vn 0.1014 -0.9827 0.1550 +vn -0.1066 -0.9387 0.3278 +vn -0.3455 -0.8507 0.3961 +vn -0.1331 -0.9536 0.2699 +vn -0.3591 -0.8584 0.3664 +vn -0.5607 -0.7033 0.4369 +vn -0.7366 -0.5073 0.4472 +vn -0.5605 -0.7031 0.4375 +vn -0.7225 -0.4993 0.4781 +vn -0.8609 -0.2770 0.4266 +vn -0.9257 -0.0293 0.3771 +vn -0.8341 -0.2618 0.4855 +vn -0.8880 -0.0079 0.4597 +vn -0.9277 0.2189 0.3024 +vn -0.8679 0.4512 0.2080 +vn -0.8817 0.2449 0.4031 +vn -0.8167 0.4801 0.3200 +vn -0.6332 0.7010 0.3281 +vn -0.3973 0.8640 0.3091 +vn -0.4704 0.8580 0.2061 +vn -0.2102 0.9640 0.1627 +vn -0.2759 0.9586 0.0700 +vn -0.0080 0.9999 0.0045 +vn -0.0619 0.9955 -0.0715 +vn 0.1960 0.9683 -0.1549 +vn 0.1576 0.9651 -0.2090 +vn 0.3878 0.8699 -0.3047 +vn 0.3677 0.8682 -0.3330 +vn 0.5535 0.7109 -0.4339 +vn 0.5531 0.7108 -0.4345 +vn 0.6810 0.5020 -0.5332 +vn 0.7003 0.5036 -0.5058 +vn 0.7608 0.2586 -0.5952 +vn 0.7986 0.2617 -0.5419 +vn 0.7878 -0.0019 -0.6159 +vn 0.8414 0.0025 -0.5404 +vn 0.7607 -0.2610 -0.5943 +vn 0.8263 -0.2556 -0.5018 +vn 0.6821 -0.5014 -0.5323 +vn 0.7551 -0.4953 -0.4294 +vn 0.4685 -0.8594 -0.2047 +vn 0.3954 -0.8654 -0.3076 +vn 0.2716 -0.9600 -0.0671 +vn 0.0555 -0.9956 0.0756 +vn 0.2061 -0.9654 -0.1595 +vn 0.0020 -1.0000 0.0001 +vn -0.1654 -0.9627 0.2138 +vn -0.3757 -0.8631 0.3376 +vn -0.2033 -0.9658 0.1605 +vn -0.3951 -0.8647 0.3103 +vn -0.5601 -0.7031 0.4381 +vn -0.7053 -0.4945 0.5080 +vn -0.5597 -0.7030 0.4387 +vn -0.6851 -0.4928 0.5364 +vn -0.8011 -0.2526 0.5425 +vn -0.8418 0.0051 0.5398 +vn -0.7627 -0.2494 0.5967 +vn -0.7878 0.0095 0.6158 +vn -0.8254 0.2608 0.5007 +vn -0.7541 0.4977 0.4284 +vn -0.7596 0.2662 0.5934 +vn -0.6810 0.5037 0.5315 +vn -0.2248 0.8411 0.4920 +vn -0.3149 0.8584 0.4050 +vn -0.0550 0.9434 0.3271 +vn -0.1361 0.9589 0.2489 +vn 0.1193 0.9830 0.1395 +vn 0.0528 0.9958 0.0753 +vn 0.2867 0.9562 -0.0587 +vn 0.2393 0.9653 -0.1045 +vn 0.4354 0.8636 -0.2542 +vn 0.4105 0.8683 -0.2782 +vn 0.5545 0.7107 -0.4328 +vn 0.5540 0.7108 -0.4334 +vn 0.6352 0.5081 -0.5817 +vn 0.6591 0.5035 -0.5586 +vn 0.6716 0.2705 -0.6897 +vn 0.7182 0.2615 -0.6448 +vn 0.6615 0.0149 -0.7498 +vn 0.7275 0.0022 -0.6861 +vn 0.6060 -0.2404 -0.7582 +vn 0.6869 -0.2559 -0.6802 +vn 0.5097 -0.4784 -0.7151 +vn 0.5998 -0.4957 -0.6281 +vn 0.3131 -0.8597 -0.4034 +vn 0.2230 -0.8425 -0.4903 +vn 0.1322 -0.9603 -0.2454 +vn -0.0583 -0.9958 -0.0701 +vn 0.0514 -0.9448 -0.3234 +vn -0.1244 -0.9832 -0.1338 +vn -0.2458 -0.9629 0.1109 +vn -0.4169 -0.8632 0.2849 +vn -0.2925 -0.9540 0.0660 +vn -0.4408 -0.8585 0.2618 +vn -0.5592 -0.7031 0.4393 +vn -0.6624 -0.4944 0.5628 +vn -0.5587 -0.7031 0.4398 +vn -0.6375 -0.4992 0.5868 +vn -0.7194 -0.2524 0.6470 +vn -0.7270 0.0053 0.6866 +vn -0.6720 -0.2615 0.6928 +vn -0.6605 -0.0074 0.7508 +vn -0.6855 0.2611 0.6796 +vn -0.5986 0.4980 0.6273 +vn -0.6044 0.2455 0.7578 +vn -0.5085 0.4808 0.7143 +vn -0.0273 0.7731 0.6337 +vn -0.1283 0.8125 0.5687 +vn 0.1226 0.8822 0.4546 +vn 0.0317 0.9176 0.3961 +vn 0.2651 0.9328 0.2441 +vn 0.1905 0.9619 0.1961 +vn 0.3905 0.9205 0.0157 +vn 0.3374 0.9412 -0.0184 +vn 0.4899 0.8448 -0.2152 +vn 0.4620 0.8557 -0.2331 +vn 0.5556 0.7103 -0.4321 +vn 0.5550 0.7105 -0.4324 +vn 0.5828 0.5261 -0.6192 +vn 0.6096 0.5156 -0.6020 +vn 0.5695 0.3056 -0.7630 +vn 0.6218 0.2852 -0.7294 +vn 0.5168 0.0647 -0.8536 +vn 0.5908 0.0358 -0.8060 +vn 0.4290 -0.1794 -0.8853 +vn 0.5196 -0.2148 -0.8270 +vn 0.3123 -0.4104 -0.8567 +vn 0.4133 -0.4498 -0.7917 +vn 0.1267 -0.8139 -0.5670 +vn 0.0257 -0.7745 -0.6320 +vn -0.0350 -0.9192 -0.3922 +vn -0.1950 -0.9622 -0.1900 +vn -0.1256 -0.8838 -0.4505 +vn -0.2690 -0.9333 -0.2376 +vn -0.3423 -0.9392 0.0263 +vn -0.4664 -0.8510 0.2415 +vn -0.3946 -0.9188 -0.0073 +vn -0.4931 -0.8405 0.2242 +vn -0.5582 -0.7033 0.4402 +vn -0.6110 -0.5071 0.6079 +vn -0.5576 -0.7035 0.4406 +vn -0.5831 -0.5179 0.6259 +vn -0.6214 -0.2765 0.7331 +vn -0.5893 -0.0285 0.8074 +vn -0.5683 -0.2972 0.7673 +vn -0.5147 -0.0576 0.8554 +vn -0.5177 0.2198 0.8268 +vn -0.4120 0.4522 0.7910 +vn -0.4268 0.1844 0.8853 +vn -0.3110 0.4127 0.8561 +vn 0.1817 0.6647 0.7247 +vn 0.0767 0.7235 0.6860 +vn 0.3106 0.7847 0.5365 +vn 0.2161 0.8376 0.5017 +vn 0.4193 0.8528 0.3113 +vn 0.3418 0.8962 0.2827 +vn 0.5003 0.8635 0.0635 +vn 0.4451 0.8944 0.0432 +vn 0.5475 0.8149 -0.1901 +vn 0.5185 0.8311 -0.2008 +vn 0.5568 0.7097 -0.4315 +vn 0.5562 0.7100 -0.4317 +vn 0.5274 0.5549 -0.6434 +vn 0.5553 0.5392 -0.6331 +vn 0.4614 0.3617 -0.8101 +vn 0.5157 0.3312 -0.7901 +vn 0.3637 0.1441 -0.9203 +vn 0.4407 0.1010 -0.8920 +vn 0.2416 -0.0822 -0.9669 +vn 0.3357 -0.1350 -0.9322 +vn 0.1035 -0.3021 -0.9476 +vn 0.2084 -0.3609 -0.9090 +vn -0.0782 -0.7250 -0.6843 +vn -0.1832 -0.6662 -0.7229 +vn -0.2188 -0.8394 -0.4975 +vn -0.3452 -0.8970 -0.2759 +vn -0.3131 -0.7866 -0.5321 +vn -0.4221 -0.8539 -0.3043 +vn -0.4483 -0.8932 -0.0344 +vn -0.5207 -0.8274 0.2103 +vn -0.5027 -0.8628 -0.0544 +vn -0.5486 -0.8118 0.2001 +vn -0.5570 -0.7038 0.4409 +vn -0.5544 -0.5316 0.6403 +vn -0.5564 -0.7042 0.4411 +vn -0.5255 -0.5478 0.6510 +vn -0.5136 -0.3233 0.7948 +vn -0.4380 -0.0942 0.8940 +vn -0.4584 -0.3542 0.8151 +vn -0.3605 -0.1376 0.9225 +vn -0.3333 0.1398 0.9324 +vn -0.2070 0.3632 0.9084 +vn -0.2388 0.0869 0.9672 +vn -0.1020 0.3043 0.9471 +vn 0.3880 0.5232 0.7587 +vn 0.2861 0.5975 0.7490 +vn 0.4961 0.6575 0.5671 +vn 0.4045 0.7243 0.5584 +vn 0.5716 0.7484 0.3363 +vn 0.4964 0.8032 0.3292 +vn 0.6088 0.7891 0.0814 +vn 0.5552 0.8282 0.0764 +vn 0.6043 0.7759 -0.1807 +vn 0.5763 0.7964 -0.1834 +vn 0.5580 0.7089 -0.4313 +vn 0.5574 0.7093 -0.4314 +vn 0.4727 0.5924 -0.6524 +vn 0.4997 0.5726 -0.6498 +vn 0.3547 0.4348 -0.8277 +vn 0.4074 0.3964 -0.8227 +vn 0.2126 0.2477 -0.9452 +vn 0.2872 0.1933 -0.9381 +vn 0.0566 0.0446 -0.9974 +vn 0.1480 -0.0220 -0.9887 +vn -0.1027 -0.1608 -0.9816 +vn -0.0008 -0.2350 -0.9720 +vn -0.2875 -0.5991 -0.7473 +vn -0.3893 -0.5248 -0.7569 +vn -0.4067 -0.7264 -0.5540 +vn -0.4986 -0.8047 -0.3221 +vn -0.4981 -0.6598 -0.5626 +vn -0.5732 -0.7503 -0.3292 +vn -0.5566 -0.8280 -0.0670 +vn -0.5763 -0.7940 0.1936 +vn -0.6093 -0.7896 -0.0719 +vn -0.6033 -0.7743 0.1911 +vn -0.5558 -0.7046 0.4412 +vn -0.4967 -0.5663 0.6577 +vn -0.5552 -0.7050 0.4413 +vn -0.4686 -0.5868 0.6603 +vn -0.4035 -0.3895 0.8279 +vn -0.2834 -0.1872 0.9405 +vn -0.3500 -0.4285 0.8330 +vn -0.2082 -0.2420 0.9477 +vn -0.1449 0.0265 0.9891 +vn 0.0024 0.2372 0.9714 +vn -0.0533 -0.0403 0.9977 +vn 0.1043 0.1629 0.9811 +vn 0.5776 0.3584 0.7335 +vn 0.4857 0.4431 0.7535 +vn 0.6666 0.5092 0.5443 +vn 0.5840 0.5854 0.5623 +vn 0.7115 0.6268 0.3177 +vn 0.6437 0.6892 0.3325 +vn 0.7084 0.7025 0.0681 +vn 0.6601 0.7470 0.0786 +vn 0.6566 0.7305 -0.1877 +vn 0.6313 0.7538 -0.1822 +vn 0.5591 0.7080 -0.4315 +vn 0.5586 0.7084 -0.4314 +vn 0.4225 0.6360 -0.6457 +vn 0.4468 0.6136 -0.6510 +vn 0.2567 0.5201 -0.8146 +vn 0.3042 0.4763 -0.8250 +vn 0.0738 0.3685 -0.9267 +vn 0.1410 0.3064 -0.9414 +vn -0.1133 0.1924 -0.9747 +vn -0.0310 0.1165 -0.9927 +vn -0.2921 0.0039 -0.9564 +vn -0.2003 -0.0807 -0.9764 +vn -0.4870 -0.4447 -0.7517 +vn -0.5787 -0.3601 -0.7317 +vn -0.5857 -0.5879 -0.5579 +vn -0.6448 -0.6916 -0.3254 +vn -0.6680 -0.5120 -0.5400 +vn -0.7121 -0.6296 -0.3107 +vn -0.6598 -0.7482 -0.0692 +vn -0.6292 -0.7530 0.1924 +vn -0.7073 -0.7044 -0.0589 +vn -0.6535 -0.7306 0.1978 +vn -0.5546 -0.7054 0.4412 +vn -0.4417 -0.6089 0.6589 +vn -0.5541 -0.7059 0.4411 +vn -0.4164 -0.6322 0.6534 +vn -0.2986 -0.4707 0.8302 +vn -0.1361 -0.3012 0.9438 +vn -0.2504 -0.5152 0.8197 +vn -0.0683 -0.3637 0.9290 +vn 0.0346 -0.1124 0.9930 +vn 0.2020 0.0827 0.9759 +vn 0.1172 -0.1886 0.9750 +vn 0.2938 -0.0019 0.9558 +vn 0.7374 0.1814 0.6506 +vn 0.6619 0.2707 0.6990 +vn 0.8104 0.3500 0.4698 +vn 0.7425 0.4303 0.5133 +vn 0.8294 0.4962 0.2566 +vn 0.7737 0.5620 0.2922 +vn 0.7924 0.6095 0.0246 +vn 0.7527 0.6564 0.0500 +vn 0.7006 0.6817 -0.2105 +vn 0.6798 0.7063 -0.1972 +vn 0.5600 0.7069 -0.4319 +vn 0.5596 0.7074 -0.4317 +vn 0.3801 0.6830 -0.6237 +vn 0.4001 0.6593 -0.6366 +vn 0.1741 0.6116 -0.7718 +vn 0.2131 0.5654 -0.7968 +vn -0.0433 0.4981 -0.8660 +vn 0.0119 0.4327 -0.9014 +vn -0.2567 0.3511 -0.9005 +vn -0.1890 0.2710 -0.9438 +vn -0.4518 0.1807 -0.8736 +vn -0.3764 0.0916 -0.9219 +vn -0.6630 -0.2725 -0.6972 +vn -0.7384 -0.1833 -0.6489 +vn -0.7436 -0.4334 -0.5090 +vn -0.7739 -0.5654 -0.2854 +vn -0.8113 -0.3534 -0.4657 +vn -0.8291 -0.5000 -0.2500 +vn -0.7510 -0.6590 -0.0410 +vn -0.6759 -0.7073 0.2069 +vn -0.7900 -0.6129 -0.0161 +vn -0.6959 -0.6836 0.2197 +vn -0.5536 -0.7064 0.4409 +vn -0.3931 -0.6564 0.6438 +vn -0.5532 -0.7069 0.4407 +vn -0.3723 -0.6810 0.6305 +vn -0.2060 -0.5612 0.8016 +vn -0.0061 -0.4284 0.9036 +vn -0.1664 -0.6081 0.7761 +vn 0.0496 -0.4942 0.8679 +vn 0.1930 -0.2675 0.9440 +vn 0.3782 -0.0896 0.9214 +vn 0.2609 -0.3477 0.9005 +vn 0.4537 -0.1789 0.8730 +vn 0.8566 0.0044 0.5159 +vn 0.8027 0.0922 0.5892 +vn 0.9176 0.1908 0.3486 +vn 0.8690 0.2698 0.4146 +vn 0.9174 0.3655 0.1571 +vn 0.8776 0.4303 0.2113 +vn 0.8550 0.5165 -0.0462 +vn 0.8267 0.5626 -0.0076 +vn 0.7335 0.6329 -0.2477 +vn 0.7186 0.6571 -0.2275 +vn 0.5607 0.7059 -0.4327 +vn 0.5604 0.7064 -0.4323 +vn 0.3485 0.7299 -0.5880 +vn 0.3628 0.7067 -0.6074 +vn 0.1124 0.7031 -0.7021 +vn 0.1403 0.6577 -0.7400 +vn -0.1306 0.6278 -0.7673 +vn -0.0911 0.5635 -0.8211 +vn -0.3636 0.5098 -0.7797 +vn -0.3152 0.4311 -0.8454 +vn -0.5709 0.3577 -0.7390 +vn -0.5170 0.2699 -0.8123 +vn -0.8036 -0.0941 -0.5876 +vn -0.8576 -0.0064 -0.5143 +vn -0.8698 -0.2733 -0.4107 +vn -0.8769 -0.4346 -0.2051 +vn -0.9182 -0.1946 -0.3449 +vn -0.9165 -0.3703 -0.1513 +vn -0.8237 -0.5667 0.0157 +vn -0.7132 -0.6600 0.2360 +vn -0.8516 -0.5213 0.0536 +vn -0.7275 -0.6367 0.2555 +vn -0.5528 -0.7074 0.4403 +vn -0.3543 -0.7056 0.6136 +vn -0.5525 -0.7079 0.4399 +vn -0.3394 -0.7298 0.5934 +vn -0.1321 -0.6551 0.7439 +vn 0.0978 -0.5601 0.8226 +vn -0.1037 -0.7012 0.7053 +vn 0.1376 -0.6249 0.7684 +vn 0.3196 -0.4281 0.8453 +vn 0.5190 -0.2681 0.8116 +vn 0.3682 -0.5070 0.7794 +vn 0.5729 -0.3559 0.7383 +vn 0.9272 -0.1606 0.3384 +vn 0.8984 -0.0804 0.4318 +vn 0.9810 0.0423 0.1890 +vn 0.9551 0.1146 0.2730 +vn 0.9695 0.2437 0.0262 +vn 0.9482 0.3029 0.0951 +vn 0.8921 0.4297 -0.1395 +vn 0.8770 0.4719 -0.0904 +vn 0.7530 0.5874 -0.2966 +vn 0.7450 0.6095 -0.2709 +vn 0.5611 0.7050 -0.4337 +vn 0.5609 0.7054 -0.4332 +vn 0.3298 0.7737 -0.5409 +vn 0.3374 0.7524 -0.5657 +vn 0.0760 0.7885 -0.6103 +vn 0.0908 0.7469 -0.6586 +vn -0.1823 0.7487 -0.6373 +vn -0.1612 0.6899 -0.7057 +vn -0.4268 0.6578 -0.6205 +vn -0.4010 0.5858 -0.7042 +vn -0.6414 0.5226 -0.5616 +vn -0.6126 0.4424 -0.6549 +vn -0.8993 0.0783 -0.4302 +vn -0.9281 0.1585 -0.3369 +vn -0.9557 -0.1186 -0.2695 +vn -0.9471 -0.3082 -0.0897 +vn -0.9815 -0.0466 -0.1857 +vn -0.9682 -0.2494 -0.0213 +vn -0.8732 -0.4775 0.0971 +vn -0.7386 -0.6142 0.2777 +vn -0.8881 -0.4360 0.1454 +vn -0.7462 -0.5929 0.3025 +vn -0.5523 -0.7084 0.4394 +vn -0.3279 -0.7532 0.5702 +vn -0.5521 -0.7089 0.4389 +vn -0.3200 -0.7753 0.5445 +vn -0.0818 -0.7458 0.6612 +vn 0.1684 -0.6875 0.7064 +vn -0.0666 -0.7880 0.6120 +vn 0.1897 -0.7468 0.6374 +vn 0.4057 -0.5832 0.7037 +vn 0.6147 -0.4407 0.6542 +vn 0.4316 -0.6554 0.6197 +vn 0.6435 -0.5210 0.5608 +vn 0.9425 -0.2351 0.2373 +vn 0.9948 -0.0246 0.0981 +vn 0.9808 0.1887 -0.0484 +vn 0.9002 0.3905 -0.1926 +vn 0.7572 0.5669 -0.3244 +vn 0.5612 0.7046 -0.4343 +vn 0.3257 0.7934 -0.5141 +vn 0.0680 0.8270 -0.5581 +vn -0.1936 0.8032 -0.5633 +vn -0.4406 0.7246 -0.5299 +vn -0.6568 0.5970 -0.4606 +vn -0.9434 0.2329 -0.2359 +vn -0.9952 0.0201 -0.0951 +vn -0.9794 -0.1948 0.0527 +vn -0.8961 -0.3975 0.1976 +vn -0.7503 -0.5732 0.3293 +vn -0.5520 -0.7093 0.4383 +vn -0.3157 -0.7959 0.5166 +vn -0.0585 -0.8271 0.5589 +vn 0.2010 -0.8017 0.5629 +vn 0.4454 -0.7224 0.5288 +vn 0.6588 -0.5955 0.4597 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +g torus_Torus.001_torus.001 +usemtl torus.001 +s 1 +f 423/159/104 417/160/105 129/161/106 +f 423/159/104 711/162/107 993/163/108 +f 993/163/108 142/164/109 507/165/110 +f 993/163/108 130/166/111 417/160/105 +f 507/165/110 502/167/112 130/166/111 +f 507/165/110 794/168/113 994/169/114 +f 994/169/114 143/170/115 579/171/116 +f 994/169/114 131/172/117 502/167/112 +f 579/171/116 574/173/118 131/172/117 +f 579/171/116 866/174/119 995/175/120 +f 995/175/120 144/176/121 651/177/122 +f 995/175/120 132/178/123 574/173/118 +f 651/177/122 647/179/124 132/178/123 +f 651/177/122 937/180/125 996/181/126 +f 996/181/126 145/182/127 713/183/128 +f 996/181/126 133/184/129 647/179/124 +f 713/183/128 708/185/130 133/184/129 +f 713/183/128 425/186/131 997/187/132 +f 997/187/132 146/188/133 796/189/134 +f 997/187/132 134/190/135 708/185/130 +f 796/189/134 790/191/136 134/190/135 +f 796/189/134 509/192/137 998/193/138 +f 998/193/138 147/194/139 868/195/140 +f 998/193/138 135/196/141 790/191/136 +f 135/197/141 999/198/142 864/199/143 +f 147/200/139 999/198/142 868/201/140 +f 581/202/144 939/203/145 999/198/142 +f 864/199/143 939/203/145 136/204/146 +f 136/204/146 1000/205/147 934/206/148 +f 148/207/149 1000/205/147 939/203/145 +f 653/208/150 427/209/151 1000/205/147 +f 934/206/148 427/209/151 137/210/152 +f 137/210/152 1001/211/153 420/212/154 +f 149/213/155 1001/211/153 427/209/151 +f 715/214/156 512/215/157 1001/211/153 +f 420/212/154 512/215/157 138/216/158 +f 138/216/158 1002/217/159 505/218/160 +f 150/219/161 1002/217/159 512/215/157 +f 798/220/162 582/221/163 1002/217/159 +f 505/218/160 582/221/163 139/222/164 +f 139/222/164 1003/223/165 577/224/166 +f 151/225/167 1003/223/165 582/221/163 +f 870/226/168 655/227/169 1003/223/165 +f 577/224/166 655/227/169 140/228/170 +f 140/228/170 1004/229/171 422/230/172 +f 152/231/173 1004/229/171 655/227/169 +f 717/232/174 423/159/104 1004/229/171 +f 422/230/172 423/159/104 129/161/106 +f 718/233/175 711/162/107 141/234/176 +f 718/233/175 429/235/177 1005/236/178 +f 1005/236/178 154/237/179 800/238/180 +f 1005/236/178 142/164/109 711/162/107 +f 800/238/180 794/168/113 142/164/109 +f 800/238/180 514/239/181 1006/240/182 +f 1006/240/182 155/241/183 872/242/184 +f 1006/240/182 143/170/115 794/168/113 +f 872/242/184 866/174/119 143/170/115 +f 872/242/184 584/243/185 1007/244/186 +f 1007/244/186 156/245/187 942/246/188 +f 1007/244/186 144/176/121 866/174/119 +f 942/246/188 937/180/125 144/176/121 +f 942/246/188 657/247/189 1008/248/190 +f 1008/248/190 157/249/191 431/250/192 +f 1008/248/190 145/182/127 937/180/125 +f 431/250/192 425/186/131 145/182/127 +f 431/250/192 720/251/193 1009/252/194 +f 1009/252/194 158/253/195 516/254/196 +f 1009/252/194 146/188/133 425/186/131 +f 516/254/196 509/192/137 146/188/133 +f 516/254/196 802/255/197 1010/256/198 +f 1010/256/198 159/257/199 586/258/200 +f 1010/256/198 147/194/139 509/192/137 +f 147/200/139 1011/259/201 581/202/144 +f 159/260/199 1011/259/201 586/261/200 +f 874/262/202 659/263/203 1011/259/201 +f 581/202/144 659/263/203 148/207/149 +f 148/207/149 1012/264/204 653/208/150 +f 160/265/205 1012/264/204 659/263/203 +f 944/266/206 722/267/207 1012/264/204 +f 653/208/150 722/267/207 149/213/155 +f 149/213/155 1013/268/208 715/214/156 +f 161/269/209 1013/268/208 722/267/207 +f 433/270/210 804/271/211 1013/268/208 +f 715/214/156 804/271/211 150/219/161 +f 150/219/161 1014/272/212 798/220/162 +f 162/273/213 1014/272/212 804/271/211 +f 517/274/214 875/275/215 1014/272/212 +f 798/220/162 875/275/215 151/225/167 +f 151/225/167 1015/276/216 870/226/168 +f 163/277/217 1015/276/216 875/275/215 +f 588/278/218 945/279/219 1015/276/216 +f 870/226/168 945/279/219 152/231/173 +f 152/231/173 1016/280/220 717/232/174 +f 164/281/221 1016/280/220 945/279/219 +f 434/282/222 718/233/175 1016/280/220 +f 717/232/174 718/233/175 141/234/176 +f 435/283/223 429/235/177 153/284/224 +f 435/283/223 723/285/225 1017/286/226 +f 1017/286/226 166/287/227 518/288/228 +f 1017/286/226 154/237/179 429/235/177 +f 518/288/228 514/239/181 154/237/179 +f 518/288/228 805/289/229 1018/290/230 +f 1018/290/230 167/291/231 589/292/232 +f 1018/290/230 155/241/183 514/239/181 +f 589/292/232 584/243/185 155/241/183 +f 589/292/232 876/293/233 1019/294/234 +f 1019/294/234 168/295/235 660/296/236 +f 1019/294/234 156/245/187 584/243/185 +f 660/296/236 657/247/189 156/245/187 +f 660/296/236 946/297/237 1020/298/238 +f 1020/298/238 169/299/239 724/300/240 +f 1020/298/238 157/249/191 657/247/189 +f 724/300/240 720/251/193 157/249/191 +f 724/300/240 436/301/241 1021/302/242 +f 1021/302/242 170/303/243 806/304/244 +f 1021/302/242 158/253/195 720/251/193 +f 806/304/244 802/255/197 158/253/195 +f 806/304/244 519/305/245 1022/306/246 +f 1022/306/246 171/307/247 877/308/248 +f 1022/306/246 159/257/199 802/255/197 +f 159/260/199 1023/309/249 874/262/202 +f 171/310/247 1023/309/249 877/311/248 +f 590/312/250 947/313/251 1023/309/249 +f 874/262/202 947/313/251 160/265/205 +f 160/265/205 1024/314/252 944/266/206 +f 172/315/253 1024/314/252 947/313/251 +f 661/316/254 437/317/255 1024/314/252 +f 944/266/206 437/317/255 161/269/209 +f 161/269/209 1025/318/256 433/270/210 +f 173/319/257 1025/318/256 437/317/255 +f 725/320/258 520/321/259 1025/318/256 +f 433/270/210 520/321/259 162/273/213 +f 162/273/213 1026/322/260 517/274/214 +f 174/323/261 1026/322/260 520/321/259 +f 807/324/262 591/325/263 1026/322/260 +f 517/274/214 591/325/263 163/277/217 +f 163/277/217 1027/326/264 588/278/218 +f 175/327/265 1027/326/264 591/325/263 +f 878/328/266 662/329/267 1027/326/264 +f 588/278/218 662/329/267 164/281/221 +f 164/281/221 1028/330/268 434/282/222 +f 176/331/269 1028/330/268 662/329/267 +f 726/332/270 435/283/223 1028/330/268 +f 434/282/222 435/283/223 153/284/224 +f 727/333/271 723/285/225 165/334/272 +f 727/333/271 438/335/273 1029/336/274 +f 1029/336/274 178/337/275 808/338/276 +f 1029/336/274 166/287/227 723/285/225 +f 808/338/276 805/289/229 166/287/227 +f 808/338/276 521/339/277 1030/340/278 +f 1030/340/278 179/341/279 879/342/280 +f 1030/340/278 167/291/231 805/289/229 +f 879/342/280 876/293/233 167/291/231 +f 879/342/280 592/343/281 1031/344/282 +f 1031/344/282 180/345/283 948/346/284 +f 1031/344/282 168/295/235 876/293/233 +f 948/346/284 946/297/237 168/295/235 +f 948/346/284 663/347/285 1032/348/286 +f 1032/348/286 181/349/287 439/350/288 +f 1032/348/286 169/299/239 946/297/237 +f 439/350/288 436/301/241 169/299/239 +f 439/350/288 728/351/289 1033/352/290 +f 1033/352/290 182/353/291 522/354/292 +f 1033/352/290 170/303/243 436/301/241 +f 522/354/292 519/305/245 170/303/243 +f 522/354/292 809/355/293 1034/356/294 +f 1034/356/294 183/357/295 593/358/296 +f 1034/356/294 171/307/247 519/305/245 +f 171/310/247 1035/359/297 590/312/250 +f 183/360/295 1035/359/297 593/361/296 +f 880/362/298 664/363/299 1035/359/297 +f 590/312/250 664/363/299 172/315/253 +f 172/315/253 1036/364/300 661/316/254 +f 184/365/301 1036/364/300 664/363/299 +f 949/366/302 729/367/303 1036/364/300 +f 661/316/254 729/367/303 173/319/257 +f 173/319/257 1037/368/304 725/320/258 +f 185/369/305 1037/368/304 729/367/303 +f 440/370/306 810/371/307 1037/368/304 +f 725/320/258 810/371/307 174/323/261 +f 174/323/261 1038/372/308 807/324/262 +f 186/373/309 1038/372/308 810/371/307 +f 523/374/310 881/375/311 1038/372/308 +f 807/324/262 881/375/311 175/327/265 +f 175/327/265 1039/376/312 878/328/266 +f 187/377/313 1039/376/312 881/375/311 +f 594/378/314 950/379/315 1039/376/312 +f 878/328/266 950/379/315 176/331/269 +f 176/331/269 1040/380/316 726/332/270 +f 188/381/317 1040/380/316 950/379/315 +f 441/382/318 727/333/271 1040/380/316 +f 726/332/270 727/333/271 165/334/272 +f 442/383/319 438/335/273 177/384/320 +f 442/383/319 730/385/321 1041/386/322 +f 1041/386/322 190/387/323 524/388/324 +f 1041/386/322 178/337/275 438/335/273 +f 524/388/324 521/339/277 178/337/275 +f 524/388/324 811/389/325 1042/390/326 +f 1042/390/326 191/391/327 595/392/328 +f 1042/390/326 179/341/279 521/339/277 +f 595/392/328 592/343/281 179/341/279 +f 595/392/328 882/393/329 1043/394/330 +f 1043/394/330 192/395/331 665/396/332 +f 1043/394/330 180/345/283 592/343/281 +f 665/396/332 663/347/285 180/345/283 +f 665/396/332 951/397/333 1044/398/334 +f 1044/398/334 193/399/335 731/400/336 +f 1044/398/334 181/349/287 663/347/285 +f 731/400/336 728/351/289 181/349/287 +f 731/400/336 443/401/337 1045/402/338 +f 1045/402/338 194/403/339 812/404/340 +f 1045/402/338 182/353/291 728/351/289 +f 812/404/340 809/355/293 182/353/291 +f 812/404/340 525/405/341 1046/406/342 +f 1046/406/342 195/407/343 883/408/344 +f 1046/406/342 183/357/295 809/355/293 +f 183/360/295 1047/409/345 880/362/298 +f 195/410/343 1047/409/345 883/411/344 +f 596/412/346 952/413/347 1047/409/345 +f 880/362/298 952/413/347 184/365/301 +f 184/365/301 1048/414/348 949/366/302 +f 196/415/349 1048/414/348 952/413/347 +f 666/416/350 444/417/351 1048/414/348 +f 949/366/302 444/417/351 185/369/305 +f 185/369/305 1049/418/352 440/370/306 +f 197/419/353 1049/418/352 444/417/351 +f 732/420/354 526/421/355 1049/418/352 +f 440/370/306 526/421/355 186/373/309 +f 186/373/309 1050/422/356 523/374/310 +f 198/423/357 1050/422/356 526/421/355 +f 813/424/358 597/425/359 1050/422/356 +f 523/374/310 597/425/359 187/377/313 +f 187/377/313 1051/426/360 594/378/314 +f 199/427/361 1051/426/360 597/425/359 +f 884/428/362 667/429/363 1051/426/360 +f 594/378/314 667/429/363 188/381/317 +f 188/381/317 1052/430/364 441/382/318 +f 200/431/365 1052/430/364 667/429/363 +f 733/432/366 442/383/319 1052/430/364 +f 441/382/318 442/383/319 177/384/320 +f 734/433/367 730/385/321 189/434/368 +f 734/433/367 445/435/369 1053/436/370 +f 1053/436/370 202/437/371 814/438/372 +f 1053/436/370 190/387/323 730/385/321 +f 814/438/372 811/389/325 190/387/323 +f 814/438/372 527/439/373 1054/440/374 +f 1054/440/374 203/441/375 885/442/376 +f 1054/440/374 191/391/327 811/389/325 +f 885/442/376 882/393/329 191/391/327 +f 885/442/376 598/443/377 1055/444/378 +f 1055/444/378 204/445/379 953/446/380 +f 1055/444/378 192/395/331 882/393/329 +f 953/446/380 951/397/333 192/395/331 +f 953/446/380 668/447/381 1056/448/382 +f 1056/448/382 205/449/383 446/450/384 +f 1056/448/382 193/399/335 951/397/333 +f 446/450/384 443/401/337 193/399/335 +f 446/450/384 735/451/385 1057/452/386 +f 1057/452/386 206/453/387 528/454/388 +f 1057/452/386 194/403/339 443/401/337 +f 528/454/388 525/405/341 194/403/339 +f 528/454/388 815/455/389 1058/456/390 +f 1058/456/390 207/457/391 599/458/392 +f 1058/456/390 195/407/343 525/405/341 +f 195/410/343 1059/459/393 596/412/346 +f 207/460/391 1059/459/393 599/461/392 +f 886/462/394 669/463/395 1059/459/393 +f 596/412/346 669/463/395 196/415/349 +f 196/415/349 1060/464/396 666/416/350 +f 208/465/397 1060/464/396 669/463/395 +f 954/466/398 736/467/399 1060/464/396 +f 666/416/350 736/467/399 197/419/353 +f 197/419/353 1061/468/400 732/420/354 +f 209/469/401 1061/468/400 736/467/399 +f 447/470/402 816/471/403 1061/468/400 +f 732/420/354 816/471/403 198/423/357 +f 198/423/357 1062/472/404 813/424/358 +f 210/473/405 1062/472/404 816/471/403 +f 529/474/406 887/475/407 1062/472/404 +f 813/424/358 887/475/407 199/427/361 +f 199/427/361 1063/476/408 884/428/362 +f 211/477/409 1063/476/408 887/475/407 +f 600/478/410 955/479/411 1063/476/408 +f 884/428/362 955/479/411 200/431/365 +f 200/431/365 1064/480/412 733/432/366 +f 212/481/413 1064/480/412 955/479/411 +f 448/482/414 734/433/367 1064/480/412 +f 733/432/366 734/433/367 189/434/368 +f 449/483/415 445/435/369 201/484/416 +f 449/483/415 737/485/417 1065/486/418 +f 1065/486/418 214/487/419 530/488/420 +f 1065/486/418 202/437/371 445/435/369 +f 530/488/420 527/439/373 202/437/371 +f 530/488/420 817/489/421 1066/490/422 +f 1066/490/422 215/491/423 601/492/424 +f 1066/490/422 203/441/375 527/439/373 +f 601/492/424 598/443/377 203/441/375 +f 601/492/424 888/493/425 1067/494/426 +f 1067/494/426 216/495/427 670/496/428 +f 1067/494/426 204/445/379 598/443/377 +f 670/496/428 668/447/381 204/445/379 +f 670/496/428 956/497/429 1068/498/430 +f 1068/498/430 217/499/431 738/500/432 +f 1068/498/430 205/449/383 668/447/381 +f 738/500/432 735/451/385 205/449/383 +f 738/500/432 450/501/433 1069/502/434 +f 1069/502/434 218/503/435 818/504/436 +f 1069/502/434 206/453/387 735/451/385 +f 818/504/436 815/455/389 206/453/387 +f 818/504/436 531/505/437 1070/506/438 +f 1070/506/438 219/507/439 889/508/440 +f 1070/506/438 207/457/391 815/455/389 +f 207/460/391 1071/509/441 886/462/394 +f 219/510/439 1071/509/441 889/511/440 +f 602/512/442 957/513/443 1071/509/441 +f 886/462/394 957/513/443 208/465/397 +f 208/465/397 1072/514/444 954/466/398 +f 220/515/445 1072/514/444 957/513/443 +f 671/516/446 451/517/447 1072/514/444 +f 954/466/398 451/517/447 209/469/401 +f 209/469/401 1073/518/448 447/470/402 +f 221/519/449 1073/518/448 451/517/447 +f 739/520/450 532/521/451 1073/518/448 +f 447/470/402 532/521/451 210/473/405 +f 210/473/405 1074/522/452 529/474/406 +f 222/523/453 1074/522/452 532/521/451 +f 819/524/454 603/525/455 1074/522/452 +f 529/474/406 603/525/455 211/477/409 +f 211/477/409 1075/526/456 600/478/410 +f 223/527/457 1075/526/456 603/525/455 +f 890/528/458 672/529/459 1075/526/456 +f 600/478/410 672/529/459 212/481/413 +f 212/481/413 1076/530/460 448/482/414 +f 224/531/461 1076/530/460 672/529/459 +f 740/532/462 449/483/415 1076/530/460 +f 448/482/414 449/483/415 201/484/416 +f 741/533/463 737/485/417 213/534/464 +f 741/533/463 452/535/465 1077/536/466 +f 1077/536/466 226/537/467 820/538/468 +f 1077/536/466 214/487/419 737/485/417 +f 820/538/468 817/489/421 214/487/419 +f 820/538/468 533/539/469 1078/540/470 +f 1078/540/470 227/541/471 891/542/472 +f 1078/540/470 215/491/423 817/489/421 +f 891/542/472 888/493/425 215/491/423 +f 891/542/472 604/543/473 1079/544/474 +f 1079/544/474 228/545/475 958/546/476 +f 1079/544/474 216/495/427 888/493/425 +f 958/546/476 956/497/429 216/495/427 +f 958/546/476 673/547/477 1080/548/478 +f 1080/548/478 229/549/479 453/550/480 +f 1080/548/478 217/499/431 956/497/429 +f 453/550/480 450/501/433 217/499/431 +f 453/550/480 742/551/481 1081/552/482 +f 1081/552/482 230/553/483 534/554/484 +f 1081/552/482 218/503/435 450/501/433 +f 534/554/484 531/505/437 218/503/435 +f 534/554/484 821/555/485 1082/556/486 +f 1082/556/486 231/557/487 605/558/488 +f 1082/556/486 219/507/439 531/505/437 +f 219/510/439 1083/559/489 602/512/442 +f 231/560/487 1083/559/489 605/561/488 +f 892/562/490 674/563/491 1083/559/489 +f 602/512/442 674/563/491 220/515/445 +f 220/515/445 1084/564/492 671/516/446 +f 232/565/493 1084/564/492 674/563/491 +f 959/566/494 743/567/495 1084/564/492 +f 671/516/446 743/567/495 221/519/449 +f 221/519/449 1085/568/496 739/520/450 +f 233/569/497 1085/568/496 743/567/495 +f 454/570/498 822/571/499 1085/568/496 +f 739/520/450 822/571/499 222/523/453 +f 222/523/453 1086/572/500 819/524/454 +f 234/573/501 1086/572/500 822/571/499 +f 535/574/502 893/575/503 1086/572/500 +f 819/524/454 893/575/503 223/527/457 +f 223/527/457 1087/576/504 890/528/458 +f 235/577/505 1087/576/504 893/575/503 +f 606/578/506 960/579/507 1087/576/504 +f 890/528/458 960/579/507 224/531/461 +f 224/531/461 1088/580/508 740/532/462 +f 236/581/509 1088/580/508 960/579/507 +f 456/582/510 741/533/463 1088/580/508 +f 740/532/462 741/533/463 213/534/464 +f 457/583/511 452/535/465 225/584/512 +f 457/583/511 744/585/513 1089/586/514 +f 1089/586/514 238/587/515 536/588/516 +f 1089/586/514 226/537/467 452/535/465 +f 536/588/516 533/539/469 226/537/467 +f 536/588/516 824/589/517 1090/590/518 +f 1090/590/518 239/591/519 607/592/520 +f 1090/590/518 227/541/471 533/539/469 +f 607/592/520 604/543/473 227/541/471 +f 607/592/520 894/593/521 1091/594/522 +f 1091/594/522 240/595/523 675/596/524 +f 1091/594/522 228/545/475 604/543/473 +f 675/596/524 673/547/477 228/545/475 +f 675/596/524 961/597/525 1092/598/526 +f 1092/598/526 241/599/527 745/600/528 +f 1092/598/526 229/549/479 673/547/477 +f 745/600/528 742/551/481 229/549/479 +f 745/600/528 458/601/529 1093/602/530 +f 1093/602/530 242/603/531 825/604/532 +f 1093/602/530 230/553/483 742/551/481 +f 825/604/532 821/555/485 230/553/483 +f 825/604/532 537/605/533 1094/606/534 +f 1094/606/534 243/607/535 895/608/536 +f 1094/606/534 231/557/487 821/555/485 +f 231/560/487 1095/609/537 892/562/490 +f 243/610/535 1095/609/537 895/611/536 +f 608/612/538 962/613/539 1095/609/537 +f 892/562/490 962/613/539 232/565/493 +f 232/565/493 1096/614/540 959/566/494 +f 244/615/541 1096/614/540 962/613/539 +f 676/616/542 459/617/543 1096/614/540 +f 959/566/494 459/617/543 233/569/497 +f 233/569/497 1097/618/544 454/570/498 +f 245/619/545 1097/618/544 459/617/543 +f 746/620/546 538/621/547 1097/618/544 +f 454/570/498 538/621/547 234/573/501 +f 234/573/501 1098/622/548 535/574/502 +f 246/623/549 1098/622/548 538/621/547 +f 826/624/550 609/625/551 1098/622/548 +f 535/574/502 609/625/551 235/577/505 +f 235/577/505 1099/626/552 606/578/506 +f 247/627/553 1099/626/552 609/625/551 +f 896/628/554 677/629/555 1099/626/552 +f 606/578/506 677/629/555 236/581/509 +f 236/581/509 1100/630/556 456/582/510 +f 248/631/557 1100/630/556 677/629/555 +f 747/632/558 457/583/511 1100/630/556 +f 456/582/510 457/583/511 225/584/512 +f 748/633/559 744/585/513 237/634/560 +f 748/633/559 460/635/561 1101/636/562 +f 1101/636/562 250/637/563 827/638/564 +f 1101/636/562 238/587/515 744/585/513 +f 827/638/564 824/589/517 238/587/515 +f 827/638/564 539/639/565 1102/640/566 +f 1102/640/566 251/641/567 897/642/568 +f 1102/640/566 239/591/519 824/589/517 +f 897/642/568 894/593/521 239/591/519 +f 897/642/568 610/643/569 1103/644/570 +f 1103/644/570 252/645/571 963/646/572 +f 1103/644/570 240/595/523 894/593/521 +f 963/646/572 961/597/525 240/595/523 +f 963/646/572 678/647/573 1104/648/574 +f 1104/648/574 253/649/575 461/650/576 +f 1104/648/574 241/599/527 961/597/525 +f 461/650/576 458/601/529 241/599/527 +f 461/650/576 749/651/577 1105/652/578 +f 1105/652/578 254/653/579 540/654/580 +f 1105/652/578 242/603/531 458/601/529 +f 540/654/580 537/605/533 242/603/531 +f 540/654/580 828/655/581 1106/656/582 +f 1106/656/582 255/657/583 611/658/584 +f 1106/656/582 243/607/535 537/605/533 +f 243/610/535 1107/659/585 608/612/538 +f 255/660/583 1107/659/585 611/661/584 +f 898/662/586 679/663/587 1107/659/585 +f 608/612/538 679/663/587 244/615/541 +f 244/615/541 1108/664/588 676/616/542 +f 256/665/589 1108/664/588 679/663/587 +f 964/666/590 750/667/591 1108/664/588 +f 676/616/542 750/667/591 245/619/545 +f 245/619/545 1109/668/592 746/620/546 +f 257/669/593 1109/668/592 750/667/591 +f 462/670/594 829/671/595 1109/668/592 +f 746/620/546 829/671/595 246/623/549 +f 246/623/549 1110/672/596 826/624/550 +f 258/673/597 1110/672/596 829/671/595 +f 541/674/598 899/675/599 1110/672/596 +f 826/624/550 899/675/599 247/627/553 +f 247/627/553 1111/676/600 896/628/554 +f 259/677/601 1111/676/600 899/675/599 +f 612/678/602 965/679/603 1111/676/600 +f 896/628/554 965/679/603 248/631/557 +f 248/631/557 1112/680/604 747/632/558 +f 260/681/605 1112/680/604 965/679/603 +f 463/682/606 748/633/559 1112/680/604 +f 747/632/558 748/633/559 237/634/560 +f 464/683/607 460/635/561 249/684/608 +f 464/683/607 751/685/609 1113/686/610 +f 1113/686/610 262/687/611 542/688/612 +f 1113/686/610 250/637/563 460/635/561 +f 542/688/612 539/639/565 250/637/563 +f 542/688/612 830/689/613 1114/690/614 +f 1114/690/614 263/691/615 614/692/616 +f 1114/690/614 251/641/567 539/639/565 +f 614/692/616 610/643/569 251/641/567 +f 614/692/616 900/693/617 1115/694/618 +f 1115/694/618 264/695/619 680/696/620 +f 1115/694/618 252/645/571 610/643/569 +f 680/696/620 678/647/573 252/645/571 +f 680/696/620 967/697/621 1116/698/622 +f 1116/698/622 265/699/623 752/700/624 +f 1116/698/622 253/649/575 678/647/573 +f 752/700/624 749/651/577 253/649/575 +f 752/700/624 465/701/625 1117/702/626 +f 1117/702/626 266/703/627 831/704/628 +f 1117/702/626 254/653/579 749/651/577 +f 831/704/628 828/655/581 254/653/579 +f 831/704/628 543/705/629 1118/706/630 +f 1118/706/630 267/707/631 901/708/632 +f 1118/706/630 255/657/583 828/655/581 +f 255/660/583 1119/709/633 898/662/586 +f 267/710/631 1119/709/633 901/711/632 +f 615/712/634 968/713/635 1119/709/633 +f 898/662/586 968/713/635 256/665/589 +f 256/665/589 1120/714/636 964/666/590 +f 268/715/637 1120/714/636 968/713/635 +f 681/716/638 466/717/639 1120/714/636 +f 964/666/590 466/717/639 257/669/593 +f 257/669/593 1121/718/640 462/670/594 +f 269/719/641 1121/718/640 466/717/639 +f 753/720/642 544/721/643 1121/718/640 +f 462/670/594 544/721/643 258/673/597 +f 258/673/597 1122/722/644 541/674/598 +f 270/723/645 1122/722/644 544/721/643 +f 832/724/646 616/725/647 1122/722/644 +f 541/674/598 616/725/647 259/677/601 +f 259/677/601 1123/726/648 612/678/602 +f 271/727/649 1123/726/648 616/725/647 +f 902/728/650 682/729/651 1123/726/648 +f 612/678/602 682/729/651 260/681/605 +f 260/681/605 1124/730/652 463/682/606 +f 272/731/653 1124/730/652 682/729/651 +f 754/732/654 464/683/607 1124/730/652 +f 463/682/606 464/683/607 249/684/608 +f 755/733/655 751/685/609 261/734/656 +f 755/733/655 467/735/657 1125/736/658 +f 1125/736/658 274/737/659 833/738/660 +f 1125/736/658 262/687/611 751/685/609 +f 833/738/660 830/689/613 262/687/611 +f 833/738/660 545/739/661 1126/740/662 +f 1126/740/662 275/741/663 903/742/664 +f 1126/740/662 263/691/615 830/689/613 +f 903/742/664 900/693/617 263/691/615 +f 903/742/664 617/743/665 1127/744/666 +f 1127/744/666 276/745/667 969/746/668 +f 1127/744/666 264/695/619 900/693/617 +f 969/746/668 967/697/621 264/695/619 +f 969/746/668 683/747/669 1128/748/670 +f 1128/748/670 277/749/671 468/750/672 +f 1128/748/670 265/699/623 967/697/621 +f 468/750/672 465/701/625 265/699/623 +f 468/750/672 756/751/673 1129/752/674 +f 1129/752/674 278/753/675 546/754/676 +f 1129/752/674 266/703/627 465/701/625 +f 546/754/676 543/705/629 266/703/627 +f 546/754/676 834/755/677 1130/756/678 +f 1130/756/678 279/757/106 618/758/679 +f 1130/756/678 267/707/631 543/705/629 +f 267/710/631 1131/759/680 615/712/634 +f 279/760/106 1131/759/680 618/761/679 +f 904/762/681 684/763/682 1131/759/680 +f 615/712/634 684/763/682 268/715/637 +f 268/715/637 1132/764/683 681/716/638 +f 280/765/684 1132/764/683 684/763/682 +f 970/766/685 757/767/686 1132/764/683 +f 681/716/638 757/767/686 269/719/641 +f 269/719/641 1133/768/687 753/720/642 +f 281/769/688 1133/768/687 757/767/686 +f 469/770/689 835/771/690 1133/768/687 +f 753/720/642 835/771/690 270/723/645 +f 270/723/645 1134/772/691 832/724/646 +f 282/773/692 1134/772/691 835/771/690 +f 547/774/693 905/775/694 1134/772/691 +f 832/724/646 905/775/694 271/727/649 +f 271/727/649 1135/776/695 902/728/650 +f 283/777/696 1135/776/695 905/775/694 +f 619/778/697 971/779/698 1135/776/695 +f 902/728/650 971/779/698 272/731/653 +f 272/731/653 1136/780/699 754/732/654 +f 284/781/700 1136/780/699 971/779/698 +f 470/782/701 755/733/655 1136/780/699 +f 754/732/654 755/733/655 261/734/656 +f 471/783/140 467/784/657 273/785/141 +f 471/783/140 758/786/702 1137/787/703 +f 1137/787/703 286/788/704 548/789/705 +f 1137/787/703 274/790/659 467/784/657 +f 548/789/705 545/791/661 274/790/659 +f 548/789/705 836/792/706 1138/793/707 +f 1138/793/707 287/794/708 620/795/709 +f 1138/793/707 275/796/663 545/791/661 +f 620/795/709 617/797/665 275/796/663 +f 620/795/709 906/798/710 1139/799/711 +f 1139/799/711 288/800/712 685/801/713 +f 1139/799/711 276/802/667 617/797/665 +f 685/801/713 683/803/669 276/802/667 +f 685/801/713 972/804/714 1140/805/715 +f 1140/805/715 289/806/716 760/807/717 +f 1140/805/715 277/808/671 683/803/669 +f 760/807/717 756/809/673 277/808/671 +f 760/807/717 472/810/718 1141/811/719 +f 1141/811/719 290/812/720 837/813/721 +f 1141/811/719 278/814/675 756/809/673 +f 837/813/721 834/815/677 278/814/675 +f 837/813/721 550/816/722 1142/817/723 +f 1142/817/723 291/818/176 907/819/104 +f 1142/817/723 279/820/106 834/815/677 +f 279/821/106 1143/822/724 904/823/681 +f 291/824/176 1143/822/724 907/825/104 +f 621/826/725 973/827/726 1143/822/724 +f 904/823/681 973/827/726 280/828/684 +f 280/828/684 1144/829/727 970/830/685 +f 292/831/728 1144/829/727 973/827/726 +f 686/832/729 473/833/730 1144/829/727 +f 970/830/685 473/833/730 281/834/688 +f 281/834/688 1145/835/731 469/836/689 +f 293/837/732 1145/835/731 473/833/730 +f 761/838/733 551/839/734 1145/835/731 +f 469/836/689 551/839/734 282/840/692 +f 282/840/692 1146/841/735 547/842/693 +f 294/843/736 1146/841/735 551/839/734 +f 838/844/737 622/845/738 1146/841/735 +f 547/842/693 622/845/738 283/846/696 +f 283/846/696 1147/847/739 619/848/697 +f 295/849/740 1147/847/739 622/845/738 +f 908/850/741 687/851/742 1147/847/739 +f 619/848/697 687/851/742 284/852/700 +f 284/852/700 1148/853/743 470/854/701 +f 296/855/744 1148/853/743 687/851/742 +f 762/856/745 471/783/140 1148/853/743 +f 470/854/701 471/783/140 273/785/141 +f 763/857/200 758/786/702 285/858/139 +f 763/857/200 474/859/746 1149/860/747 +f 1149/860/747 298/861/748 839/862/749 +f 1149/860/747 286/788/704 758/786/702 +f 839/862/749 836/792/706 286/788/704 +f 839/862/749 552/863/750 1150/864/751 +f 1150/864/751 299/865/752 909/866/753 +f 1150/864/751 287/794/708 836/792/706 +f 909/866/753 906/798/710 287/794/708 +f 909/866/753 623/867/754 1151/868/755 +f 1151/868/755 300/869/756 974/870/757 +f 1151/868/755 288/800/712 906/798/710 +f 974/870/757 972/804/714 288/800/712 +f 974/870/757 688/871/758 1152/872/759 +f 1152/872/759 301/873/760 475/874/761 +f 1152/872/759 289/806/716 972/804/714 +f 475/874/761 472/810/718 289/806/716 +f 475/874/761 764/875/762 1153/876/763 +f 1153/876/763 302/877/764 553/878/765 +f 1153/876/763 290/812/720 472/810/718 +f 553/878/765 550/816/722 290/812/720 +f 553/878/765 840/879/766 1154/880/767 +f 1154/880/767 303/881/224 624/882/175 +f 1154/880/767 291/818/176 550/816/722 +f 291/824/176 1155/883/768 621/826/725 +f 303/884/224 1155/883/768 624/885/175 +f 910/886/769 689/887/770 1155/883/768 +f 621/826/725 689/887/770 292/831/728 +f 292/831/728 1156/888/771 686/832/729 +f 304/889/772 1156/888/771 689/887/770 +f 975/890/773 765/891/774 1156/888/771 +f 686/832/729 765/891/774 293/837/732 +f 293/837/732 1157/892/775 761/838/733 +f 305/893/776 1157/892/775 765/891/774 +f 476/894/777 841/895/778 1157/892/775 +f 761/838/733 841/895/778 294/843/736 +f 294/843/736 1158/896/779 838/844/737 +f 306/897/780 1158/896/779 841/895/778 +f 554/898/781 911/899/782 1158/896/779 +f 838/844/737 911/899/782 295/849/740 +f 295/849/740 1159/900/783 908/850/741 +f 307/901/784 1159/900/783 911/899/782 +f 625/902/785 976/903/786 1159/900/783 +f 908/850/741 976/903/786 296/855/744 +f 296/855/744 1160/904/787 762/856/745 +f 308/905/788 1160/904/787 976/903/786 +f 477/906/789 763/857/200 1160/904/787 +f 762/856/745 763/857/200 285/858/139 +f 478/907/248 474/859/746 297/908/199 +f 478/907/248 766/909/790 1161/910/791 +f 1161/910/791 310/911/792 555/912/793 +f 1161/910/791 298/861/748 474/859/746 +f 555/912/793 552/863/750 298/861/748 +f 555/912/793 842/913/794 1162/914/795 +f 1162/914/795 311/915/796 626/916/797 +f 1162/914/795 299/865/752 552/863/750 +f 626/916/797 623/867/754 299/865/752 +f 626/916/797 912/917/798 1163/918/799 +f 1163/918/799 312/919/800 690/920/801 +f 1163/918/799 300/869/756 623/867/754 +f 690/920/801 688/871/758 300/869/756 +f 690/920/801 977/921/802 1164/922/803 +f 1164/922/803 313/923/804 767/924/805 +f 1164/922/803 301/873/760 688/871/758 +f 767/924/805 764/875/762 301/873/760 +f 767/924/805 479/925/806 1165/926/807 +f 1165/926/807 314/927/808 843/928/809 +f 1165/926/807 302/877/764 764/875/762 +f 843/928/809 840/879/766 302/877/764 +f 843/928/809 556/929/810 1166/930/811 +f 1166/930/811 315/931/272 914/932/223 +f 1166/930/811 303/881/224 840/879/766 +f 303/884/224 1167/933/812 910/886/769 +f 315/934/272 1167/933/812 914/935/223 +f 627/936/813 978/937/814 1167/933/812 +f 910/886/769 978/937/814 304/889/772 +f 304/889/772 1168/938/815 975/890/773 +f 316/939/816 1168/938/815 978/937/814 +f 692/940/817 480/941/818 1168/938/815 +f 975/890/773 480/941/818 305/893/776 +f 305/893/776 1169/942/819 476/894/777 +f 317/943/820 1169/942/819 480/941/818 +f 768/944/821 557/945/822 1169/942/819 +f 476/894/777 557/945/822 306/897/780 +f 306/897/780 1170/946/823 554/898/781 +f 318/947/824 1170/946/823 557/945/822 +f 844/948/825 628/949/826 1170/946/823 +f 554/898/781 628/949/826 307/901/784 +f 307/901/784 1171/950/827 625/902/785 +f 319/951/828 1171/950/827 628/949/826 +f 915/952/829 693/953/830 1171/950/827 +f 625/902/785 693/953/830 308/905/788 +f 308/905/788 1172/954/831 477/906/789 +f 320/955/832 1172/954/831 693/953/830 +f 769/956/833 478/907/248 1172/954/831 +f 477/906/789 478/907/248 297/908/199 +f 770/957/296 766/909/790 309/958/247 +f 770/957/296 481/959/834 1173/960/835 +f 1173/960/835 322/961/836 845/962/837 +f 1173/960/835 310/911/792 766/909/790 +f 845/962/837 842/913/794 310/911/792 +f 845/962/837 558/963/838 1174/964/839 +f 1174/964/839 323/965/840 916/966/841 +f 1174/964/839 311/915/796 842/913/794 +f 916/966/841 912/917/798 311/915/796 +f 916/966/841 629/967/842 1175/968/843 +f 1175/968/843 324/969/844 979/970/845 +f 1175/968/843 312/919/800 912/917/798 +f 979/970/845 977/921/802 312/919/800 +f 979/970/845 694/971/846 1176/972/847 +f 1176/972/847 325/973/848 482/974/849 +f 1176/972/847 313/923/804 977/921/802 +f 482/974/849 479/925/806 313/923/804 +f 482/974/849 771/975/850 1177/976/851 +f 1177/976/851 326/977/852 559/978/853 +f 1177/976/851 314/927/808 479/925/806 +f 559/978/853 556/929/810 314/927/808 +f 559/978/853 846/979/854 1178/980/855 +f 1178/980/855 327/981/320 630/982/271 +f 1178/980/855 315/931/272 556/929/810 +f 315/934/272 1179/983/856 627/936/813 +f 327/984/320 1179/983/856 630/985/271 +f 917/986/857 695/987/858 1179/983/856 +f 627/936/813 695/987/858 316/939/816 +f 316/939/816 1180/988/859 692/940/817 +f 328/989/860 1180/988/859 695/987/858 +f 980/990/861 772/991/862 1180/988/859 +f 692/940/817 772/991/862 317/943/820 +f 317/943/820 1181/992/863 768/944/821 +f 329/993/864 1181/992/863 772/991/862 +f 483/994/865 847/995/866 1181/992/863 +f 768/944/821 847/995/866 318/947/824 +f 318/947/824 1182/996/867 844/948/825 +f 330/997/868 1182/996/867 847/995/866 +f 560/998/869 918/999/870 1182/996/867 +f 844/948/825 918/999/870 319/951/828 +f 319/951/828 1183/1000/871 915/952/829 +f 331/1001/872 1183/1000/871 918/999/870 +f 631/1002/873 981/1003/874 1183/1000/871 +f 915/952/829 981/1003/874 320/955/832 +f 320/955/832 1184/1004/875 769/956/833 +f 332/1005/876 1184/1004/875 981/1003/874 +f 484/1006/877 770/957/296 1184/1004/875 +f 769/956/833 770/957/296 309/958/247 +f 485/1007/344 481/959/834 321/1008/295 +f 485/1007/344 773/1009/878 1185/1010/879 +f 1185/1010/879 334/1011/880 561/1012/881 +f 1185/1010/879 322/961/836 481/959/834 +f 561/1012/881 558/963/838 322/961/836 +f 561/1012/881 848/1013/882 1186/1014/883 +f 1186/1014/883 335/1015/884 632/1016/885 +f 1186/1014/883 323/965/840 558/963/838 +f 632/1016/885 629/967/842 323/965/840 +f 632/1016/885 919/1017/886 1187/1018/887 +f 1187/1018/887 336/1019/888 696/1020/889 +f 1187/1018/887 324/969/844 629/967/842 +f 696/1020/889 694/971/846 324/969/844 +f 696/1020/889 982/1021/890 1188/1022/891 +f 1188/1022/891 337/1023/892 774/1024/893 +f 1188/1022/891 325/973/848 694/971/846 +f 774/1024/893 771/975/850 325/973/848 +f 774/1024/893 486/1025/894 1189/1026/895 +f 1189/1026/895 338/1027/896 849/1028/897 +f 1189/1026/895 326/977/852 771/975/850 +f 849/1028/897 846/979/854 326/977/852 +f 849/1028/897 562/1029/898 1190/1030/899 +f 1190/1030/899 339/1031/368 920/1032/319 +f 1190/1030/899 327/981/320 846/979/854 +f 327/984/320 1191/1033/900 917/986/857 +f 339/1034/368 1191/1033/900 920/1035/319 +f 633/1036/901 983/1037/902 1191/1033/900 +f 917/986/857 983/1037/902 328/989/860 +f 328/989/860 1192/1038/903 980/990/861 +f 340/1039/904 1192/1038/903 983/1037/902 +f 697/1040/905 488/1041/906 1192/1038/903 +f 980/990/861 488/1041/906 329/993/864 +f 329/993/864 1193/1042/907 483/994/865 +f 341/1043/908 1193/1042/907 488/1041/906 +f 775/1044/909 563/1045/910 1193/1042/907 +f 483/994/865 563/1045/910 330/997/868 +f 330/997/868 1194/1046/911 560/998/869 +f 342/1047/912 1194/1046/911 563/1045/910 +f 851/1048/913 634/1049/914 1194/1046/911 +f 560/998/869 634/1049/914 331/1001/872 +f 331/1001/872 1195/1050/915 631/1002/873 +f 343/1051/916 1195/1050/915 634/1049/914 +f 921/1052/917 698/1053/918 1195/1050/915 +f 631/1002/873 698/1053/918 332/1005/876 +f 332/1005/876 1196/1054/919 484/1006/877 +f 344/1055/920 1196/1054/919 698/1053/918 +f 776/1056/921 485/1007/344 1196/1054/919 +f 484/1006/877 485/1007/344 321/1008/295 +f 777/1057/392 773/1009/878 333/1058/343 +f 777/1057/392 489/1059/922 1197/1060/923 +f 1197/1060/923 346/1061/924 852/1062/925 +f 1197/1060/923 334/1011/880 773/1009/878 +f 852/1062/925 848/1013/882 334/1011/880 +f 852/1062/925 564/1063/926 1198/1064/927 +f 1198/1064/927 347/1065/928 922/1066/929 +f 1198/1064/927 335/1015/884 848/1013/882 +f 922/1066/929 919/1017/886 335/1015/884 +f 922/1066/929 635/1067/930 1199/1068/931 +f 1199/1068/931 348/1069/932 984/1070/933 +f 1199/1068/931 336/1019/888 919/1017/886 +f 984/1070/933 982/1021/890 336/1019/888 +f 984/1070/933 699/1071/934 1200/1072/935 +f 1200/1072/935 349/1073/936 490/1074/937 +f 1200/1072/935 337/1023/892 982/1021/890 +f 490/1074/937 486/1025/894 337/1023/892 +f 490/1074/937 778/1075/938 1201/1076/939 +f 1201/1076/939 350/1077/940 565/1078/941 +f 1201/1076/939 338/1027/896 486/1025/894 +f 565/1078/941 562/1029/898 338/1027/896 +f 565/1078/941 853/1079/942 1202/1080/943 +f 1202/1080/943 351/1081/416 636/1082/367 +f 1202/1080/943 339/1031/368 562/1029/898 +f 339/1034/368 1203/1083/944 633/1036/901 +f 351/1084/416 1203/1083/944 636/1085/367 +f 923/1086/945 700/1087/946 1203/1083/944 +f 633/1036/901 700/1087/946 340/1039/904 +f 340/1039/904 1204/1088/947 697/1040/905 +f 352/1089/948 1204/1088/947 700/1087/946 +f 985/1090/949 779/1091/950 1204/1088/947 +f 697/1040/905 779/1091/950 341/1043/908 +f 341/1043/908 1205/1092/951 775/1044/909 +f 353/1093/952 1205/1092/951 779/1091/950 +f 491/1094/953 854/1095/954 1205/1092/951 +f 775/1044/909 854/1095/954 342/1047/912 +f 342/1047/912 1206/1096/955 851/1048/913 +f 354/1097/956 1206/1096/955 854/1095/954 +f 566/1098/957 924/1099/958 1206/1096/955 +f 851/1048/913 924/1099/958 343/1051/916 +f 343/1051/916 1207/1100/959 921/1052/917 +f 355/1101/960 1207/1100/959 924/1099/958 +f 637/1102/961 986/1103/962 1207/1100/959 +f 921/1052/917 986/1103/962 344/1055/920 +f 344/1055/920 1208/1104/963 776/1056/921 +f 356/1105/964 1208/1104/963 986/1103/962 +f 492/1106/965 777/1057/392 1208/1104/963 +f 776/1056/921 777/1057/392 333/1058/343 +f 493/1107/440 489/1059/922 345/1108/391 +f 493/1107/440 780/1109/966 1209/1110/967 +f 1209/1110/967 358/1111/968 567/1112/969 +f 1209/1110/967 346/1061/924 489/1059/922 +f 567/1112/969 564/1063/926 346/1061/924 +f 567/1112/969 855/1113/970 1210/1114/971 +f 1210/1114/971 359/1115/972 638/1116/973 +f 1210/1114/971 347/1065/928 564/1063/926 +f 638/1116/973 635/1067/930 347/1065/928 +f 638/1116/973 925/1117/974 1211/1118/975 +f 1211/1118/975 360/1119/976 701/1120/977 +f 1211/1118/975 348/1069/932 635/1067/930 +f 701/1120/977 699/1071/934 348/1069/932 +f 701/1120/977 987/1121/978 1212/1122/979 +f 1212/1122/979 361/1123/980 781/1124/981 +f 1212/1122/979 349/1073/936 699/1071/934 +f 781/1124/981 778/1075/938 349/1073/936 +f 781/1124/981 494/1125/982 1213/1126/983 +f 1213/1126/983 362/1127/984 856/1128/985 +f 1213/1126/983 350/1077/940 778/1075/938 +f 856/1128/985 853/1079/942 350/1077/940 +f 856/1128/985 568/1129/986 1214/1130/987 +f 1214/1130/987 363/1131/464 926/1132/415 +f 1214/1130/987 351/1081/416 853/1079/942 +f 351/1084/416 1215/1133/988 923/1086/945 +f 363/1134/464 1215/1133/988 926/1135/415 +f 639/1136/989 988/1137/990 1215/1133/988 +f 923/1086/945 988/1137/990 352/1089/948 +f 352/1089/948 1216/1138/991 985/1090/949 +f 364/1139/992 1216/1138/991 988/1137/990 +f 702/1140/993 495/1141/994 1216/1138/991 +f 985/1090/949 495/1141/994 353/1093/952 +f 353/1093/952 1217/1142/995 491/1094/953 +f 365/1143/996 1217/1142/995 495/1141/994 +f 782/1144/997 569/1145/998 1217/1142/995 +f 491/1094/953 569/1145/998 354/1097/956 +f 354/1097/956 1218/1146/999 566/1098/957 +f 366/1147/1000 1218/1146/999 569/1145/998 +f 857/1148/1001 641/1149/1002 1218/1146/999 +f 566/1098/957 641/1149/1002 355/1101/960 +f 355/1101/960 1219/1150/1003 637/1102/961 +f 367/1151/1004 1219/1150/1003 641/1149/1002 +f 927/1152/1005 703/1153/1006 1219/1150/1003 +f 637/1102/961 703/1153/1006 356/1105/964 +f 356/1105/964 1220/1154/1007 492/1106/965 +f 368/1155/1008 1220/1154/1007 703/1153/1006 +f 783/1156/1009 493/1107/440 1220/1154/1007 +f 492/1106/965 493/1107/440 345/1108/391 +f 784/1157/488 780/1109/966 357/1158/439 +f 784/1157/488 496/1159/1010 1221/1160/1011 +f 1221/1160/1011 370/1161/1012 858/1162/1013 +f 1221/1160/1011 358/1111/968 780/1109/966 +f 858/1162/1013 855/1113/970 358/1111/968 +f 858/1162/1013 570/1163/1014 1222/1164/1015 +f 1222/1164/1015 371/1165/1016 928/1166/1017 +f 1222/1164/1015 359/1115/972 855/1113/970 +f 928/1166/1017 925/1117/974 359/1115/972 +f 928/1166/1017 642/1167/1018 1223/1168/1019 +f 1223/1168/1019 372/1169/1020 990/1170/1021 +f 1223/1168/1019 360/1119/976 925/1117/974 +f 990/1170/1021 987/1121/978 360/1119/976 +f 990/1170/1021 704/1171/1022 1224/1172/1023 +f 1224/1172/1023 373/1173/1024 497/1174/1025 +f 1224/1172/1023 361/1123/980 987/1121/978 +f 497/1174/1025 494/1125/982 361/1123/980 +f 497/1174/1025 785/1175/1026 1225/1176/1027 +f 1225/1176/1027 374/1177/1028 571/1178/1029 +f 1225/1176/1027 362/1127/984 494/1125/982 +f 571/1178/1029 568/1129/986 362/1127/984 +f 571/1178/1029 859/1179/1030 1226/1180/1031 +f 1226/1180/1031 375/1181/512 643/1182/463 +f 1226/1180/1031 363/1131/464 568/1129/986 +f 363/1134/464 1227/1183/1032 639/1136/989 +f 375/1184/512 1227/1183/1032 643/1185/463 +f 929/1186/1033 705/1187/1034 1227/1183/1032 +f 639/1136/989 705/1187/1034 364/1139/992 +f 364/1139/992 1228/1188/1035 702/1140/993 +f 376/1189/1036 1228/1188/1035 705/1187/1034 +f 991/1190/1037 786/1191/1038 1228/1188/1035 +f 702/1140/993 786/1191/1038 365/1143/996 +f 365/1143/996 1229/1192/1039 782/1144/997 +f 377/1193/1040 1229/1192/1039 786/1191/1038 +f 498/1194/1041 860/1195/1042 1229/1192/1039 +f 782/1144/997 860/1195/1042 366/1147/1000 +f 366/1147/1000 1230/1196/1043 857/1148/1001 +f 378/1197/1044 1230/1196/1043 860/1195/1042 +f 572/1198/1045 930/1199/1046 1230/1196/1043 +f 857/1148/1001 930/1199/1046 367/1151/1004 +f 367/1151/1004 1231/1200/1047 927/1152/1005 +f 379/1201/1048 1231/1200/1047 930/1199/1046 +f 644/1202/1049 992/1203/1050 1231/1200/1047 +f 927/1152/1005 992/1203/1050 368/1155/1008 +f 368/1155/1008 1232/1204/1051 783/1156/1009 +f 380/1205/1052 1232/1204/1051 992/1203/1050 +f 499/1206/1053 784/1157/488 1232/1204/1051 +f 783/1156/1009 784/1157/488 357/1158/439 +f 500/1207/1054 496/1159/1010 369/1208/487 +f 500/1207/1054 787/1209/1055 1233/1210/1056 +f 1233/1210/1056 382/1211/1057 573/1212/1058 +f 1233/1210/1056 370/1161/1012 496/1159/1010 +f 573/1212/1058 570/1163/1014 370/1161/1012 +f 573/1212/1058 861/1213/1059 1234/1214/1060 +f 1234/1214/1060 383/1215/1061 645/1216/1062 +f 1234/1214/1060 371/1165/1016 570/1163/1014 +f 645/1216/1062 642/1167/1018 371/1165/1016 +f 645/1216/1062 931/1217/1063 1235/1218/1064 +f 1235/1218/1064 384/1219/1065 706/1220/1066 +f 1235/1218/1064 372/1169/1020 642/1167/1018 +f 706/1220/1066 704/1171/1022 372/1169/1020 +f 706/1220/1066 862/1221/1067 1236/1222/1068 +f 1236/1222/1068 385/1223/1069 788/1224/1070 +f 1236/1222/1068 373/1173/1024 704/1171/1022 +f 788/1224/1070 785/1175/1026 373/1173/1024 +f 788/1224/1070 501/1225/1071 1237/1226/1072 +f 1237/1226/1072 386/1227/1073 707/1228/1074 +f 1237/1226/1072 374/1177/1028 785/1175/1026 +f 707/1228/1074 859/1179/1030 374/1177/1028 +f 707/1228/1074 418/1229/1075 1238/1230/1076 +f 1238/1230/1076 387/1231/560 932/1232/511 +f 1238/1230/1076 375/1181/512 859/1179/1030 +f 375/1184/512 1239/1233/1077 929/1186/1033 +f 387/1234/560 1239/1233/1077 932/1235/511 +f 646/1236/1078 863/1237/1079 1239/1233/1077 +f 929/1186/1033 863/1237/1079 376/1189/1036 +f 376/1189/1036 1240/1238/1080 991/1190/1037 +f 388/1239/1081 1240/1238/1080 863/1237/1079 +f 575/1240/1082 503/1241/1083 1240/1238/1080 +f 991/1190/1037 503/1241/1083 377/1193/1040 +f 377/1193/1040 1241/1242/1084 498/1194/1041 +f 389/1243/1085 1241/1242/1084 503/1241/1083 +f 789/1244/1086 419/1245/1087 1241/1242/1084 +f 498/1194/1041 419/1245/1087 378/1197/1044 +f 378/1197/1044 1242/1246/1088 572/1198/1045 +f 390/1247/1089 1242/1246/1088 419/1245/1087 +f 709/1248/1090 648/1249/1091 1242/1246/1088 +f 572/1198/1045 648/1249/1091 379/1201/1048 +f 379/1201/1048 1243/1250/1092 644/1202/1049 +f 391/1251/1093 1243/1250/1092 648/1249/1091 +f 933/1252/1094 576/1253/1095 1243/1250/1092 +f 644/1202/1049 576/1253/1095 380/1205/1052 +f 380/1205/1052 1244/1254/1096 499/1206/1053 +f 392/1255/1097 1244/1254/1096 576/1253/1095 +f 791/1256/1098 500/1207/1054 1244/1254/1096 +f 499/1206/1053 500/1207/1054 369/1208/487 +f 792/1257/584 787/1209/1055 381/1258/535 +f 792/1257/584 504/1259/1099 1245/1260/1100 +f 1245/1260/1100 394/1261/1101 710/1262/1102 +f 1245/1260/1100 382/1211/1057 787/1209/1055 +f 710/1262/1102 861/1213/1059 382/1211/1057 +f 710/1262/1102 421/1263/1103 1246/1264/1104 +f 1246/1264/1104 395/1265/1105 935/1266/1106 +f 1246/1264/1104 383/1215/1061 861/1213/1059 +f 935/1266/1106 931/1217/1063 383/1215/1061 +f 935/1266/1106 649/1267/1107 1247/1268/1108 +f 1247/1268/1108 396/1269/1109 865/1270/1110 +f 1247/1268/1108 384/1219/1065 931/1217/1063 +f 865/1270/1110 862/1221/1067 384/1219/1065 +f 865/1270/1110 578/1271/1111 1248/1272/1112 +f 1248/1272/1112 397/1273/1113 506/1274/1114 +f 1248/1272/1112 385/1223/1069 862/1221/1067 +f 506/1274/1114 501/1225/1071 385/1223/1069 +f 506/1274/1114 793/1275/1115 1249/1276/1116 +f 1249/1276/1116 398/1277/1117 424/1278/1118 +f 1249/1276/1116 386/1227/1073 501/1225/1071 +f 424/1278/1118 418/1229/1075 386/1227/1073 +f 424/1278/1118 712/1279/1119 1250/1280/1120 +f 1250/1280/1120 399/1281/608 650/1282/559 +f 1250/1280/1120 387/1231/560 418/1229/1075 +f 387/1234/560 1251/1283/1121 646/1236/1078 +f 399/1284/608 1251/1283/1121 650/1285/559 +f 936/1286/1122 580/1287/1123 1251/1283/1121 +f 646/1236/1078 580/1287/1123 388/1239/1081 +f 388/1239/1081 1252/1288/1124 575/1240/1082 +f 400/1289/1125 1252/1288/1124 580/1287/1123 +f 867/1290/1126 795/1291/1127 1252/1288/1124 +f 575/1240/1082 795/1291/1127 389/1243/1085 +f 389/1243/1085 1253/1292/1128 789/1244/1086 +f 401/1293/1129 1253/1292/1128 795/1291/1127 +f 508/1294/1130 714/1295/1131 1253/1292/1128 +f 789/1244/1086 714/1295/1131 390/1247/1089 +f 390/1247/1089 1254/1296/1132 709/1248/1090 +f 402/1297/1133 1254/1296/1132 714/1295/1131 +f 426/1298/1134 938/1299/1135 1254/1296/1132 +f 709/1248/1090 938/1299/1135 391/1251/1093 +f 391/1251/1093 1255/1300/1136 933/1252/1094 +f 403/1301/1137 1255/1300/1136 938/1299/1135 +f 652/1302/1138 869/1303/1139 1255/1300/1136 +f 933/1252/1094 869/1303/1139 392/1255/1097 +f 392/1255/1097 1256/1304/1140 791/1256/1098 +f 404/1305/1141 1256/1304/1140 869/1303/1139 +f 510/1306/1142 792/1257/584 1256/1304/1140 +f 791/1256/1098 792/1257/584 381/1258/535 +f 511/1307/632 504/1259/1099 393/1308/583 +f 511/1307/632 797/1309/1143 1257/1310/1144 +f 1257/1310/1144 406/1311/1145 428/1312/1146 +f 1257/1310/1144 394/1261/1101 504/1259/1099 +f 428/1312/1146 421/1263/1103 394/1261/1101 +f 428/1312/1146 716/1313/1147 1258/1314/1148 +f 1258/1314/1148 407/1315/1149 654/1316/1150 +f 1258/1314/1148 395/1265/1105 421/1263/1103 +f 654/1316/1150 649/1267/1107 395/1265/1105 +f 654/1316/1150 940/1317/1151 1259/1318/1152 +f 1259/1318/1152 408/1319/1153 583/1320/1154 +f 1259/1318/1152 396/1269/1109 649/1267/1107 +f 583/1320/1154 578/1271/1111 396/1269/1109 +f 583/1320/1154 871/1321/1155 1260/1322/1156 +f 1260/1322/1156 409/1323/1157 799/1324/1158 +f 1260/1322/1156 397/1273/1113 578/1271/1111 +f 799/1324/1158 793/1275/1115 397/1273/1113 +f 799/1324/1158 513/1325/1159 1261/1326/1160 +f 1261/1326/1160 410/1327/1161 719/1328/1162 +f 1261/1326/1160 398/1277/1117 793/1275/1115 +f 719/1328/1162 712/1279/1119 398/1277/1117 +f 719/1328/1162 430/1329/1163 1262/1330/1164 +f 1262/1330/1164 411/1331/656 941/1332/607 +f 1262/1330/1164 399/1281/608 712/1279/1119 +f 399/1284/608 1263/1333/1165 936/1286/1122 +f 411/1334/656 1263/1333/1165 941/1335/607 +f 656/1336/1166 873/1337/1167 1263/1333/1165 +f 936/1286/1122 873/1337/1167 400/1289/1125 +f 400/1289/1125 1264/1338/1168 867/1290/1126 +f 412/1339/1169 1264/1338/1168 873/1337/1167 +f 585/1340/1170 515/1341/1171 1264/1338/1168 +f 867/1290/1126 515/1341/1171 401/1293/1129 +f 401/1293/1129 1265/1342/1172 508/1294/1130 +f 413/1343/1173 1265/1342/1172 515/1341/1171 +f 801/1344/1174 432/1345/1175 1265/1342/1172 +f 508/1294/1130 432/1345/1175 402/1297/1133 +f 402/1297/1133 1266/1346/1176 426/1298/1134 +f 414/1347/1177 1266/1346/1176 432/1345/1175 +f 721/1348/1178 658/1349/1179 1266/1346/1176 +f 426/1298/1134 658/1349/1179 403/1301/1137 +f 403/1301/1137 1267/1350/1180 652/1302/1138 +f 415/1351/1181 1267/1350/1180 658/1349/1179 +f 943/1352/1182 587/1353/1183 1267/1350/1180 +f 652/1302/1138 587/1353/1183 404/1305/1141 +f 404/1305/1141 1268/1354/1184 510/1306/1142 +f 416/1355/1185 1268/1354/1184 587/1353/1183 +f 803/1356/1186 511/1307/632 1268/1354/1184 +f 510/1306/1142 511/1307/632 393/1308/583 +f 823/1357/679 797/1309/1143 405/1358/631 +f 823/1357/679 417/160/105 1269/1359/1187 +f 1269/1359/1187 130/166/111 455/1360/1188 +f 1269/1359/1187 406/1311/1145 797/1309/1143 +f 455/1360/1188 716/1313/1147 406/1311/1145 +f 455/1360/1188 502/167/112 1270/1361/1189 +f 1270/1361/1189 131/172/117 966/1362/1190 +f 1270/1361/1189 407/1315/1149 716/1313/1147 +f 966/1362/1190 940/1317/1151 407/1315/1149 +f 966/1362/1190 574/173/118 1271/1363/1191 +f 1271/1363/1191 132/178/123 613/1364/1192 +f 1271/1363/1191 408/1319/1153 940/1317/1151 +f 613/1364/1192 871/1321/1155 408/1319/1153 +f 613/1364/1192 647/179/124 1272/1365/1193 +f 1272/1365/1193 133/184/129 549/1366/1194 +f 1272/1365/1193 409/1323/1157 871/1321/1155 +f 549/1366/1194 513/1325/1159 409/1323/1157 +f 549/1366/1194 708/185/130 1273/1367/1195 +f 1273/1367/1195 134/190/135 759/1368/1196 +f 1273/1367/1195 410/1327/1161 513/1325/1159 +f 759/1368/1196 430/1329/1163 410/1327/1161 +f 759/1368/1196 790/191/136 1274/1369/1197 +f 1274/1369/1197 135/196/141 691/1370/655 +f 1274/1369/1197 411/1331/656 430/1329/1163 +f 411/1334/656 1275/1371/1198 656/1336/1166 +f 135/197/141 1275/1371/1198 691/1372/655 +f 864/199/143 913/1373/1199 1275/1371/1198 +f 656/1336/1166 913/1373/1199 412/1339/1169 +f 412/1339/1169 1276/1374/1200 585/1340/1170 +f 136/204/146 1276/1374/1200 913/1373/1199 +f 934/206/148 850/1375/1201 1276/1374/1200 +f 585/1340/1170 850/1375/1201 413/1343/1173 +f 413/1343/1173 1277/1376/1202 801/1344/1174 +f 137/210/152 1277/1376/1202 850/1375/1201 +f 420/212/154 487/1377/1203 1277/1376/1202 +f 801/1344/1174 487/1377/1203 414/1347/1177 +f 414/1347/1177 1278/1378/1204 721/1348/1178 +f 138/216/158 1278/1378/1204 487/1377/1203 +f 505/218/160 989/1379/1205 1278/1378/1204 +f 721/1348/1178 989/1379/1205 415/1351/1181 +f 415/1351/1181 1279/1380/1206 943/1352/1182 +f 139/222/164 1279/1380/1206 989/1379/1205 +f 577/224/166 640/1381/1207 1279/1380/1206 +f 943/1352/1182 640/1381/1207 416/1355/1185 +f 416/1355/1185 1280/1382/1208 803/1356/1186 +f 140/228/170 1280/1382/1208 640/1381/1207 +f 422/230/172 823/1357/679 1280/1382/1208 +f 803/1356/1186 823/1357/679 405/1358/631 +f 423/159/104 993/163/108 417/160/105 +f 423/159/104 141/234/176 711/162/107 +f 993/163/108 711/162/107 142/164/109 +f 993/163/108 507/165/110 130/166/111 +f 507/165/110 994/169/114 502/167/112 +f 507/165/110 142/164/109 794/168/113 +f 994/169/114 794/168/113 143/170/115 +f 994/169/114 579/171/116 131/172/117 +f 579/171/116 995/175/120 574/173/118 +f 579/171/116 143/170/115 866/174/119 +f 995/175/120 866/174/119 144/176/121 +f 995/175/120 651/177/122 132/178/123 +f 651/177/122 996/181/126 647/179/124 +f 651/177/122 144/176/121 937/180/125 +f 996/181/126 937/180/125 145/182/127 +f 996/181/126 713/183/128 133/184/129 +f 713/183/128 997/187/132 708/185/130 +f 713/183/128 145/182/127 425/186/131 +f 997/187/132 425/186/131 146/188/133 +f 997/187/132 796/189/134 134/190/135 +f 796/189/134 998/193/138 790/191/136 +f 796/189/134 146/188/133 509/192/137 +f 998/193/138 509/192/137 147/194/139 +f 998/193/138 868/195/140 135/196/141 +f 135/197/141 868/201/140 999/198/142 +f 147/200/139 581/202/144 999/198/142 +f 581/202/144 148/207/149 939/203/145 +f 864/199/143 999/198/142 939/203/145 +f 136/204/146 939/203/145 1000/205/147 +f 148/207/149 653/208/150 1000/205/147 +f 653/208/150 149/213/155 427/209/151 +f 934/206/148 1000/205/147 427/209/151 +f 137/210/152 427/209/151 1001/211/153 +f 149/213/155 715/214/156 1001/211/153 +f 715/214/156 150/219/161 512/215/157 +f 420/212/154 1001/211/153 512/215/157 +f 138/216/158 512/215/157 1002/217/159 +f 150/219/161 798/220/162 1002/217/159 +f 798/220/162 151/225/167 582/221/163 +f 505/218/160 1002/217/159 582/221/163 +f 139/222/164 582/221/163 1003/223/165 +f 151/225/167 870/226/168 1003/223/165 +f 870/226/168 152/231/173 655/227/169 +f 577/224/166 1003/223/165 655/227/169 +f 140/228/170 655/227/169 1004/229/171 +f 152/231/173 717/232/174 1004/229/171 +f 717/232/174 141/234/176 423/159/104 +f 422/230/172 1004/229/171 423/159/104 +f 718/233/175 1005/236/178 711/162/107 +f 718/233/175 153/284/224 429/235/177 +f 1005/236/178 429/235/177 154/237/179 +f 1005/236/178 800/238/180 142/164/109 +f 800/238/180 1006/240/182 794/168/113 +f 800/238/180 154/237/179 514/239/181 +f 1006/240/182 514/239/181 155/241/183 +f 1006/240/182 872/242/184 143/170/115 +f 872/242/184 1007/244/186 866/174/119 +f 872/242/184 155/241/183 584/243/185 +f 1007/244/186 584/243/185 156/245/187 +f 1007/244/186 942/246/188 144/176/121 +f 942/246/188 1008/248/190 937/180/125 +f 942/246/188 156/245/187 657/247/189 +f 1008/248/190 657/247/189 157/249/191 +f 1008/248/190 431/250/192 145/182/127 +f 431/250/192 1009/252/194 425/186/131 +f 431/250/192 157/249/191 720/251/193 +f 1009/252/194 720/251/193 158/253/195 +f 1009/252/194 516/254/196 146/188/133 +f 516/254/196 1010/256/198 509/192/137 +f 516/254/196 158/253/195 802/255/197 +f 1010/256/198 802/255/197 159/257/199 +f 1010/256/198 586/258/200 147/194/139 +f 147/200/139 586/261/200 1011/259/201 +f 159/260/199 874/262/202 1011/259/201 +f 874/262/202 160/265/205 659/263/203 +f 581/202/144 1011/259/201 659/263/203 +f 148/207/149 659/263/203 1012/264/204 +f 160/265/205 944/266/206 1012/264/204 +f 944/266/206 161/269/209 722/267/207 +f 653/208/150 1012/264/204 722/267/207 +f 149/213/155 722/267/207 1013/268/208 +f 161/269/209 433/270/210 1013/268/208 +f 433/270/210 162/273/213 804/271/211 +f 715/214/156 1013/268/208 804/271/211 +f 150/219/161 804/271/211 1014/272/212 +f 162/273/213 517/274/214 1014/272/212 +f 517/274/214 163/277/217 875/275/215 +f 798/220/162 1014/272/212 875/275/215 +f 151/225/167 875/275/215 1015/276/216 +f 163/277/217 588/278/218 1015/276/216 +f 588/278/218 164/281/221 945/279/219 +f 870/226/168 1015/276/216 945/279/219 +f 152/231/173 945/279/219 1016/280/220 +f 164/281/221 434/282/222 1016/280/220 +f 434/282/222 153/284/224 718/233/175 +f 717/232/174 1016/280/220 718/233/175 +f 435/283/223 1017/286/226 429/235/177 +f 435/283/223 165/334/272 723/285/225 +f 1017/286/226 723/285/225 166/287/227 +f 1017/286/226 518/288/228 154/237/179 +f 518/288/228 1018/290/230 514/239/181 +f 518/288/228 166/287/227 805/289/229 +f 1018/290/230 805/289/229 167/291/231 +f 1018/290/230 589/292/232 155/241/183 +f 589/292/232 1019/294/234 584/243/185 +f 589/292/232 167/291/231 876/293/233 +f 1019/294/234 876/293/233 168/295/235 +f 1019/294/234 660/296/236 156/245/187 +f 660/296/236 1020/298/238 657/247/189 +f 660/296/236 168/295/235 946/297/237 +f 1020/298/238 946/297/237 169/299/239 +f 1020/298/238 724/300/240 157/249/191 +f 724/300/240 1021/302/242 720/251/193 +f 724/300/240 169/299/239 436/301/241 +f 1021/302/242 436/301/241 170/303/243 +f 1021/302/242 806/304/244 158/253/195 +f 806/304/244 1022/306/246 802/255/197 +f 806/304/244 170/303/243 519/305/245 +f 1022/306/246 519/305/245 171/307/247 +f 1022/306/246 877/308/248 159/257/199 +f 159/260/199 877/311/248 1023/309/249 +f 171/310/247 590/312/250 1023/309/249 +f 590/312/250 172/315/253 947/313/251 +f 874/262/202 1023/309/249 947/313/251 +f 160/265/205 947/313/251 1024/314/252 +f 172/315/253 661/316/254 1024/314/252 +f 661/316/254 173/319/257 437/317/255 +f 944/266/206 1024/314/252 437/317/255 +f 161/269/209 437/317/255 1025/318/256 +f 173/319/257 725/320/258 1025/318/256 +f 725/320/258 174/323/261 520/321/259 +f 433/270/210 1025/318/256 520/321/259 +f 162/273/213 520/321/259 1026/322/260 +f 174/323/261 807/324/262 1026/322/260 +f 807/324/262 175/327/265 591/325/263 +f 517/274/214 1026/322/260 591/325/263 +f 163/277/217 591/325/263 1027/326/264 +f 175/327/265 878/328/266 1027/326/264 +f 878/328/266 176/331/269 662/329/267 +f 588/278/218 1027/326/264 662/329/267 +f 164/281/221 662/329/267 1028/330/268 +f 176/331/269 726/332/270 1028/330/268 +f 726/332/270 165/334/272 435/283/223 +f 434/282/222 1028/330/268 435/283/223 +f 727/333/271 1029/336/274 723/285/225 +f 727/333/271 177/384/320 438/335/273 +f 1029/336/274 438/335/273 178/337/275 +f 1029/336/274 808/338/276 166/287/227 +f 808/338/276 1030/340/278 805/289/229 +f 808/338/276 178/337/275 521/339/277 +f 1030/340/278 521/339/277 179/341/279 +f 1030/340/278 879/342/280 167/291/231 +f 879/342/280 1031/344/282 876/293/233 +f 879/342/280 179/341/279 592/343/281 +f 1031/344/282 592/343/281 180/345/283 +f 1031/344/282 948/346/284 168/295/235 +f 948/346/284 1032/348/286 946/297/237 +f 948/346/284 180/345/283 663/347/285 +f 1032/348/286 663/347/285 181/349/287 +f 1032/348/286 439/350/288 169/299/239 +f 439/350/288 1033/352/290 436/301/241 +f 439/350/288 181/349/287 728/351/289 +f 1033/352/290 728/351/289 182/353/291 +f 1033/352/290 522/354/292 170/303/243 +f 522/354/292 1034/356/294 519/305/245 +f 522/354/292 182/353/291 809/355/293 +f 1034/356/294 809/355/293 183/357/295 +f 1034/356/294 593/358/296 171/307/247 +f 171/310/247 593/361/296 1035/359/297 +f 183/360/295 880/362/298 1035/359/297 +f 880/362/298 184/365/301 664/363/299 +f 590/312/250 1035/359/297 664/363/299 +f 172/315/253 664/363/299 1036/364/300 +f 184/365/301 949/366/302 1036/364/300 +f 949/366/302 185/369/305 729/367/303 +f 661/316/254 1036/364/300 729/367/303 +f 173/319/257 729/367/303 1037/368/304 +f 185/369/305 440/370/306 1037/368/304 +f 440/370/306 186/373/309 810/371/307 +f 725/320/258 1037/368/304 810/371/307 +f 174/323/261 810/371/307 1038/372/308 +f 186/373/309 523/374/310 1038/372/308 +f 523/374/310 187/377/313 881/375/311 +f 807/324/262 1038/372/308 881/375/311 +f 175/327/265 881/375/311 1039/376/312 +f 187/377/313 594/378/314 1039/376/312 +f 594/378/314 188/381/317 950/379/315 +f 878/328/266 1039/376/312 950/379/315 +f 176/331/269 950/379/315 1040/380/316 +f 188/381/317 441/382/318 1040/380/316 +f 441/382/318 177/384/320 727/333/271 +f 726/332/270 1040/380/316 727/333/271 +f 442/383/319 1041/386/322 438/335/273 +f 442/383/319 189/434/368 730/385/321 +f 1041/386/322 730/385/321 190/387/323 +f 1041/386/322 524/388/324 178/337/275 +f 524/388/324 1042/390/326 521/339/277 +f 524/388/324 190/387/323 811/389/325 +f 1042/390/326 811/389/325 191/391/327 +f 1042/390/326 595/392/328 179/341/279 +f 595/392/328 1043/394/330 592/343/281 +f 595/392/328 191/391/327 882/393/329 +f 1043/394/330 882/393/329 192/395/331 +f 1043/394/330 665/396/332 180/345/283 +f 665/396/332 1044/398/334 663/347/285 +f 665/396/332 192/395/331 951/397/333 +f 1044/398/334 951/397/333 193/399/335 +f 1044/398/334 731/400/336 181/349/287 +f 731/400/336 1045/402/338 728/351/289 +f 731/400/336 193/399/335 443/401/337 +f 1045/402/338 443/401/337 194/403/339 +f 1045/402/338 812/404/340 182/353/291 +f 812/404/340 1046/406/342 809/355/293 +f 812/404/340 194/403/339 525/405/341 +f 1046/406/342 525/405/341 195/407/343 +f 1046/406/342 883/408/344 183/357/295 +f 183/360/295 883/411/344 1047/409/345 +f 195/410/343 596/412/346 1047/409/345 +f 596/412/346 196/415/349 952/413/347 +f 880/362/298 1047/409/345 952/413/347 +f 184/365/301 952/413/347 1048/414/348 +f 196/415/349 666/416/350 1048/414/348 +f 666/416/350 197/419/353 444/417/351 +f 949/366/302 1048/414/348 444/417/351 +f 185/369/305 444/417/351 1049/418/352 +f 197/419/353 732/420/354 1049/418/352 +f 732/420/354 198/423/357 526/421/355 +f 440/370/306 1049/418/352 526/421/355 +f 186/373/309 526/421/355 1050/422/356 +f 198/423/357 813/424/358 1050/422/356 +f 813/424/358 199/427/361 597/425/359 +f 523/374/310 1050/422/356 597/425/359 +f 187/377/313 597/425/359 1051/426/360 +f 199/427/361 884/428/362 1051/426/360 +f 884/428/362 200/431/365 667/429/363 +f 594/378/314 1051/426/360 667/429/363 +f 188/381/317 667/429/363 1052/430/364 +f 200/431/365 733/432/366 1052/430/364 +f 733/432/366 189/434/368 442/383/319 +f 441/382/318 1052/430/364 442/383/319 +f 734/433/367 1053/436/370 730/385/321 +f 734/433/367 201/484/416 445/435/369 +f 1053/436/370 445/435/369 202/437/371 +f 1053/436/370 814/438/372 190/387/323 +f 814/438/372 1054/440/374 811/389/325 +f 814/438/372 202/437/371 527/439/373 +f 1054/440/374 527/439/373 203/441/375 +f 1054/440/374 885/442/376 191/391/327 +f 885/442/376 1055/444/378 882/393/329 +f 885/442/376 203/441/375 598/443/377 +f 1055/444/378 598/443/377 204/445/379 +f 1055/444/378 953/446/380 192/395/331 +f 953/446/380 1056/448/382 951/397/333 +f 953/446/380 204/445/379 668/447/381 +f 1056/448/382 668/447/381 205/449/383 +f 1056/448/382 446/450/384 193/399/335 +f 446/450/384 1057/452/386 443/401/337 +f 446/450/384 205/449/383 735/451/385 +f 1057/452/386 735/451/385 206/453/387 +f 1057/452/386 528/454/388 194/403/339 +f 528/454/388 1058/456/390 525/405/341 +f 528/454/388 206/453/387 815/455/389 +f 1058/456/390 815/455/389 207/457/391 +f 1058/456/390 599/458/392 195/407/343 +f 195/410/343 599/461/392 1059/459/393 +f 207/460/391 886/462/394 1059/459/393 +f 886/462/394 208/465/397 669/463/395 +f 596/412/346 1059/459/393 669/463/395 +f 196/415/349 669/463/395 1060/464/396 +f 208/465/397 954/466/398 1060/464/396 +f 954/466/398 209/469/401 736/467/399 +f 666/416/350 1060/464/396 736/467/399 +f 197/419/353 736/467/399 1061/468/400 +f 209/469/401 447/470/402 1061/468/400 +f 447/470/402 210/473/405 816/471/403 +f 732/420/354 1061/468/400 816/471/403 +f 198/423/357 816/471/403 1062/472/404 +f 210/473/405 529/474/406 1062/472/404 +f 529/474/406 211/477/409 887/475/407 +f 813/424/358 1062/472/404 887/475/407 +f 199/427/361 887/475/407 1063/476/408 +f 211/477/409 600/478/410 1063/476/408 +f 600/478/410 212/481/413 955/479/411 +f 884/428/362 1063/476/408 955/479/411 +f 200/431/365 955/479/411 1064/480/412 +f 212/481/413 448/482/414 1064/480/412 +f 448/482/414 201/484/416 734/433/367 +f 733/432/366 1064/480/412 734/433/367 +f 449/483/415 1065/486/418 445/435/369 +f 449/483/415 213/534/464 737/485/417 +f 1065/486/418 737/485/417 214/487/419 +f 1065/486/418 530/488/420 202/437/371 +f 530/488/420 1066/490/422 527/439/373 +f 530/488/420 214/487/419 817/489/421 +f 1066/490/422 817/489/421 215/491/423 +f 1066/490/422 601/492/424 203/441/375 +f 601/492/424 1067/494/426 598/443/377 +f 601/492/424 215/491/423 888/493/425 +f 1067/494/426 888/493/425 216/495/427 +f 1067/494/426 670/496/428 204/445/379 +f 670/496/428 1068/498/430 668/447/381 +f 670/496/428 216/495/427 956/497/429 +f 1068/498/430 956/497/429 217/499/431 +f 1068/498/430 738/500/432 205/449/383 +f 738/500/432 1069/502/434 735/451/385 +f 738/500/432 217/499/431 450/501/433 +f 1069/502/434 450/501/433 218/503/435 +f 1069/502/434 818/504/436 206/453/387 +f 818/504/436 1070/506/438 815/455/389 +f 818/504/436 218/503/435 531/505/437 +f 1070/506/438 531/505/437 219/507/439 +f 1070/506/438 889/508/440 207/457/391 +f 207/460/391 889/511/440 1071/509/441 +f 219/510/439 602/512/442 1071/509/441 +f 602/512/442 220/515/445 957/513/443 +f 886/462/394 1071/509/441 957/513/443 +f 208/465/397 957/513/443 1072/514/444 +f 220/515/445 671/516/446 1072/514/444 +f 671/516/446 221/519/449 451/517/447 +f 954/466/398 1072/514/444 451/517/447 +f 209/469/401 451/517/447 1073/518/448 +f 221/519/449 739/520/450 1073/518/448 +f 739/520/450 222/523/453 532/521/451 +f 447/470/402 1073/518/448 532/521/451 +f 210/473/405 532/521/451 1074/522/452 +f 222/523/453 819/524/454 1074/522/452 +f 819/524/454 223/527/457 603/525/455 +f 529/474/406 1074/522/452 603/525/455 +f 211/477/409 603/525/455 1075/526/456 +f 223/527/457 890/528/458 1075/526/456 +f 890/528/458 224/531/461 672/529/459 +f 600/478/410 1075/526/456 672/529/459 +f 212/481/413 672/529/459 1076/530/460 +f 224/531/461 740/532/462 1076/530/460 +f 740/532/462 213/534/464 449/483/415 +f 448/482/414 1076/530/460 449/483/415 +f 741/533/463 1077/536/466 737/485/417 +f 741/533/463 225/584/512 452/535/465 +f 1077/536/466 452/535/465 226/537/467 +f 1077/536/466 820/538/468 214/487/419 +f 820/538/468 1078/540/470 817/489/421 +f 820/538/468 226/537/467 533/539/469 +f 1078/540/470 533/539/469 227/541/471 +f 1078/540/470 891/542/472 215/491/423 +f 891/542/472 1079/544/474 888/493/425 +f 891/542/472 227/541/471 604/543/473 +f 1079/544/474 604/543/473 228/545/475 +f 1079/544/474 958/546/476 216/495/427 +f 958/546/476 1080/548/478 956/497/429 +f 958/546/476 228/545/475 673/547/477 +f 1080/548/478 673/547/477 229/549/479 +f 1080/548/478 453/550/480 217/499/431 +f 453/550/480 1081/552/482 450/501/433 +f 453/550/480 229/549/479 742/551/481 +f 1081/552/482 742/551/481 230/553/483 +f 1081/552/482 534/554/484 218/503/435 +f 534/554/484 1082/556/486 531/505/437 +f 534/554/484 230/553/483 821/555/485 +f 1082/556/486 821/555/485 231/557/487 +f 1082/556/486 605/558/488 219/507/439 +f 219/510/439 605/561/488 1083/559/489 +f 231/560/487 892/562/490 1083/559/489 +f 892/562/490 232/565/493 674/563/491 +f 602/512/442 1083/559/489 674/563/491 +f 220/515/445 674/563/491 1084/564/492 +f 232/565/493 959/566/494 1084/564/492 +f 959/566/494 233/569/497 743/567/495 +f 671/516/446 1084/564/492 743/567/495 +f 221/519/449 743/567/495 1085/568/496 +f 233/569/497 454/570/498 1085/568/496 +f 454/570/498 234/573/501 822/571/499 +f 739/520/450 1085/568/496 822/571/499 +f 222/523/453 822/571/499 1086/572/500 +f 234/573/501 535/574/502 1086/572/500 +f 535/574/502 235/577/505 893/575/503 +f 819/524/454 1086/572/500 893/575/503 +f 223/527/457 893/575/503 1087/576/504 +f 235/577/505 606/578/506 1087/576/504 +f 606/578/506 236/581/509 960/579/507 +f 890/528/458 1087/576/504 960/579/507 +f 224/531/461 960/579/507 1088/580/508 +f 236/581/509 456/582/510 1088/580/508 +f 456/582/510 225/584/512 741/533/463 +f 740/532/462 1088/580/508 741/533/463 +f 457/583/511 1089/586/514 452/535/465 +f 457/583/511 237/634/560 744/585/513 +f 1089/586/514 744/585/513 238/587/515 +f 1089/586/514 536/588/516 226/537/467 +f 536/588/516 1090/590/518 533/539/469 +f 536/588/516 238/587/515 824/589/517 +f 1090/590/518 824/589/517 239/591/519 +f 1090/590/518 607/592/520 227/541/471 +f 607/592/520 1091/594/522 604/543/473 +f 607/592/520 239/591/519 894/593/521 +f 1091/594/522 894/593/521 240/595/523 +f 1091/594/522 675/596/524 228/545/475 +f 675/596/524 1092/598/526 673/547/477 +f 675/596/524 240/595/523 961/597/525 +f 1092/598/526 961/597/525 241/599/527 +f 1092/598/526 745/600/528 229/549/479 +f 745/600/528 1093/602/530 742/551/481 +f 745/600/528 241/599/527 458/601/529 +f 1093/602/530 458/601/529 242/603/531 +f 1093/602/530 825/604/532 230/553/483 +f 825/604/532 1094/606/534 821/555/485 +f 825/604/532 242/603/531 537/605/533 +f 1094/606/534 537/605/533 243/607/535 +f 1094/606/534 895/608/536 231/557/487 +f 231/560/487 895/611/536 1095/609/537 +f 243/610/535 608/612/538 1095/609/537 +f 608/612/538 244/615/541 962/613/539 +f 892/562/490 1095/609/537 962/613/539 +f 232/565/493 962/613/539 1096/614/540 +f 244/615/541 676/616/542 1096/614/540 +f 676/616/542 245/619/545 459/617/543 +f 959/566/494 1096/614/540 459/617/543 +f 233/569/497 459/617/543 1097/618/544 +f 245/619/545 746/620/546 1097/618/544 +f 746/620/546 246/623/549 538/621/547 +f 454/570/498 1097/618/544 538/621/547 +f 234/573/501 538/621/547 1098/622/548 +f 246/623/549 826/624/550 1098/622/548 +f 826/624/550 247/627/553 609/625/551 +f 535/574/502 1098/622/548 609/625/551 +f 235/577/505 609/625/551 1099/626/552 +f 247/627/553 896/628/554 1099/626/552 +f 896/628/554 248/631/557 677/629/555 +f 606/578/506 1099/626/552 677/629/555 +f 236/581/509 677/629/555 1100/630/556 +f 248/631/557 747/632/558 1100/630/556 +f 747/632/558 237/634/560 457/583/511 +f 456/582/510 1100/630/556 457/583/511 +f 748/633/559 1101/636/562 744/585/513 +f 748/633/559 249/684/608 460/635/561 +f 1101/636/562 460/635/561 250/637/563 +f 1101/636/562 827/638/564 238/587/515 +f 827/638/564 1102/640/566 824/589/517 +f 827/638/564 250/637/563 539/639/565 +f 1102/640/566 539/639/565 251/641/567 +f 1102/640/566 897/642/568 239/591/519 +f 897/642/568 1103/644/570 894/593/521 +f 897/642/568 251/641/567 610/643/569 +f 1103/644/570 610/643/569 252/645/571 +f 1103/644/570 963/646/572 240/595/523 +f 963/646/572 1104/648/574 961/597/525 +f 963/646/572 252/645/571 678/647/573 +f 1104/648/574 678/647/573 253/649/575 +f 1104/648/574 461/650/576 241/599/527 +f 461/650/576 1105/652/578 458/601/529 +f 461/650/576 253/649/575 749/651/577 +f 1105/652/578 749/651/577 254/653/579 +f 1105/652/578 540/654/580 242/603/531 +f 540/654/580 1106/656/582 537/605/533 +f 540/654/580 254/653/579 828/655/581 +f 1106/656/582 828/655/581 255/657/583 +f 1106/656/582 611/658/584 243/607/535 +f 243/610/535 611/661/584 1107/659/585 +f 255/660/583 898/662/586 1107/659/585 +f 898/662/586 256/665/589 679/663/587 +f 608/612/538 1107/659/585 679/663/587 +f 244/615/541 679/663/587 1108/664/588 +f 256/665/589 964/666/590 1108/664/588 +f 964/666/590 257/669/593 750/667/591 +f 676/616/542 1108/664/588 750/667/591 +f 245/619/545 750/667/591 1109/668/592 +f 257/669/593 462/670/594 1109/668/592 +f 462/670/594 258/673/597 829/671/595 +f 746/620/546 1109/668/592 829/671/595 +f 246/623/549 829/671/595 1110/672/596 +f 258/673/597 541/674/598 1110/672/596 +f 541/674/598 259/677/601 899/675/599 +f 826/624/550 1110/672/596 899/675/599 +f 247/627/553 899/675/599 1111/676/600 +f 259/677/601 612/678/602 1111/676/600 +f 612/678/602 260/681/605 965/679/603 +f 896/628/554 1111/676/600 965/679/603 +f 248/631/557 965/679/603 1112/680/604 +f 260/681/605 463/682/606 1112/680/604 +f 463/682/606 249/684/608 748/633/559 +f 747/632/558 1112/680/604 748/633/559 +f 464/683/607 1113/686/610 460/635/561 +f 464/683/607 261/734/656 751/685/609 +f 1113/686/610 751/685/609 262/687/611 +f 1113/686/610 542/688/612 250/637/563 +f 542/688/612 1114/690/614 539/639/565 +f 542/688/612 262/687/611 830/689/613 +f 1114/690/614 830/689/613 263/691/615 +f 1114/690/614 614/692/616 251/641/567 +f 614/692/616 1115/694/618 610/643/569 +f 614/692/616 263/691/615 900/693/617 +f 1115/694/618 900/693/617 264/695/619 +f 1115/694/618 680/696/620 252/645/571 +f 680/696/620 1116/698/622 678/647/573 +f 680/696/620 264/695/619 967/697/621 +f 1116/698/622 967/697/621 265/699/623 +f 1116/698/622 752/700/624 253/649/575 +f 752/700/624 1117/702/626 749/651/577 +f 752/700/624 265/699/623 465/701/625 +f 1117/702/626 465/701/625 266/703/627 +f 1117/702/626 831/704/628 254/653/579 +f 831/704/628 1118/706/630 828/655/581 +f 831/704/628 266/703/627 543/705/629 +f 1118/706/630 543/705/629 267/707/631 +f 1118/706/630 901/708/632 255/657/583 +f 255/660/583 901/711/632 1119/709/633 +f 267/710/631 615/712/634 1119/709/633 +f 615/712/634 268/715/637 968/713/635 +f 898/662/586 1119/709/633 968/713/635 +f 256/665/589 968/713/635 1120/714/636 +f 268/715/637 681/716/638 1120/714/636 +f 681/716/638 269/719/641 466/717/639 +f 964/666/590 1120/714/636 466/717/639 +f 257/669/593 466/717/639 1121/718/640 +f 269/719/641 753/720/642 1121/718/640 +f 753/720/642 270/723/645 544/721/643 +f 462/670/594 1121/718/640 544/721/643 +f 258/673/597 544/721/643 1122/722/644 +f 270/723/645 832/724/646 1122/722/644 +f 832/724/646 271/727/649 616/725/647 +f 541/674/598 1122/722/644 616/725/647 +f 259/677/601 616/725/647 1123/726/648 +f 271/727/649 902/728/650 1123/726/648 +f 902/728/650 272/731/653 682/729/651 +f 612/678/602 1123/726/648 682/729/651 +f 260/681/605 682/729/651 1124/730/652 +f 272/731/653 754/732/654 1124/730/652 +f 754/732/654 261/734/656 464/683/607 +f 463/682/606 1124/730/652 464/683/607 +f 755/733/655 1125/736/658 751/685/609 +f 755/733/655 273/1383/141 467/735/657 +f 1125/736/658 467/735/657 274/737/659 +f 1125/736/658 833/738/660 262/687/611 +f 833/738/660 1126/740/662 830/689/613 +f 833/738/660 274/737/659 545/739/661 +f 1126/740/662 545/739/661 275/741/663 +f 1126/740/662 903/742/664 263/691/615 +f 903/742/664 1127/744/666 900/693/617 +f 903/742/664 275/741/663 617/743/665 +f 1127/744/666 617/743/665 276/745/667 +f 1127/744/666 969/746/668 264/695/619 +f 969/746/668 1128/748/670 967/697/621 +f 969/746/668 276/745/667 683/747/669 +f 1128/748/670 683/747/669 277/749/671 +f 1128/748/670 468/750/672 265/699/623 +f 468/750/672 1129/752/674 465/701/625 +f 468/750/672 277/749/671 756/751/673 +f 1129/752/674 756/751/673 278/753/675 +f 1129/752/674 546/754/676 266/703/627 +f 546/754/676 1130/756/678 543/705/629 +f 546/754/676 278/753/675 834/755/677 +f 1130/756/678 834/755/677 279/757/106 +f 1130/756/678 618/758/679 267/707/631 +f 267/710/631 618/761/679 1131/759/680 +f 279/760/106 904/762/681 1131/759/680 +f 904/762/681 280/765/684 684/763/682 +f 615/712/634 1131/759/680 684/763/682 +f 268/715/637 684/763/682 1132/764/683 +f 280/765/684 970/766/685 1132/764/683 +f 970/766/685 281/769/688 757/767/686 +f 681/716/638 1132/764/683 757/767/686 +f 269/719/641 757/767/686 1133/768/687 +f 281/769/688 469/770/689 1133/768/687 +f 469/770/689 282/773/692 835/771/690 +f 753/720/642 1133/768/687 835/771/690 +f 270/723/645 835/771/690 1134/772/691 +f 282/773/692 547/774/693 1134/772/691 +f 547/774/693 283/777/696 905/775/694 +f 832/724/646 1134/772/691 905/775/694 +f 271/727/649 905/775/694 1135/776/695 +f 283/777/696 619/778/697 1135/776/695 +f 619/778/697 284/781/700 971/779/698 +f 902/728/650 1135/776/695 971/779/698 +f 272/731/653 971/779/698 1136/780/699 +f 284/781/700 470/782/701 1136/780/699 +f 470/782/701 273/1383/141 755/733/655 +f 754/732/654 1136/780/699 755/733/655 +f 471/783/140 1137/787/703 467/784/657 +f 471/783/140 285/858/139 758/786/702 +f 1137/787/703 758/786/702 286/788/704 +f 1137/787/703 548/789/705 274/790/659 +f 548/789/705 1138/793/707 545/791/661 +f 548/789/705 286/788/704 836/792/706 +f 1138/793/707 836/792/706 287/794/708 +f 1138/793/707 620/795/709 275/796/663 +f 620/795/709 1139/799/711 617/797/665 +f 620/795/709 287/794/708 906/798/710 +f 1139/799/711 906/798/710 288/800/712 +f 1139/799/711 685/801/713 276/802/667 +f 685/801/713 1140/805/715 683/803/669 +f 685/801/713 288/800/712 972/804/714 +f 1140/805/715 972/804/714 289/806/716 +f 1140/805/715 760/807/717 277/808/671 +f 760/807/717 1141/811/719 756/809/673 +f 760/807/717 289/806/716 472/810/718 +f 1141/811/719 472/810/718 290/812/720 +f 1141/811/719 837/813/721 278/814/675 +f 837/813/721 1142/817/723 834/815/677 +f 837/813/721 290/812/720 550/816/722 +f 1142/817/723 550/816/722 291/818/176 +f 1142/817/723 907/819/104 279/820/106 +f 279/821/106 907/825/104 1143/822/724 +f 291/824/176 621/826/725 1143/822/724 +f 621/826/725 292/831/728 973/827/726 +f 904/823/681 1143/822/724 973/827/726 +f 280/828/684 973/827/726 1144/829/727 +f 292/831/728 686/832/729 1144/829/727 +f 686/832/729 293/837/732 473/833/730 +f 970/830/685 1144/829/727 473/833/730 +f 281/834/688 473/833/730 1145/835/731 +f 293/837/732 761/838/733 1145/835/731 +f 761/838/733 294/843/736 551/839/734 +f 469/836/689 1145/835/731 551/839/734 +f 282/840/692 551/839/734 1146/841/735 +f 294/843/736 838/844/737 1146/841/735 +f 838/844/737 295/849/740 622/845/738 +f 547/842/693 1146/841/735 622/845/738 +f 283/846/696 622/845/738 1147/847/739 +f 295/849/740 908/850/741 1147/847/739 +f 908/850/741 296/855/744 687/851/742 +f 619/848/697 1147/847/739 687/851/742 +f 284/852/700 687/851/742 1148/853/743 +f 296/855/744 762/856/745 1148/853/743 +f 762/856/745 285/858/139 471/783/140 +f 470/854/701 1148/853/743 471/783/140 +f 763/857/200 1149/860/747 758/786/702 +f 763/857/200 297/908/199 474/859/746 +f 1149/860/747 474/859/746 298/861/748 +f 1149/860/747 839/862/749 286/788/704 +f 839/862/749 1150/864/751 836/792/706 +f 839/862/749 298/861/748 552/863/750 +f 1150/864/751 552/863/750 299/865/752 +f 1150/864/751 909/866/753 287/794/708 +f 909/866/753 1151/868/755 906/798/710 +f 909/866/753 299/865/752 623/867/754 +f 1151/868/755 623/867/754 300/869/756 +f 1151/868/755 974/870/757 288/800/712 +f 974/870/757 1152/872/759 972/804/714 +f 974/870/757 300/869/756 688/871/758 +f 1152/872/759 688/871/758 301/873/760 +f 1152/872/759 475/874/761 289/806/716 +f 475/874/761 1153/876/763 472/810/718 +f 475/874/761 301/873/760 764/875/762 +f 1153/876/763 764/875/762 302/877/764 +f 1153/876/763 553/878/765 290/812/720 +f 553/878/765 1154/880/767 550/816/722 +f 553/878/765 302/877/764 840/879/766 +f 1154/880/767 840/879/766 303/881/224 +f 1154/880/767 624/882/175 291/818/176 +f 291/824/176 624/885/175 1155/883/768 +f 303/884/224 910/886/769 1155/883/768 +f 910/886/769 304/889/772 689/887/770 +f 621/826/725 1155/883/768 689/887/770 +f 292/831/728 689/887/770 1156/888/771 +f 304/889/772 975/890/773 1156/888/771 +f 975/890/773 305/893/776 765/891/774 +f 686/832/729 1156/888/771 765/891/774 +f 293/837/732 765/891/774 1157/892/775 +f 305/893/776 476/894/777 1157/892/775 +f 476/894/777 306/897/780 841/895/778 +f 761/838/733 1157/892/775 841/895/778 +f 294/843/736 841/895/778 1158/896/779 +f 306/897/780 554/898/781 1158/896/779 +f 554/898/781 307/901/784 911/899/782 +f 838/844/737 1158/896/779 911/899/782 +f 295/849/740 911/899/782 1159/900/783 +f 307/901/784 625/902/785 1159/900/783 +f 625/902/785 308/905/788 976/903/786 +f 908/850/741 1159/900/783 976/903/786 +f 296/855/744 976/903/786 1160/904/787 +f 308/905/788 477/906/789 1160/904/787 +f 477/906/789 297/908/199 763/857/200 +f 762/856/745 1160/904/787 763/857/200 +f 478/907/248 1161/910/791 474/859/746 +f 478/907/248 309/958/247 766/909/790 +f 1161/910/791 766/909/790 310/911/792 +f 1161/910/791 555/912/793 298/861/748 +f 555/912/793 1162/914/795 552/863/750 +f 555/912/793 310/911/792 842/913/794 +f 1162/914/795 842/913/794 311/915/796 +f 1162/914/795 626/916/797 299/865/752 +f 626/916/797 1163/918/799 623/867/754 +f 626/916/797 311/915/796 912/917/798 +f 1163/918/799 912/917/798 312/919/800 +f 1163/918/799 690/920/801 300/869/756 +f 690/920/801 1164/922/803 688/871/758 +f 690/920/801 312/919/800 977/921/802 +f 1164/922/803 977/921/802 313/923/804 +f 1164/922/803 767/924/805 301/873/760 +f 767/924/805 1165/926/807 764/875/762 +f 767/924/805 313/923/804 479/925/806 +f 1165/926/807 479/925/806 314/927/808 +f 1165/926/807 843/928/809 302/877/764 +f 843/928/809 1166/930/811 840/879/766 +f 843/928/809 314/927/808 556/929/810 +f 1166/930/811 556/929/810 315/931/272 +f 1166/930/811 914/932/223 303/881/224 +f 303/884/224 914/935/223 1167/933/812 +f 315/934/272 627/936/813 1167/933/812 +f 627/936/813 316/939/816 978/937/814 +f 910/886/769 1167/933/812 978/937/814 +f 304/889/772 978/937/814 1168/938/815 +f 316/939/816 692/940/817 1168/938/815 +f 692/940/817 317/943/820 480/941/818 +f 975/890/773 1168/938/815 480/941/818 +f 305/893/776 480/941/818 1169/942/819 +f 317/943/820 768/944/821 1169/942/819 +f 768/944/821 318/947/824 557/945/822 +f 476/894/777 1169/942/819 557/945/822 +f 306/897/780 557/945/822 1170/946/823 +f 318/947/824 844/948/825 1170/946/823 +f 844/948/825 319/951/828 628/949/826 +f 554/898/781 1170/946/823 628/949/826 +f 307/901/784 628/949/826 1171/950/827 +f 319/951/828 915/952/829 1171/950/827 +f 915/952/829 320/955/832 693/953/830 +f 625/902/785 1171/950/827 693/953/830 +f 308/905/788 693/953/830 1172/954/831 +f 320/955/832 769/956/833 1172/954/831 +f 769/956/833 309/958/247 478/907/248 +f 477/906/789 1172/954/831 478/907/248 +f 770/957/296 1173/960/835 766/909/790 +f 770/957/296 321/1008/295 481/959/834 +f 1173/960/835 481/959/834 322/961/836 +f 1173/960/835 845/962/837 310/911/792 +f 845/962/837 1174/964/839 842/913/794 +f 845/962/837 322/961/836 558/963/838 +f 1174/964/839 558/963/838 323/965/840 +f 1174/964/839 916/966/841 311/915/796 +f 916/966/841 1175/968/843 912/917/798 +f 916/966/841 323/965/840 629/967/842 +f 1175/968/843 629/967/842 324/969/844 +f 1175/968/843 979/970/845 312/919/800 +f 979/970/845 1176/972/847 977/921/802 +f 979/970/845 324/969/844 694/971/846 +f 1176/972/847 694/971/846 325/973/848 +f 1176/972/847 482/974/849 313/923/804 +f 482/974/849 1177/976/851 479/925/806 +f 482/974/849 325/973/848 771/975/850 +f 1177/976/851 771/975/850 326/977/852 +f 1177/976/851 559/978/853 314/927/808 +f 559/978/853 1178/980/855 556/929/810 +f 559/978/853 326/977/852 846/979/854 +f 1178/980/855 846/979/854 327/981/320 +f 1178/980/855 630/982/271 315/931/272 +f 315/934/272 630/985/271 1179/983/856 +f 327/984/320 917/986/857 1179/983/856 +f 917/986/857 328/989/860 695/987/858 +f 627/936/813 1179/983/856 695/987/858 +f 316/939/816 695/987/858 1180/988/859 +f 328/989/860 980/990/861 1180/988/859 +f 980/990/861 329/993/864 772/991/862 +f 692/940/817 1180/988/859 772/991/862 +f 317/943/820 772/991/862 1181/992/863 +f 329/993/864 483/994/865 1181/992/863 +f 483/994/865 330/997/868 847/995/866 +f 768/944/821 1181/992/863 847/995/866 +f 318/947/824 847/995/866 1182/996/867 +f 330/997/868 560/998/869 1182/996/867 +f 560/998/869 331/1001/872 918/999/870 +f 844/948/825 1182/996/867 918/999/870 +f 319/951/828 918/999/870 1183/1000/871 +f 331/1001/872 631/1002/873 1183/1000/871 +f 631/1002/873 332/1005/876 981/1003/874 +f 915/952/829 1183/1000/871 981/1003/874 +f 320/955/832 981/1003/874 1184/1004/875 +f 332/1005/876 484/1006/877 1184/1004/875 +f 484/1006/877 321/1008/295 770/957/296 +f 769/956/833 1184/1004/875 770/957/296 +f 485/1007/344 1185/1010/879 481/959/834 +f 485/1007/344 333/1058/343 773/1009/878 +f 1185/1010/879 773/1009/878 334/1011/880 +f 1185/1010/879 561/1012/881 322/961/836 +f 561/1012/881 1186/1014/883 558/963/838 +f 561/1012/881 334/1011/880 848/1013/882 +f 1186/1014/883 848/1013/882 335/1015/884 +f 1186/1014/883 632/1016/885 323/965/840 +f 632/1016/885 1187/1018/887 629/967/842 +f 632/1016/885 335/1015/884 919/1017/886 +f 1187/1018/887 919/1017/886 336/1019/888 +f 1187/1018/887 696/1020/889 324/969/844 +f 696/1020/889 1188/1022/891 694/971/846 +f 696/1020/889 336/1019/888 982/1021/890 +f 1188/1022/891 982/1021/890 337/1023/892 +f 1188/1022/891 774/1024/893 325/973/848 +f 774/1024/893 1189/1026/895 771/975/850 +f 774/1024/893 337/1023/892 486/1025/894 +f 1189/1026/895 486/1025/894 338/1027/896 +f 1189/1026/895 849/1028/897 326/977/852 +f 849/1028/897 1190/1030/899 846/979/854 +f 849/1028/897 338/1027/896 562/1029/898 +f 1190/1030/899 562/1029/898 339/1031/368 +f 1190/1030/899 920/1032/319 327/981/320 +f 327/984/320 920/1035/319 1191/1033/900 +f 339/1034/368 633/1036/901 1191/1033/900 +f 633/1036/901 340/1039/904 983/1037/902 +f 917/986/857 1191/1033/900 983/1037/902 +f 328/989/860 983/1037/902 1192/1038/903 +f 340/1039/904 697/1040/905 1192/1038/903 +f 697/1040/905 341/1043/908 488/1041/906 +f 980/990/861 1192/1038/903 488/1041/906 +f 329/993/864 488/1041/906 1193/1042/907 +f 341/1043/908 775/1044/909 1193/1042/907 +f 775/1044/909 342/1047/912 563/1045/910 +f 483/994/865 1193/1042/907 563/1045/910 +f 330/997/868 563/1045/910 1194/1046/911 +f 342/1047/912 851/1048/913 1194/1046/911 +f 851/1048/913 343/1051/916 634/1049/914 +f 560/998/869 1194/1046/911 634/1049/914 +f 331/1001/872 634/1049/914 1195/1050/915 +f 343/1051/916 921/1052/917 1195/1050/915 +f 921/1052/917 344/1055/920 698/1053/918 +f 631/1002/873 1195/1050/915 698/1053/918 +f 332/1005/876 698/1053/918 1196/1054/919 +f 344/1055/920 776/1056/921 1196/1054/919 +f 776/1056/921 333/1058/343 485/1007/344 +f 484/1006/877 1196/1054/919 485/1007/344 +f 777/1057/392 1197/1060/923 773/1009/878 +f 777/1057/392 345/1108/391 489/1059/922 +f 1197/1060/923 489/1059/922 346/1061/924 +f 1197/1060/923 852/1062/925 334/1011/880 +f 852/1062/925 1198/1064/927 848/1013/882 +f 852/1062/925 346/1061/924 564/1063/926 +f 1198/1064/927 564/1063/926 347/1065/928 +f 1198/1064/927 922/1066/929 335/1015/884 +f 922/1066/929 1199/1068/931 919/1017/886 +f 922/1066/929 347/1065/928 635/1067/930 +f 1199/1068/931 635/1067/930 348/1069/932 +f 1199/1068/931 984/1070/933 336/1019/888 +f 984/1070/933 1200/1072/935 982/1021/890 +f 984/1070/933 348/1069/932 699/1071/934 +f 1200/1072/935 699/1071/934 349/1073/936 +f 1200/1072/935 490/1074/937 337/1023/892 +f 490/1074/937 1201/1076/939 486/1025/894 +f 490/1074/937 349/1073/936 778/1075/938 +f 1201/1076/939 778/1075/938 350/1077/940 +f 1201/1076/939 565/1078/941 338/1027/896 +f 565/1078/941 1202/1080/943 562/1029/898 +f 565/1078/941 350/1077/940 853/1079/942 +f 1202/1080/943 853/1079/942 351/1081/416 +f 1202/1080/943 636/1082/367 339/1031/368 +f 339/1034/368 636/1085/367 1203/1083/944 +f 351/1084/416 923/1086/945 1203/1083/944 +f 923/1086/945 352/1089/948 700/1087/946 +f 633/1036/901 1203/1083/944 700/1087/946 +f 340/1039/904 700/1087/946 1204/1088/947 +f 352/1089/948 985/1090/949 1204/1088/947 +f 985/1090/949 353/1093/952 779/1091/950 +f 697/1040/905 1204/1088/947 779/1091/950 +f 341/1043/908 779/1091/950 1205/1092/951 +f 353/1093/952 491/1094/953 1205/1092/951 +f 491/1094/953 354/1097/956 854/1095/954 +f 775/1044/909 1205/1092/951 854/1095/954 +f 342/1047/912 854/1095/954 1206/1096/955 +f 354/1097/956 566/1098/957 1206/1096/955 +f 566/1098/957 355/1101/960 924/1099/958 +f 851/1048/913 1206/1096/955 924/1099/958 +f 343/1051/916 924/1099/958 1207/1100/959 +f 355/1101/960 637/1102/961 1207/1100/959 +f 637/1102/961 356/1105/964 986/1103/962 +f 921/1052/917 1207/1100/959 986/1103/962 +f 344/1055/920 986/1103/962 1208/1104/963 +f 356/1105/964 492/1106/965 1208/1104/963 +f 492/1106/965 345/1108/391 777/1057/392 +f 776/1056/921 1208/1104/963 777/1057/392 +f 493/1107/440 1209/1110/967 489/1059/922 +f 493/1107/440 357/1158/439 780/1109/966 +f 1209/1110/967 780/1109/966 358/1111/968 +f 1209/1110/967 567/1112/969 346/1061/924 +f 567/1112/969 1210/1114/971 564/1063/926 +f 567/1112/969 358/1111/968 855/1113/970 +f 1210/1114/971 855/1113/970 359/1115/972 +f 1210/1114/971 638/1116/973 347/1065/928 +f 638/1116/973 1211/1118/975 635/1067/930 +f 638/1116/973 359/1115/972 925/1117/974 +f 1211/1118/975 925/1117/974 360/1119/976 +f 1211/1118/975 701/1120/977 348/1069/932 +f 701/1120/977 1212/1122/979 699/1071/934 +f 701/1120/977 360/1119/976 987/1121/978 +f 1212/1122/979 987/1121/978 361/1123/980 +f 1212/1122/979 781/1124/981 349/1073/936 +f 781/1124/981 1213/1126/983 778/1075/938 +f 781/1124/981 361/1123/980 494/1125/982 +f 1213/1126/983 494/1125/982 362/1127/984 +f 1213/1126/983 856/1128/985 350/1077/940 +f 856/1128/985 1214/1130/987 853/1079/942 +f 856/1128/985 362/1127/984 568/1129/986 +f 1214/1130/987 568/1129/986 363/1131/464 +f 1214/1130/987 926/1132/415 351/1081/416 +f 351/1084/416 926/1135/415 1215/1133/988 +f 363/1134/464 639/1136/989 1215/1133/988 +f 639/1136/989 364/1139/992 988/1137/990 +f 923/1086/945 1215/1133/988 988/1137/990 +f 352/1089/948 988/1137/990 1216/1138/991 +f 364/1139/992 702/1140/993 1216/1138/991 +f 702/1140/993 365/1143/996 495/1141/994 +f 985/1090/949 1216/1138/991 495/1141/994 +f 353/1093/952 495/1141/994 1217/1142/995 +f 365/1143/996 782/1144/997 1217/1142/995 +f 782/1144/997 366/1147/1000 569/1145/998 +f 491/1094/953 1217/1142/995 569/1145/998 +f 354/1097/956 569/1145/998 1218/1146/999 +f 366/1147/1000 857/1148/1001 1218/1146/999 +f 857/1148/1001 367/1151/1004 641/1149/1002 +f 566/1098/957 1218/1146/999 641/1149/1002 +f 355/1101/960 641/1149/1002 1219/1150/1003 +f 367/1151/1004 927/1152/1005 1219/1150/1003 +f 927/1152/1005 368/1155/1008 703/1153/1006 +f 637/1102/961 1219/1150/1003 703/1153/1006 +f 356/1105/964 703/1153/1006 1220/1154/1007 +f 368/1155/1008 783/1156/1009 1220/1154/1007 +f 783/1156/1009 357/1158/439 493/1107/440 +f 492/1106/965 1220/1154/1007 493/1107/440 +f 784/1157/488 1221/1160/1011 780/1109/966 +f 784/1157/488 369/1208/487 496/1159/1010 +f 1221/1160/1011 496/1159/1010 370/1161/1012 +f 1221/1160/1011 858/1162/1013 358/1111/968 +f 858/1162/1013 1222/1164/1015 855/1113/970 +f 858/1162/1013 370/1161/1012 570/1163/1014 +f 1222/1164/1015 570/1163/1014 371/1165/1016 +f 1222/1164/1015 928/1166/1017 359/1115/972 +f 928/1166/1017 1223/1168/1019 925/1117/974 +f 928/1166/1017 371/1165/1016 642/1167/1018 +f 1223/1168/1019 642/1167/1018 372/1169/1020 +f 1223/1168/1019 990/1170/1021 360/1119/976 +f 990/1170/1021 1224/1172/1023 987/1121/978 +f 990/1170/1021 372/1169/1020 704/1171/1022 +f 1224/1172/1023 704/1171/1022 373/1173/1024 +f 1224/1172/1023 497/1174/1025 361/1123/980 +f 497/1174/1025 1225/1176/1027 494/1125/982 +f 497/1174/1025 373/1173/1024 785/1175/1026 +f 1225/1176/1027 785/1175/1026 374/1177/1028 +f 1225/1176/1027 571/1178/1029 362/1127/984 +f 571/1178/1029 1226/1180/1031 568/1129/986 +f 571/1178/1029 374/1177/1028 859/1179/1030 +f 1226/1180/1031 859/1179/1030 375/1181/512 +f 1226/1180/1031 643/1182/463 363/1131/464 +f 363/1134/464 643/1185/463 1227/1183/1032 +f 375/1184/512 929/1186/1033 1227/1183/1032 +f 929/1186/1033 376/1189/1036 705/1187/1034 +f 639/1136/989 1227/1183/1032 705/1187/1034 +f 364/1139/992 705/1187/1034 1228/1188/1035 +f 376/1189/1036 991/1190/1037 1228/1188/1035 +f 991/1190/1037 377/1193/1040 786/1191/1038 +f 702/1140/993 1228/1188/1035 786/1191/1038 +f 365/1143/996 786/1191/1038 1229/1192/1039 +f 377/1193/1040 498/1194/1041 1229/1192/1039 +f 498/1194/1041 378/1197/1044 860/1195/1042 +f 782/1144/997 1229/1192/1039 860/1195/1042 +f 366/1147/1000 860/1195/1042 1230/1196/1043 +f 378/1197/1044 572/1198/1045 1230/1196/1043 +f 572/1198/1045 379/1201/1048 930/1199/1046 +f 857/1148/1001 1230/1196/1043 930/1199/1046 +f 367/1151/1004 930/1199/1046 1231/1200/1047 +f 379/1201/1048 644/1202/1049 1231/1200/1047 +f 644/1202/1049 380/1205/1052 992/1203/1050 +f 927/1152/1005 1231/1200/1047 992/1203/1050 +f 368/1155/1008 992/1203/1050 1232/1204/1051 +f 380/1205/1052 499/1206/1053 1232/1204/1051 +f 499/1206/1053 369/1208/487 784/1157/488 +f 783/1156/1009 1232/1204/1051 784/1157/488 +f 500/1207/1054 1233/1210/1056 496/1159/1010 +f 500/1207/1054 381/1258/535 787/1209/1055 +f 1233/1210/1056 787/1209/1055 382/1211/1057 +f 1233/1210/1056 573/1212/1058 370/1161/1012 +f 573/1212/1058 1234/1214/1060 570/1163/1014 +f 573/1212/1058 382/1211/1057 861/1213/1059 +f 1234/1214/1060 861/1213/1059 383/1215/1061 +f 1234/1214/1060 645/1216/1062 371/1165/1016 +f 645/1216/1062 1235/1218/1064 642/1167/1018 +f 645/1216/1062 383/1215/1061 931/1217/1063 +f 1235/1218/1064 931/1217/1063 384/1219/1065 +f 1235/1218/1064 706/1220/1066 372/1169/1020 +f 706/1220/1066 1236/1222/1068 704/1171/1022 +f 706/1220/1066 384/1219/1065 862/1221/1067 +f 1236/1222/1068 862/1221/1067 385/1223/1069 +f 1236/1222/1068 788/1224/1070 373/1173/1024 +f 788/1224/1070 1237/1226/1072 785/1175/1026 +f 788/1224/1070 385/1223/1069 501/1225/1071 +f 1237/1226/1072 501/1225/1071 386/1227/1073 +f 1237/1226/1072 707/1228/1074 374/1177/1028 +f 707/1228/1074 1238/1230/1076 859/1179/1030 +f 707/1228/1074 386/1227/1073 418/1229/1075 +f 1238/1230/1076 418/1229/1075 387/1231/560 +f 1238/1230/1076 932/1232/511 375/1181/512 +f 375/1184/512 932/1235/511 1239/1233/1077 +f 387/1234/560 646/1236/1078 1239/1233/1077 +f 646/1236/1078 388/1239/1081 863/1237/1079 +f 929/1186/1033 1239/1233/1077 863/1237/1079 +f 376/1189/1036 863/1237/1079 1240/1238/1080 +f 388/1239/1081 575/1240/1082 1240/1238/1080 +f 575/1240/1082 389/1243/1085 503/1241/1083 +f 991/1190/1037 1240/1238/1080 503/1241/1083 +f 377/1193/1040 503/1241/1083 1241/1242/1084 +f 389/1243/1085 789/1244/1086 1241/1242/1084 +f 789/1244/1086 390/1247/1089 419/1245/1087 +f 498/1194/1041 1241/1242/1084 419/1245/1087 +f 378/1197/1044 419/1245/1087 1242/1246/1088 +f 390/1247/1089 709/1248/1090 1242/1246/1088 +f 709/1248/1090 391/1251/1093 648/1249/1091 +f 572/1198/1045 1242/1246/1088 648/1249/1091 +f 379/1201/1048 648/1249/1091 1243/1250/1092 +f 391/1251/1093 933/1252/1094 1243/1250/1092 +f 933/1252/1094 392/1255/1097 576/1253/1095 +f 644/1202/1049 1243/1250/1092 576/1253/1095 +f 380/1205/1052 576/1253/1095 1244/1254/1096 +f 392/1255/1097 791/1256/1098 1244/1254/1096 +f 791/1256/1098 381/1258/535 500/1207/1054 +f 499/1206/1053 1244/1254/1096 500/1207/1054 +f 792/1257/584 1245/1260/1100 787/1209/1055 +f 792/1257/584 393/1308/583 504/1259/1099 +f 1245/1260/1100 504/1259/1099 394/1261/1101 +f 1245/1260/1100 710/1262/1102 382/1211/1057 +f 710/1262/1102 1246/1264/1104 861/1213/1059 +f 710/1262/1102 394/1261/1101 421/1263/1103 +f 1246/1264/1104 421/1263/1103 395/1265/1105 +f 1246/1264/1104 935/1266/1106 383/1215/1061 +f 935/1266/1106 1247/1268/1108 931/1217/1063 +f 935/1266/1106 395/1265/1105 649/1267/1107 +f 1247/1268/1108 649/1267/1107 396/1269/1109 +f 1247/1268/1108 865/1270/1110 384/1219/1065 +f 865/1270/1110 1248/1272/1112 862/1221/1067 +f 865/1270/1110 396/1269/1109 578/1271/1111 +f 1248/1272/1112 578/1271/1111 397/1273/1113 +f 1248/1272/1112 506/1274/1114 385/1223/1069 +f 506/1274/1114 1249/1276/1116 501/1225/1071 +f 506/1274/1114 397/1273/1113 793/1275/1115 +f 1249/1276/1116 793/1275/1115 398/1277/1117 +f 1249/1276/1116 424/1278/1118 386/1227/1073 +f 424/1278/1118 1250/1280/1120 418/1229/1075 +f 424/1278/1118 398/1277/1117 712/1279/1119 +f 1250/1280/1120 712/1279/1119 399/1281/608 +f 1250/1280/1120 650/1282/559 387/1231/560 +f 387/1234/560 650/1285/559 1251/1283/1121 +f 399/1284/608 936/1286/1122 1251/1283/1121 +f 936/1286/1122 400/1289/1125 580/1287/1123 +f 646/1236/1078 1251/1283/1121 580/1287/1123 +f 388/1239/1081 580/1287/1123 1252/1288/1124 +f 400/1289/1125 867/1290/1126 1252/1288/1124 +f 867/1290/1126 401/1293/1129 795/1291/1127 +f 575/1240/1082 1252/1288/1124 795/1291/1127 +f 389/1243/1085 795/1291/1127 1253/1292/1128 +f 401/1293/1129 508/1294/1130 1253/1292/1128 +f 508/1294/1130 402/1297/1133 714/1295/1131 +f 789/1244/1086 1253/1292/1128 714/1295/1131 +f 390/1247/1089 714/1295/1131 1254/1296/1132 +f 402/1297/1133 426/1298/1134 1254/1296/1132 +f 426/1298/1134 403/1301/1137 938/1299/1135 +f 709/1248/1090 1254/1296/1132 938/1299/1135 +f 391/1251/1093 938/1299/1135 1255/1300/1136 +f 403/1301/1137 652/1302/1138 1255/1300/1136 +f 652/1302/1138 404/1305/1141 869/1303/1139 +f 933/1252/1094 1255/1300/1136 869/1303/1139 +f 392/1255/1097 869/1303/1139 1256/1304/1140 +f 404/1305/1141 510/1306/1142 1256/1304/1140 +f 510/1306/1142 393/1308/583 792/1257/584 +f 791/1256/1098 1256/1304/1140 792/1257/584 +f 511/1307/632 1257/1310/1144 504/1259/1099 +f 511/1307/632 405/1358/631 797/1309/1143 +f 1257/1310/1144 797/1309/1143 406/1311/1145 +f 1257/1310/1144 428/1312/1146 394/1261/1101 +f 428/1312/1146 1258/1314/1148 421/1263/1103 +f 428/1312/1146 406/1311/1145 716/1313/1147 +f 1258/1314/1148 716/1313/1147 407/1315/1149 +f 1258/1314/1148 654/1316/1150 395/1265/1105 +f 654/1316/1150 1259/1318/1152 649/1267/1107 +f 654/1316/1150 407/1315/1149 940/1317/1151 +f 1259/1318/1152 940/1317/1151 408/1319/1153 +f 1259/1318/1152 583/1320/1154 396/1269/1109 +f 583/1320/1154 1260/1322/1156 578/1271/1111 +f 583/1320/1154 408/1319/1153 871/1321/1155 +f 1260/1322/1156 871/1321/1155 409/1323/1157 +f 1260/1322/1156 799/1324/1158 397/1273/1113 +f 799/1324/1158 1261/1326/1160 793/1275/1115 +f 799/1324/1158 409/1323/1157 513/1325/1159 +f 1261/1326/1160 513/1325/1159 410/1327/1161 +f 1261/1326/1160 719/1328/1162 398/1277/1117 +f 719/1328/1162 1262/1330/1164 712/1279/1119 +f 719/1328/1162 410/1327/1161 430/1329/1163 +f 1262/1330/1164 430/1329/1163 411/1331/656 +f 1262/1330/1164 941/1332/607 399/1281/608 +f 399/1284/608 941/1335/607 1263/1333/1165 +f 411/1334/656 656/1336/1166 1263/1333/1165 +f 656/1336/1166 412/1339/1169 873/1337/1167 +f 936/1286/1122 1263/1333/1165 873/1337/1167 +f 400/1289/1125 873/1337/1167 1264/1338/1168 +f 412/1339/1169 585/1340/1170 1264/1338/1168 +f 585/1340/1170 413/1343/1173 515/1341/1171 +f 867/1290/1126 1264/1338/1168 515/1341/1171 +f 401/1293/1129 515/1341/1171 1265/1342/1172 +f 413/1343/1173 801/1344/1174 1265/1342/1172 +f 801/1344/1174 414/1347/1177 432/1345/1175 +f 508/1294/1130 1265/1342/1172 432/1345/1175 +f 402/1297/1133 432/1345/1175 1266/1346/1176 +f 414/1347/1177 721/1348/1178 1266/1346/1176 +f 721/1348/1178 415/1351/1181 658/1349/1179 +f 426/1298/1134 1266/1346/1176 658/1349/1179 +f 403/1301/1137 658/1349/1179 1267/1350/1180 +f 415/1351/1181 943/1352/1182 1267/1350/1180 +f 943/1352/1182 416/1355/1185 587/1353/1183 +f 652/1302/1138 1267/1350/1180 587/1353/1183 +f 404/1305/1141 587/1353/1183 1268/1354/1184 +f 416/1355/1185 803/1356/1186 1268/1354/1184 +f 803/1356/1186 405/1358/631 511/1307/632 +f 510/1306/1142 1268/1354/1184 511/1307/632 +f 823/1357/679 1269/1359/1187 797/1309/1143 +f 823/1357/679 129/161/106 417/160/105 +f 1269/1359/1187 417/160/105 130/166/111 +f 1269/1359/1187 455/1360/1188 406/1311/1145 +f 455/1360/1188 1270/1361/1189 716/1313/1147 +f 455/1360/1188 130/166/111 502/167/112 +f 1270/1361/1189 502/167/112 131/172/117 +f 1270/1361/1189 966/1362/1190 407/1315/1149 +f 966/1362/1190 1271/1363/1191 940/1317/1151 +f 966/1362/1190 131/172/117 574/173/118 +f 1271/1363/1191 574/173/118 132/178/123 +f 1271/1363/1191 613/1364/1192 408/1319/1153 +f 613/1364/1192 1272/1365/1193 871/1321/1155 +f 613/1364/1192 132/178/123 647/179/124 +f 1272/1365/1193 647/179/124 133/184/129 +f 1272/1365/1193 549/1366/1194 409/1323/1157 +f 549/1366/1194 1273/1367/1195 513/1325/1159 +f 549/1366/1194 133/184/129 708/185/130 +f 1273/1367/1195 708/185/130 134/190/135 +f 1273/1367/1195 759/1368/1196 410/1327/1161 +f 759/1368/1196 1274/1369/1197 430/1329/1163 +f 759/1368/1196 134/190/135 790/191/136 +f 1274/1369/1197 790/191/136 135/196/141 +f 1274/1369/1197 691/1370/655 411/1331/656 +f 411/1334/656 691/1372/655 1275/1371/1198 +f 135/197/141 864/199/143 1275/1371/1198 +f 864/199/143 136/204/146 913/1373/1199 +f 656/1336/1166 1275/1371/1198 913/1373/1199 +f 412/1339/1169 913/1373/1199 1276/1374/1200 +f 136/204/146 934/206/148 1276/1374/1200 +f 934/206/148 137/210/152 850/1375/1201 +f 585/1340/1170 1276/1374/1200 850/1375/1201 +f 413/1343/1173 850/1375/1201 1277/1376/1202 +f 137/210/152 420/212/154 1277/1376/1202 +f 420/212/154 138/216/158 487/1377/1203 +f 801/1344/1174 1277/1376/1202 487/1377/1203 +f 414/1347/1177 487/1377/1203 1278/1378/1204 +f 138/216/158 505/218/160 1278/1378/1204 +f 505/218/160 139/222/164 989/1379/1205 +f 721/1348/1178 1278/1378/1204 989/1379/1205 +f 415/1351/1181 989/1379/1205 1279/1380/1206 +f 139/222/164 577/224/166 1279/1380/1206 +f 577/224/166 140/228/170 640/1381/1207 +f 943/1352/1182 1279/1380/1206 640/1381/1207 +f 416/1355/1185 640/1381/1207 1280/1382/1208 +f 140/228/170 422/230/172 1280/1382/1208 +f 422/230/172 129/161/106 823/1357/679 +f 803/1356/1186 1280/1382/1208 823/1357/679 +g torus_Torus.001_torus.000 +usemtl torus.000 +f 1575/1384/1209 1569/1385/1210 1281/1386/1211 +f 1575/1384/1209 1863/1387/1212 2145/1388/1213 +f 2145/1388/1213 1294/1389/1214 1659/1390/1215 +f 2145/1388/1213 1282/1391/1216 1569/1385/1210 +f 1659/1390/1215 1654/1392/1217 1282/1391/1216 +f 1659/1390/1215 1946/1393/1218 2146/1394/1219 +f 2146/1394/1219 1295/1395/1220 1731/1396/1221 +f 2146/1394/1219 1283/1397/1222 1654/1392/1217 +f 1731/1396/1221 1726/1398/1223 1283/1397/1222 +f 1731/1396/1221 2018/1399/1224 2147/1400/1225 +f 2147/1400/1225 1296/1401/1226 1803/1402/1227 +f 2147/1400/1225 1284/1403/1228 1726/1398/1223 +f 1803/1402/1227 1799/1404/1229 1284/1403/1228 +f 1803/1402/1227 2089/1405/1230 2148/1406/1231 +f 2148/1406/1231 1297/1407/1232 1865/1408/1233 +f 2148/1406/1231 1285/1409/1234 1799/1404/1229 +f 1865/1408/1233 1860/1410/1235 1285/1409/1234 +f 1865/1408/1233 1577/1411/1236 2149/1412/1237 +f 2149/1412/1237 1298/1413/1238 1948/1414/1239 +f 2149/1412/1237 1286/1415/1240 1860/1410/1235 +f 1948/1414/1239 1942/1416/1241 1286/1415/1240 +f 1948/1414/1239 1661/1417/1242 2150/1418/1243 +f 2150/1418/1243 1299/1419/1244 2020/1420/1245 +f 2150/1418/1243 1287/1421/1246 1942/1416/1241 +f 1287/1422/1246 2151/1423/1247 2016/1424/1248 +f 1299/1425/1244 2151/1423/1247 2020/1426/1245 +f 1733/1427/1249 2091/1428/1250 2151/1423/1247 +f 2016/1424/1248 2091/1428/1250 1288/1429/1251 +f 1288/1429/1251 2152/1430/1252 2086/1431/1253 +f 1300/1432/1254 2152/1430/1252 2091/1428/1250 +f 1805/1433/1255 1579/1434/1256 2152/1430/1252 +f 2086/1431/1253 1579/1434/1256 1289/1435/1257 +f 1289/1435/1257 2153/1436/1258 1572/1437/1259 +f 1301/1438/1260 2153/1436/1258 1579/1434/1256 +f 1867/1439/1261 1664/1440/1262 2153/1436/1258 +f 1572/1437/1259 1664/1440/1262 1290/1441/1263 +f 1290/1441/1263 2154/1442/1264 1657/1443/1265 +f 1302/1444/1266 2154/1442/1264 1664/1440/1262 +f 1950/1445/1267 1734/1446/1268 2154/1442/1264 +f 1657/1443/1265 1734/1446/1268 1291/1447/1269 +f 1291/1447/1269 2155/1448/1270 1729/1449/1271 +f 1303/1450/1272 2155/1448/1270 1734/1446/1268 +f 2022/1451/1273 1807/1452/1274 2155/1448/1270 +f 1729/1449/1271 1807/1452/1274 1292/1453/1275 +f 1292/1453/1275 2156/1454/1276 1574/1455/1277 +f 1304/1456/1278 2156/1454/1276 1807/1452/1274 +f 1869/1457/1279 1575/1384/1209 2156/1454/1276 +f 1574/1455/1277 1575/1384/1209 1281/1386/1211 +f 1870/1458/1280 1863/1387/1212 1293/1459/1281 +f 1870/1458/1280 1581/1460/1282 2157/1461/1283 +f 2157/1461/1283 1306/1462/1284 1952/1463/1285 +f 2157/1461/1283 1294/1389/1214 1863/1387/1212 +f 1952/1463/1285 1946/1393/1218 1294/1389/1214 +f 1952/1463/1285 1666/1464/1286 2158/1465/1287 +f 2158/1465/1287 1307/1466/1288 2024/1467/1289 +f 2158/1465/1287 1295/1395/1220 1946/1393/1218 +f 2024/1467/1289 2018/1399/1224 1295/1395/1220 +f 2024/1467/1289 1736/1468/1290 2159/1469/1291 +f 2159/1469/1291 1308/1470/1292 2094/1471/1293 +f 2159/1469/1291 1296/1401/1226 2018/1399/1224 +f 2094/1471/1293 2089/1405/1230 1296/1401/1226 +f 2094/1471/1293 1809/1472/1294 2160/1473/1295 +f 2160/1473/1295 1309/1474/1296 1583/1475/1297 +f 2160/1473/1295 1297/1407/1232 2089/1405/1230 +f 1583/1475/1297 1577/1411/1236 1297/1407/1232 +f 1583/1475/1297 1872/1476/1298 2161/1477/1299 +f 2161/1477/1299 1310/1478/1300 1668/1479/1301 +f 2161/1477/1299 1298/1413/1238 1577/1411/1236 +f 1668/1479/1301 1661/1417/1242 1298/1413/1238 +f 1668/1479/1301 1954/1480/1302 2162/1481/1303 +f 2162/1481/1303 1311/1482/1304 1738/1483/1305 +f 2162/1481/1303 1299/1419/1244 1661/1417/1242 +f 1299/1425/1244 2163/1484/1306 1733/1427/1249 +f 1311/1485/1304 2163/1484/1306 1738/1486/1305 +f 2026/1487/1307 1811/1488/1308 2163/1484/1306 +f 1733/1427/1249 1811/1488/1308 1300/1432/1254 +f 1300/1432/1254 2164/1489/1309 1805/1433/1255 +f 1312/1490/1310 2164/1489/1309 1811/1488/1308 +f 2096/1491/1311 1874/1492/1312 2164/1489/1309 +f 1805/1433/1255 1874/1492/1312 1301/1438/1260 +f 1301/1438/1260 2165/1493/1313 1867/1439/1261 +f 1313/1494/1314 2165/1493/1313 1874/1492/1312 +f 1585/1495/1315 1956/1496/1316 2165/1493/1313 +f 1867/1439/1261 1956/1496/1316 1302/1444/1266 +f 1302/1444/1266 2166/1497/1317 1950/1445/1267 +f 1314/1498/1318 2166/1497/1317 1956/1496/1316 +f 1669/1499/1319 2027/1500/1320 2166/1497/1317 +f 1950/1445/1267 2027/1500/1320 1303/1450/1272 +f 1303/1450/1272 2167/1501/1321 2022/1451/1273 +f 1315/1502/1322 2167/1501/1321 2027/1500/1320 +f 1740/1503/1323 2097/1504/1324 2167/1501/1321 +f 2022/1451/1273 2097/1504/1324 1304/1456/1278 +f 1304/1456/1278 2168/1505/1325 1869/1457/1279 +f 1316/1506/1326 2168/1505/1325 2097/1504/1324 +f 1586/1507/1327 1870/1458/1280 2168/1505/1325 +f 1869/1457/1279 1870/1458/1280 1293/1459/1281 +f 1587/1508/1328 1581/1460/1282 1305/1509/1329 +f 1587/1508/1328 1875/1510/1330 2169/1511/1331 +f 2169/1511/1331 1318/1512/1332 1670/1513/1333 +f 2169/1511/1331 1306/1462/1284 1581/1460/1282 +f 1670/1513/1333 1666/1464/1286 1306/1462/1284 +f 1670/1513/1333 1957/1514/1334 2170/1515/1335 +f 2170/1515/1335 1319/1516/1336 1741/1517/1337 +f 2170/1515/1335 1307/1466/1288 1666/1464/1286 +f 1741/1517/1337 1736/1468/1290 1307/1466/1288 +f 1741/1517/1337 2028/1518/1338 2171/1519/1339 +f 2171/1519/1339 1320/1520/1340 1812/1521/1341 +f 2171/1519/1339 1308/1470/1292 1736/1468/1290 +f 1812/1521/1341 1809/1472/1294 1308/1470/1292 +f 1812/1521/1341 2098/1522/1342 2172/1523/1343 +f 2172/1523/1343 1321/1524/1344 1876/1525/1345 +f 2172/1523/1343 1309/1474/1296 1809/1472/1294 +f 1876/1525/1345 1872/1476/1298 1309/1474/1296 +f 1876/1525/1345 1588/1526/1346 2173/1527/1347 +f 2173/1527/1347 1322/1528/1348 1958/1529/1349 +f 2173/1527/1347 1310/1478/1300 1872/1476/1298 +f 1958/1529/1349 1954/1480/1302 1310/1478/1300 +f 1958/1529/1349 1671/1530/1350 2174/1531/1351 +f 2174/1531/1351 1323/1532/1352 2029/1533/1353 +f 2174/1531/1351 1311/1482/1304 1954/1480/1302 +f 1311/1485/1304 2175/1534/1354 2026/1487/1307 +f 1323/1535/1352 2175/1534/1354 2029/1536/1353 +f 1742/1537/1355 2099/1538/1356 2175/1534/1354 +f 2026/1487/1307 2099/1538/1356 1312/1490/1310 +f 1312/1490/1310 2176/1539/1357 2096/1491/1311 +f 1324/1540/1358 2176/1539/1357 2099/1538/1356 +f 1813/1541/1359 1589/1542/1360 2176/1539/1357 +f 2096/1491/1311 1589/1542/1360 1313/1494/1314 +f 1313/1494/1314 2177/1543/1361 1585/1495/1315 +f 1325/1544/1362 2177/1543/1361 1589/1542/1360 +f 1877/1545/1363 1672/1546/1364 2177/1543/1361 +f 1585/1495/1315 1672/1546/1364 1314/1498/1318 +f 1314/1498/1318 2178/1547/1365 1669/1499/1319 +f 1326/1548/1366 2178/1547/1365 1672/1546/1364 +f 1959/1549/1367 1743/1550/1368 2178/1547/1365 +f 1669/1499/1319 1743/1550/1368 1315/1502/1322 +f 1315/1502/1322 2179/1551/1369 1740/1503/1323 +f 1327/1552/1370 2179/1551/1369 1743/1550/1368 +f 2030/1553/1371 1814/1554/1372 2179/1551/1369 +f 1740/1503/1323 1814/1554/1372 1316/1506/1326 +f 1316/1506/1326 2180/1555/1373 1586/1507/1327 +f 1328/1556/1374 2180/1555/1373 1814/1554/1372 +f 1878/1557/1375 1587/1508/1328 2180/1555/1373 +f 1586/1507/1327 1587/1508/1328 1305/1509/1329 +f 1879/1558/1376 1875/1510/1330 1317/1559/1377 +f 1879/1558/1376 1590/1560/1378 2181/1561/1379 +f 2181/1561/1379 1330/1562/1380 1960/1563/1381 +f 2181/1561/1379 1318/1512/1332 1875/1510/1330 +f 1960/1563/1381 1957/1514/1334 1318/1512/1332 +f 1960/1563/1381 1673/1564/1382 2182/1565/1383 +f 2182/1565/1383 1331/1566/1384 2031/1567/1385 +f 2182/1565/1383 1319/1516/1336 1957/1514/1334 +f 2031/1567/1385 2028/1518/1338 1319/1516/1336 +f 2031/1567/1385 1744/1568/1386 2183/1569/1387 +f 2183/1569/1387 1332/1570/1388 2100/1571/1389 +f 2183/1569/1387 1320/1520/1340 2028/1518/1338 +f 2100/1571/1389 2098/1522/1342 1320/1520/1340 +f 2100/1571/1389 1815/1572/1390 2184/1573/1391 +f 2184/1573/1391 1333/1574/1392 1591/1575/1393 +f 2184/1573/1391 1321/1524/1344 2098/1522/1342 +f 1591/1575/1393 1588/1526/1346 1321/1524/1344 +f 1591/1575/1393 1880/1576/1394 2185/1577/1395 +f 2185/1577/1395 1334/1578/1396 1674/1579/1397 +f 2185/1577/1395 1322/1528/1348 1588/1526/1346 +f 1674/1579/1397 1671/1530/1350 1322/1528/1348 +f 1674/1579/1397 1961/1580/1398 2186/1581/1399 +f 2186/1581/1399 1335/1582/1400 1745/1583/1401 +f 2186/1581/1399 1323/1532/1352 1671/1530/1350 +f 1323/1535/1352 2187/1584/1402 1742/1537/1355 +f 1335/1585/1400 2187/1584/1402 1745/1586/1401 +f 2032/1587/1403 1816/1588/1404 2187/1584/1402 +f 1742/1537/1355 1816/1588/1404 1324/1540/1358 +f 1324/1540/1358 2188/1589/1405 1813/1541/1359 +f 1336/1590/1406 2188/1589/1405 1816/1588/1404 +f 2101/1591/1407 1881/1592/1408 2188/1589/1405 +f 1813/1541/1359 1881/1592/1408 1325/1544/1362 +f 1325/1544/1362 2189/1593/1409 1877/1545/1363 +f 1337/1594/1410 2189/1593/1409 1881/1592/1408 +f 1592/1595/1411 1962/1596/1412 2189/1593/1409 +f 1877/1545/1363 1962/1596/1412 1326/1548/1366 +f 1326/1548/1366 2190/1597/1413 1959/1549/1367 +f 1338/1598/1414 2190/1597/1413 1962/1596/1412 +f 1675/1599/1415 2033/1600/1416 2190/1597/1413 +f 1959/1549/1367 2033/1600/1416 1327/1552/1370 +f 1327/1552/1370 2191/1601/1417 2030/1553/1371 +f 1339/1602/1418 2191/1601/1417 2033/1600/1416 +f 1746/1603/1419 2102/1604/1420 2191/1601/1417 +f 2030/1553/1371 2102/1604/1420 1328/1556/1374 +f 1328/1556/1374 2192/1605/1421 1878/1557/1375 +f 1340/1606/1422 2192/1605/1421 2102/1604/1420 +f 1593/1607/1423 1879/1558/1376 2192/1605/1421 +f 1878/1557/1375 1879/1558/1376 1317/1559/1377 +f 1594/1608/1424 1590/1560/1378 1329/1609/1425 +f 1594/1608/1424 1882/1610/1426 2193/1611/1427 +f 2193/1611/1427 1342/1612/1428 1676/1613/1429 +f 2193/1611/1427 1330/1562/1380 1590/1560/1378 +f 1676/1613/1429 1673/1564/1382 1330/1562/1380 +f 1676/1613/1429 1963/1614/1430 2194/1615/1431 +f 2194/1615/1431 1343/1616/1432 1747/1617/1433 +f 2194/1615/1431 1331/1566/1384 1673/1564/1382 +f 1747/1617/1433 1744/1568/1386 1331/1566/1384 +f 1747/1617/1433 2034/1618/1434 2195/1619/1435 +f 2195/1619/1435 1344/1620/1436 1817/1621/1437 +f 2195/1619/1435 1332/1570/1388 1744/1568/1386 +f 1817/1621/1437 1815/1572/1390 1332/1570/1388 +f 1817/1621/1437 2103/1622/1438 2196/1623/1439 +f 2196/1623/1439 1345/1624/1440 1883/1625/1441 +f 2196/1623/1439 1333/1574/1392 1815/1572/1390 +f 1883/1625/1441 1880/1576/1394 1333/1574/1392 +f 1883/1625/1441 1595/1626/1442 2197/1627/1443 +f 2197/1627/1443 1346/1628/1444 1964/1629/1445 +f 2197/1627/1443 1334/1578/1396 1880/1576/1394 +f 1964/1629/1445 1961/1580/1398 1334/1578/1396 +f 1964/1629/1445 1677/1630/1446 2198/1631/1447 +f 2198/1631/1447 1347/1632/1448 2035/1633/1449 +f 2198/1631/1447 1335/1582/1400 1961/1580/1398 +f 1335/1585/1400 2199/1634/1450 2032/1587/1403 +f 1347/1635/1448 2199/1634/1450 2035/1636/1449 +f 1748/1637/1451 2104/1638/1452 2199/1634/1450 +f 2032/1587/1403 2104/1638/1452 1336/1590/1406 +f 1336/1590/1406 2200/1639/1453 2101/1591/1407 +f 1348/1640/1454 2200/1639/1453 2104/1638/1452 +f 1818/1641/1455 1596/1642/1456 2200/1639/1453 +f 2101/1591/1407 1596/1642/1456 1337/1594/1410 +f 1337/1594/1410 2201/1643/1457 1592/1595/1411 +f 1349/1644/1458 2201/1643/1457 1596/1642/1456 +f 1884/1645/1459 1678/1646/1460 2201/1643/1457 +f 1592/1595/1411 1678/1646/1460 1338/1598/1414 +f 1338/1598/1414 2202/1647/1461 1675/1599/1415 +f 1350/1648/1462 2202/1647/1461 1678/1646/1460 +f 1965/1649/1463 1749/1650/1464 2202/1647/1461 +f 1675/1599/1415 1749/1650/1464 1339/1602/1418 +f 1339/1602/1418 2203/1651/1465 1746/1603/1419 +f 1351/1652/1466 2203/1651/1465 1749/1650/1464 +f 2036/1653/1467 1819/1654/1468 2203/1651/1465 +f 1746/1603/1419 1819/1654/1468 1340/1606/1422 +f 1340/1606/1422 2204/1655/1469 1593/1607/1423 +f 1352/1656/1470 2204/1655/1469 1819/1654/1468 +f 1885/1657/1471 1594/1608/1424 2204/1655/1469 +f 1593/1607/1423 1594/1608/1424 1329/1609/1425 +f 1886/1658/1472 1882/1610/1426 1341/1659/1473 +f 1886/1658/1472 1597/1660/1474 2205/1661/1475 +f 2205/1661/1475 1354/1662/1476 1966/1663/1477 +f 2205/1661/1475 1342/1612/1428 1882/1610/1426 +f 1966/1663/1477 1963/1614/1430 1342/1612/1428 +f 1966/1663/1477 1679/1664/1478 2206/1665/1479 +f 2206/1665/1479 1355/1666/1480 2037/1667/1481 +f 2206/1665/1479 1343/1616/1432 1963/1614/1430 +f 2037/1667/1481 2034/1618/1434 1343/1616/1432 +f 2037/1667/1481 1750/1668/1482 2207/1669/1483 +f 2207/1669/1483 1356/1670/1484 2105/1671/1485 +f 2207/1669/1483 1344/1620/1436 2034/1618/1434 +f 2105/1671/1485 2103/1622/1438 1344/1620/1436 +f 2105/1671/1485 1820/1672/1486 2208/1673/1487 +f 2208/1673/1487 1357/1674/1488 1598/1675/1489 +f 2208/1673/1487 1345/1624/1440 2103/1622/1438 +f 1598/1675/1489 1595/1626/1442 1345/1624/1440 +f 1598/1675/1489 1887/1676/1490 2209/1677/1491 +f 2209/1677/1491 1358/1678/1492 1680/1679/1493 +f 2209/1677/1491 1346/1628/1444 1595/1626/1442 +f 1680/1679/1493 1677/1630/1446 1346/1628/1444 +f 1680/1679/1493 1967/1680/1494 2210/1681/1495 +f 2210/1681/1495 1359/1682/1496 1751/1683/1497 +f 2210/1681/1495 1347/1632/1448 1677/1630/1446 +f 1347/1635/1448 2211/1684/1498 1748/1637/1451 +f 1359/1685/1496 2211/1684/1498 1751/1686/1497 +f 2038/1687/1499 1821/1688/1500 2211/1684/1498 +f 1748/1637/1451 1821/1688/1500 1348/1640/1454 +f 1348/1640/1454 2212/1689/1501 1818/1641/1455 +f 1360/1690/1502 2212/1689/1501 1821/1688/1500 +f 2106/1691/1503 1888/1692/1504 2212/1689/1501 +f 1818/1641/1455 1888/1692/1504 1349/1644/1458 +f 1349/1644/1458 2213/1693/1505 1884/1645/1459 +f 1361/1694/1506 2213/1693/1505 1888/1692/1504 +f 1599/1695/1507 1968/1696/1508 2213/1693/1505 +f 1884/1645/1459 1968/1696/1508 1350/1648/1462 +f 1350/1648/1462 2214/1697/1509 1965/1649/1463 +f 1362/1698/1510 2214/1697/1509 1968/1696/1508 +f 1681/1699/1511 2039/1700/1512 2214/1697/1509 +f 1965/1649/1463 2039/1700/1512 1351/1652/1466 +f 1351/1652/1466 2215/1701/1513 2036/1653/1467 +f 1363/1702/1514 2215/1701/1513 2039/1700/1512 +f 1752/1703/1515 2107/1704/1516 2215/1701/1513 +f 2036/1653/1467 2107/1704/1516 1352/1656/1470 +f 1352/1656/1470 2216/1705/1517 1885/1657/1471 +f 1364/1706/1518 2216/1705/1517 2107/1704/1516 +f 1600/1707/1519 1886/1658/1472 2216/1705/1517 +f 1885/1657/1471 1886/1658/1472 1341/1659/1473 +f 1601/1708/1520 1597/1660/1474 1353/1709/1521 +f 1601/1708/1520 1889/1710/1522 2217/1711/1523 +f 2217/1711/1523 1366/1712/1524 1682/1713/1525 +f 2217/1711/1523 1354/1662/1476 1597/1660/1474 +f 1682/1713/1525 1679/1664/1478 1354/1662/1476 +f 1682/1713/1525 1969/1714/1526 2218/1715/1527 +f 2218/1715/1527 1367/1716/1528 1753/1717/1529 +f 2218/1715/1527 1355/1666/1480 1679/1664/1478 +f 1753/1717/1529 1750/1668/1482 1355/1666/1480 +f 1753/1717/1529 2040/1718/1530 2219/1719/1531 +f 2219/1719/1531 1368/1720/1532 1822/1721/1533 +f 2219/1719/1531 1356/1670/1484 1750/1668/1482 +f 1822/1721/1533 1820/1672/1486 1356/1670/1484 +f 1822/1721/1533 2108/1722/1534 2220/1723/1535 +f 2220/1723/1535 1369/1724/1536 1890/1725/1537 +f 2220/1723/1535 1357/1674/1488 1820/1672/1486 +f 1890/1725/1537 1887/1676/1490 1357/1674/1488 +f 1890/1725/1537 1602/1726/1538 2221/1727/1539 +f 2221/1727/1539 1370/1728/1540 1970/1729/1541 +f 2221/1727/1539 1358/1678/1492 1887/1676/1490 +f 1970/1729/1541 1967/1680/1494 1358/1678/1492 +f 1970/1729/1541 1683/1730/1542 2222/1731/1543 +f 2222/1731/1543 1371/1732/1544 2041/1733/1545 +f 2222/1731/1543 1359/1682/1496 1967/1680/1494 +f 1359/1685/1496 2223/1734/1546 2038/1687/1499 +f 1371/1735/1544 2223/1734/1546 2041/1736/1545 +f 1754/1737/1547 2109/1738/1548 2223/1734/1546 +f 2038/1687/1499 2109/1738/1548 1360/1690/1502 +f 1360/1690/1502 2224/1739/1549 2106/1691/1503 +f 1372/1740/1550 2224/1739/1549 2109/1738/1548 +f 1823/1741/1551 1603/1742/1552 2224/1739/1549 +f 2106/1691/1503 1603/1742/1552 1361/1694/1506 +f 1361/1694/1506 2225/1743/1553 1599/1695/1507 +f 1373/1744/1554 2225/1743/1553 1603/1742/1552 +f 1891/1745/1555 1684/1746/1556 2225/1743/1553 +f 1599/1695/1507 1684/1746/1556 1362/1698/1510 +f 1362/1698/1510 2226/1747/1557 1681/1699/1511 +f 1374/1748/1558 2226/1747/1557 1684/1746/1556 +f 1971/1749/1559 1755/1750/1560 2226/1747/1557 +f 1681/1699/1511 1755/1750/1560 1363/1702/1514 +f 1363/1702/1514 2227/1751/1561 1752/1703/1515 +f 1375/1752/1562 2227/1751/1561 1755/1750/1560 +f 2042/1753/1563 1824/1754/1564 2227/1751/1561 +f 1752/1703/1515 1824/1754/1564 1364/1706/1518 +f 1364/1706/1518 2228/1755/1565 1600/1707/1519 +f 1376/1756/1566 2228/1755/1565 1824/1754/1564 +f 1892/1757/1567 1601/1708/1520 2228/1755/1565 +f 1600/1707/1519 1601/1708/1520 1353/1709/1521 +f 1893/1758/1568 1889/1710/1522 1365/1759/1569 +f 1893/1758/1568 1604/1760/1570 2229/1761/1571 +f 2229/1761/1571 1378/1762/1572 1972/1763/1573 +f 2229/1761/1571 1366/1712/1524 1889/1710/1522 +f 1972/1763/1573 1969/1714/1526 1366/1712/1524 +f 1972/1763/1573 1685/1764/1574 2230/1765/1575 +f 2230/1765/1575 1379/1766/1576 2043/1767/1577 +f 2230/1765/1575 1367/1716/1528 1969/1714/1526 +f 2043/1767/1577 2040/1718/1530 1367/1716/1528 +f 2043/1767/1577 1756/1768/1578 2231/1769/1579 +f 2231/1769/1579 1380/1770/1580 2110/1771/1581 +f 2231/1769/1579 1368/1720/1532 2040/1718/1530 +f 2110/1771/1581 2108/1722/1534 1368/1720/1532 +f 2110/1771/1581 1825/1772/1582 2232/1773/1583 +f 2232/1773/1583 1381/1774/1584 1605/1775/1585 +f 2232/1773/1583 1369/1724/1536 2108/1722/1534 +f 1605/1775/1585 1602/1726/1538 1369/1724/1536 +f 1605/1775/1585 1894/1776/1586 2233/1777/1587 +f 2233/1777/1587 1382/1778/1588 1686/1779/1589 +f 2233/1777/1587 1370/1728/1540 1602/1726/1538 +f 1686/1779/1589 1683/1730/1542 1370/1728/1540 +f 1686/1779/1589 1973/1780/1590 2234/1781/1591 +f 2234/1781/1591 1383/1782/1592 1757/1783/1593 +f 2234/1781/1591 1371/1732/1544 1683/1730/1542 +f 1371/1735/1544 2235/1784/1594 1754/1737/1547 +f 1383/1785/1592 2235/1784/1594 1757/1786/1593 +f 2044/1787/1595 1826/1788/1596 2235/1784/1594 +f 1754/1737/1547 1826/1788/1596 1372/1740/1550 +f 1372/1740/1550 2236/1789/1597 1823/1741/1551 +f 1384/1790/1598 2236/1789/1597 1826/1788/1596 +f 2111/1791/1599 1895/1792/1600 2236/1789/1597 +f 1823/1741/1551 1895/1792/1600 1373/1744/1554 +f 1373/1744/1554 2237/1793/1601 1891/1745/1555 +f 1385/1794/1602 2237/1793/1601 1895/1792/1600 +f 1606/1795/1603 1974/1796/1604 2237/1793/1601 +f 1891/1745/1555 1974/1796/1604 1374/1748/1558 +f 1374/1748/1558 2238/1797/1605 1971/1749/1559 +f 1386/1798/1606 2238/1797/1605 1974/1796/1604 +f 1687/1799/1607 2045/1800/1608 2238/1797/1605 +f 1971/1749/1559 2045/1800/1608 1375/1752/1562 +f 1375/1752/1562 2239/1801/1609 2042/1753/1563 +f 1387/1802/1610 2239/1801/1609 2045/1800/1608 +f 1758/1803/1611 2112/1804/1612 2239/1801/1609 +f 2042/1753/1563 2112/1804/1612 1376/1756/1566 +f 1376/1756/1566 2240/1805/1613 1892/1757/1567 +f 1388/1806/1614 2240/1805/1613 2112/1804/1612 +f 1608/1807/1615 1893/1758/1568 2240/1805/1613 +f 1892/1757/1567 1893/1758/1568 1365/1759/1569 +f 1609/1808/1616 1604/1760/1570 1377/1809/1617 +f 1609/1808/1616 1896/1810/1618 2241/1811/1619 +f 2241/1811/1619 1390/1812/1620 1688/1813/1621 +f 2241/1811/1619 1378/1762/1572 1604/1760/1570 +f 1688/1813/1621 1685/1764/1574 1378/1762/1572 +f 1688/1813/1621 1976/1814/1622 2242/1815/1623 +f 2242/1815/1623 1391/1816/1624 1759/1817/1625 +f 2242/1815/1623 1379/1766/1576 1685/1764/1574 +f 1759/1817/1625 1756/1768/1578 1379/1766/1576 +f 1759/1817/1625 2046/1818/1626 2243/1819/1627 +f 2243/1819/1627 1392/1820/1628 1827/1821/1629 +f 2243/1819/1627 1380/1770/1580 1756/1768/1578 +f 1827/1821/1629 1825/1772/1582 1380/1770/1580 +f 1827/1821/1629 2113/1822/1630 2244/1823/1631 +f 2244/1823/1631 1393/1824/1632 1897/1825/1633 +f 2244/1823/1631 1381/1774/1584 1825/1772/1582 +f 1897/1825/1633 1894/1776/1586 1381/1774/1584 +f 1897/1825/1633 1610/1826/1634 2245/1827/1635 +f 2245/1827/1635 1394/1828/1636 1977/1829/1637 +f 2245/1827/1635 1382/1778/1588 1894/1776/1586 +f 1977/1829/1637 1973/1780/1590 1382/1778/1588 +f 1977/1829/1637 1689/1830/1638 2246/1831/1639 +f 2246/1831/1639 1395/1832/1640 2047/1833/1641 +f 2246/1831/1639 1383/1782/1592 1973/1780/1590 +f 1383/1785/1592 2247/1834/1642 2044/1787/1595 +f 1395/1835/1640 2247/1834/1642 2047/1836/1641 +f 1760/1837/1643 2114/1838/1644 2247/1834/1642 +f 2044/1787/1595 2114/1838/1644 1384/1790/1598 +f 1384/1790/1598 2248/1839/1645 2111/1791/1599 +f 1396/1840/1646 2248/1839/1645 2114/1838/1644 +f 1828/1841/1647 1611/1842/1648 2248/1839/1645 +f 2111/1791/1599 1611/1842/1648 1385/1794/1602 +f 1385/1794/1602 2249/1843/1649 1606/1795/1603 +f 1397/1844/1650 2249/1843/1649 1611/1842/1648 +f 1898/1845/1651 1690/1846/1652 2249/1843/1649 +f 1606/1795/1603 1690/1846/1652 1386/1798/1606 +f 1386/1798/1606 2250/1847/1653 1687/1799/1607 +f 1398/1848/1654 2250/1847/1653 1690/1846/1652 +f 1978/1849/1655 1761/1850/1656 2250/1847/1653 +f 1687/1799/1607 1761/1850/1656 1387/1802/1610 +f 1387/1802/1610 2251/1851/1657 1758/1803/1611 +f 1399/1852/1658 2251/1851/1657 1761/1850/1656 +f 2048/1853/1659 1829/1854/1660 2251/1851/1657 +f 1758/1803/1611 1829/1854/1660 1388/1806/1614 +f 1388/1806/1614 2252/1855/1661 1608/1807/1615 +f 1400/1856/1662 2252/1855/1661 1829/1854/1660 +f 1899/1857/1663 1609/1808/1616 2252/1855/1661 +f 1608/1807/1615 1609/1808/1616 1377/1809/1617 +f 1900/1858/1664 1896/1810/1618 1389/1859/1665 +f 1900/1858/1664 1612/1860/1666 2253/1861/1667 +f 2253/1861/1667 1402/1862/1668 1979/1863/1669 +f 2253/1861/1667 1390/1812/1620 1896/1810/1618 +f 1979/1863/1669 1976/1814/1622 1390/1812/1620 +f 1979/1863/1669 1691/1864/1670 2254/1865/1671 +f 2254/1865/1671 1403/1866/1672 2049/1867/1673 +f 2254/1865/1671 1391/1816/1624 1976/1814/1622 +f 2049/1867/1673 2046/1818/1626 1391/1816/1624 +f 2049/1867/1673 1762/1868/1674 2255/1869/1675 +f 2255/1869/1675 1404/1870/1676 2115/1871/1677 +f 2255/1869/1675 1392/1820/1628 2046/1818/1626 +f 2115/1871/1677 2113/1822/1630 1392/1820/1628 +f 2115/1871/1677 1830/1872/1678 2256/1873/1679 +f 2256/1873/1679 1405/1874/1680 1613/1875/1681 +f 2256/1873/1679 1393/1824/1632 2113/1822/1630 +f 1613/1875/1681 1610/1826/1634 1393/1824/1632 +f 1613/1875/1681 1901/1876/1682 2257/1877/1683 +f 2257/1877/1683 1406/1878/1684 1692/1879/1685 +f 2257/1877/1683 1394/1828/1636 1610/1826/1634 +f 1692/1879/1685 1689/1830/1638 1394/1828/1636 +f 1692/1879/1685 1980/1880/1686 2258/1881/1687 +f 2258/1881/1687 1407/1882/1688 1763/1883/1689 +f 2258/1881/1687 1395/1832/1640 1689/1830/1638 +f 1395/1835/1640 2259/1884/1690 1760/1837/1643 +f 1407/1885/1688 2259/1884/1690 1763/1886/1689 +f 2050/1887/1691 1831/1888/1692 2259/1884/1690 +f 1760/1837/1643 1831/1888/1692 1396/1840/1646 +f 1396/1840/1646 2260/1889/1693 1828/1841/1647 +f 1408/1890/1694 2260/1889/1693 1831/1888/1692 +f 2116/1891/1695 1902/1892/1696 2260/1889/1693 +f 1828/1841/1647 1902/1892/1696 1397/1844/1650 +f 1397/1844/1650 2261/1893/1697 1898/1845/1651 +f 1409/1894/1698 2261/1893/1697 1902/1892/1696 +f 1614/1895/1699 1981/1896/1700 2261/1893/1697 +f 1898/1845/1651 1981/1896/1700 1398/1848/1654 +f 1398/1848/1654 2262/1897/1701 1978/1849/1655 +f 1410/1898/1702 2262/1897/1701 1981/1896/1700 +f 1693/1899/1703 2051/1900/1704 2262/1897/1701 +f 1978/1849/1655 2051/1900/1704 1399/1852/1658 +f 1399/1852/1658 2263/1901/1705 2048/1853/1659 +f 1411/1902/1706 2263/1901/1705 2051/1900/1704 +f 1764/1903/1707 2117/1904/1708 2263/1901/1705 +f 2048/1853/1659 2117/1904/1708 1400/1856/1662 +f 1400/1856/1662 2264/1905/1709 1899/1857/1663 +f 1412/1906/1710 2264/1905/1709 2117/1904/1708 +f 1615/1907/1711 1900/1858/1664 2264/1905/1709 +f 1899/1857/1663 1900/1858/1664 1389/1859/1665 +f 1616/1908/1712 1612/1860/1666 1401/1909/1713 +f 1616/1908/1712 1903/1910/1714 2265/1911/1715 +f 2265/1911/1715 1414/1912/1716 1694/1913/1717 +f 2265/1911/1715 1402/1862/1668 1612/1860/1666 +f 1694/1913/1717 1691/1864/1670 1402/1862/1668 +f 1694/1913/1717 1982/1914/1718 2266/1915/1719 +f 2266/1915/1719 1415/1916/1720 1766/1917/1721 +f 2266/1915/1719 1403/1866/1672 1691/1864/1670 +f 1766/1917/1721 1762/1868/1674 1403/1866/1672 +f 1766/1917/1721 2052/1918/1722 2267/1919/1723 +f 2267/1919/1723 1416/1920/1724 1832/1921/1725 +f 2267/1919/1723 1404/1870/1676 1762/1868/1674 +f 1832/1921/1725 1830/1872/1678 1404/1870/1676 +f 1832/1921/1725 2119/1922/1726 2268/1923/1727 +f 2268/1923/1727 1417/1924/1728 1904/1925/1729 +f 2268/1923/1727 1405/1874/1680 1830/1872/1678 +f 1904/1925/1729 1901/1876/1682 1405/1874/1680 +f 1904/1925/1729 1617/1926/1730 2269/1927/1731 +f 2269/1927/1731 1418/1928/1732 1983/1929/1733 +f 2269/1927/1731 1406/1878/1684 1901/1876/1682 +f 1983/1929/1733 1980/1880/1686 1406/1878/1684 +f 1983/1929/1733 1695/1930/1734 2270/1931/1735 +f 2270/1931/1735 1419/1932/1736 2053/1933/1737 +f 2270/1931/1735 1407/1882/1688 1980/1880/1686 +f 1407/1885/1688 2271/1934/1738 2050/1887/1691 +f 1419/1935/1736 2271/1934/1738 2053/1936/1737 +f 1767/1937/1739 2120/1938/1740 2271/1934/1738 +f 2050/1887/1691 2120/1938/1740 1408/1890/1694 +f 1408/1890/1694 2272/1939/1741 2116/1891/1695 +f 1420/1940/1742 2272/1939/1741 2120/1938/1740 +f 1833/1941/1743 1618/1942/1744 2272/1939/1741 +f 2116/1891/1695 1618/1942/1744 1409/1894/1698 +f 1409/1894/1698 2273/1943/1745 1614/1895/1699 +f 1421/1944/1746 2273/1943/1745 1618/1942/1744 +f 1905/1945/1747 1696/1946/1748 2273/1943/1745 +f 1614/1895/1699 1696/1946/1748 1410/1898/1702 +f 1410/1898/1702 2274/1947/1749 1693/1899/1703 +f 1422/1948/1750 2274/1947/1749 1696/1946/1748 +f 1984/1949/1751 1768/1950/1752 2274/1947/1749 +f 1693/1899/1703 1768/1950/1752 1411/1902/1706 +f 1411/1902/1706 2275/1951/1753 1764/1903/1707 +f 1423/1952/1754 2275/1951/1753 1768/1950/1752 +f 2054/1953/1755 1834/1954/1756 2275/1951/1753 +f 1764/1903/1707 1834/1954/1756 1412/1906/1710 +f 1412/1906/1710 2276/1955/1757 1615/1907/1711 +f 1424/1956/1758 2276/1955/1757 1834/1954/1756 +f 1906/1957/1759 1616/1908/1712 2276/1955/1757 +f 1615/1907/1711 1616/1908/1712 1401/1909/1713 +f 1907/1958/1760 1903/1910/1714 1413/1959/1761 +f 1907/1958/1760 1619/1960/1762 2277/1961/1763 +f 2277/1961/1763 1426/1962/1764 1985/1963/1765 +f 2277/1961/1763 1414/1912/1716 1903/1910/1714 +f 1985/1963/1765 1982/1914/1718 1414/1912/1716 +f 1985/1963/1765 1697/1964/1766 2278/1965/1767 +f 2278/1965/1767 1427/1966/1768 2055/1967/1769 +f 2278/1965/1767 1415/1916/1720 1982/1914/1718 +f 2055/1967/1769 2052/1918/1722 1415/1916/1720 +f 2055/1967/1769 1769/1968/1770 2279/1969/1771 +f 2279/1969/1771 1428/1970/1772 2121/1971/1773 +f 2279/1969/1771 1416/1920/1724 2052/1918/1722 +f 2121/1971/1773 2119/1922/1726 1416/1920/1724 +f 2121/1971/1773 1835/1972/1774 2280/1973/1775 +f 2280/1973/1775 1429/1974/1776 1620/1975/1777 +f 2280/1973/1775 1417/1924/1728 2119/1922/1726 +f 1620/1975/1777 1617/1926/1730 1417/1924/1728 +f 1620/1975/1777 1908/1976/1778 2281/1977/1779 +f 2281/1977/1779 1430/1978/1780 1698/1979/1781 +f 2281/1977/1779 1418/1928/1732 1617/1926/1730 +f 1698/1979/1781 1695/1930/1734 1418/1928/1732 +f 1698/1979/1781 1986/1980/1782 2282/1981/1783 +f 2282/1981/1783 1431/1982/1211 1770/1983/1784 +f 2282/1981/1783 1419/1932/1736 1695/1930/1734 +f 1419/1935/1736 2283/1984/1785 1767/1937/1739 +f 1431/1985/1211 2283/1984/1785 1770/1986/1784 +f 2056/1987/1786 1836/1988/1787 2283/1984/1785 +f 1767/1937/1739 1836/1988/1787 1420/1940/1742 +f 1420/1940/1742 2284/1989/1788 1833/1941/1743 +f 1432/1990/1789 2284/1989/1788 1836/1988/1787 +f 2122/1991/1790 1909/1992/1791 2284/1989/1788 +f 1833/1941/1743 1909/1992/1791 1421/1944/1746 +f 1421/1944/1746 2285/1993/1792 1905/1945/1747 +f 1433/1994/1793 2285/1993/1792 1909/1992/1791 +f 1621/1995/1794 1987/1996/1795 2285/1993/1792 +f 1905/1945/1747 1987/1996/1795 1422/1948/1750 +f 1422/1948/1750 2286/1997/1796 1984/1949/1751 +f 1434/1998/1797 2286/1997/1796 1987/1996/1795 +f 1699/1999/1798 2057/2000/1799 2286/1997/1796 +f 1984/1949/1751 2057/2000/1799 1423/1952/1754 +f 1423/1952/1754 2287/2001/1800 2054/1953/1755 +f 1435/2002/1801 2287/2001/1800 2057/2000/1799 +f 1771/2003/1802 2123/2004/1803 2287/2001/1800 +f 2054/1953/1755 2123/2004/1803 1424/1956/1758 +f 1424/1956/1758 2288/2005/1804 1906/1957/1759 +f 1436/2006/1805 2288/2005/1804 2123/2004/1803 +f 1622/2007/1806 1907/1958/1760 2288/2005/1804 +f 1906/1957/1759 1907/1958/1760 1413/1959/1761 +f 1623/2008/1245 1619/2009/1762 1425/2010/1246 +f 1623/2008/1245 1910/2011/1807 2289/2012/1808 +f 2289/2012/1808 1438/2013/1809 1700/2014/1810 +f 2289/2012/1808 1426/2015/1764 1619/2009/1762 +f 1700/2014/1810 1697/2016/1766 1426/2015/1764 +f 1700/2014/1810 1988/2017/1811 2290/2018/1812 +f 2290/2018/1812 1439/2019/1813 1772/2020/1814 +f 2290/2018/1812 1427/2021/1768 1697/2016/1766 +f 1772/2020/1814 1769/2022/1770 1427/2021/1768 +f 1772/2020/1814 2058/2023/1815 2291/2024/1816 +f 2291/2024/1816 1440/2025/1817 1837/2026/1818 +f 2291/2024/1816 1428/2027/1772 1769/2022/1770 +f 1837/2026/1818 1835/2028/1774 1428/2027/1772 +f 1837/2026/1818 2124/2029/1819 2292/2030/1820 +f 2292/2030/1820 1441/2031/1821 1912/2032/1822 +f 2292/2030/1820 1429/2033/1776 1835/2028/1774 +f 1912/2032/1822 1908/2034/1778 1429/2033/1776 +f 1912/2032/1822 1624/2035/1823 2293/2036/1824 +f 2293/2036/1824 1442/2037/1825 1989/2038/1826 +f 2293/2036/1824 1430/2039/1780 1908/2034/1778 +f 1989/2038/1826 1986/2040/1782 1430/2039/1780 +f 1989/2038/1826 1702/2041/1827 2294/2042/1828 +f 2294/2042/1828 1443/2043/1281 2059/2044/1209 +f 2294/2042/1828 1431/2045/1211 1986/2040/1782 +f 1431/2046/1211 2295/2047/1829 2056/2048/1786 +f 1443/2049/1281 2295/2047/1829 2059/2050/1209 +f 1773/2051/1830 2125/2052/1831 2295/2047/1829 +f 2056/2048/1786 2125/2052/1831 1432/2053/1789 +f 1432/2053/1789 2296/2054/1832 2122/2055/1790 +f 1444/2056/1833 2296/2054/1832 2125/2052/1831 +f 1838/2057/1834 1625/2058/1835 2296/2054/1832 +f 2122/2055/1790 1625/2058/1835 1433/2059/1793 +f 1433/2059/1793 2297/2060/1836 1621/2061/1794 +f 1445/2062/1837 2297/2060/1836 1625/2058/1835 +f 1913/2063/1838 1703/2064/1839 2297/2060/1836 +f 1621/2061/1794 1703/2064/1839 1434/2065/1797 +f 1434/2065/1797 2298/2066/1840 1699/2067/1798 +f 1446/2068/1841 2298/2066/1840 1703/2064/1839 +f 1990/2069/1842 1774/2070/1843 2298/2066/1840 +f 1699/2067/1798 1774/2070/1843 1435/2071/1801 +f 1435/2071/1801 2299/2072/1844 1771/2073/1802 +f 1447/2074/1845 2299/2072/1844 1774/2070/1843 +f 2060/2075/1846 1839/2076/1847 2299/2072/1844 +f 1771/2073/1802 1839/2076/1847 1436/2077/1805 +f 1436/2077/1805 2300/2078/1848 1622/2079/1806 +f 1448/2080/1849 2300/2078/1848 1839/2076/1847 +f 1914/2081/1850 1623/2008/1245 2300/2078/1848 +f 1622/2079/1806 1623/2008/1245 1425/2010/1246 +f 1915/2082/1305 1910/2011/1807 1437/2083/1244 +f 1915/2082/1305 1626/2084/1851 2301/2085/1852 +f 2301/2085/1852 1450/2086/1853 1991/2087/1854 +f 2301/2085/1852 1438/2013/1809 1910/2011/1807 +f 1991/2087/1854 1988/2017/1811 1438/2013/1809 +f 1991/2087/1854 1704/2088/1855 2302/2089/1856 +f 2302/2089/1856 1451/2090/1857 2061/2091/1858 +f 2302/2089/1856 1439/2019/1813 1988/2017/1811 +f 2061/2091/1858 2058/2023/1815 1439/2019/1813 +f 2061/2091/1858 1775/2092/1859 2303/2093/1860 +f 2303/2093/1860 1452/2094/1861 2126/2095/1862 +f 2303/2093/1860 1440/2025/1817 2058/2023/1815 +f 2126/2095/1862 2124/2029/1819 1440/2025/1817 +f 2126/2095/1862 1840/2096/1863 2304/2097/1864 +f 2304/2097/1864 1453/2098/1865 1627/2099/1866 +f 2304/2097/1864 1441/2031/1821 2124/2029/1819 +f 1627/2099/1866 1624/2035/1823 1441/2031/1821 +f 1627/2099/1866 1916/2100/1867 2305/2101/1868 +f 2305/2101/1868 1454/2102/1869 1705/2103/1870 +f 2305/2101/1868 1442/2037/1825 1624/2035/1823 +f 1705/2103/1870 1702/2041/1827 1442/2037/1825 +f 1705/2103/1870 1992/2104/1871 2306/2105/1872 +f 2306/2105/1872 1455/2106/1329 1776/2107/1280 +f 2306/2105/1872 1443/2043/1281 1702/2041/1827 +f 1443/2049/1281 2307/2108/1873 1773/2051/1830 +f 1455/2109/1329 2307/2108/1873 1776/2110/1280 +f 2062/2111/1874 1841/2112/1875 2307/2108/1873 +f 1773/2051/1830 1841/2112/1875 1444/2056/1833 +f 1444/2056/1833 2308/2113/1876 1838/2057/1834 +f 1456/2114/1877 2308/2113/1876 1841/2112/1875 +f 2127/2115/1878 1917/2116/1879 2308/2113/1876 +f 1838/2057/1834 1917/2116/1879 1445/2062/1837 +f 1445/2062/1837 2309/2117/1880 1913/2063/1838 +f 1457/2118/1881 2309/2117/1880 1917/2116/1879 +f 1628/2119/1882 1993/2120/1883 2309/2117/1880 +f 1913/2063/1838 1993/2120/1883 1446/2068/1841 +f 1446/2068/1841 2310/2121/1884 1990/2069/1842 +f 1458/2122/1885 2310/2121/1884 1993/2120/1883 +f 1706/2123/1886 2063/2124/1887 2310/2121/1884 +f 1990/2069/1842 2063/2124/1887 1447/2074/1845 +f 1447/2074/1845 2311/2125/1888 2060/2075/1846 +f 1459/2126/1889 2311/2125/1888 2063/2124/1887 +f 1777/2127/1890 2128/2128/1891 2311/2125/1888 +f 2060/2075/1846 2128/2128/1891 1448/2080/1849 +f 1448/2080/1849 2312/2129/1892 1914/2081/1850 +f 1460/2130/1893 2312/2129/1892 2128/2128/1891 +f 1629/2131/1894 1915/2082/1305 2312/2129/1892 +f 1914/2081/1850 1915/2082/1305 1437/2083/1244 +f 1630/2132/1353 1626/2084/1851 1449/2133/1304 +f 1630/2132/1353 1918/2134/1895 2313/2135/1896 +f 2313/2135/1896 1462/2136/1897 1707/2137/1898 +f 2313/2135/1896 1450/2086/1853 1626/2084/1851 +f 1707/2137/1898 1704/2088/1855 1450/2086/1853 +f 1707/2137/1898 1994/2138/1899 2314/2139/1900 +f 2314/2139/1900 1463/2140/1901 1778/2141/1902 +f 2314/2139/1900 1451/2090/1857 1704/2088/1855 +f 1778/2141/1902 1775/2092/1859 1451/2090/1857 +f 1778/2141/1902 2064/2142/1903 2315/2143/1904 +f 2315/2143/1904 1464/2144/1905 1842/2145/1906 +f 2315/2143/1904 1452/2094/1861 1775/2092/1859 +f 1842/2145/1906 1840/2096/1863 1452/2094/1861 +f 1842/2145/1906 2129/2146/1907 2316/2147/1908 +f 2316/2147/1908 1465/2148/1909 1919/2149/1910 +f 2316/2147/1908 1453/2098/1865 1840/2096/1863 +f 1919/2149/1910 1916/2100/1867 1453/2098/1865 +f 1919/2149/1910 1631/2150/1911 2317/2151/1912 +f 2317/2151/1912 1466/2152/1913 1995/2153/1914 +f 2317/2151/1912 1454/2102/1869 1916/2100/1867 +f 1995/2153/1914 1992/2104/1871 1454/2102/1869 +f 1995/2153/1914 1708/2154/1915 2318/2155/1916 +f 2318/2155/1916 1467/2156/1377 2066/2157/1328 +f 2318/2155/1916 1455/2106/1329 1992/2104/1871 +f 1455/2109/1329 2319/2158/1917 2062/2111/1874 +f 1467/2159/1377 2319/2158/1917 2066/2160/1328 +f 1779/2161/1918 2130/2162/1919 2319/2158/1917 +f 2062/2111/1874 2130/2162/1919 1456/2114/1877 +f 1456/2114/1877 2320/2163/1920 2127/2115/1878 +f 1468/2164/1921 2320/2163/1920 2130/2162/1919 +f 1844/2165/1922 1632/2166/1923 2320/2163/1920 +f 2127/2115/1878 1632/2166/1923 1457/2118/1881 +f 1457/2118/1881 2321/2167/1924 1628/2119/1882 +f 1469/2168/1925 2321/2167/1924 1632/2166/1923 +f 1920/2169/1926 1709/2170/1927 2321/2167/1924 +f 1628/2119/1882 1709/2170/1927 1458/2122/1885 +f 1458/2122/1885 2322/2171/1928 1706/2123/1886 +f 1470/2172/1929 2322/2171/1928 1709/2170/1927 +f 1996/2173/1930 1780/2174/1931 2322/2171/1928 +f 1706/2123/1886 1780/2174/1931 1459/2126/1889 +f 1459/2126/1889 2323/2175/1932 1777/2127/1890 +f 1471/2176/1933 2323/2175/1932 1780/2174/1931 +f 2067/2177/1934 1845/2178/1935 2323/2175/1932 +f 1777/2127/1890 1845/2178/1935 1460/2130/1893 +f 1460/2130/1893 2324/2179/1936 1629/2131/1894 +f 1472/2180/1937 2324/2179/1936 1845/2178/1935 +f 1921/2181/1938 1630/2132/1353 2324/2179/1936 +f 1629/2131/1894 1630/2132/1353 1449/2133/1304 +f 1922/2182/1401 1918/2134/1895 1461/2183/1352 +f 1922/2182/1401 1633/2184/1939 2325/2185/1940 +f 2325/2185/1940 1474/2186/1941 1997/2187/1942 +f 2325/2185/1940 1462/2136/1897 1918/2134/1895 +f 1997/2187/1942 1994/2138/1899 1462/2136/1897 +f 1997/2187/1942 1710/2188/1943 2326/2189/1944 +f 2326/2189/1944 1475/2190/1945 2068/2191/1946 +f 2326/2189/1944 1463/2140/1901 1994/2138/1899 +f 2068/2191/1946 2064/2142/1903 1463/2140/1901 +f 2068/2191/1946 1781/2192/1947 2327/2193/1948 +f 2327/2193/1948 1476/2194/1949 2131/2195/1950 +f 2327/2193/1948 1464/2144/1905 2064/2142/1903 +f 2131/2195/1950 2129/2146/1907 1464/2144/1905 +f 2131/2195/1950 1846/2196/1951 2328/2197/1952 +f 2328/2197/1952 1477/2198/1953 1634/2199/1954 +f 2328/2197/1952 1465/2148/1909 2129/2146/1907 +f 1634/2199/1954 1631/2150/1911 1465/2148/1909 +f 1634/2199/1954 1923/2200/1955 2329/2201/1956 +f 2329/2201/1956 1478/2202/1957 1711/2203/1958 +f 2329/2201/1956 1466/2152/1913 1631/2150/1911 +f 1711/2203/1958 1708/2154/1915 1466/2152/1913 +f 1711/2203/1958 1998/2204/1959 2330/2205/1960 +f 2330/2205/1960 1479/2206/1425 1782/2207/1376 +f 2330/2205/1960 1467/2156/1377 1708/2154/1915 +f 1467/2159/1377 2331/2208/1961 1779/2161/1918 +f 1479/2209/1425 2331/2208/1961 1782/2210/1376 +f 2069/2211/1962 1847/2212/1963 2331/2208/1961 +f 1779/2161/1918 1847/2212/1963 1468/2164/1921 +f 1468/2164/1921 2332/2213/1964 1844/2165/1922 +f 1480/2214/1965 2332/2213/1964 1847/2212/1963 +f 2132/2215/1966 1924/2216/1967 2332/2213/1964 +f 1844/2165/1922 1924/2216/1967 1469/2168/1925 +f 1469/2168/1925 2333/2217/1968 1920/2169/1926 +f 1481/2218/1969 2333/2217/1968 1924/2216/1967 +f 1635/2219/1970 1999/2220/1971 2333/2217/1968 +f 1920/2169/1926 1999/2220/1971 1470/2172/1929 +f 1470/2172/1929 2334/2221/1972 1996/2173/1930 +f 1482/2222/1973 2334/2221/1972 1999/2220/1971 +f 1712/2223/1974 2070/2224/1975 2334/2221/1972 +f 1996/2173/1930 2070/2224/1975 1471/2176/1933 +f 1471/2176/1933 2335/2225/1976 2067/2177/1934 +f 1483/2226/1977 2335/2225/1976 2070/2224/1975 +f 1783/2227/1978 2133/2228/1979 2335/2225/1976 +f 2067/2177/1934 2133/2228/1979 1472/2180/1937 +f 1472/2180/1937 2336/2229/1980 1921/2181/1938 +f 1484/2230/1981 2336/2229/1980 2133/2228/1979 +f 1636/2231/1982 1922/2182/1401 2336/2229/1980 +f 1921/2181/1938 1922/2182/1401 1461/2183/1352 +f 1637/2232/1449 1633/2184/1939 1473/2233/1400 +f 1637/2232/1449 1925/2234/1983 2337/2235/1984 +f 2337/2235/1984 1486/2236/1985 1713/2237/1986 +f 2337/2235/1984 1474/2186/1941 1633/2184/1939 +f 1713/2237/1986 1710/2188/1943 1474/2186/1941 +f 1713/2237/1986 2000/2238/1987 2338/2239/1988 +f 2338/2239/1988 1487/2240/1989 1784/2241/1990 +f 2338/2239/1988 1475/2190/1945 1710/2188/1943 +f 1784/2241/1990 1781/2192/1947 1475/2190/1945 +f 1784/2241/1990 2071/2242/1991 2339/2243/1992 +f 2339/2243/1992 1488/2244/1993 1848/2245/1994 +f 2339/2243/1992 1476/2194/1949 1781/2192/1947 +f 1848/2245/1994 1846/2196/1951 1476/2194/1949 +f 1848/2245/1994 2134/2246/1995 2340/2247/1996 +f 2340/2247/1996 1489/2248/1997 1926/2249/1998 +f 2340/2247/1996 1477/2198/1953 1846/2196/1951 +f 1926/2249/1998 1923/2200/1955 1477/2198/1953 +f 1926/2249/1998 1638/2250/1999 2341/2251/2000 +f 2341/2251/2000 1490/2252/2001 2001/2253/2002 +f 2341/2251/2000 1478/2202/1957 1923/2200/1955 +f 2001/2253/2002 1998/2204/1959 1478/2202/1957 +f 2001/2253/2002 1714/2254/2003 2342/2255/2004 +f 2342/2255/2004 1491/2256/1473 2072/2257/1424 +f 2342/2255/2004 1479/2206/1425 1998/2204/1959 +f 1479/2209/1425 2343/2258/2005 2069/2211/1962 +f 1491/2259/1473 2343/2258/2005 2072/2260/1424 +f 1785/2261/2006 2135/2262/2007 2343/2258/2005 +f 2069/2211/1962 2135/2262/2007 1480/2214/1965 +f 1480/2214/1965 2344/2263/2008 2132/2215/1966 +f 1492/2264/2009 2344/2263/2008 2135/2262/2007 +f 1849/2265/2010 1640/2266/2011 2344/2263/2008 +f 2132/2215/1966 1640/2266/2011 1481/2218/1969 +f 1481/2218/1969 2345/2267/2012 1635/2219/1970 +f 1493/2268/2013 2345/2267/2012 1640/2266/2011 +f 1927/2269/2014 1715/2270/2015 2345/2267/2012 +f 1635/2219/1970 1715/2270/2015 1482/2222/1973 +f 1482/2222/1973 2346/2271/2016 1712/2223/1974 +f 1494/2272/2017 2346/2271/2016 1715/2270/2015 +f 2003/2273/2018 1786/2274/2019 2346/2271/2016 +f 1712/2223/1974 1786/2274/2019 1483/2226/1977 +f 1483/2226/1977 2347/2275/2020 1783/2227/1978 +f 1495/2276/2021 2347/2275/2020 1786/2274/2019 +f 2073/2277/2022 1850/2278/2023 2347/2275/2020 +f 1783/2227/1978 1850/2278/2023 1484/2230/1981 +f 1484/2230/1981 2348/2279/2024 1636/2231/1982 +f 1496/2280/2025 2348/2279/2024 1850/2278/2023 +f 1928/2281/2026 1637/2232/1449 2348/2279/2024 +f 1636/2231/1982 1637/2232/1449 1473/2233/1400 +f 1929/2282/1497 1925/2234/1983 1485/2283/1448 +f 1929/2282/1497 1641/2284/2027 2349/2285/2028 +f 2349/2285/2028 1498/2286/2029 2004/2287/2030 +f 2349/2285/2028 1486/2236/1985 1925/2234/1983 +f 2004/2287/2030 2000/2238/1987 1486/2236/1985 +f 2004/2287/2030 1716/2288/2031 2350/2289/2032 +f 2350/2289/2032 1499/2290/2033 2074/2291/2034 +f 2350/2289/2032 1487/2240/1989 2000/2238/1987 +f 2074/2291/2034 2071/2242/1991 1487/2240/1989 +f 2074/2291/2034 1787/2292/2035 2351/2293/2036 +f 2351/2293/2036 1500/2294/2037 2136/2295/2038 +f 2351/2293/2036 1488/2244/1993 2071/2242/1991 +f 2136/2295/2038 2134/2246/1995 1488/2244/1993 +f 2136/2295/2038 1851/2296/2039 2352/2297/2040 +f 2352/2297/2040 1501/2298/2041 1642/2299/2042 +f 2352/2297/2040 1489/2248/1997 2134/2246/1995 +f 1642/2299/2042 1638/2250/1999 1489/2248/1997 +f 1642/2299/2042 1930/2300/2043 2353/2301/2044 +f 2353/2301/2044 1502/2302/2045 1717/2303/2046 +f 2353/2301/2044 1490/2252/2001 1638/2250/1999 +f 1717/2303/2046 1714/2254/2003 1490/2252/2001 +f 1717/2303/2046 2005/2304/2047 2354/2305/2048 +f 2354/2305/2048 1503/2306/1521 1788/2307/1472 +f 2354/2305/2048 1491/2256/1473 1714/2254/2003 +f 1491/2259/1473 2355/2308/2049 1785/2261/2006 +f 1503/2309/1521 2355/2308/2049 1788/2310/1472 +f 2075/2311/2050 1852/2312/2051 2355/2308/2049 +f 1785/2261/2006 1852/2312/2051 1492/2264/2009 +f 1492/2264/2009 2356/2313/2052 1849/2265/2010 +f 1504/2314/2053 2356/2313/2052 1852/2312/2051 +f 2137/2315/2054 1931/2316/2055 2356/2313/2052 +f 1849/2265/2010 1931/2316/2055 1493/2268/2013 +f 1493/2268/2013 2357/2317/2056 1927/2269/2014 +f 1505/2318/2057 2357/2317/2056 1931/2316/2055 +f 1643/2319/2058 2006/2320/2059 2357/2317/2056 +f 1927/2269/2014 2006/2320/2059 1494/2272/2017 +f 1494/2272/2017 2358/2321/2060 2003/2273/2018 +f 1506/2322/2061 2358/2321/2060 2006/2320/2059 +f 1718/2323/2062 2076/2324/2063 2358/2321/2060 +f 2003/2273/2018 2076/2324/2063 1495/2276/2021 +f 1495/2276/2021 2359/2325/2064 2073/2277/2022 +f 1507/2326/2065 2359/2325/2064 2076/2324/2063 +f 1789/2327/2066 2138/2328/2067 2359/2325/2064 +f 2073/2277/2022 2138/2328/2067 1496/2280/2025 +f 1496/2280/2025 2360/2329/2068 1928/2281/2026 +f 1508/2330/2069 2360/2329/2068 2138/2328/2067 +f 1644/2331/2070 1929/2282/1497 2360/2329/2068 +f 1928/2281/2026 1929/2282/1497 1485/2283/1448 +f 1645/2332/1545 1641/2284/2027 1497/2333/1496 +f 1645/2332/1545 1932/2334/2071 2361/2335/2072 +f 2361/2335/2072 1510/2336/2073 1719/2337/2074 +f 2361/2335/2072 1498/2286/2029 1641/2284/2027 +f 1719/2337/2074 1716/2288/2031 1498/2286/2029 +f 1719/2337/2074 2007/2338/2075 2362/2339/2076 +f 2362/2339/2076 1511/2340/2077 1790/2341/2078 +f 2362/2339/2076 1499/2290/2033 1716/2288/2031 +f 1790/2341/2078 1787/2292/2035 1499/2290/2033 +f 1790/2341/2078 2077/2342/2079 2363/2343/2080 +f 2363/2343/2080 1512/2344/2081 1853/2345/2082 +f 2363/2343/2080 1500/2294/2037 1787/2292/2035 +f 1853/2345/2082 1851/2296/2039 1500/2294/2037 +f 1853/2345/2082 2139/2346/2083 2364/2347/2084 +f 2364/2347/2084 1513/2348/2085 1933/2349/2086 +f 2364/2347/2084 1501/2298/2041 1851/2296/2039 +f 1933/2349/2086 1930/2300/2043 1501/2298/2041 +f 1933/2349/2086 1646/2350/2087 2365/2351/2088 +f 2365/2351/2088 1514/2352/2089 2008/2353/2090 +f 2365/2351/2088 1502/2302/2045 1930/2300/2043 +f 2008/2353/2090 2005/2304/2047 1502/2302/2045 +f 2008/2353/2090 1720/2354/2091 2366/2355/2092 +f 2366/2355/2092 1515/2356/1569 2078/2357/1520 +f 2366/2355/2092 1503/2306/1521 2005/2304/2047 +f 1503/2309/1521 2367/2358/2093 2075/2311/2050 +f 1515/2359/1569 2367/2358/2093 2078/2360/1520 +f 1791/2361/2094 2140/2362/2095 2367/2358/2093 +f 2075/2311/2050 2140/2362/2095 1504/2314/2053 +f 1504/2314/2053 2368/2363/2096 2137/2315/2054 +f 1516/2364/2097 2368/2363/2096 2140/2362/2095 +f 1854/2365/2098 1647/2366/2099 2368/2363/2096 +f 2137/2315/2054 1647/2366/2099 1505/2318/2057 +f 1505/2318/2057 2369/2367/2100 1643/2319/2058 +f 1517/2368/2101 2369/2367/2100 1647/2366/2099 +f 1934/2369/2102 1721/2370/2103 2369/2367/2100 +f 1643/2319/2058 1721/2370/2103 1506/2322/2061 +f 1506/2322/2061 2370/2371/2104 1718/2323/2062 +f 1518/2372/2105 2370/2371/2104 1721/2370/2103 +f 2009/2373/2106 1793/2374/2107 2370/2371/2104 +f 1718/2323/2062 1793/2374/2107 1507/2326/2065 +f 1507/2326/2065 2371/2375/2108 1789/2327/2066 +f 1519/2376/2109 2371/2375/2108 1793/2374/2107 +f 2079/2377/2110 1855/2378/2111 2371/2375/2108 +f 1789/2327/2066 1855/2378/2111 1508/2330/2069 +f 1508/2330/2069 2372/2379/2112 1644/2331/2070 +f 1520/2380/2113 2372/2379/2112 1855/2378/2111 +f 1935/2381/2114 1645/2332/1545 2372/2379/2112 +f 1644/2331/2070 1645/2332/1545 1497/2333/1496 +f 1936/2382/1593 1932/2334/2071 1509/2383/1544 +f 1936/2382/1593 1648/2384/2115 2373/2385/2116 +f 2373/2385/2116 1522/2386/2117 2010/2387/2118 +f 2373/2385/2116 1510/2336/2073 1932/2334/2071 +f 2010/2387/2118 2007/2338/2075 1510/2336/2073 +f 2010/2387/2118 1722/2388/2119 2374/2389/2120 +f 2374/2389/2120 1523/2390/2121 2080/2391/2122 +f 2374/2389/2120 1511/2340/2077 2007/2338/2075 +f 2080/2391/2122 2077/2342/2079 1511/2340/2077 +f 2080/2391/2122 1794/2392/2123 2375/2393/2124 +f 2375/2393/2124 1524/2394/2125 2142/2395/2126 +f 2375/2393/2124 1512/2344/2081 2077/2342/2079 +f 2142/2395/2126 2139/2346/2083 1512/2344/2081 +f 2142/2395/2126 1856/2396/2127 2376/2397/2128 +f 2376/2397/2128 1525/2398/2129 1649/2399/2130 +f 2376/2397/2128 1513/2348/2085 2139/2346/2083 +f 1649/2399/2130 1646/2350/2087 1513/2348/2085 +f 1649/2399/2130 1937/2400/2131 2377/2401/2132 +f 2377/2401/2132 1526/2402/2133 1723/2403/2134 +f 2377/2401/2132 1514/2352/2089 1646/2350/2087 +f 1723/2403/2134 1720/2354/2091 1514/2352/2089 +f 1723/2403/2134 2011/2404/2135 2378/2405/2136 +f 2378/2405/2136 1527/2406/1617 1795/2407/1568 +f 2378/2405/2136 1515/2356/1569 1720/2354/2091 +f 1515/2359/1569 2379/2408/2137 1791/2361/2094 +f 1527/2409/1617 2379/2408/2137 1795/2410/1568 +f 2081/2411/2138 1857/2412/2139 2379/2408/2137 +f 1791/2361/2094 1857/2412/2139 1516/2364/2097 +f 1516/2364/2097 2380/2413/2140 1854/2365/2098 +f 1528/2414/2141 2380/2413/2140 1857/2412/2139 +f 2143/2415/2142 1938/2416/2143 2380/2413/2140 +f 1854/2365/2098 1938/2416/2143 1517/2368/2101 +f 1517/2368/2101 2381/2417/2144 1934/2369/2102 +f 1529/2418/2145 2381/2417/2144 1938/2416/2143 +f 1650/2419/2146 2012/2420/2147 2381/2417/2144 +f 1934/2369/2102 2012/2420/2147 1518/2372/2105 +f 1518/2372/2105 2382/2421/2148 2009/2373/2106 +f 1530/2422/2149 2382/2421/2148 2012/2420/2147 +f 1724/2423/2150 2082/2424/2151 2382/2421/2148 +f 2009/2373/2106 2082/2424/2151 1519/2376/2109 +f 1519/2376/2109 2383/2425/2152 2079/2377/2110 +f 1531/2426/2153 2383/2425/2152 2082/2424/2151 +f 1796/2427/2154 2144/2428/2155 2383/2425/2152 +f 2079/2377/2110 2144/2428/2155 1520/2380/2113 +f 1520/2380/2113 2384/2429/2156 1935/2381/2114 +f 1532/2430/2157 2384/2429/2156 2144/2428/2155 +f 1651/2431/2158 1936/2382/1593 2384/2429/2156 +f 1935/2381/2114 1936/2382/1593 1509/2383/1544 +f 1652/2432/1641 1648/2384/2115 1521/2433/1592 +f 1652/2432/1641 1939/2434/2159 2385/2435/2160 +f 2385/2435/2160 1534/2436/2161 1725/2437/2162 +f 2385/2435/2160 1522/2386/2117 1648/2384/2115 +f 1725/2437/2162 1722/2388/2119 1522/2386/2117 +f 1725/2437/2162 2013/2438/2163 2386/2439/2164 +f 2386/2439/2164 1535/2440/2165 1797/2441/2166 +f 2386/2439/2164 1523/2390/2121 1722/2388/2119 +f 1797/2441/2166 1794/2392/2123 1523/2390/2121 +f 1797/2441/2166 2083/2442/2167 2387/2443/2168 +f 2387/2443/2168 1536/2444/2169 1858/2445/2170 +f 2387/2443/2168 1524/2394/2125 1794/2392/2123 +f 1858/2445/2170 1856/2396/2127 1524/2394/2125 +f 1858/2445/2170 2014/2446/2171 2388/2447/2172 +f 2388/2447/2172 1537/2448/2173 1940/2449/2174 +f 2388/2447/2172 1525/2398/2129 1856/2396/2127 +f 1940/2449/2174 1937/2400/2131 1525/2398/2129 +f 1940/2449/2174 1653/2450/2175 2389/2451/2176 +f 2389/2451/2176 1538/2452/2177 1859/2453/2178 +f 2389/2451/2176 1526/2402/2133 1937/2400/2131 +f 1859/2453/2178 2011/2404/2135 1526/2402/2133 +f 1859/2453/2178 1570/2454/2179 2390/2455/2180 +f 2390/2455/2180 1539/2456/1665 2084/2457/1616 +f 2390/2455/2180 1527/2406/1617 2011/2404/2135 +f 1527/2409/1617 2391/2458/2181 2081/2411/2138 +f 1539/2459/1665 2391/2458/2181 2084/2460/1616 +f 1798/2461/2182 2015/2462/2183 2391/2458/2181 +f 2081/2411/2138 2015/2462/2183 1528/2414/2141 +f 1528/2414/2141 2392/2463/2184 2143/2415/2142 +f 1540/2464/2185 2392/2463/2184 2015/2462/2183 +f 1727/2465/2186 1655/2466/2187 2392/2463/2184 +f 2143/2415/2142 1655/2466/2187 1529/2418/2145 +f 1529/2418/2145 2393/2467/2188 1650/2419/2146 +f 1541/2468/2189 2393/2467/2188 1655/2466/2187 +f 1941/2469/2190 1571/2470/2191 2393/2467/2188 +f 1650/2419/2146 1571/2470/2191 1530/2422/2149 +f 1530/2422/2149 2394/2471/2192 1724/2423/2150 +f 1542/2472/2193 2394/2471/2192 1571/2470/2191 +f 1861/2473/2194 1800/2474/2195 2394/2471/2192 +f 1724/2423/2150 1800/2474/2195 1531/2426/2153 +f 1531/2426/2153 2395/2475/2196 1796/2427/2154 +f 1543/2476/2197 2395/2475/2196 1800/2474/2195 +f 2085/2477/2198 1728/2478/2199 2395/2475/2196 +f 1796/2427/2154 1728/2478/2199 1532/2430/2157 +f 1532/2430/2157 2396/2479/2200 1651/2431/2158 +f 1544/2480/2201 2396/2479/2200 1728/2478/2199 +f 1943/2481/2202 1652/2432/1641 2396/2479/2200 +f 1651/2431/2158 1652/2432/1641 1521/2433/1592 +f 1944/2482/1689 1939/2434/2159 1533/2483/1640 +f 1944/2482/1689 1656/2484/2203 2397/2485/2204 +f 2397/2485/2204 1546/2486/2205 1862/2487/2206 +f 2397/2485/2204 1534/2436/2161 1939/2434/2159 +f 1862/2487/2206 2013/2438/2163 1534/2436/2161 +f 1862/2487/2206 1573/2488/2207 2398/2489/2208 +f 2398/2489/2208 1547/2490/2209 2087/2491/2210 +f 2398/2489/2208 1535/2440/2165 2013/2438/2163 +f 2087/2491/2210 2083/2442/2167 1535/2440/2165 +f 2087/2491/2210 1801/2492/2211 2399/2493/2212 +f 2399/2493/2212 1548/2494/2213 2017/2495/2214 +f 2399/2493/2212 1536/2444/2169 2083/2442/2167 +f 2017/2495/2214 2014/2446/2171 1536/2444/2169 +f 2017/2495/2214 1730/2496/2215 2400/2497/2216 +f 2400/2497/2216 1549/2498/2217 1658/2499/2218 +f 2400/2497/2216 1537/2448/2173 2014/2446/2171 +f 1658/2499/2218 1653/2450/2175 1537/2448/2173 +f 1658/2499/2218 1945/2500/2219 2401/2501/2220 +f 2401/2501/2220 1550/2502/2221 1576/2503/2222 +f 2401/2501/2220 1538/2452/2177 1653/2450/2175 +f 1576/2503/2222 1570/2454/2179 1538/2452/2177 +f 1576/2503/2222 1864/2504/2223 2402/2505/2224 +f 2402/2505/2224 1551/2506/1713 1802/2507/1664 +f 2402/2505/2224 1539/2456/1665 1570/2454/2179 +f 1539/2459/1665 2403/2508/2225 1798/2461/2182 +f 1551/2509/1713 2403/2508/2225 1802/2510/1664 +f 2088/2511/2226 1732/2512/2227 2403/2508/2225 +f 1798/2461/2182 1732/2512/2227 1540/2464/2185 +f 1540/2464/2185 2404/2513/2228 1727/2465/2186 +f 1552/2514/2229 2404/2513/2228 1732/2512/2227 +f 2019/2515/2230 1947/2516/2231 2404/2513/2228 +f 1727/2465/2186 1947/2516/2231 1541/2468/2189 +f 1541/2468/2189 2405/2517/2232 1941/2469/2190 +f 1553/2518/2233 2405/2517/2232 1947/2516/2231 +f 1660/2519/2234 1866/2520/2235 2405/2517/2232 +f 1941/2469/2190 1866/2520/2235 1542/2472/2193 +f 1542/2472/2193 2406/2521/2236 1861/2473/2194 +f 1554/2522/2237 2406/2521/2236 1866/2520/2235 +f 1578/2523/2238 2090/2524/2239 2406/2521/2236 +f 1861/2473/2194 2090/2524/2239 1543/2476/2197 +f 1543/2476/2197 2407/2525/2240 2085/2477/2198 +f 1555/2526/2241 2407/2525/2240 2090/2524/2239 +f 1804/2527/2242 2021/2528/2243 2407/2525/2240 +f 2085/2477/2198 2021/2528/2243 1544/2480/2201 +f 1544/2480/2201 2408/2529/2244 1943/2481/2202 +f 1556/2530/2245 2408/2529/2244 2021/2528/2243 +f 1662/2531/2246 1944/2482/1689 2408/2529/2244 +f 1943/2481/2202 1944/2482/1689 1533/2483/1640 +f 1663/2532/1737 1656/2484/2203 1545/2533/1688 +f 1663/2532/1737 1949/2534/2247 2409/2535/2248 +f 2409/2535/2248 1558/2536/2249 1580/2537/2250 +f 2409/2535/2248 1546/2486/2205 1656/2484/2203 +f 1580/2537/2250 1573/2488/2207 1546/2486/2205 +f 1580/2537/2250 1868/2538/2251 2410/2539/2252 +f 2410/2539/2252 1559/2540/2253 1806/2541/2254 +f 2410/2539/2252 1547/2490/2209 1573/2488/2207 +f 1806/2541/2254 1801/2492/2211 1547/2490/2209 +f 1806/2541/2254 2092/2542/2255 2411/2543/2256 +f 2411/2543/2256 1560/2544/2257 1735/2545/2258 +f 2411/2543/2256 1548/2494/2213 1801/2492/2211 +f 1735/2545/2258 1730/2496/2215 1548/2494/2213 +f 1735/2545/2258 2023/2546/2259 2412/2547/2260 +f 2412/2547/2260 1561/2548/2261 1951/2549/2262 +f 2412/2547/2260 1549/2498/2217 1730/2496/2215 +f 1951/2549/2262 1945/2500/2219 1549/2498/2217 +f 1951/2549/2262 1665/2550/2263 2413/2551/2264 +f 2413/2551/2264 1562/2552/2265 1871/2553/2266 +f 2413/2551/2264 1550/2502/2221 1945/2500/2219 +f 1871/2553/2266 1864/2504/2223 1550/2502/2221 +f 1871/2553/2266 1582/2554/2267 2414/2555/2268 +f 2414/2555/2268 1563/2556/1761 2093/2557/1712 +f 2414/2555/2268 1551/2506/1713 1864/2504/2223 +f 1551/2509/1713 2415/2558/2269 2088/2511/2226 +f 1563/2559/1761 2415/2558/2269 2093/2560/1712 +f 1808/2561/2270 2025/2562/2271 2415/2558/2269 +f 2088/2511/2226 2025/2562/2271 1552/2514/2229 +f 1552/2514/2229 2416/2563/2272 2019/2515/2230 +f 1564/2564/2273 2416/2563/2272 2025/2562/2271 +f 1737/2565/2274 1667/2566/2275 2416/2563/2272 +f 2019/2515/2230 1667/2566/2275 1553/2518/2233 +f 1553/2518/2233 2417/2567/2276 1660/2519/2234 +f 1565/2568/2277 2417/2567/2276 1667/2566/2275 +f 1953/2569/2278 1584/2570/2279 2417/2567/2276 +f 1660/2519/2234 1584/2570/2279 1554/2522/2237 +f 1554/2522/2237 2418/2571/2280 1578/2523/2238 +f 1566/2572/2281 2418/2571/2280 1584/2570/2279 +f 1873/2573/2282 1810/2574/2283 2418/2571/2280 +f 1578/2523/2238 1810/2574/2283 1555/2526/2241 +f 1555/2526/2241 2419/2575/2284 1804/2527/2242 +f 1567/2576/2285 2419/2575/2284 1810/2574/2283 +f 2095/2577/2286 1739/2578/2287 2419/2575/2284 +f 1804/2527/2242 1739/2578/2287 1556/2530/2245 +f 1556/2530/2245 2420/2579/2288 1662/2531/2246 +f 1568/2580/2289 2420/2579/2288 1739/2578/2287 +f 1955/2581/2290 1663/2532/1737 2420/2579/2288 +f 1662/2531/2246 1663/2532/1737 1545/2533/1688 +f 1975/2582/1784 1949/2534/2247 1557/2583/1736 +f 1975/2582/1784 1569/1385/1210 2421/2584/2291 +f 2421/2584/2291 1282/1391/1216 1607/2585/2292 +f 2421/2584/2291 1558/2536/2249 1949/2534/2247 +f 1607/2585/2292 1868/2538/2251 1558/2536/2249 +f 1607/2585/2292 1654/1392/1217 2422/2586/2293 +f 2422/2586/2293 1283/1397/1222 2118/2587/2294 +f 2422/2586/2293 1559/2540/2253 1868/2538/2251 +f 2118/2587/2294 2092/2542/2255 1559/2540/2253 +f 2118/2587/2294 1726/1398/1223 2423/2588/2295 +f 2423/2588/2295 1284/1403/1228 1765/2589/2296 +f 2423/2588/2295 1560/2544/2257 2092/2542/2255 +f 1765/2589/2296 2023/2546/2259 1560/2544/2257 +f 1765/2589/2296 1799/1404/1229 2424/2590/2297 +f 2424/2590/2297 1285/1409/1234 1701/2591/2298 +f 2424/2590/2297 1561/2548/2261 2023/2546/2259 +f 1701/2591/2298 1665/2550/2263 1561/2548/2261 +f 1701/2591/2298 1860/1410/1235 2425/2592/2299 +f 2425/2592/2299 1286/1415/1240 1911/2593/2300 +f 2425/2592/2299 1562/2552/2265 1665/2550/2263 +f 1911/2593/2300 1582/2554/2267 1562/2552/2265 +f 1911/2593/2300 1942/1416/1241 2426/2594/2301 +f 2426/2594/2301 1287/1421/1246 1843/2595/1760 +f 2426/2594/2301 1563/2556/1761 1582/2554/2267 +f 1563/2559/1761 2427/2596/2302 1808/2561/2270 +f 1287/1422/1246 2427/2596/2302 1843/2597/1760 +f 2016/1424/1248 2065/2598/2303 2427/2596/2302 +f 1808/2561/2270 2065/2598/2303 1564/2564/2273 +f 1564/2564/2273 2428/2599/2304 1737/2565/2274 +f 1288/1429/1251 2428/2599/2304 2065/2598/2303 +f 2086/1431/1253 2002/2600/2305 2428/2599/2304 +f 1737/2565/2274 2002/2600/2305 1565/2568/2277 +f 1565/2568/2277 2429/2601/2306 1953/2569/2278 +f 1289/1435/1257 2429/2601/2306 2002/2600/2305 +f 1572/1437/1259 1639/2602/2307 2429/2601/2306 +f 1953/2569/2278 1639/2602/2307 1566/2572/2281 +f 1566/2572/2281 2430/2603/2308 1873/2573/2282 +f 1290/1441/1263 2430/2603/2308 1639/2602/2307 +f 1657/1443/1265 2141/2604/2309 2430/2603/2308 +f 1873/2573/2282 2141/2604/2309 1567/2576/2285 +f 1567/2576/2285 2431/2605/2310 2095/2577/2286 +f 1291/1447/1269 2431/2605/2310 2141/2604/2309 +f 1729/1449/1271 1792/2606/2311 2431/2605/2310 +f 2095/2577/2286 1792/2606/2311 1568/2580/2289 +f 1568/2580/2289 2432/2607/2312 1955/2581/2290 +f 1292/1453/1275 2432/2607/2312 1792/2606/2311 +f 1574/1455/1277 1975/2582/1784 2432/2607/2312 +f 1955/2581/2290 1975/2582/1784 1557/2583/1736 +f 1575/1384/1209 2145/1388/1213 1569/1385/1210 +f 1575/1384/1209 1293/1459/1281 1863/1387/1212 +f 2145/1388/1213 1863/1387/1212 1294/1389/1214 +f 2145/1388/1213 1659/1390/1215 1282/1391/1216 +f 1659/1390/1215 2146/1394/1219 1654/1392/1217 +f 1659/1390/1215 1294/1389/1214 1946/1393/1218 +f 2146/1394/1219 1946/1393/1218 1295/1395/1220 +f 2146/1394/1219 1731/1396/1221 1283/1397/1222 +f 1731/1396/1221 2147/1400/1225 1726/1398/1223 +f 1731/1396/1221 1295/1395/1220 2018/1399/1224 +f 2147/1400/1225 2018/1399/1224 1296/1401/1226 +f 2147/1400/1225 1803/1402/1227 1284/1403/1228 +f 1803/1402/1227 2148/1406/1231 1799/1404/1229 +f 1803/1402/1227 1296/1401/1226 2089/1405/1230 +f 2148/1406/1231 2089/1405/1230 1297/1407/1232 +f 2148/1406/1231 1865/1408/1233 1285/1409/1234 +f 1865/1408/1233 2149/1412/1237 1860/1410/1235 +f 1865/1408/1233 1297/1407/1232 1577/1411/1236 +f 2149/1412/1237 1577/1411/1236 1298/1413/1238 +f 2149/1412/1237 1948/1414/1239 1286/1415/1240 +f 1948/1414/1239 2150/1418/1243 1942/1416/1241 +f 1948/1414/1239 1298/1413/1238 1661/1417/1242 +f 2150/1418/1243 1661/1417/1242 1299/1419/1244 +f 2150/1418/1243 2020/1420/1245 1287/1421/1246 +f 1287/1422/1246 2020/1426/1245 2151/1423/1247 +f 1299/1425/1244 1733/1427/1249 2151/1423/1247 +f 1733/1427/1249 1300/1432/1254 2091/1428/1250 +f 2016/1424/1248 2151/1423/1247 2091/1428/1250 +f 1288/1429/1251 2091/1428/1250 2152/1430/1252 +f 1300/1432/1254 1805/1433/1255 2152/1430/1252 +f 1805/1433/1255 1301/1438/1260 1579/1434/1256 +f 2086/1431/1253 2152/1430/1252 1579/1434/1256 +f 1289/1435/1257 1579/1434/1256 2153/1436/1258 +f 1301/1438/1260 1867/1439/1261 2153/1436/1258 +f 1867/1439/1261 1302/1444/1266 1664/1440/1262 +f 1572/1437/1259 2153/1436/1258 1664/1440/1262 +f 1290/1441/1263 1664/1440/1262 2154/1442/1264 +f 1302/1444/1266 1950/1445/1267 2154/1442/1264 +f 1950/1445/1267 1303/1450/1272 1734/1446/1268 +f 1657/1443/1265 2154/1442/1264 1734/1446/1268 +f 1291/1447/1269 1734/1446/1268 2155/1448/1270 +f 1303/1450/1272 2022/1451/1273 2155/1448/1270 +f 2022/1451/1273 1304/1456/1278 1807/1452/1274 +f 1729/1449/1271 2155/1448/1270 1807/1452/1274 +f 1292/1453/1275 1807/1452/1274 2156/1454/1276 +f 1304/1456/1278 1869/1457/1279 2156/1454/1276 +f 1869/1457/1279 1293/1459/1281 1575/1384/1209 +f 1574/1455/1277 2156/1454/1276 1575/1384/1209 +f 1870/1458/1280 2157/1461/1283 1863/1387/1212 +f 1870/1458/1280 1305/1509/1329 1581/1460/1282 +f 2157/1461/1283 1581/1460/1282 1306/1462/1284 +f 2157/1461/1283 1952/1463/1285 1294/1389/1214 +f 1952/1463/1285 2158/1465/1287 1946/1393/1218 +f 1952/1463/1285 1306/1462/1284 1666/1464/1286 +f 2158/1465/1287 1666/1464/1286 1307/1466/1288 +f 2158/1465/1287 2024/1467/1289 1295/1395/1220 +f 2024/1467/1289 2159/1469/1291 2018/1399/1224 +f 2024/1467/1289 1307/1466/1288 1736/1468/1290 +f 2159/1469/1291 1736/1468/1290 1308/1470/1292 +f 2159/1469/1291 2094/1471/1293 1296/1401/1226 +f 2094/1471/1293 2160/1473/1295 2089/1405/1230 +f 2094/1471/1293 1308/1470/1292 1809/1472/1294 +f 2160/1473/1295 1809/1472/1294 1309/1474/1296 +f 2160/1473/1295 1583/1475/1297 1297/1407/1232 +f 1583/1475/1297 2161/1477/1299 1577/1411/1236 +f 1583/1475/1297 1309/1474/1296 1872/1476/1298 +f 2161/1477/1299 1872/1476/1298 1310/1478/1300 +f 2161/1477/1299 1668/1479/1301 1298/1413/1238 +f 1668/1479/1301 2162/1481/1303 1661/1417/1242 +f 1668/1479/1301 1310/1478/1300 1954/1480/1302 +f 2162/1481/1303 1954/1480/1302 1311/1482/1304 +f 2162/1481/1303 1738/1483/1305 1299/1419/1244 +f 1299/1425/1244 1738/1486/1305 2163/1484/1306 +f 1311/1485/1304 2026/1487/1307 2163/1484/1306 +f 2026/1487/1307 1312/1490/1310 1811/1488/1308 +f 1733/1427/1249 2163/1484/1306 1811/1488/1308 +f 1300/1432/1254 1811/1488/1308 2164/1489/1309 +f 1312/1490/1310 2096/1491/1311 2164/1489/1309 +f 2096/1491/1311 1313/1494/1314 1874/1492/1312 +f 1805/1433/1255 2164/1489/1309 1874/1492/1312 +f 1301/1438/1260 1874/1492/1312 2165/1493/1313 +f 1313/1494/1314 1585/1495/1315 2165/1493/1313 +f 1585/1495/1315 1314/1498/1318 1956/1496/1316 +f 1867/1439/1261 2165/1493/1313 1956/1496/1316 +f 1302/1444/1266 1956/1496/1316 2166/1497/1317 +f 1314/1498/1318 1669/1499/1319 2166/1497/1317 +f 1669/1499/1319 1315/1502/1322 2027/1500/1320 +f 1950/1445/1267 2166/1497/1317 2027/1500/1320 +f 1303/1450/1272 2027/1500/1320 2167/1501/1321 +f 1315/1502/1322 1740/1503/1323 2167/1501/1321 +f 1740/1503/1323 1316/1506/1326 2097/1504/1324 +f 2022/1451/1273 2167/1501/1321 2097/1504/1324 +f 1304/1456/1278 2097/1504/1324 2168/1505/1325 +f 1316/1506/1326 1586/1507/1327 2168/1505/1325 +f 1586/1507/1327 1305/1509/1329 1870/1458/1280 +f 1869/1457/1279 2168/1505/1325 1870/1458/1280 +f 1587/1508/1328 2169/1511/1331 1581/1460/1282 +f 1587/1508/1328 1317/1559/1377 1875/1510/1330 +f 2169/1511/1331 1875/1510/1330 1318/1512/1332 +f 2169/1511/1331 1670/1513/1333 1306/1462/1284 +f 1670/1513/1333 2170/1515/1335 1666/1464/1286 +f 1670/1513/1333 1318/1512/1332 1957/1514/1334 +f 2170/1515/1335 1957/1514/1334 1319/1516/1336 +f 2170/1515/1335 1741/1517/1337 1307/1466/1288 +f 1741/1517/1337 2171/1519/1339 1736/1468/1290 +f 1741/1517/1337 1319/1516/1336 2028/1518/1338 +f 2171/1519/1339 2028/1518/1338 1320/1520/1340 +f 2171/1519/1339 1812/1521/1341 1308/1470/1292 +f 1812/1521/1341 2172/1523/1343 1809/1472/1294 +f 1812/1521/1341 1320/1520/1340 2098/1522/1342 +f 2172/1523/1343 2098/1522/1342 1321/1524/1344 +f 2172/1523/1343 1876/1525/1345 1309/1474/1296 +f 1876/1525/1345 2173/1527/1347 1872/1476/1298 +f 1876/1525/1345 1321/1524/1344 1588/1526/1346 +f 2173/1527/1347 1588/1526/1346 1322/1528/1348 +f 2173/1527/1347 1958/1529/1349 1310/1478/1300 +f 1958/1529/1349 2174/1531/1351 1954/1480/1302 +f 1958/1529/1349 1322/1528/1348 1671/1530/1350 +f 2174/1531/1351 1671/1530/1350 1323/1532/1352 +f 2174/1531/1351 2029/1533/1353 1311/1482/1304 +f 1311/1485/1304 2029/1536/1353 2175/1534/1354 +f 1323/1535/1352 1742/1537/1355 2175/1534/1354 +f 1742/1537/1355 1324/1540/1358 2099/1538/1356 +f 2026/1487/1307 2175/1534/1354 2099/1538/1356 +f 1312/1490/1310 2099/1538/1356 2176/1539/1357 +f 1324/1540/1358 1813/1541/1359 2176/1539/1357 +f 1813/1541/1359 1325/1544/1362 1589/1542/1360 +f 2096/1491/1311 2176/1539/1357 1589/1542/1360 +f 1313/1494/1314 1589/1542/1360 2177/1543/1361 +f 1325/1544/1362 1877/1545/1363 2177/1543/1361 +f 1877/1545/1363 1326/1548/1366 1672/1546/1364 +f 1585/1495/1315 2177/1543/1361 1672/1546/1364 +f 1314/1498/1318 1672/1546/1364 2178/1547/1365 +f 1326/1548/1366 1959/1549/1367 2178/1547/1365 +f 1959/1549/1367 1327/1552/1370 1743/1550/1368 +f 1669/1499/1319 2178/1547/1365 1743/1550/1368 +f 1315/1502/1322 1743/1550/1368 2179/1551/1369 +f 1327/1552/1370 2030/1553/1371 2179/1551/1369 +f 2030/1553/1371 1328/1556/1374 1814/1554/1372 +f 1740/1503/1323 2179/1551/1369 1814/1554/1372 +f 1316/1506/1326 1814/1554/1372 2180/1555/1373 +f 1328/1556/1374 1878/1557/1375 2180/1555/1373 +f 1878/1557/1375 1317/1559/1377 1587/1508/1328 +f 1586/1507/1327 2180/1555/1373 1587/1508/1328 +f 1879/1558/1376 2181/1561/1379 1875/1510/1330 +f 1879/1558/1376 1329/1609/1425 1590/1560/1378 +f 2181/1561/1379 1590/1560/1378 1330/1562/1380 +f 2181/1561/1379 1960/1563/1381 1318/1512/1332 +f 1960/1563/1381 2182/1565/1383 1957/1514/1334 +f 1960/1563/1381 1330/1562/1380 1673/1564/1382 +f 2182/1565/1383 1673/1564/1382 1331/1566/1384 +f 2182/1565/1383 2031/1567/1385 1319/1516/1336 +f 2031/1567/1385 2183/1569/1387 2028/1518/1338 +f 2031/1567/1385 1331/1566/1384 1744/1568/1386 +f 2183/1569/1387 1744/1568/1386 1332/1570/1388 +f 2183/1569/1387 2100/1571/1389 1320/1520/1340 +f 2100/1571/1389 2184/1573/1391 2098/1522/1342 +f 2100/1571/1389 1332/1570/1388 1815/1572/1390 +f 2184/1573/1391 1815/1572/1390 1333/1574/1392 +f 2184/1573/1391 1591/1575/1393 1321/1524/1344 +f 1591/1575/1393 2185/1577/1395 1588/1526/1346 +f 1591/1575/1393 1333/1574/1392 1880/1576/1394 +f 2185/1577/1395 1880/1576/1394 1334/1578/1396 +f 2185/1577/1395 1674/1579/1397 1322/1528/1348 +f 1674/1579/1397 2186/1581/1399 1671/1530/1350 +f 1674/1579/1397 1334/1578/1396 1961/1580/1398 +f 2186/1581/1399 1961/1580/1398 1335/1582/1400 +f 2186/1581/1399 1745/1583/1401 1323/1532/1352 +f 1323/1535/1352 1745/1586/1401 2187/1584/1402 +f 1335/1585/1400 2032/1587/1403 2187/1584/1402 +f 2032/1587/1403 1336/1590/1406 1816/1588/1404 +f 1742/1537/1355 2187/1584/1402 1816/1588/1404 +f 1324/1540/1358 1816/1588/1404 2188/1589/1405 +f 1336/1590/1406 2101/1591/1407 2188/1589/1405 +f 2101/1591/1407 1337/1594/1410 1881/1592/1408 +f 1813/1541/1359 2188/1589/1405 1881/1592/1408 +f 1325/1544/1362 1881/1592/1408 2189/1593/1409 +f 1337/1594/1410 1592/1595/1411 2189/1593/1409 +f 1592/1595/1411 1338/1598/1414 1962/1596/1412 +f 1877/1545/1363 2189/1593/1409 1962/1596/1412 +f 1326/1548/1366 1962/1596/1412 2190/1597/1413 +f 1338/1598/1414 1675/1599/1415 2190/1597/1413 +f 1675/1599/1415 1339/1602/1418 2033/1600/1416 +f 1959/1549/1367 2190/1597/1413 2033/1600/1416 +f 1327/1552/1370 2033/1600/1416 2191/1601/1417 +f 1339/1602/1418 1746/1603/1419 2191/1601/1417 +f 1746/1603/1419 1340/1606/1422 2102/1604/1420 +f 2030/1553/1371 2191/1601/1417 2102/1604/1420 +f 1328/1556/1374 2102/1604/1420 2192/1605/1421 +f 1340/1606/1422 1593/1607/1423 2192/1605/1421 +f 1593/1607/1423 1329/1609/1425 1879/1558/1376 +f 1878/1557/1375 2192/1605/1421 1879/1558/1376 +f 1594/1608/1424 2193/1611/1427 1590/1560/1378 +f 1594/1608/1424 1341/1659/1473 1882/1610/1426 +f 2193/1611/1427 1882/1610/1426 1342/1612/1428 +f 2193/1611/1427 1676/1613/1429 1330/1562/1380 +f 1676/1613/1429 2194/1615/1431 1673/1564/1382 +f 1676/1613/1429 1342/1612/1428 1963/1614/1430 +f 2194/1615/1431 1963/1614/1430 1343/1616/1432 +f 2194/1615/1431 1747/1617/1433 1331/1566/1384 +f 1747/1617/1433 2195/1619/1435 1744/1568/1386 +f 1747/1617/1433 1343/1616/1432 2034/1618/1434 +f 2195/1619/1435 2034/1618/1434 1344/1620/1436 +f 2195/1619/1435 1817/1621/1437 1332/1570/1388 +f 1817/1621/1437 2196/1623/1439 1815/1572/1390 +f 1817/1621/1437 1344/1620/1436 2103/1622/1438 +f 2196/1623/1439 2103/1622/1438 1345/1624/1440 +f 2196/1623/1439 1883/1625/1441 1333/1574/1392 +f 1883/1625/1441 2197/1627/1443 1880/1576/1394 +f 1883/1625/1441 1345/1624/1440 1595/1626/1442 +f 2197/1627/1443 1595/1626/1442 1346/1628/1444 +f 2197/1627/1443 1964/1629/1445 1334/1578/1396 +f 1964/1629/1445 2198/1631/1447 1961/1580/1398 +f 1964/1629/1445 1346/1628/1444 1677/1630/1446 +f 2198/1631/1447 1677/1630/1446 1347/1632/1448 +f 2198/1631/1447 2035/1633/1449 1335/1582/1400 +f 1335/1585/1400 2035/1636/1449 2199/1634/1450 +f 1347/1635/1448 1748/1637/1451 2199/1634/1450 +f 1748/1637/1451 1348/1640/1454 2104/1638/1452 +f 2032/1587/1403 2199/1634/1450 2104/1638/1452 +f 1336/1590/1406 2104/1638/1452 2200/1639/1453 +f 1348/1640/1454 1818/1641/1455 2200/1639/1453 +f 1818/1641/1455 1349/1644/1458 1596/1642/1456 +f 2101/1591/1407 2200/1639/1453 1596/1642/1456 +f 1337/1594/1410 1596/1642/1456 2201/1643/1457 +f 1349/1644/1458 1884/1645/1459 2201/1643/1457 +f 1884/1645/1459 1350/1648/1462 1678/1646/1460 +f 1592/1595/1411 2201/1643/1457 1678/1646/1460 +f 1338/1598/1414 1678/1646/1460 2202/1647/1461 +f 1350/1648/1462 1965/1649/1463 2202/1647/1461 +f 1965/1649/1463 1351/1652/1466 1749/1650/1464 +f 1675/1599/1415 2202/1647/1461 1749/1650/1464 +f 1339/1602/1418 1749/1650/1464 2203/1651/1465 +f 1351/1652/1466 2036/1653/1467 2203/1651/1465 +f 2036/1653/1467 1352/1656/1470 1819/1654/1468 +f 1746/1603/1419 2203/1651/1465 1819/1654/1468 +f 1340/1606/1422 1819/1654/1468 2204/1655/1469 +f 1352/1656/1470 1885/1657/1471 2204/1655/1469 +f 1885/1657/1471 1341/1659/1473 1594/1608/1424 +f 1593/1607/1423 2204/1655/1469 1594/1608/1424 +f 1886/1658/1472 2205/1661/1475 1882/1610/1426 +f 1886/1658/1472 1353/1709/1521 1597/1660/1474 +f 2205/1661/1475 1597/1660/1474 1354/1662/1476 +f 2205/1661/1475 1966/1663/1477 1342/1612/1428 +f 1966/1663/1477 2206/1665/1479 1963/1614/1430 +f 1966/1663/1477 1354/1662/1476 1679/1664/1478 +f 2206/1665/1479 1679/1664/1478 1355/1666/1480 +f 2206/1665/1479 2037/1667/1481 1343/1616/1432 +f 2037/1667/1481 2207/1669/1483 2034/1618/1434 +f 2037/1667/1481 1355/1666/1480 1750/1668/1482 +f 2207/1669/1483 1750/1668/1482 1356/1670/1484 +f 2207/1669/1483 2105/1671/1485 1344/1620/1436 +f 2105/1671/1485 2208/1673/1487 2103/1622/1438 +f 2105/1671/1485 1356/1670/1484 1820/1672/1486 +f 2208/1673/1487 1820/1672/1486 1357/1674/1488 +f 2208/1673/1487 1598/1675/1489 1345/1624/1440 +f 1598/1675/1489 2209/1677/1491 1595/1626/1442 +f 1598/1675/1489 1357/1674/1488 1887/1676/1490 +f 2209/1677/1491 1887/1676/1490 1358/1678/1492 +f 2209/1677/1491 1680/1679/1493 1346/1628/1444 +f 1680/1679/1493 2210/1681/1495 1677/1630/1446 +f 1680/1679/1493 1358/1678/1492 1967/1680/1494 +f 2210/1681/1495 1967/1680/1494 1359/1682/1496 +f 2210/1681/1495 1751/1683/1497 1347/1632/1448 +f 1347/1635/1448 1751/1686/1497 2211/1684/1498 +f 1359/1685/1496 2038/1687/1499 2211/1684/1498 +f 2038/1687/1499 1360/1690/1502 1821/1688/1500 +f 1748/1637/1451 2211/1684/1498 1821/1688/1500 +f 1348/1640/1454 1821/1688/1500 2212/1689/1501 +f 1360/1690/1502 2106/1691/1503 2212/1689/1501 +f 2106/1691/1503 1361/1694/1506 1888/1692/1504 +f 1818/1641/1455 2212/1689/1501 1888/1692/1504 +f 1349/1644/1458 1888/1692/1504 2213/1693/1505 +f 1361/1694/1506 1599/1695/1507 2213/1693/1505 +f 1599/1695/1507 1362/1698/1510 1968/1696/1508 +f 1884/1645/1459 2213/1693/1505 1968/1696/1508 +f 1350/1648/1462 1968/1696/1508 2214/1697/1509 +f 1362/1698/1510 1681/1699/1511 2214/1697/1509 +f 1681/1699/1511 1363/1702/1514 2039/1700/1512 +f 1965/1649/1463 2214/1697/1509 2039/1700/1512 +f 1351/1652/1466 2039/1700/1512 2215/1701/1513 +f 1363/1702/1514 1752/1703/1515 2215/1701/1513 +f 1752/1703/1515 1364/1706/1518 2107/1704/1516 +f 2036/1653/1467 2215/1701/1513 2107/1704/1516 +f 1352/1656/1470 2107/1704/1516 2216/1705/1517 +f 1364/1706/1518 1600/1707/1519 2216/1705/1517 +f 1600/1707/1519 1353/1709/1521 1886/1658/1472 +f 1885/1657/1471 2216/1705/1517 1886/1658/1472 +f 1601/1708/1520 2217/1711/1523 1597/1660/1474 +f 1601/1708/1520 1365/1759/1569 1889/1710/1522 +f 2217/1711/1523 1889/1710/1522 1366/1712/1524 +f 2217/1711/1523 1682/1713/1525 1354/1662/1476 +f 1682/1713/1525 2218/1715/1527 1679/1664/1478 +f 1682/1713/1525 1366/1712/1524 1969/1714/1526 +f 2218/1715/1527 1969/1714/1526 1367/1716/1528 +f 2218/1715/1527 1753/1717/1529 1355/1666/1480 +f 1753/1717/1529 2219/1719/1531 1750/1668/1482 +f 1753/1717/1529 1367/1716/1528 2040/1718/1530 +f 2219/1719/1531 2040/1718/1530 1368/1720/1532 +f 2219/1719/1531 1822/1721/1533 1356/1670/1484 +f 1822/1721/1533 2220/1723/1535 1820/1672/1486 +f 1822/1721/1533 1368/1720/1532 2108/1722/1534 +f 2220/1723/1535 2108/1722/1534 1369/1724/1536 +f 2220/1723/1535 1890/1725/1537 1357/1674/1488 +f 1890/1725/1537 2221/1727/1539 1887/1676/1490 +f 1890/1725/1537 1369/1724/1536 1602/1726/1538 +f 2221/1727/1539 1602/1726/1538 1370/1728/1540 +f 2221/1727/1539 1970/1729/1541 1358/1678/1492 +f 1970/1729/1541 2222/1731/1543 1967/1680/1494 +f 1970/1729/1541 1370/1728/1540 1683/1730/1542 +f 2222/1731/1543 1683/1730/1542 1371/1732/1544 +f 2222/1731/1543 2041/1733/1545 1359/1682/1496 +f 1359/1685/1496 2041/1736/1545 2223/1734/1546 +f 1371/1735/1544 1754/1737/1547 2223/1734/1546 +f 1754/1737/1547 1372/1740/1550 2109/1738/1548 +f 2038/1687/1499 2223/1734/1546 2109/1738/1548 +f 1360/1690/1502 2109/1738/1548 2224/1739/1549 +f 1372/1740/1550 1823/1741/1551 2224/1739/1549 +f 1823/1741/1551 1373/1744/1554 1603/1742/1552 +f 2106/1691/1503 2224/1739/1549 1603/1742/1552 +f 1361/1694/1506 1603/1742/1552 2225/1743/1553 +f 1373/1744/1554 1891/1745/1555 2225/1743/1553 +f 1891/1745/1555 1374/1748/1558 1684/1746/1556 +f 1599/1695/1507 2225/1743/1553 1684/1746/1556 +f 1362/1698/1510 1684/1746/1556 2226/1747/1557 +f 1374/1748/1558 1971/1749/1559 2226/1747/1557 +f 1971/1749/1559 1375/1752/1562 1755/1750/1560 +f 1681/1699/1511 2226/1747/1557 1755/1750/1560 +f 1363/1702/1514 1755/1750/1560 2227/1751/1561 +f 1375/1752/1562 2042/1753/1563 2227/1751/1561 +f 2042/1753/1563 1376/1756/1566 1824/1754/1564 +f 1752/1703/1515 2227/1751/1561 1824/1754/1564 +f 1364/1706/1518 1824/1754/1564 2228/1755/1565 +f 1376/1756/1566 1892/1757/1567 2228/1755/1565 +f 1892/1757/1567 1365/1759/1569 1601/1708/1520 +f 1600/1707/1519 2228/1755/1565 1601/1708/1520 +f 1893/1758/1568 2229/1761/1571 1889/1710/1522 +f 1893/1758/1568 1377/1809/1617 1604/1760/1570 +f 2229/1761/1571 1604/1760/1570 1378/1762/1572 +f 2229/1761/1571 1972/1763/1573 1366/1712/1524 +f 1972/1763/1573 2230/1765/1575 1969/1714/1526 +f 1972/1763/1573 1378/1762/1572 1685/1764/1574 +f 2230/1765/1575 1685/1764/1574 1379/1766/1576 +f 2230/1765/1575 2043/1767/1577 1367/1716/1528 +f 2043/1767/1577 2231/1769/1579 2040/1718/1530 +f 2043/1767/1577 1379/1766/1576 1756/1768/1578 +f 2231/1769/1579 1756/1768/1578 1380/1770/1580 +f 2231/1769/1579 2110/1771/1581 1368/1720/1532 +f 2110/1771/1581 2232/1773/1583 2108/1722/1534 +f 2110/1771/1581 1380/1770/1580 1825/1772/1582 +f 2232/1773/1583 1825/1772/1582 1381/1774/1584 +f 2232/1773/1583 1605/1775/1585 1369/1724/1536 +f 1605/1775/1585 2233/1777/1587 1602/1726/1538 +f 1605/1775/1585 1381/1774/1584 1894/1776/1586 +f 2233/1777/1587 1894/1776/1586 1382/1778/1588 +f 2233/1777/1587 1686/1779/1589 1370/1728/1540 +f 1686/1779/1589 2234/1781/1591 1683/1730/1542 +f 1686/1779/1589 1382/1778/1588 1973/1780/1590 +f 2234/1781/1591 1973/1780/1590 1383/1782/1592 +f 2234/1781/1591 1757/1783/1593 1371/1732/1544 +f 1371/1735/1544 1757/1786/1593 2235/1784/1594 +f 1383/1785/1592 2044/1787/1595 2235/1784/1594 +f 2044/1787/1595 1384/1790/1598 1826/1788/1596 +f 1754/1737/1547 2235/1784/1594 1826/1788/1596 +f 1372/1740/1550 1826/1788/1596 2236/1789/1597 +f 1384/1790/1598 2111/1791/1599 2236/1789/1597 +f 2111/1791/1599 1385/1794/1602 1895/1792/1600 +f 1823/1741/1551 2236/1789/1597 1895/1792/1600 +f 1373/1744/1554 1895/1792/1600 2237/1793/1601 +f 1385/1794/1602 1606/1795/1603 2237/1793/1601 +f 1606/1795/1603 1386/1798/1606 1974/1796/1604 +f 1891/1745/1555 2237/1793/1601 1974/1796/1604 +f 1374/1748/1558 1974/1796/1604 2238/1797/1605 +f 1386/1798/1606 1687/1799/1607 2238/1797/1605 +f 1687/1799/1607 1387/1802/1610 2045/1800/1608 +f 1971/1749/1559 2238/1797/1605 2045/1800/1608 +f 1375/1752/1562 2045/1800/1608 2239/1801/1609 +f 1387/1802/1610 1758/1803/1611 2239/1801/1609 +f 1758/1803/1611 1388/1806/1614 2112/1804/1612 +f 2042/1753/1563 2239/1801/1609 2112/1804/1612 +f 1376/1756/1566 2112/1804/1612 2240/1805/1613 +f 1388/1806/1614 1608/1807/1615 2240/1805/1613 +f 1608/1807/1615 1377/1809/1617 1893/1758/1568 +f 1892/1757/1567 2240/1805/1613 1893/1758/1568 +f 1609/1808/1616 2241/1811/1619 1604/1760/1570 +f 1609/1808/1616 1389/1859/1665 1896/1810/1618 +f 2241/1811/1619 1896/1810/1618 1390/1812/1620 +f 2241/1811/1619 1688/1813/1621 1378/1762/1572 +f 1688/1813/1621 2242/1815/1623 1685/1764/1574 +f 1688/1813/1621 1390/1812/1620 1976/1814/1622 +f 2242/1815/1623 1976/1814/1622 1391/1816/1624 +f 2242/1815/1623 1759/1817/1625 1379/1766/1576 +f 1759/1817/1625 2243/1819/1627 1756/1768/1578 +f 1759/1817/1625 1391/1816/1624 2046/1818/1626 +f 2243/1819/1627 2046/1818/1626 1392/1820/1628 +f 2243/1819/1627 1827/1821/1629 1380/1770/1580 +f 1827/1821/1629 2244/1823/1631 1825/1772/1582 +f 1827/1821/1629 1392/1820/1628 2113/1822/1630 +f 2244/1823/1631 2113/1822/1630 1393/1824/1632 +f 2244/1823/1631 1897/1825/1633 1381/1774/1584 +f 1897/1825/1633 2245/1827/1635 1894/1776/1586 +f 1897/1825/1633 1393/1824/1632 1610/1826/1634 +f 2245/1827/1635 1610/1826/1634 1394/1828/1636 +f 2245/1827/1635 1977/1829/1637 1382/1778/1588 +f 1977/1829/1637 2246/1831/1639 1973/1780/1590 +f 1977/1829/1637 1394/1828/1636 1689/1830/1638 +f 2246/1831/1639 1689/1830/1638 1395/1832/1640 +f 2246/1831/1639 2047/1833/1641 1383/1782/1592 +f 1383/1785/1592 2047/1836/1641 2247/1834/1642 +f 1395/1835/1640 1760/1837/1643 2247/1834/1642 +f 1760/1837/1643 1396/1840/1646 2114/1838/1644 +f 2044/1787/1595 2247/1834/1642 2114/1838/1644 +f 1384/1790/1598 2114/1838/1644 2248/1839/1645 +f 1396/1840/1646 1828/1841/1647 2248/1839/1645 +f 1828/1841/1647 1397/1844/1650 1611/1842/1648 +f 2111/1791/1599 2248/1839/1645 1611/1842/1648 +f 1385/1794/1602 1611/1842/1648 2249/1843/1649 +f 1397/1844/1650 1898/1845/1651 2249/1843/1649 +f 1898/1845/1651 1398/1848/1654 1690/1846/1652 +f 1606/1795/1603 2249/1843/1649 1690/1846/1652 +f 1386/1798/1606 1690/1846/1652 2250/1847/1653 +f 1398/1848/1654 1978/1849/1655 2250/1847/1653 +f 1978/1849/1655 1399/1852/1658 1761/1850/1656 +f 1687/1799/1607 2250/1847/1653 1761/1850/1656 +f 1387/1802/1610 1761/1850/1656 2251/1851/1657 +f 1399/1852/1658 2048/1853/1659 2251/1851/1657 +f 2048/1853/1659 1400/1856/1662 1829/1854/1660 +f 1758/1803/1611 2251/1851/1657 1829/1854/1660 +f 1388/1806/1614 1829/1854/1660 2252/1855/1661 +f 1400/1856/1662 1899/1857/1663 2252/1855/1661 +f 1899/1857/1663 1389/1859/1665 1609/1808/1616 +f 1608/1807/1615 2252/1855/1661 1609/1808/1616 +f 1900/1858/1664 2253/1861/1667 1896/1810/1618 +f 1900/1858/1664 1401/1909/1713 1612/1860/1666 +f 2253/1861/1667 1612/1860/1666 1402/1862/1668 +f 2253/1861/1667 1979/1863/1669 1390/1812/1620 +f 1979/1863/1669 2254/1865/1671 1976/1814/1622 +f 1979/1863/1669 1402/1862/1668 1691/1864/1670 +f 2254/1865/1671 1691/1864/1670 1403/1866/1672 +f 2254/1865/1671 2049/1867/1673 1391/1816/1624 +f 2049/1867/1673 2255/1869/1675 2046/1818/1626 +f 2049/1867/1673 1403/1866/1672 1762/1868/1674 +f 2255/1869/1675 1762/1868/1674 1404/1870/1676 +f 2255/1869/1675 2115/1871/1677 1392/1820/1628 +f 2115/1871/1677 2256/1873/1679 2113/1822/1630 +f 2115/1871/1677 1404/1870/1676 1830/1872/1678 +f 2256/1873/1679 1830/1872/1678 1405/1874/1680 +f 2256/1873/1679 1613/1875/1681 1393/1824/1632 +f 1613/1875/1681 2257/1877/1683 1610/1826/1634 +f 1613/1875/1681 1405/1874/1680 1901/1876/1682 +f 2257/1877/1683 1901/1876/1682 1406/1878/1684 +f 2257/1877/1683 1692/1879/1685 1394/1828/1636 +f 1692/1879/1685 2258/1881/1687 1689/1830/1638 +f 1692/1879/1685 1406/1878/1684 1980/1880/1686 +f 2258/1881/1687 1980/1880/1686 1407/1882/1688 +f 2258/1881/1687 1763/1883/1689 1395/1832/1640 +f 1395/1835/1640 1763/1886/1689 2259/1884/1690 +f 1407/1885/1688 2050/1887/1691 2259/1884/1690 +f 2050/1887/1691 1408/1890/1694 1831/1888/1692 +f 1760/1837/1643 2259/1884/1690 1831/1888/1692 +f 1396/1840/1646 1831/1888/1692 2260/1889/1693 +f 1408/1890/1694 2116/1891/1695 2260/1889/1693 +f 2116/1891/1695 1409/1894/1698 1902/1892/1696 +f 1828/1841/1647 2260/1889/1693 1902/1892/1696 +f 1397/1844/1650 1902/1892/1696 2261/1893/1697 +f 1409/1894/1698 1614/1895/1699 2261/1893/1697 +f 1614/1895/1699 1410/1898/1702 1981/1896/1700 +f 1898/1845/1651 2261/1893/1697 1981/1896/1700 +f 1398/1848/1654 1981/1896/1700 2262/1897/1701 +f 1410/1898/1702 1693/1899/1703 2262/1897/1701 +f 1693/1899/1703 1411/1902/1706 2051/1900/1704 +f 1978/1849/1655 2262/1897/1701 2051/1900/1704 +f 1399/1852/1658 2051/1900/1704 2263/1901/1705 +f 1411/1902/1706 1764/1903/1707 2263/1901/1705 +f 1764/1903/1707 1412/1906/1710 2117/1904/1708 +f 2048/1853/1659 2263/1901/1705 2117/1904/1708 +f 1400/1856/1662 2117/1904/1708 2264/1905/1709 +f 1412/1906/1710 1615/1907/1711 2264/1905/1709 +f 1615/1907/1711 1401/1909/1713 1900/1858/1664 +f 1899/1857/1663 2264/1905/1709 1900/1858/1664 +f 1616/1908/1712 2265/1911/1715 1612/1860/1666 +f 1616/1908/1712 1413/1959/1761 1903/1910/1714 +f 2265/1911/1715 1903/1910/1714 1414/1912/1716 +f 2265/1911/1715 1694/1913/1717 1402/1862/1668 +f 1694/1913/1717 2266/1915/1719 1691/1864/1670 +f 1694/1913/1717 1414/1912/1716 1982/1914/1718 +f 2266/1915/1719 1982/1914/1718 1415/1916/1720 +f 2266/1915/1719 1766/1917/1721 1403/1866/1672 +f 1766/1917/1721 2267/1919/1723 1762/1868/1674 +f 1766/1917/1721 1415/1916/1720 2052/1918/1722 +f 2267/1919/1723 2052/1918/1722 1416/1920/1724 +f 2267/1919/1723 1832/1921/1725 1404/1870/1676 +f 1832/1921/1725 2268/1923/1727 1830/1872/1678 +f 1832/1921/1725 1416/1920/1724 2119/1922/1726 +f 2268/1923/1727 2119/1922/1726 1417/1924/1728 +f 2268/1923/1727 1904/1925/1729 1405/1874/1680 +f 1904/1925/1729 2269/1927/1731 1901/1876/1682 +f 1904/1925/1729 1417/1924/1728 1617/1926/1730 +f 2269/1927/1731 1617/1926/1730 1418/1928/1732 +f 2269/1927/1731 1983/1929/1733 1406/1878/1684 +f 1983/1929/1733 2270/1931/1735 1980/1880/1686 +f 1983/1929/1733 1418/1928/1732 1695/1930/1734 +f 2270/1931/1735 1695/1930/1734 1419/1932/1736 +f 2270/1931/1735 2053/1933/1737 1407/1882/1688 +f 1407/1885/1688 2053/1936/1737 2271/1934/1738 +f 1419/1935/1736 1767/1937/1739 2271/1934/1738 +f 1767/1937/1739 1420/1940/1742 2120/1938/1740 +f 2050/1887/1691 2271/1934/1738 2120/1938/1740 +f 1408/1890/1694 2120/1938/1740 2272/1939/1741 +f 1420/1940/1742 1833/1941/1743 2272/1939/1741 +f 1833/1941/1743 1421/1944/1746 1618/1942/1744 +f 2116/1891/1695 2272/1939/1741 1618/1942/1744 +f 1409/1894/1698 1618/1942/1744 2273/1943/1745 +f 1421/1944/1746 1905/1945/1747 2273/1943/1745 +f 1905/1945/1747 1422/1948/1750 1696/1946/1748 +f 1614/1895/1699 2273/1943/1745 1696/1946/1748 +f 1410/1898/1702 1696/1946/1748 2274/1947/1749 +f 1422/1948/1750 1984/1949/1751 2274/1947/1749 +f 1984/1949/1751 1423/1952/1754 1768/1950/1752 +f 1693/1899/1703 2274/1947/1749 1768/1950/1752 +f 1411/1902/1706 1768/1950/1752 2275/1951/1753 +f 1423/1952/1754 2054/1953/1755 2275/1951/1753 +f 2054/1953/1755 1424/1956/1758 1834/1954/1756 +f 1764/1903/1707 2275/1951/1753 1834/1954/1756 +f 1412/1906/1710 1834/1954/1756 2276/1955/1757 +f 1424/1956/1758 1906/1957/1759 2276/1955/1757 +f 1906/1957/1759 1413/1959/1761 1616/1908/1712 +f 1615/1907/1711 2276/1955/1757 1616/1908/1712 +f 1907/1958/1760 2277/1961/1763 1903/1910/1714 +f 1907/1958/1760 1425/2608/1246 1619/1960/1762 +f 2277/1961/1763 1619/1960/1762 1426/1962/1764 +f 2277/1961/1763 1985/1963/1765 1414/1912/1716 +f 1985/1963/1765 2278/1965/1767 1982/1914/1718 +f 1985/1963/1765 1426/1962/1764 1697/1964/1766 +f 2278/1965/1767 1697/1964/1766 1427/1966/1768 +f 2278/1965/1767 2055/1967/1769 1415/1916/1720 +f 2055/1967/1769 2279/1969/1771 2052/1918/1722 +f 2055/1967/1769 1427/1966/1768 1769/1968/1770 +f 2279/1969/1771 1769/1968/1770 1428/1970/1772 +f 2279/1969/1771 2121/1971/1773 1416/1920/1724 +f 2121/1971/1773 2280/1973/1775 2119/1922/1726 +f 2121/1971/1773 1428/1970/1772 1835/1972/1774 +f 2280/1973/1775 1835/1972/1774 1429/1974/1776 +f 2280/1973/1775 1620/1975/1777 1417/1924/1728 +f 1620/1975/1777 2281/1977/1779 1617/1926/1730 +f 1620/1975/1777 1429/1974/1776 1908/1976/1778 +f 2281/1977/1779 1908/1976/1778 1430/1978/1780 +f 2281/1977/1779 1698/1979/1781 1418/1928/1732 +f 1698/1979/1781 2282/1981/1783 1695/1930/1734 +f 1698/1979/1781 1430/1978/1780 1986/1980/1782 +f 2282/1981/1783 1986/1980/1782 1431/1982/1211 +f 2282/1981/1783 1770/1983/1784 1419/1932/1736 +f 1419/1935/1736 1770/1986/1784 2283/1984/1785 +f 1431/1985/1211 2056/1987/1786 2283/1984/1785 +f 2056/1987/1786 1432/1990/1789 1836/1988/1787 +f 1767/1937/1739 2283/1984/1785 1836/1988/1787 +f 1420/1940/1742 1836/1988/1787 2284/1989/1788 +f 1432/1990/1789 2122/1991/1790 2284/1989/1788 +f 2122/1991/1790 1433/1994/1793 1909/1992/1791 +f 1833/1941/1743 2284/1989/1788 1909/1992/1791 +f 1421/1944/1746 1909/1992/1791 2285/1993/1792 +f 1433/1994/1793 1621/1995/1794 2285/1993/1792 +f 1621/1995/1794 1434/1998/1797 1987/1996/1795 +f 1905/1945/1747 2285/1993/1792 1987/1996/1795 +f 1422/1948/1750 1987/1996/1795 2286/1997/1796 +f 1434/1998/1797 1699/1999/1798 2286/1997/1796 +f 1699/1999/1798 1435/2002/1801 2057/2000/1799 +f 1984/1949/1751 2286/1997/1796 2057/2000/1799 +f 1423/1952/1754 2057/2000/1799 2287/2001/1800 +f 1435/2002/1801 1771/2003/1802 2287/2001/1800 +f 1771/2003/1802 1436/2006/1805 2123/2004/1803 +f 2054/1953/1755 2287/2001/1800 2123/2004/1803 +f 1424/1956/1758 2123/2004/1803 2288/2005/1804 +f 1436/2006/1805 1622/2007/1806 2288/2005/1804 +f 1622/2007/1806 1425/2608/1246 1907/1958/1760 +f 1906/1957/1759 2288/2005/1804 1907/1958/1760 +f 1623/2008/1245 2289/2012/1808 1619/2009/1762 +f 1623/2008/1245 1437/2083/1244 1910/2011/1807 +f 2289/2012/1808 1910/2011/1807 1438/2013/1809 +f 2289/2012/1808 1700/2014/1810 1426/2015/1764 +f 1700/2014/1810 2290/2018/1812 1697/2016/1766 +f 1700/2014/1810 1438/2013/1809 1988/2017/1811 +f 2290/2018/1812 1988/2017/1811 1439/2019/1813 +f 2290/2018/1812 1772/2020/1814 1427/2021/1768 +f 1772/2020/1814 2291/2024/1816 1769/2022/1770 +f 1772/2020/1814 1439/2019/1813 2058/2023/1815 +f 2291/2024/1816 2058/2023/1815 1440/2025/1817 +f 2291/2024/1816 1837/2026/1818 1428/2027/1772 +f 1837/2026/1818 2292/2030/1820 1835/2028/1774 +f 1837/2026/1818 1440/2025/1817 2124/2029/1819 +f 2292/2030/1820 2124/2029/1819 1441/2031/1821 +f 2292/2030/1820 1912/2032/1822 1429/2033/1776 +f 1912/2032/1822 2293/2036/1824 1908/2034/1778 +f 1912/2032/1822 1441/2031/1821 1624/2035/1823 +f 2293/2036/1824 1624/2035/1823 1442/2037/1825 +f 2293/2036/1824 1989/2038/1826 1430/2039/1780 +f 1989/2038/1826 2294/2042/1828 1986/2040/1782 +f 1989/2038/1826 1442/2037/1825 1702/2041/1827 +f 2294/2042/1828 1702/2041/1827 1443/2043/1281 +f 2294/2042/1828 2059/2044/1209 1431/2045/1211 +f 1431/2046/1211 2059/2050/1209 2295/2047/1829 +f 1443/2049/1281 1773/2051/1830 2295/2047/1829 +f 1773/2051/1830 1444/2056/1833 2125/2052/1831 +f 2056/2048/1786 2295/2047/1829 2125/2052/1831 +f 1432/2053/1789 2125/2052/1831 2296/2054/1832 +f 1444/2056/1833 1838/2057/1834 2296/2054/1832 +f 1838/2057/1834 1445/2062/1837 1625/2058/1835 +f 2122/2055/1790 2296/2054/1832 1625/2058/1835 +f 1433/2059/1793 1625/2058/1835 2297/2060/1836 +f 1445/2062/1837 1913/2063/1838 2297/2060/1836 +f 1913/2063/1838 1446/2068/1841 1703/2064/1839 +f 1621/2061/1794 2297/2060/1836 1703/2064/1839 +f 1434/2065/1797 1703/2064/1839 2298/2066/1840 +f 1446/2068/1841 1990/2069/1842 2298/2066/1840 +f 1990/2069/1842 1447/2074/1845 1774/2070/1843 +f 1699/2067/1798 2298/2066/1840 1774/2070/1843 +f 1435/2071/1801 1774/2070/1843 2299/2072/1844 +f 1447/2074/1845 2060/2075/1846 2299/2072/1844 +f 2060/2075/1846 1448/2080/1849 1839/2076/1847 +f 1771/2073/1802 2299/2072/1844 1839/2076/1847 +f 1436/2077/1805 1839/2076/1847 2300/2078/1848 +f 1448/2080/1849 1914/2081/1850 2300/2078/1848 +f 1914/2081/1850 1437/2083/1244 1623/2008/1245 +f 1622/2079/1806 2300/2078/1848 1623/2008/1245 +f 1915/2082/1305 2301/2085/1852 1910/2011/1807 +f 1915/2082/1305 1449/2133/1304 1626/2084/1851 +f 2301/2085/1852 1626/2084/1851 1450/2086/1853 +f 2301/2085/1852 1991/2087/1854 1438/2013/1809 +f 1991/2087/1854 2302/2089/1856 1988/2017/1811 +f 1991/2087/1854 1450/2086/1853 1704/2088/1855 +f 2302/2089/1856 1704/2088/1855 1451/2090/1857 +f 2302/2089/1856 2061/2091/1858 1439/2019/1813 +f 2061/2091/1858 2303/2093/1860 2058/2023/1815 +f 2061/2091/1858 1451/2090/1857 1775/2092/1859 +f 2303/2093/1860 1775/2092/1859 1452/2094/1861 +f 2303/2093/1860 2126/2095/1862 1440/2025/1817 +f 2126/2095/1862 2304/2097/1864 2124/2029/1819 +f 2126/2095/1862 1452/2094/1861 1840/2096/1863 +f 2304/2097/1864 1840/2096/1863 1453/2098/1865 +f 2304/2097/1864 1627/2099/1866 1441/2031/1821 +f 1627/2099/1866 2305/2101/1868 1624/2035/1823 +f 1627/2099/1866 1453/2098/1865 1916/2100/1867 +f 2305/2101/1868 1916/2100/1867 1454/2102/1869 +f 2305/2101/1868 1705/2103/1870 1442/2037/1825 +f 1705/2103/1870 2306/2105/1872 1702/2041/1827 +f 1705/2103/1870 1454/2102/1869 1992/2104/1871 +f 2306/2105/1872 1992/2104/1871 1455/2106/1329 +f 2306/2105/1872 1776/2107/1280 1443/2043/1281 +f 1443/2049/1281 1776/2110/1280 2307/2108/1873 +f 1455/2109/1329 2062/2111/1874 2307/2108/1873 +f 2062/2111/1874 1456/2114/1877 1841/2112/1875 +f 1773/2051/1830 2307/2108/1873 1841/2112/1875 +f 1444/2056/1833 1841/2112/1875 2308/2113/1876 +f 1456/2114/1877 2127/2115/1878 2308/2113/1876 +f 2127/2115/1878 1457/2118/1881 1917/2116/1879 +f 1838/2057/1834 2308/2113/1876 1917/2116/1879 +f 1445/2062/1837 1917/2116/1879 2309/2117/1880 +f 1457/2118/1881 1628/2119/1882 2309/2117/1880 +f 1628/2119/1882 1458/2122/1885 1993/2120/1883 +f 1913/2063/1838 2309/2117/1880 1993/2120/1883 +f 1446/2068/1841 1993/2120/1883 2310/2121/1884 +f 1458/2122/1885 1706/2123/1886 2310/2121/1884 +f 1706/2123/1886 1459/2126/1889 2063/2124/1887 +f 1990/2069/1842 2310/2121/1884 2063/2124/1887 +f 1447/2074/1845 2063/2124/1887 2311/2125/1888 +f 1459/2126/1889 1777/2127/1890 2311/2125/1888 +f 1777/2127/1890 1460/2130/1893 2128/2128/1891 +f 2060/2075/1846 2311/2125/1888 2128/2128/1891 +f 1448/2080/1849 2128/2128/1891 2312/2129/1892 +f 1460/2130/1893 1629/2131/1894 2312/2129/1892 +f 1629/2131/1894 1449/2133/1304 1915/2082/1305 +f 1914/2081/1850 2312/2129/1892 1915/2082/1305 +f 1630/2132/1353 2313/2135/1896 1626/2084/1851 +f 1630/2132/1353 1461/2183/1352 1918/2134/1895 +f 2313/2135/1896 1918/2134/1895 1462/2136/1897 +f 2313/2135/1896 1707/2137/1898 1450/2086/1853 +f 1707/2137/1898 2314/2139/1900 1704/2088/1855 +f 1707/2137/1898 1462/2136/1897 1994/2138/1899 +f 2314/2139/1900 1994/2138/1899 1463/2140/1901 +f 2314/2139/1900 1778/2141/1902 1451/2090/1857 +f 1778/2141/1902 2315/2143/1904 1775/2092/1859 +f 1778/2141/1902 1463/2140/1901 2064/2142/1903 +f 2315/2143/1904 2064/2142/1903 1464/2144/1905 +f 2315/2143/1904 1842/2145/1906 1452/2094/1861 +f 1842/2145/1906 2316/2147/1908 1840/2096/1863 +f 1842/2145/1906 1464/2144/1905 2129/2146/1907 +f 2316/2147/1908 2129/2146/1907 1465/2148/1909 +f 2316/2147/1908 1919/2149/1910 1453/2098/1865 +f 1919/2149/1910 2317/2151/1912 1916/2100/1867 +f 1919/2149/1910 1465/2148/1909 1631/2150/1911 +f 2317/2151/1912 1631/2150/1911 1466/2152/1913 +f 2317/2151/1912 1995/2153/1914 1454/2102/1869 +f 1995/2153/1914 2318/2155/1916 1992/2104/1871 +f 1995/2153/1914 1466/2152/1913 1708/2154/1915 +f 2318/2155/1916 1708/2154/1915 1467/2156/1377 +f 2318/2155/1916 2066/2157/1328 1455/2106/1329 +f 1455/2109/1329 2066/2160/1328 2319/2158/1917 +f 1467/2159/1377 1779/2161/1918 2319/2158/1917 +f 1779/2161/1918 1468/2164/1921 2130/2162/1919 +f 2062/2111/1874 2319/2158/1917 2130/2162/1919 +f 1456/2114/1877 2130/2162/1919 2320/2163/1920 +f 1468/2164/1921 1844/2165/1922 2320/2163/1920 +f 1844/2165/1922 1469/2168/1925 1632/2166/1923 +f 2127/2115/1878 2320/2163/1920 1632/2166/1923 +f 1457/2118/1881 1632/2166/1923 2321/2167/1924 +f 1469/2168/1925 1920/2169/1926 2321/2167/1924 +f 1920/2169/1926 1470/2172/1929 1709/2170/1927 +f 1628/2119/1882 2321/2167/1924 1709/2170/1927 +f 1458/2122/1885 1709/2170/1927 2322/2171/1928 +f 1470/2172/1929 1996/2173/1930 2322/2171/1928 +f 1996/2173/1930 1471/2176/1933 1780/2174/1931 +f 1706/2123/1886 2322/2171/1928 1780/2174/1931 +f 1459/2126/1889 1780/2174/1931 2323/2175/1932 +f 1471/2176/1933 2067/2177/1934 2323/2175/1932 +f 2067/2177/1934 1472/2180/1937 1845/2178/1935 +f 1777/2127/1890 2323/2175/1932 1845/2178/1935 +f 1460/2130/1893 1845/2178/1935 2324/2179/1936 +f 1472/2180/1937 1921/2181/1938 2324/2179/1936 +f 1921/2181/1938 1461/2183/1352 1630/2132/1353 +f 1629/2131/1894 2324/2179/1936 1630/2132/1353 +f 1922/2182/1401 2325/2185/1940 1918/2134/1895 +f 1922/2182/1401 1473/2233/1400 1633/2184/1939 +f 2325/2185/1940 1633/2184/1939 1474/2186/1941 +f 2325/2185/1940 1997/2187/1942 1462/2136/1897 +f 1997/2187/1942 2326/2189/1944 1994/2138/1899 +f 1997/2187/1942 1474/2186/1941 1710/2188/1943 +f 2326/2189/1944 1710/2188/1943 1475/2190/1945 +f 2326/2189/1944 2068/2191/1946 1463/2140/1901 +f 2068/2191/1946 2327/2193/1948 2064/2142/1903 +f 2068/2191/1946 1475/2190/1945 1781/2192/1947 +f 2327/2193/1948 1781/2192/1947 1476/2194/1949 +f 2327/2193/1948 2131/2195/1950 1464/2144/1905 +f 2131/2195/1950 2328/2197/1952 2129/2146/1907 +f 2131/2195/1950 1476/2194/1949 1846/2196/1951 +f 2328/2197/1952 1846/2196/1951 1477/2198/1953 +f 2328/2197/1952 1634/2199/1954 1465/2148/1909 +f 1634/2199/1954 2329/2201/1956 1631/2150/1911 +f 1634/2199/1954 1477/2198/1953 1923/2200/1955 +f 2329/2201/1956 1923/2200/1955 1478/2202/1957 +f 2329/2201/1956 1711/2203/1958 1466/2152/1913 +f 1711/2203/1958 2330/2205/1960 1708/2154/1915 +f 1711/2203/1958 1478/2202/1957 1998/2204/1959 +f 2330/2205/1960 1998/2204/1959 1479/2206/1425 +f 2330/2205/1960 1782/2207/1376 1467/2156/1377 +f 1467/2159/1377 1782/2210/1376 2331/2208/1961 +f 1479/2209/1425 2069/2211/1962 2331/2208/1961 +f 2069/2211/1962 1480/2214/1965 1847/2212/1963 +f 1779/2161/1918 2331/2208/1961 1847/2212/1963 +f 1468/2164/1921 1847/2212/1963 2332/2213/1964 +f 1480/2214/1965 2132/2215/1966 2332/2213/1964 +f 2132/2215/1966 1481/2218/1969 1924/2216/1967 +f 1844/2165/1922 2332/2213/1964 1924/2216/1967 +f 1469/2168/1925 1924/2216/1967 2333/2217/1968 +f 1481/2218/1969 1635/2219/1970 2333/2217/1968 +f 1635/2219/1970 1482/2222/1973 1999/2220/1971 +f 1920/2169/1926 2333/2217/1968 1999/2220/1971 +f 1470/2172/1929 1999/2220/1971 2334/2221/1972 +f 1482/2222/1973 1712/2223/1974 2334/2221/1972 +f 1712/2223/1974 1483/2226/1977 2070/2224/1975 +f 1996/2173/1930 2334/2221/1972 2070/2224/1975 +f 1471/2176/1933 2070/2224/1975 2335/2225/1976 +f 1483/2226/1977 1783/2227/1978 2335/2225/1976 +f 1783/2227/1978 1484/2230/1981 2133/2228/1979 +f 2067/2177/1934 2335/2225/1976 2133/2228/1979 +f 1472/2180/1937 2133/2228/1979 2336/2229/1980 +f 1484/2230/1981 1636/2231/1982 2336/2229/1980 +f 1636/2231/1982 1473/2233/1400 1922/2182/1401 +f 1921/2181/1938 2336/2229/1980 1922/2182/1401 +f 1637/2232/1449 2337/2235/1984 1633/2184/1939 +f 1637/2232/1449 1485/2283/1448 1925/2234/1983 +f 2337/2235/1984 1925/2234/1983 1486/2236/1985 +f 2337/2235/1984 1713/2237/1986 1474/2186/1941 +f 1713/2237/1986 2338/2239/1988 1710/2188/1943 +f 1713/2237/1986 1486/2236/1985 2000/2238/1987 +f 2338/2239/1988 2000/2238/1987 1487/2240/1989 +f 2338/2239/1988 1784/2241/1990 1475/2190/1945 +f 1784/2241/1990 2339/2243/1992 1781/2192/1947 +f 1784/2241/1990 1487/2240/1989 2071/2242/1991 +f 2339/2243/1992 2071/2242/1991 1488/2244/1993 +f 2339/2243/1992 1848/2245/1994 1476/2194/1949 +f 1848/2245/1994 2340/2247/1996 1846/2196/1951 +f 1848/2245/1994 1488/2244/1993 2134/2246/1995 +f 2340/2247/1996 2134/2246/1995 1489/2248/1997 +f 2340/2247/1996 1926/2249/1998 1477/2198/1953 +f 1926/2249/1998 2341/2251/2000 1923/2200/1955 +f 1926/2249/1998 1489/2248/1997 1638/2250/1999 +f 2341/2251/2000 1638/2250/1999 1490/2252/2001 +f 2341/2251/2000 2001/2253/2002 1478/2202/1957 +f 2001/2253/2002 2342/2255/2004 1998/2204/1959 +f 2001/2253/2002 1490/2252/2001 1714/2254/2003 +f 2342/2255/2004 1714/2254/2003 1491/2256/1473 +f 2342/2255/2004 2072/2257/1424 1479/2206/1425 +f 1479/2209/1425 2072/2260/1424 2343/2258/2005 +f 1491/2259/1473 1785/2261/2006 2343/2258/2005 +f 1785/2261/2006 1492/2264/2009 2135/2262/2007 +f 2069/2211/1962 2343/2258/2005 2135/2262/2007 +f 1480/2214/1965 2135/2262/2007 2344/2263/2008 +f 1492/2264/2009 1849/2265/2010 2344/2263/2008 +f 1849/2265/2010 1493/2268/2013 1640/2266/2011 +f 2132/2215/1966 2344/2263/2008 1640/2266/2011 +f 1481/2218/1969 1640/2266/2011 2345/2267/2012 +f 1493/2268/2013 1927/2269/2014 2345/2267/2012 +f 1927/2269/2014 1494/2272/2017 1715/2270/2015 +f 1635/2219/1970 2345/2267/2012 1715/2270/2015 +f 1482/2222/1973 1715/2270/2015 2346/2271/2016 +f 1494/2272/2017 2003/2273/2018 2346/2271/2016 +f 2003/2273/2018 1495/2276/2021 1786/2274/2019 +f 1712/2223/1974 2346/2271/2016 1786/2274/2019 +f 1483/2226/1977 1786/2274/2019 2347/2275/2020 +f 1495/2276/2021 2073/2277/2022 2347/2275/2020 +f 2073/2277/2022 1496/2280/2025 1850/2278/2023 +f 1783/2227/1978 2347/2275/2020 1850/2278/2023 +f 1484/2230/1981 1850/2278/2023 2348/2279/2024 +f 1496/2280/2025 1928/2281/2026 2348/2279/2024 +f 1928/2281/2026 1485/2283/1448 1637/2232/1449 +f 1636/2231/1982 2348/2279/2024 1637/2232/1449 +f 1929/2282/1497 2349/2285/2028 1925/2234/1983 +f 1929/2282/1497 1497/2333/1496 1641/2284/2027 +f 2349/2285/2028 1641/2284/2027 1498/2286/2029 +f 2349/2285/2028 2004/2287/2030 1486/2236/1985 +f 2004/2287/2030 2350/2289/2032 2000/2238/1987 +f 2004/2287/2030 1498/2286/2029 1716/2288/2031 +f 2350/2289/2032 1716/2288/2031 1499/2290/2033 +f 2350/2289/2032 2074/2291/2034 1487/2240/1989 +f 2074/2291/2034 2351/2293/2036 2071/2242/1991 +f 2074/2291/2034 1499/2290/2033 1787/2292/2035 +f 2351/2293/2036 1787/2292/2035 1500/2294/2037 +f 2351/2293/2036 2136/2295/2038 1488/2244/1993 +f 2136/2295/2038 2352/2297/2040 2134/2246/1995 +f 2136/2295/2038 1500/2294/2037 1851/2296/2039 +f 2352/2297/2040 1851/2296/2039 1501/2298/2041 +f 2352/2297/2040 1642/2299/2042 1489/2248/1997 +f 1642/2299/2042 2353/2301/2044 1638/2250/1999 +f 1642/2299/2042 1501/2298/2041 1930/2300/2043 +f 2353/2301/2044 1930/2300/2043 1502/2302/2045 +f 2353/2301/2044 1717/2303/2046 1490/2252/2001 +f 1717/2303/2046 2354/2305/2048 1714/2254/2003 +f 1717/2303/2046 1502/2302/2045 2005/2304/2047 +f 2354/2305/2048 2005/2304/2047 1503/2306/1521 +f 2354/2305/2048 1788/2307/1472 1491/2256/1473 +f 1491/2259/1473 1788/2310/1472 2355/2308/2049 +f 1503/2309/1521 2075/2311/2050 2355/2308/2049 +f 2075/2311/2050 1504/2314/2053 1852/2312/2051 +f 1785/2261/2006 2355/2308/2049 1852/2312/2051 +f 1492/2264/2009 1852/2312/2051 2356/2313/2052 +f 1504/2314/2053 2137/2315/2054 2356/2313/2052 +f 2137/2315/2054 1505/2318/2057 1931/2316/2055 +f 1849/2265/2010 2356/2313/2052 1931/2316/2055 +f 1493/2268/2013 1931/2316/2055 2357/2317/2056 +f 1505/2318/2057 1643/2319/2058 2357/2317/2056 +f 1643/2319/2058 1506/2322/2061 2006/2320/2059 +f 1927/2269/2014 2357/2317/2056 2006/2320/2059 +f 1494/2272/2017 2006/2320/2059 2358/2321/2060 +f 1506/2322/2061 1718/2323/2062 2358/2321/2060 +f 1718/2323/2062 1507/2326/2065 2076/2324/2063 +f 2003/2273/2018 2358/2321/2060 2076/2324/2063 +f 1495/2276/2021 2076/2324/2063 2359/2325/2064 +f 1507/2326/2065 1789/2327/2066 2359/2325/2064 +f 1789/2327/2066 1508/2330/2069 2138/2328/2067 +f 2073/2277/2022 2359/2325/2064 2138/2328/2067 +f 1496/2280/2025 2138/2328/2067 2360/2329/2068 +f 1508/2330/2069 1644/2331/2070 2360/2329/2068 +f 1644/2331/2070 1497/2333/1496 1929/2282/1497 +f 1928/2281/2026 2360/2329/2068 1929/2282/1497 +f 1645/2332/1545 2361/2335/2072 1641/2284/2027 +f 1645/2332/1545 1509/2383/1544 1932/2334/2071 +f 2361/2335/2072 1932/2334/2071 1510/2336/2073 +f 2361/2335/2072 1719/2337/2074 1498/2286/2029 +f 1719/2337/2074 2362/2339/2076 1716/2288/2031 +f 1719/2337/2074 1510/2336/2073 2007/2338/2075 +f 2362/2339/2076 2007/2338/2075 1511/2340/2077 +f 2362/2339/2076 1790/2341/2078 1499/2290/2033 +f 1790/2341/2078 2363/2343/2080 1787/2292/2035 +f 1790/2341/2078 1511/2340/2077 2077/2342/2079 +f 2363/2343/2080 2077/2342/2079 1512/2344/2081 +f 2363/2343/2080 1853/2345/2082 1500/2294/2037 +f 1853/2345/2082 2364/2347/2084 1851/2296/2039 +f 1853/2345/2082 1512/2344/2081 2139/2346/2083 +f 2364/2347/2084 2139/2346/2083 1513/2348/2085 +f 2364/2347/2084 1933/2349/2086 1501/2298/2041 +f 1933/2349/2086 2365/2351/2088 1930/2300/2043 +f 1933/2349/2086 1513/2348/2085 1646/2350/2087 +f 2365/2351/2088 1646/2350/2087 1514/2352/2089 +f 2365/2351/2088 2008/2353/2090 1502/2302/2045 +f 2008/2353/2090 2366/2355/2092 2005/2304/2047 +f 2008/2353/2090 1514/2352/2089 1720/2354/2091 +f 2366/2355/2092 1720/2354/2091 1515/2356/1569 +f 2366/2355/2092 2078/2357/1520 1503/2306/1521 +f 1503/2309/1521 2078/2360/1520 2367/2358/2093 +f 1515/2359/1569 1791/2361/2094 2367/2358/2093 +f 1791/2361/2094 1516/2364/2097 2140/2362/2095 +f 2075/2311/2050 2367/2358/2093 2140/2362/2095 +f 1504/2314/2053 2140/2362/2095 2368/2363/2096 +f 1516/2364/2097 1854/2365/2098 2368/2363/2096 +f 1854/2365/2098 1517/2368/2101 1647/2366/2099 +f 2137/2315/2054 2368/2363/2096 1647/2366/2099 +f 1505/2318/2057 1647/2366/2099 2369/2367/2100 +f 1517/2368/2101 1934/2369/2102 2369/2367/2100 +f 1934/2369/2102 1518/2372/2105 1721/2370/2103 +f 1643/2319/2058 2369/2367/2100 1721/2370/2103 +f 1506/2322/2061 1721/2370/2103 2370/2371/2104 +f 1518/2372/2105 2009/2373/2106 2370/2371/2104 +f 2009/2373/2106 1519/2376/2109 1793/2374/2107 +f 1718/2323/2062 2370/2371/2104 1793/2374/2107 +f 1507/2326/2065 1793/2374/2107 2371/2375/2108 +f 1519/2376/2109 2079/2377/2110 2371/2375/2108 +f 2079/2377/2110 1520/2380/2113 1855/2378/2111 +f 1789/2327/2066 2371/2375/2108 1855/2378/2111 +f 1508/2330/2069 1855/2378/2111 2372/2379/2112 +f 1520/2380/2113 1935/2381/2114 2372/2379/2112 +f 1935/2381/2114 1509/2383/1544 1645/2332/1545 +f 1644/2331/2070 2372/2379/2112 1645/2332/1545 +f 1936/2382/1593 2373/2385/2116 1932/2334/2071 +f 1936/2382/1593 1521/2433/1592 1648/2384/2115 +f 2373/2385/2116 1648/2384/2115 1522/2386/2117 +f 2373/2385/2116 2010/2387/2118 1510/2336/2073 +f 2010/2387/2118 2374/2389/2120 2007/2338/2075 +f 2010/2387/2118 1522/2386/2117 1722/2388/2119 +f 2374/2389/2120 1722/2388/2119 1523/2390/2121 +f 2374/2389/2120 2080/2391/2122 1511/2340/2077 +f 2080/2391/2122 2375/2393/2124 2077/2342/2079 +f 2080/2391/2122 1523/2390/2121 1794/2392/2123 +f 2375/2393/2124 1794/2392/2123 1524/2394/2125 +f 2375/2393/2124 2142/2395/2126 1512/2344/2081 +f 2142/2395/2126 2376/2397/2128 2139/2346/2083 +f 2142/2395/2126 1524/2394/2125 1856/2396/2127 +f 2376/2397/2128 1856/2396/2127 1525/2398/2129 +f 2376/2397/2128 1649/2399/2130 1513/2348/2085 +f 1649/2399/2130 2377/2401/2132 1646/2350/2087 +f 1649/2399/2130 1525/2398/2129 1937/2400/2131 +f 2377/2401/2132 1937/2400/2131 1526/2402/2133 +f 2377/2401/2132 1723/2403/2134 1514/2352/2089 +f 1723/2403/2134 2378/2405/2136 1720/2354/2091 +f 1723/2403/2134 1526/2402/2133 2011/2404/2135 +f 2378/2405/2136 2011/2404/2135 1527/2406/1617 +f 2378/2405/2136 1795/2407/1568 1515/2356/1569 +f 1515/2359/1569 1795/2410/1568 2379/2408/2137 +f 1527/2409/1617 2081/2411/2138 2379/2408/2137 +f 2081/2411/2138 1528/2414/2141 1857/2412/2139 +f 1791/2361/2094 2379/2408/2137 1857/2412/2139 +f 1516/2364/2097 1857/2412/2139 2380/2413/2140 +f 1528/2414/2141 2143/2415/2142 2380/2413/2140 +f 2143/2415/2142 1529/2418/2145 1938/2416/2143 +f 1854/2365/2098 2380/2413/2140 1938/2416/2143 +f 1517/2368/2101 1938/2416/2143 2381/2417/2144 +f 1529/2418/2145 1650/2419/2146 2381/2417/2144 +f 1650/2419/2146 1530/2422/2149 2012/2420/2147 +f 1934/2369/2102 2381/2417/2144 2012/2420/2147 +f 1518/2372/2105 2012/2420/2147 2382/2421/2148 +f 1530/2422/2149 1724/2423/2150 2382/2421/2148 +f 1724/2423/2150 1531/2426/2153 2082/2424/2151 +f 2009/2373/2106 2382/2421/2148 2082/2424/2151 +f 1519/2376/2109 2082/2424/2151 2383/2425/2152 +f 1531/2426/2153 1796/2427/2154 2383/2425/2152 +f 1796/2427/2154 1532/2430/2157 2144/2428/2155 +f 2079/2377/2110 2383/2425/2152 2144/2428/2155 +f 1520/2380/2113 2144/2428/2155 2384/2429/2156 +f 1532/2430/2157 1651/2431/2158 2384/2429/2156 +f 1651/2431/2158 1521/2433/1592 1936/2382/1593 +f 1935/2381/2114 2384/2429/2156 1936/2382/1593 +f 1652/2432/1641 2385/2435/2160 1648/2384/2115 +f 1652/2432/1641 1533/2483/1640 1939/2434/2159 +f 2385/2435/2160 1939/2434/2159 1534/2436/2161 +f 2385/2435/2160 1725/2437/2162 1522/2386/2117 +f 1725/2437/2162 2386/2439/2164 1722/2388/2119 +f 1725/2437/2162 1534/2436/2161 2013/2438/2163 +f 2386/2439/2164 2013/2438/2163 1535/2440/2165 +f 2386/2439/2164 1797/2441/2166 1523/2390/2121 +f 1797/2441/2166 2387/2443/2168 1794/2392/2123 +f 1797/2441/2166 1535/2440/2165 2083/2442/2167 +f 2387/2443/2168 2083/2442/2167 1536/2444/2169 +f 2387/2443/2168 1858/2445/2170 1524/2394/2125 +f 1858/2445/2170 2388/2447/2172 1856/2396/2127 +f 1858/2445/2170 1536/2444/2169 2014/2446/2171 +f 2388/2447/2172 2014/2446/2171 1537/2448/2173 +f 2388/2447/2172 1940/2449/2174 1525/2398/2129 +f 1940/2449/2174 2389/2451/2176 1937/2400/2131 +f 1940/2449/2174 1537/2448/2173 1653/2450/2175 +f 2389/2451/2176 1653/2450/2175 1538/2452/2177 +f 2389/2451/2176 1859/2453/2178 1526/2402/2133 +f 1859/2453/2178 2390/2455/2180 2011/2404/2135 +f 1859/2453/2178 1538/2452/2177 1570/2454/2179 +f 2390/2455/2180 1570/2454/2179 1539/2456/1665 +f 2390/2455/2180 2084/2457/1616 1527/2406/1617 +f 1527/2409/1617 2084/2460/1616 2391/2458/2181 +f 1539/2459/1665 1798/2461/2182 2391/2458/2181 +f 1798/2461/2182 1540/2464/2185 2015/2462/2183 +f 2081/2411/2138 2391/2458/2181 2015/2462/2183 +f 1528/2414/2141 2015/2462/2183 2392/2463/2184 +f 1540/2464/2185 1727/2465/2186 2392/2463/2184 +f 1727/2465/2186 1541/2468/2189 1655/2466/2187 +f 2143/2415/2142 2392/2463/2184 1655/2466/2187 +f 1529/2418/2145 1655/2466/2187 2393/2467/2188 +f 1541/2468/2189 1941/2469/2190 2393/2467/2188 +f 1941/2469/2190 1542/2472/2193 1571/2470/2191 +f 1650/2419/2146 2393/2467/2188 1571/2470/2191 +f 1530/2422/2149 1571/2470/2191 2394/2471/2192 +f 1542/2472/2193 1861/2473/2194 2394/2471/2192 +f 1861/2473/2194 1543/2476/2197 1800/2474/2195 +f 1724/2423/2150 2394/2471/2192 1800/2474/2195 +f 1531/2426/2153 1800/2474/2195 2395/2475/2196 +f 1543/2476/2197 2085/2477/2198 2395/2475/2196 +f 2085/2477/2198 1544/2480/2201 1728/2478/2199 +f 1796/2427/2154 2395/2475/2196 1728/2478/2199 +f 1532/2430/2157 1728/2478/2199 2396/2479/2200 +f 1544/2480/2201 1943/2481/2202 2396/2479/2200 +f 1943/2481/2202 1533/2483/1640 1652/2432/1641 +f 1651/2431/2158 2396/2479/2200 1652/2432/1641 +f 1944/2482/1689 2397/2485/2204 1939/2434/2159 +f 1944/2482/1689 1545/2533/1688 1656/2484/2203 +f 2397/2485/2204 1656/2484/2203 1546/2486/2205 +f 2397/2485/2204 1862/2487/2206 1534/2436/2161 +f 1862/2487/2206 2398/2489/2208 2013/2438/2163 +f 1862/2487/2206 1546/2486/2205 1573/2488/2207 +f 2398/2489/2208 1573/2488/2207 1547/2490/2209 +f 2398/2489/2208 2087/2491/2210 1535/2440/2165 +f 2087/2491/2210 2399/2493/2212 2083/2442/2167 +f 2087/2491/2210 1547/2490/2209 1801/2492/2211 +f 2399/2493/2212 1801/2492/2211 1548/2494/2213 +f 2399/2493/2212 2017/2495/2214 1536/2444/2169 +f 2017/2495/2214 2400/2497/2216 2014/2446/2171 +f 2017/2495/2214 1548/2494/2213 1730/2496/2215 +f 2400/2497/2216 1730/2496/2215 1549/2498/2217 +f 2400/2497/2216 1658/2499/2218 1537/2448/2173 +f 1658/2499/2218 2401/2501/2220 1653/2450/2175 +f 1658/2499/2218 1549/2498/2217 1945/2500/2219 +f 2401/2501/2220 1945/2500/2219 1550/2502/2221 +f 2401/2501/2220 1576/2503/2222 1538/2452/2177 +f 1576/2503/2222 2402/2505/2224 1570/2454/2179 +f 1576/2503/2222 1550/2502/2221 1864/2504/2223 +f 2402/2505/2224 1864/2504/2223 1551/2506/1713 +f 2402/2505/2224 1802/2507/1664 1539/2456/1665 +f 1539/2459/1665 1802/2510/1664 2403/2508/2225 +f 1551/2509/1713 2088/2511/2226 2403/2508/2225 +f 2088/2511/2226 1552/2514/2229 1732/2512/2227 +f 1798/2461/2182 2403/2508/2225 1732/2512/2227 +f 1540/2464/2185 1732/2512/2227 2404/2513/2228 +f 1552/2514/2229 2019/2515/2230 2404/2513/2228 +f 2019/2515/2230 1553/2518/2233 1947/2516/2231 +f 1727/2465/2186 2404/2513/2228 1947/2516/2231 +f 1541/2468/2189 1947/2516/2231 2405/2517/2232 +f 1553/2518/2233 1660/2519/2234 2405/2517/2232 +f 1660/2519/2234 1554/2522/2237 1866/2520/2235 +f 1941/2469/2190 2405/2517/2232 1866/2520/2235 +f 1542/2472/2193 1866/2520/2235 2406/2521/2236 +f 1554/2522/2237 1578/2523/2238 2406/2521/2236 +f 1578/2523/2238 1555/2526/2241 2090/2524/2239 +f 1861/2473/2194 2406/2521/2236 2090/2524/2239 +f 1543/2476/2197 2090/2524/2239 2407/2525/2240 +f 1555/2526/2241 1804/2527/2242 2407/2525/2240 +f 1804/2527/2242 1556/2530/2245 2021/2528/2243 +f 2085/2477/2198 2407/2525/2240 2021/2528/2243 +f 1544/2480/2201 2021/2528/2243 2408/2529/2244 +f 1556/2530/2245 1662/2531/2246 2408/2529/2244 +f 1662/2531/2246 1545/2533/1688 1944/2482/1689 +f 1943/2481/2202 2408/2529/2244 1944/2482/1689 +f 1663/2532/1737 2409/2535/2248 1656/2484/2203 +f 1663/2532/1737 1557/2583/1736 1949/2534/2247 +f 2409/2535/2248 1949/2534/2247 1558/2536/2249 +f 2409/2535/2248 1580/2537/2250 1546/2486/2205 +f 1580/2537/2250 2410/2539/2252 1573/2488/2207 +f 1580/2537/2250 1558/2536/2249 1868/2538/2251 +f 2410/2539/2252 1868/2538/2251 1559/2540/2253 +f 2410/2539/2252 1806/2541/2254 1547/2490/2209 +f 1806/2541/2254 2411/2543/2256 1801/2492/2211 +f 1806/2541/2254 1559/2540/2253 2092/2542/2255 +f 2411/2543/2256 2092/2542/2255 1560/2544/2257 +f 2411/2543/2256 1735/2545/2258 1548/2494/2213 +f 1735/2545/2258 2412/2547/2260 1730/2496/2215 +f 1735/2545/2258 1560/2544/2257 2023/2546/2259 +f 2412/2547/2260 2023/2546/2259 1561/2548/2261 +f 2412/2547/2260 1951/2549/2262 1549/2498/2217 +f 1951/2549/2262 2413/2551/2264 1945/2500/2219 +f 1951/2549/2262 1561/2548/2261 1665/2550/2263 +f 2413/2551/2264 1665/2550/2263 1562/2552/2265 +f 2413/2551/2264 1871/2553/2266 1550/2502/2221 +f 1871/2553/2266 2414/2555/2268 1864/2504/2223 +f 1871/2553/2266 1562/2552/2265 1582/2554/2267 +f 2414/2555/2268 1582/2554/2267 1563/2556/1761 +f 2414/2555/2268 2093/2557/1712 1551/2506/1713 +f 1551/2509/1713 2093/2560/1712 2415/2558/2269 +f 1563/2559/1761 1808/2561/2270 2415/2558/2269 +f 1808/2561/2270 1564/2564/2273 2025/2562/2271 +f 2088/2511/2226 2415/2558/2269 2025/2562/2271 +f 1552/2514/2229 2025/2562/2271 2416/2563/2272 +f 1564/2564/2273 1737/2565/2274 2416/2563/2272 +f 1737/2565/2274 1565/2568/2277 1667/2566/2275 +f 2019/2515/2230 2416/2563/2272 1667/2566/2275 +f 1553/2518/2233 1667/2566/2275 2417/2567/2276 +f 1565/2568/2277 1953/2569/2278 2417/2567/2276 +f 1953/2569/2278 1566/2572/2281 1584/2570/2279 +f 1660/2519/2234 2417/2567/2276 1584/2570/2279 +f 1554/2522/2237 1584/2570/2279 2418/2571/2280 +f 1566/2572/2281 1873/2573/2282 2418/2571/2280 +f 1873/2573/2282 1567/2576/2285 1810/2574/2283 +f 1578/2523/2238 2418/2571/2280 1810/2574/2283 +f 1555/2526/2241 1810/2574/2283 2419/2575/2284 +f 1567/2576/2285 2095/2577/2286 2419/2575/2284 +f 2095/2577/2286 1568/2580/2289 1739/2578/2287 +f 1804/2527/2242 2419/2575/2284 1739/2578/2287 +f 1556/2530/2245 1739/2578/2287 2420/2579/2288 +f 1568/2580/2289 1955/2581/2290 2420/2579/2288 +f 1955/2581/2290 1557/2583/1736 1663/2532/1737 +f 1662/2531/2246 2420/2579/2288 1663/2532/1737 +f 1975/2582/1784 2421/2584/2291 1949/2534/2247 +f 1975/2582/1784 1281/1386/1211 1569/1385/1210 +f 2421/2584/2291 1569/1385/1210 1282/1391/1216 +f 2421/2584/2291 1607/2585/2292 1558/2536/2249 +f 1607/2585/2292 2422/2586/2293 1868/2538/2251 +f 1607/2585/2292 1282/1391/1216 1654/1392/1217 +f 2422/2586/2293 1654/1392/1217 1283/1397/1222 +f 2422/2586/2293 2118/2587/2294 1559/2540/2253 +f 2118/2587/2294 2423/2588/2295 2092/2542/2255 +f 2118/2587/2294 1283/1397/1222 1726/1398/1223 +f 2423/2588/2295 1726/1398/1223 1284/1403/1228 +f 2423/2588/2295 1765/2589/2296 1560/2544/2257 +f 1765/2589/2296 2424/2590/2297 2023/2546/2259 +f 1765/2589/2296 1284/1403/1228 1799/1404/1229 +f 2424/2590/2297 1799/1404/1229 1285/1409/1234 +f 2424/2590/2297 1701/2591/2298 1561/2548/2261 +f 1701/2591/2298 2425/2592/2299 1665/2550/2263 +f 1701/2591/2298 1285/1409/1234 1860/1410/1235 +f 2425/2592/2299 1860/1410/1235 1286/1415/1240 +f 2425/2592/2299 1911/2593/2300 1562/2552/2265 +f 1911/2593/2300 2426/2594/2301 1582/2554/2267 +f 1911/2593/2300 1286/1415/1240 1942/1416/1241 +f 2426/2594/2301 1942/1416/1241 1287/1421/1246 +f 2426/2594/2301 1843/2595/1760 1563/2556/1761 +f 1563/2559/1761 1843/2597/1760 2427/2596/2302 +f 1287/1422/1246 2016/1424/1248 2427/2596/2302 +f 2016/1424/1248 1288/1429/1251 2065/2598/2303 +f 1808/2561/2270 2427/2596/2302 2065/2598/2303 +f 1564/2564/2273 2065/2598/2303 2428/2599/2304 +f 1288/1429/1251 2086/1431/1253 2428/2599/2304 +f 2086/1431/1253 1289/1435/1257 2002/2600/2305 +f 1737/2565/2274 2428/2599/2304 2002/2600/2305 +f 1565/2568/2277 2002/2600/2305 2429/2601/2306 +f 1289/1435/1257 1572/1437/1259 2429/2601/2306 +f 1572/1437/1259 1290/1441/1263 1639/2602/2307 +f 1953/2569/2278 2429/2601/2306 1639/2602/2307 +f 1566/2572/2281 1639/2602/2307 2430/2603/2308 +f 1290/1441/1263 1657/1443/1265 2430/2603/2308 +f 1657/1443/1265 1291/1447/1269 2141/2604/2309 +f 1873/2573/2282 2430/2603/2308 2141/2604/2309 +f 1567/2576/2285 2141/2604/2309 2431/2605/2310 +f 1291/1447/1269 1729/1449/1271 2431/2605/2310 +f 1729/1449/1271 1292/1453/1275 1792/2606/2311 +f 2095/2577/2286 2431/2605/2310 1792/2606/2311 +f 1568/2580/2289 1792/2606/2311 2432/2607/2312 +f 1292/1453/1275 1574/1455/1277 2432/2607/2312 +f 1574/1455/1277 1281/1386/1211 1975/2582/1784 +f 1955/2581/2290 2432/2607/2312 1975/2582/1784 +g torus_Torus.001_torus.002 +usemtl torus.002 +f 2727/2609/2313 2721/2610/2314 2433/2611/2315 +f 2727/2609/2313 3015/2612/2316 3297/2613/2317 +f 3297/2613/2317 2446/2614/2318 2811/2615/2319 +f 3297/2613/2317 2434/2616/2320 2721/2610/2314 +f 2811/2615/2319 2806/2617/2321 2434/2616/2320 +f 2811/2615/2319 3098/2618/2322 3298/2619/2323 +f 3298/2619/2323 2447/2620/2324 2883/2621/2325 +f 3298/2619/2323 2435/2622/2326 2806/2617/2321 +f 2883/2621/2325 2878/2623/2327 2435/2622/2326 +f 2883/2621/2325 3170/2624/2328 3299/2625/2329 +f 3299/2625/2329 2448/2626/2330 2955/2627/2331 +f 3299/2625/2329 2436/2628/2332 2878/2623/2327 +f 2955/2627/2331 2951/2629/2333 2436/2628/2332 +f 2955/2627/2331 3241/2630/2334 3300/2631/2335 +f 3300/2631/2335 2449/2632/2336 3017/2633/2337 +f 3300/2631/2335 2437/2634/2338 2951/2629/2333 +f 3017/2633/2337 3012/2635/2339 2437/2634/2338 +f 3017/2633/2337 2729/2636/2340 3301/2637/2341 +f 3301/2637/2341 2450/2638/2342 3100/2639/2343 +f 3301/2637/2341 2438/2640/2344 3012/2635/2339 +f 3100/2639/2343 3094/2641/2345 2438/2640/2344 +f 3100/2639/2343 2813/2642/2346 3302/2643/2347 +f 3302/2643/2347 2451/2644/2348 3172/2645/2349 +f 3302/2643/2347 2439/2646/2350 3094/2641/2345 +f 2439/2647/2350 3303/2648/2351 3168/2649/2352 +f 2451/2650/2348 3303/2648/2351 3172/2651/2349 +f 2885/2652/2353 3243/2653/2354 3303/2648/2351 +f 3168/2649/2352 3243/2653/2354 2440/2654/2355 +f 2440/2654/2355 3304/2655/2356 3238/2656/2357 +f 2452/2657/2358 3304/2655/2356 3243/2653/2354 +f 2957/2658/2359 2731/2659/2360 3304/2655/2356 +f 3238/2656/2357 2731/2659/2360 2441/2660/2361 +f 2441/2660/2361 3305/2661/2362 2724/2662/2363 +f 2453/2663/2364 3305/2661/2362 2731/2659/2360 +f 3019/2664/2365 2816/2665/2366 3305/2661/2362 +f 2724/2662/2363 2816/2665/2366 2442/2666/2367 +f 2442/2666/2367 3306/2667/2368 2809/2668/2369 +f 2454/2669/2370 3306/2667/2368 2816/2665/2366 +f 3102/2670/2371 2886/2671/2372 3306/2667/2368 +f 2809/2668/2369 2886/2671/2372 2443/2672/2373 +f 2443/2672/2373 3307/2673/2374 2881/2674/2375 +f 2455/2675/2376 3307/2673/2374 2886/2671/2372 +f 3174/2676/2377 2959/2677/2378 3307/2673/2374 +f 2881/2674/2375 2959/2677/2378 2444/2678/2379 +f 2444/2678/2379 3308/2679/2380 2726/2680/2381 +f 2456/2681/2382 3308/2679/2380 2959/2677/2378 +f 3021/2682/2383 2727/2609/2313 3308/2679/2380 +f 2726/2680/2381 2727/2609/2313 2433/2611/2315 +f 3022/2683/2384 3015/2612/2316 2445/2684/2385 +f 3022/2683/2384 2733/2685/2386 3309/2686/2387 +f 3309/2686/2387 2458/2687/2388 3104/2688/2389 +f 3309/2686/2387 2446/2614/2318 3015/2612/2316 +f 3104/2688/2389 3098/2618/2322 2446/2614/2318 +f 3104/2688/2389 2818/2689/2390 3310/2690/2391 +f 3310/2690/2391 2459/2691/2392 3176/2692/2393 +f 3310/2690/2391 2447/2620/2324 3098/2618/2322 +f 3176/2692/2393 3170/2624/2328 2447/2620/2324 +f 3176/2692/2393 2888/2693/2394 3311/2694/2395 +f 3311/2694/2395 2460/2695/2396 3246/2696/2397 +f 3311/2694/2395 2448/2626/2330 3170/2624/2328 +f 3246/2696/2397 3241/2630/2334 2448/2626/2330 +f 3246/2696/2397 2961/2697/2398 3312/2698/2399 +f 3312/2698/2399 2461/2699/2400 2735/2700/2401 +f 3312/2698/2399 2449/2632/2336 3241/2630/2334 +f 2735/2700/2401 2729/2636/2340 2449/2632/2336 +f 2735/2700/2401 3024/2701/2402 3313/2702/2403 +f 3313/2702/2403 2462/2703/2404 2820/2704/2405 +f 3313/2702/2403 2450/2638/2342 2729/2636/2340 +f 2820/2704/2405 2813/2642/2346 2450/2638/2342 +f 2820/2704/2405 3106/2705/2406 3314/2706/2407 +f 3314/2706/2407 2463/2707/2408 2890/2708/2409 +f 3314/2706/2407 2451/2644/2348 2813/2642/2346 +f 2451/2650/2348 3315/2709/2410 2885/2652/2353 +f 2463/2710/2408 3315/2709/2410 2890/2711/2409 +f 3178/2712/2411 2963/2713/2412 3315/2709/2410 +f 2885/2652/2353 2963/2713/2412 2452/2657/2358 +f 2452/2657/2358 3316/2714/2413 2957/2658/2359 +f 2464/2715/2414 3316/2714/2413 2963/2713/2412 +f 3248/2716/2415 3026/2717/2416 3316/2714/2413 +f 2957/2658/2359 3026/2717/2416 2453/2663/2364 +f 2453/2663/2364 3317/2718/2417 3019/2664/2365 +f 2465/2719/2418 3317/2718/2417 3026/2717/2416 +f 2737/2720/2419 3108/2721/2420 3317/2718/2417 +f 3019/2664/2365 3108/2721/2420 2454/2669/2370 +f 2454/2669/2370 3318/2722/2421 3102/2670/2371 +f 2466/2723/2422 3318/2722/2421 3108/2721/2420 +f 2821/2724/2423 3179/2725/2424 3318/2722/2421 +f 3102/2670/2371 3179/2725/2424 2455/2675/2376 +f 2455/2675/2376 3319/2726/2425 3174/2676/2377 +f 2467/2727/2426 3319/2726/2425 3179/2725/2424 +f 2892/2728/2427 3249/2729/2428 3319/2726/2425 +f 3174/2676/2377 3249/2729/2428 2456/2681/2382 +f 2456/2681/2382 3320/2730/2429 3021/2682/2383 +f 2468/2731/2430 3320/2730/2429 3249/2729/2428 +f 2738/2732/2431 3022/2683/2384 3320/2730/2429 +f 3021/2682/2383 3022/2683/2384 2445/2684/2385 +f 2739/2733/2432 2733/2685/2386 2457/2734/2433 +f 2739/2733/2432 3027/2735/2434 3321/2736/2435 +f 3321/2736/2435 2470/2737/2436 2822/2738/2437 +f 3321/2736/2435 2458/2687/2388 2733/2685/2386 +f 2822/2738/2437 2818/2689/2390 2458/2687/2388 +f 2822/2738/2437 3109/2739/2438 3322/2740/2439 +f 3322/2740/2439 2471/2741/2440 2893/2742/2441 +f 3322/2740/2439 2459/2691/2392 2818/2689/2390 +f 2893/2742/2441 2888/2693/2394 2459/2691/2392 +f 2893/2742/2441 3180/2743/2442 3323/2744/2443 +f 3323/2744/2443 2472/2745/2444 2964/2746/2445 +f 3323/2744/2443 2460/2695/2396 2888/2693/2394 +f 2964/2746/2445 2961/2697/2398 2460/2695/2396 +f 2964/2746/2445 3250/2747/2446 3324/2748/2447 +f 3324/2748/2447 2473/2749/2448 3028/2750/2449 +f 3324/2748/2447 2461/2699/2400 2961/2697/2398 +f 3028/2750/2449 3024/2701/2402 2461/2699/2400 +f 3028/2750/2449 2740/2751/2450 3325/2752/2451 +f 3325/2752/2451 2474/2753/2452 3110/2754/2453 +f 3325/2752/2451 2462/2703/2404 3024/2701/2402 +f 3110/2754/2453 3106/2705/2406 2462/2703/2404 +f 3110/2754/2453 2823/2755/2454 3326/2756/2455 +f 3326/2756/2455 2475/2757/2456 3181/2758/2457 +f 3326/2756/2455 2463/2707/2408 3106/2705/2406 +f 2463/2710/2408 3327/2759/2458 3178/2712/2411 +f 2475/2760/2456 3327/2759/2458 3181/2761/2457 +f 2894/2762/2459 3251/2763/2460 3327/2759/2458 +f 3178/2712/2411 3251/2763/2460 2464/2715/2414 +f 2464/2715/2414 3328/2764/2461 3248/2716/2415 +f 2476/2765/2462 3328/2764/2461 3251/2763/2460 +f 2965/2766/2463 2741/2767/2464 3328/2764/2461 +f 3248/2716/2415 2741/2767/2464 2465/2719/2418 +f 2465/2719/2418 3329/2768/2465 2737/2720/2419 +f 2477/2769/2466 3329/2768/2465 2741/2767/2464 +f 3029/2770/2467 2824/2771/2468 3329/2768/2465 +f 2737/2720/2419 2824/2771/2468 2466/2723/2422 +f 2466/2723/2422 3330/2772/2469 2821/2724/2423 +f 2478/2773/2470 3330/2772/2469 2824/2771/2468 +f 3111/2774/2471 2895/2775/2472 3330/2772/2469 +f 2821/2724/2423 2895/2775/2472 2467/2727/2426 +f 2467/2727/2426 3331/2776/2473 2892/2728/2427 +f 2479/2777/2474 3331/2776/2473 2895/2775/2472 +f 3182/2778/2475 2966/2779/2476 3331/2776/2473 +f 2892/2728/2427 2966/2779/2476 2468/2731/2430 +f 2468/2731/2430 3332/2780/2477 2738/2732/2431 +f 2480/2781/2478 3332/2780/2477 2966/2779/2476 +f 3030/2782/2479 2739/2733/2432 3332/2780/2477 +f 2738/2732/2431 2739/2733/2432 2457/2734/2433 +f 3031/2783/2480 3027/2735/2434 2469/2784/2481 +f 3031/2783/2480 2742/2785/2482 3333/2786/2483 +f 3333/2786/2483 2482/2787/2484 3112/2788/2485 +f 3333/2786/2483 2470/2737/2436 3027/2735/2434 +f 3112/2788/2485 3109/2739/2438 2470/2737/2436 +f 3112/2788/2485 2825/2789/2486 3334/2790/2487 +f 3334/2790/2487 2483/2791/2488 3183/2792/2489 +f 3334/2790/2487 2471/2741/2440 3109/2739/2438 +f 3183/2792/2489 3180/2743/2442 2471/2741/2440 +f 3183/2792/2489 2896/2793/2490 3335/2794/2491 +f 3335/2794/2491 2484/2795/2492 3252/2796/2493 +f 3335/2794/2491 2472/2745/2444 3180/2743/2442 +f 3252/2796/2493 3250/2747/2446 2472/2745/2444 +f 3252/2796/2493 2967/2797/2494 3336/2798/2495 +f 3336/2798/2495 2485/2799/2496 2743/2800/2497 +f 3336/2798/2495 2473/2749/2448 3250/2747/2446 +f 2743/2800/2497 2740/2751/2450 2473/2749/2448 +f 2743/2800/2497 3032/2801/2498 3337/2802/2499 +f 3337/2802/2499 2486/2803/2500 2826/2804/2501 +f 3337/2802/2499 2474/2753/2452 2740/2751/2450 +f 2826/2804/2501 2823/2755/2454 2474/2753/2452 +f 2826/2804/2501 3113/2805/2502 3338/2806/2503 +f 3338/2806/2503 2487/2807/2504 2897/2808/2505 +f 3338/2806/2503 2475/2757/2456 2823/2755/2454 +f 2475/2760/2456 3339/2809/2506 2894/2762/2459 +f 2487/2810/2504 3339/2809/2506 2897/2811/2505 +f 3184/2812/2507 2968/2813/2508 3339/2809/2506 +f 2894/2762/2459 2968/2813/2508 2476/2765/2462 +f 2476/2765/2462 3340/2814/2509 2965/2766/2463 +f 2488/2815/2510 3340/2814/2509 2968/2813/2508 +f 3253/2816/2511 3033/2817/2512 3340/2814/2509 +f 2965/2766/2463 3033/2817/2512 2477/2769/2466 +f 2477/2769/2466 3341/2818/2513 3029/2770/2467 +f 2489/2819/2514 3341/2818/2513 3033/2817/2512 +f 2744/2820/2515 3114/2821/2516 3341/2818/2513 +f 3029/2770/2467 3114/2821/2516 2478/2773/2470 +f 2478/2773/2470 3342/2822/2517 3111/2774/2471 +f 2490/2823/2518 3342/2822/2517 3114/2821/2516 +f 2827/2824/2519 3185/2825/2520 3342/2822/2517 +f 3111/2774/2471 3185/2825/2520 2479/2777/2474 +f 2479/2777/2474 3343/2826/2521 3182/2778/2475 +f 2491/2827/2522 3343/2826/2521 3185/2825/2520 +f 2898/2828/2523 3254/2829/2524 3343/2826/2521 +f 3182/2778/2475 3254/2829/2524 2480/2781/2478 +f 2480/2781/2478 3344/2830/2525 3030/2782/2479 +f 2492/2831/2526 3344/2830/2525 3254/2829/2524 +f 2745/2832/2527 3031/2783/2480 3344/2830/2525 +f 3030/2782/2479 3031/2783/2480 2469/2784/2481 +f 2746/2833/2528 2742/2785/2482 2481/2834/2529 +f 2746/2833/2528 3034/2835/2530 3345/2836/2531 +f 3345/2836/2531 2494/2837/2532 2828/2838/2533 +f 3345/2836/2531 2482/2787/2484 2742/2785/2482 +f 2828/2838/2533 2825/2789/2486 2482/2787/2484 +f 2828/2838/2533 3115/2839/2534 3346/2840/2535 +f 3346/2840/2535 2495/2841/2536 2899/2842/2537 +f 3346/2840/2535 2483/2791/2488 2825/2789/2486 +f 2899/2842/2537 2896/2793/2490 2483/2791/2488 +f 2899/2842/2537 3186/2843/2538 3347/2844/2539 +f 3347/2844/2539 2496/2845/2540 2969/2846/2541 +f 3347/2844/2539 2484/2795/2492 2896/2793/2490 +f 2969/2846/2541 2967/2797/2494 2484/2795/2492 +f 2969/2846/2541 3255/2847/2542 3348/2848/2543 +f 3348/2848/2543 2497/2849/2544 3035/2850/2545 +f 3348/2848/2543 2485/2799/2496 2967/2797/2494 +f 3035/2850/2545 3032/2801/2498 2485/2799/2496 +f 3035/2850/2545 2747/2851/2546 3349/2852/2547 +f 3349/2852/2547 2498/2853/2548 3116/2854/2549 +f 3349/2852/2547 2486/2803/2500 3032/2801/2498 +f 3116/2854/2549 3113/2805/2502 2486/2803/2500 +f 3116/2854/2549 2829/2855/2550 3350/2856/2551 +f 3350/2856/2551 2499/2857/2552 3187/2858/2553 +f 3350/2856/2551 2487/2807/2504 3113/2805/2502 +f 2487/2810/2504 3351/2859/2554 3184/2812/2507 +f 2499/2860/2552 3351/2859/2554 3187/2861/2553 +f 2900/2862/2555 3256/2863/2556 3351/2859/2554 +f 3184/2812/2507 3256/2863/2556 2488/2815/2510 +f 2488/2815/2510 3352/2864/2557 3253/2816/2511 +f 2500/2865/2558 3352/2864/2557 3256/2863/2556 +f 2970/2866/2559 2748/2867/2560 3352/2864/2557 +f 3253/2816/2511 2748/2867/2560 2489/2819/2514 +f 2489/2819/2514 3353/2868/2561 2744/2820/2515 +f 2501/2869/2562 3353/2868/2561 2748/2867/2560 +f 3036/2870/2563 2830/2871/2564 3353/2868/2561 +f 2744/2820/2515 2830/2871/2564 2490/2823/2518 +f 2490/2823/2518 3354/2872/2565 2827/2824/2519 +f 2502/2873/2566 3354/2872/2565 2830/2871/2564 +f 3117/2874/2567 2901/2875/2568 3354/2872/2565 +f 2827/2824/2519 2901/2875/2568 2491/2827/2522 +f 2491/2827/2522 3355/2876/2569 2898/2828/2523 +f 2503/2877/2570 3355/2876/2569 2901/2875/2568 +f 3188/2878/2571 2971/2879/2572 3355/2876/2569 +f 2898/2828/2523 2971/2879/2572 2492/2831/2526 +f 2492/2831/2526 3356/2880/2573 2745/2832/2527 +f 2504/2881/2574 3356/2880/2573 2971/2879/2572 +f 3037/2882/2575 2746/2833/2528 3356/2880/2573 +f 2745/2832/2527 2746/2833/2528 2481/2834/2529 +f 3038/2883/2576 3034/2835/2530 2493/2884/2577 +f 3038/2883/2576 2749/2885/2578 3357/2886/2579 +f 3357/2886/2579 2506/2887/2580 3118/2888/2581 +f 3357/2886/2579 2494/2837/2532 3034/2835/2530 +f 3118/2888/2581 3115/2839/2534 2494/2837/2532 +f 3118/2888/2581 2831/2889/2582 3358/2890/2583 +f 3358/2890/2583 2507/2891/2584 3189/2892/2585 +f 3358/2890/2583 2495/2841/2536 3115/2839/2534 +f 3189/2892/2585 3186/2843/2538 2495/2841/2536 +f 3189/2892/2585 2902/2893/2586 3359/2894/2587 +f 3359/2894/2587 2508/2895/2588 3257/2896/2589 +f 3359/2894/2587 2496/2845/2540 3186/2843/2538 +f 3257/2896/2589 3255/2847/2542 2496/2845/2540 +f 3257/2896/2589 2972/2897/2590 3360/2898/2591 +f 3360/2898/2591 2509/2899/2592 2750/2900/2593 +f 3360/2898/2591 2497/2849/2544 3255/2847/2542 +f 2750/2900/2593 2747/2851/2546 2497/2849/2544 +f 2750/2900/2593 3039/2901/2594 3361/2902/2595 +f 3361/2902/2595 2510/2903/2596 2832/2904/2597 +f 3361/2902/2595 2498/2853/2548 2747/2851/2546 +f 2832/2904/2597 2829/2855/2550 2498/2853/2548 +f 2832/2904/2597 3119/2905/2598 3362/2906/2599 +f 3362/2906/2599 2511/2907/2600 2903/2908/2601 +f 3362/2906/2599 2499/2857/2552 2829/2855/2550 +f 2499/2860/2552 3363/2909/2602 2900/2862/2555 +f 2511/2910/2600 3363/2909/2602 2903/2911/2601 +f 3190/2912/2603 2973/2913/2604 3363/2909/2602 +f 2900/2862/2555 2973/2913/2604 2500/2865/2558 +f 2500/2865/2558 3364/2914/2605 2970/2866/2559 +f 2512/2915/2606 3364/2914/2605 2973/2913/2604 +f 3258/2916/2607 3040/2917/2608 3364/2914/2605 +f 2970/2866/2559 3040/2917/2608 2501/2869/2562 +f 2501/2869/2562 3365/2918/2609 3036/2870/2563 +f 2513/2919/2610 3365/2918/2609 3040/2917/2608 +f 2751/2920/2611 3120/2921/2612 3365/2918/2609 +f 3036/2870/2563 3120/2921/2612 2502/2873/2566 +f 2502/2873/2566 3366/2922/2613 3117/2874/2567 +f 2514/2923/2614 3366/2922/2613 3120/2921/2612 +f 2833/2924/2615 3191/2925/2616 3366/2922/2613 +f 3117/2874/2567 3191/2925/2616 2503/2877/2570 +f 2503/2877/2570 3367/2926/2617 3188/2878/2571 +f 2515/2927/2618 3367/2926/2617 3191/2925/2616 +f 2904/2928/2619 3259/2929/2620 3367/2926/2617 +f 3188/2878/2571 3259/2929/2620 2504/2881/2574 +f 2504/2881/2574 3368/2930/2621 3037/2882/2575 +f 2516/2931/2622 3368/2930/2621 3259/2929/2620 +f 2752/2932/2623 3038/2883/2576 3368/2930/2621 +f 3037/2882/2575 3038/2883/2576 2493/2884/2577 +f 2753/2933/2624 2749/2885/2578 2505/2934/2625 +f 2753/2933/2624 3041/2935/2626 3369/2936/2627 +f 3369/2936/2627 2518/2937/2628 2834/2938/2629 +f 3369/2936/2627 2506/2887/2580 2749/2885/2578 +f 2834/2938/2629 2831/2889/2582 2506/2887/2580 +f 2834/2938/2629 3121/2939/2630 3370/2940/2631 +f 3370/2940/2631 2519/2941/2632 2905/2942/2633 +f 3370/2940/2631 2507/2891/2584 2831/2889/2582 +f 2905/2942/2633 2902/2893/2586 2507/2891/2584 +f 2905/2942/2633 3192/2943/2634 3371/2944/2635 +f 3371/2944/2635 2520/2945/2636 2974/2946/2637 +f 3371/2944/2635 2508/2895/2588 2902/2893/2586 +f 2974/2946/2637 2972/2897/2590 2508/2895/2588 +f 2974/2946/2637 3260/2947/2638 3372/2948/2639 +f 3372/2948/2639 2521/2949/2640 3042/2950/2641 +f 3372/2948/2639 2509/2899/2592 2972/2897/2590 +f 3042/2950/2641 3039/2901/2594 2509/2899/2592 +f 3042/2950/2641 2754/2951/2642 3373/2952/2643 +f 3373/2952/2643 2522/2953/2644 3122/2954/2645 +f 3373/2952/2643 2510/2903/2596 3039/2901/2594 +f 3122/2954/2645 3119/2905/2598 2510/2903/2596 +f 3122/2954/2645 2835/2955/2646 3374/2956/2647 +f 3374/2956/2647 2523/2957/2648 3193/2958/2649 +f 3374/2956/2647 2511/2907/2600 3119/2905/2598 +f 2511/2910/2600 3375/2959/2650 3190/2912/2603 +f 2523/2960/2648 3375/2959/2650 3193/2961/2649 +f 2906/2962/2651 3261/2963/2652 3375/2959/2650 +f 3190/2912/2603 3261/2963/2652 2512/2915/2606 +f 2512/2915/2606 3376/2964/2653 3258/2916/2607 +f 2524/2965/2654 3376/2964/2653 3261/2963/2652 +f 2975/2966/2655 2755/2967/2656 3376/2964/2653 +f 3258/2916/2607 2755/2967/2656 2513/2919/2610 +f 2513/2919/2610 3377/2968/2657 2751/2920/2611 +f 2525/2969/2658 3377/2968/2657 2755/2967/2656 +f 3043/2970/2659 2836/2971/2660 3377/2968/2657 +f 2751/2920/2611 2836/2971/2660 2514/2923/2614 +f 2514/2923/2614 3378/2972/2661 2833/2924/2615 +f 2526/2973/2662 3378/2972/2661 2836/2971/2660 +f 3123/2974/2663 2907/2975/2664 3378/2972/2661 +f 2833/2924/2615 2907/2975/2664 2515/2927/2618 +f 2515/2927/2618 3379/2976/2665 2904/2928/2619 +f 2527/2977/2666 3379/2976/2665 2907/2975/2664 +f 3194/2978/2667 2976/2979/2668 3379/2976/2665 +f 2904/2928/2619 2976/2979/2668 2516/2931/2622 +f 2516/2931/2622 3380/2980/2669 2752/2932/2623 +f 2528/2981/2670 3380/2980/2669 2976/2979/2668 +f 3044/2982/2671 2753/2933/2624 3380/2980/2669 +f 2752/2932/2623 2753/2933/2624 2505/2934/2625 +f 3045/2983/2672 3041/2935/2626 2517/2984/2673 +f 3045/2983/2672 2756/2985/2674 3381/2986/2675 +f 3381/2986/2675 2530/2987/2676 3124/2988/2677 +f 3381/2986/2675 2518/2937/2628 3041/2935/2626 +f 3124/2988/2677 3121/2939/2630 2518/2937/2628 +f 3124/2988/2677 2837/2989/2678 3382/2990/2679 +f 3382/2990/2679 2531/2991/2680 3195/2992/2681 +f 3382/2990/2679 2519/2941/2632 3121/2939/2630 +f 3195/2992/2681 3192/2943/2634 2519/2941/2632 +f 3195/2992/2681 2908/2993/2682 3383/2994/2683 +f 3383/2994/2683 2532/2995/2684 3262/2996/2685 +f 3383/2994/2683 2520/2945/2636 3192/2943/2634 +f 3262/2996/2685 3260/2947/2638 2520/2945/2636 +f 3262/2996/2685 2977/2997/2686 3384/2998/2687 +f 3384/2998/2687 2533/2999/2688 2757/3000/2689 +f 3384/2998/2687 2521/2949/2640 3260/2947/2638 +f 2757/3000/2689 2754/2951/2642 2521/2949/2640 +f 2757/3000/2689 3046/3001/2690 3385/3002/2691 +f 3385/3002/2691 2534/3003/2692 2838/3004/2693 +f 3385/3002/2691 2522/2953/2644 2754/2951/2642 +f 2838/3004/2693 2835/2955/2646 2522/2953/2644 +f 2838/3004/2693 3125/3005/2694 3386/3006/2695 +f 3386/3006/2695 2535/3007/2696 2909/3008/2697 +f 3386/3006/2695 2523/2957/2648 2835/2955/2646 +f 2523/2960/2648 3387/3009/2698 2906/2962/2651 +f 2535/3010/2696 3387/3009/2698 2909/3011/2697 +f 3196/3012/2699 2978/3013/2700 3387/3009/2698 +f 2906/2962/2651 2978/3013/2700 2524/2965/2654 +f 2524/2965/2654 3388/3014/2701 2975/2966/2655 +f 2536/3015/2702 3388/3014/2701 2978/3013/2700 +f 3263/3016/2703 3047/3017/2704 3388/3014/2701 +f 2975/2966/2655 3047/3017/2704 2525/2969/2658 +f 2525/2969/2658 3389/3018/2705 3043/2970/2659 +f 2537/3019/2706 3389/3018/2705 3047/3017/2704 +f 2758/3020/2707 3126/3021/2708 3389/3018/2705 +f 3043/2970/2659 3126/3021/2708 2526/2973/2662 +f 2526/2973/2662 3390/3022/2709 3123/2974/2663 +f 2538/3023/2710 3390/3022/2709 3126/3021/2708 +f 2839/3024/2711 3197/3025/2712 3390/3022/2709 +f 3123/2974/2663 3197/3025/2712 2527/2977/2666 +f 2527/2977/2666 3391/3026/2713 3194/2978/2667 +f 2539/3027/2714 3391/3026/2713 3197/3025/2712 +f 2910/3028/2715 3264/3029/2716 3391/3026/2713 +f 3194/2978/2667 3264/3029/2716 2528/2981/2670 +f 2528/2981/2670 3392/3030/2717 3044/2982/2671 +f 2540/3031/2718 3392/3030/2717 3264/3029/2716 +f 2760/3032/2719 3045/2983/2672 3392/3030/2717 +f 3044/2982/2671 3045/2983/2672 2517/2984/2673 +f 2761/3033/2720 2756/2985/2674 2529/3034/2721 +f 2761/3033/2720 3048/3035/2722 3393/3036/2723 +f 3393/3036/2723 2542/3037/2724 2840/3038/2725 +f 3393/3036/2723 2530/2987/2676 2756/2985/2674 +f 2840/3038/2725 2837/2989/2678 2530/2987/2676 +f 2840/3038/2725 3128/3039/2726 3394/3040/2727 +f 3394/3040/2727 2543/3041/2728 2911/3042/2729 +f 3394/3040/2727 2531/2991/2680 2837/2989/2678 +f 2911/3042/2729 2908/2993/2682 2531/2991/2680 +f 2911/3042/2729 3198/3043/2730 3395/3044/2731 +f 3395/3044/2731 2544/3045/2732 2979/3046/2733 +f 3395/3044/2731 2532/2995/2684 2908/2993/2682 +f 2979/3046/2733 2977/2997/2686 2532/2995/2684 +f 2979/3046/2733 3265/3047/2734 3396/3048/2735 +f 3396/3048/2735 2545/3049/2736 3049/3050/2737 +f 3396/3048/2735 2533/2999/2688 2977/2997/2686 +f 3049/3050/2737 3046/3001/2690 2533/2999/2688 +f 3049/3050/2737 2762/3051/2738 3397/3052/2739 +f 3397/3052/2739 2546/3053/2740 3129/3054/2741 +f 3397/3052/2739 2534/3003/2692 3046/3001/2690 +f 3129/3054/2741 3125/3005/2694 2534/3003/2692 +f 3129/3054/2741 2841/3055/2742 3398/3056/2743 +f 3398/3056/2743 2547/3057/2744 3199/3058/2745 +f 3398/3056/2743 2535/3007/2696 3125/3005/2694 +f 2535/3010/2696 3399/3059/2746 3196/3012/2699 +f 2547/3060/2744 3399/3059/2746 3199/3061/2745 +f 2912/3062/2747 3266/3063/2748 3399/3059/2746 +f 3196/3012/2699 3266/3063/2748 2536/3015/2702 +f 2536/3015/2702 3400/3064/2749 3263/3016/2703 +f 2548/3065/2750 3400/3064/2749 3266/3063/2748 +f 2980/3066/2751 2763/3067/2752 3400/3064/2749 +f 3263/3016/2703 2763/3067/2752 2537/3019/2706 +f 2537/3019/2706 3401/3068/2753 2758/3020/2707 +f 2549/3069/2754 3401/3068/2753 2763/3067/2752 +f 3050/3070/2755 2842/3071/2756 3401/3068/2753 +f 2758/3020/2707 2842/3071/2756 2538/3023/2710 +f 2538/3023/2710 3402/3072/2757 2839/3024/2711 +f 2550/3073/2758 3402/3072/2757 2842/3071/2756 +f 3130/3074/2759 2913/3075/2760 3402/3072/2757 +f 2839/3024/2711 2913/3075/2760 2539/3027/2714 +f 2539/3027/2714 3403/3076/2761 2910/3028/2715 +f 2551/3077/2762 3403/3076/2761 2913/3075/2760 +f 3200/3078/2763 2981/3079/2764 3403/3076/2761 +f 2910/3028/2715 2981/3079/2764 2540/3031/2718 +f 2540/3031/2718 3404/3080/2765 2760/3032/2719 +f 2552/3081/2766 3404/3080/2765 2981/3079/2764 +f 3051/3082/2767 2761/3033/2720 3404/3080/2765 +f 2760/3032/2719 2761/3033/2720 2529/3034/2721 +f 3052/3083/2768 3048/3035/2722 2541/3084/2769 +f 3052/3083/2768 2764/3085/2770 3405/3086/2771 +f 3405/3086/2771 2554/3087/2772 3131/3088/2773 +f 3405/3086/2771 2542/3037/2724 3048/3035/2722 +f 3131/3088/2773 3128/3039/2726 2542/3037/2724 +f 3131/3088/2773 2843/3089/2774 3406/3090/2775 +f 3406/3090/2775 2555/3091/2776 3201/3092/2777 +f 3406/3090/2775 2543/3041/2728 3128/3039/2726 +f 3201/3092/2777 3198/3043/2730 2543/3041/2728 +f 3201/3092/2777 2914/3093/2778 3407/3094/2779 +f 3407/3094/2779 2556/3095/2780 3267/3096/2781 +f 3407/3094/2779 2544/3045/2732 3198/3043/2730 +f 3267/3096/2781 3265/3047/2734 2544/3045/2732 +f 3267/3096/2781 2982/3097/2782 3408/3098/2783 +f 3408/3098/2783 2557/3099/2784 2765/3100/2785 +f 3408/3098/2783 2545/3049/2736 3265/3047/2734 +f 2765/3100/2785 2762/3051/2738 2545/3049/2736 +f 2765/3100/2785 3053/3101/2786 3409/3102/2787 +f 3409/3102/2787 2558/3103/2788 2844/3104/2789 +f 3409/3102/2787 2546/3053/2740 2762/3051/2738 +f 2844/3104/2789 2841/3055/2742 2546/3053/2740 +f 2844/3104/2789 3132/3105/2790 3410/3106/2791 +f 3410/3106/2791 2559/3107/2792 2915/3108/2793 +f 3410/3106/2791 2547/3057/2744 2841/3055/2742 +f 2547/3060/2744 3411/3109/2794 2912/3062/2747 +f 2559/3110/2792 3411/3109/2794 2915/3111/2793 +f 3202/3112/2795 2983/3113/2796 3411/3109/2794 +f 2912/3062/2747 2983/3113/2796 2548/3065/2750 +f 2548/3065/2750 3412/3114/2797 2980/3066/2751 +f 2560/3115/2798 3412/3114/2797 2983/3113/2796 +f 3268/3116/2799 3054/3117/2800 3412/3114/2797 +f 2980/3066/2751 3054/3117/2800 2549/3069/2754 +f 2549/3069/2754 3413/3118/2801 3050/3070/2755 +f 2561/3119/2802 3413/3118/2801 3054/3117/2800 +f 2766/3120/2803 3133/3121/2804 3413/3118/2801 +f 3050/3070/2755 3133/3121/2804 2550/3073/2758 +f 2550/3073/2758 3414/3122/2805 3130/3074/2759 +f 2562/3123/2806 3414/3122/2805 3133/3121/2804 +f 2845/3124/2807 3203/3125/2808 3414/3122/2805 +f 3130/3074/2759 3203/3125/2808 2551/3077/2762 +f 2551/3077/2762 3415/3126/2809 3200/3078/2763 +f 2563/3127/2810 3415/3126/2809 3203/3125/2808 +f 2916/3128/2811 3269/3129/2812 3415/3126/2809 +f 3200/3078/2763 3269/3129/2812 2552/3081/2766 +f 2552/3081/2766 3416/3130/2813 3051/3082/2767 +f 2564/3131/2814 3416/3130/2813 3269/3129/2812 +f 2767/3132/2815 3052/3083/2768 3416/3130/2813 +f 3051/3082/2767 3052/3083/2768 2541/3084/2769 +f 2768/3133/2816 2764/3085/2770 2553/3134/2817 +f 2768/3133/2816 3055/3135/2818 3417/3136/2819 +f 3417/3136/2819 2566/3137/2820 2846/3138/2821 +f 3417/3136/2819 2554/3087/2772 2764/3085/2770 +f 2846/3138/2821 2843/3089/2774 2554/3087/2772 +f 2846/3138/2821 3134/3139/2822 3418/3140/2823 +f 3418/3140/2823 2567/3141/2824 2918/3142/2825 +f 3418/3140/2823 2555/3091/2776 2843/3089/2774 +f 2918/3142/2825 2914/3093/2778 2555/3091/2776 +f 2918/3142/2825 3204/3143/2826 3419/3144/2827 +f 3419/3144/2827 2568/3145/2828 2984/3146/2829 +f 3419/3144/2827 2556/3095/2780 2914/3093/2778 +f 2984/3146/2829 2982/3097/2782 2556/3095/2780 +f 2984/3146/2829 3271/3147/2830 3420/3148/2831 +f 3420/3148/2831 2569/3149/2832 3056/3150/2833 +f 3420/3148/2831 2557/3099/2784 2982/3097/2782 +f 3056/3150/2833 3053/3101/2786 2557/3099/2784 +f 3056/3150/2833 2769/3151/2834 3421/3152/2835 +f 3421/3152/2835 2570/3153/2836 3135/3154/2837 +f 3421/3152/2835 2558/3103/2788 3053/3101/2786 +f 3135/3154/2837 3132/3105/2790 2558/3103/2788 +f 3135/3154/2837 2847/3155/2838 3422/3156/2839 +f 3422/3156/2839 2571/3157/2840 3205/3158/2841 +f 3422/3156/2839 2559/3107/2792 3132/3105/2790 +f 2559/3110/2792 3423/3159/2842 3202/3112/2795 +f 2571/3160/2840 3423/3159/2842 3205/3161/2841 +f 2919/3162/2843 3272/3163/2844 3423/3159/2842 +f 3202/3112/2795 3272/3163/2844 2560/3115/2798 +f 2560/3115/2798 3424/3164/2845 3268/3116/2799 +f 2572/3165/2846 3424/3164/2845 3272/3163/2844 +f 2985/3166/2847 2770/3167/2848 3424/3164/2845 +f 3268/3116/2799 2770/3167/2848 2561/3119/2802 +f 2561/3119/2802 3425/3168/2849 2766/3120/2803 +f 2573/3169/2850 3425/3168/2849 2770/3167/2848 +f 3057/3170/2851 2848/3171/2852 3425/3168/2849 +f 2766/3120/2803 2848/3171/2852 2562/3123/2806 +f 2562/3123/2806 3426/3172/2853 2845/3124/2807 +f 2574/3173/2854 3426/3172/2853 2848/3171/2852 +f 3136/3174/2855 2920/3175/2856 3426/3172/2853 +f 2845/3124/2807 2920/3175/2856 2563/3127/2810 +f 2563/3127/2810 3427/3176/2857 2916/3128/2811 +f 2575/3177/2858 3427/3176/2857 2920/3175/2856 +f 3206/3178/2859 2986/3179/2860 3427/3176/2857 +f 2916/3128/2811 2986/3179/2860 2564/3131/2814 +f 2564/3131/2814 3428/3180/2861 2767/3132/2815 +f 2576/3181/2862 3428/3180/2861 2986/3179/2860 +f 3058/3182/2863 2768/3133/2816 3428/3180/2861 +f 2767/3132/2815 2768/3133/2816 2553/3134/2817 +f 3059/3183/2864 3055/3135/2818 2565/3184/2865 +f 3059/3183/2864 2771/3185/2866 3429/3186/2867 +f 3429/3186/2867 2578/3187/2868 3137/3188/2869 +f 3429/3186/2867 2566/3137/2820 3055/3135/2818 +f 3137/3188/2869 3134/3139/2822 2566/3137/2820 +f 3137/3188/2869 2849/3189/2870 3430/3190/2871 +f 3430/3190/2871 2579/3191/2872 3207/3192/2873 +f 3430/3190/2871 2567/3141/2824 3134/3139/2822 +f 3207/3192/2873 3204/3143/2826 2567/3141/2824 +f 3207/3192/2873 2921/3193/2874 3431/3194/2875 +f 3431/3194/2875 2580/3195/2876 3273/3196/2877 +f 3431/3194/2875 2568/3145/2828 3204/3143/2826 +f 3273/3196/2877 3271/3147/2830 2568/3145/2828 +f 3273/3196/2877 2987/3197/2878 3432/3198/2879 +f 3432/3198/2879 2581/3199/2880 2772/3200/2881 +f 3432/3198/2879 2569/3149/2832 3271/3147/2830 +f 2772/3200/2881 2769/3151/2834 2569/3149/2832 +f 2772/3200/2881 3060/3201/2882 3433/3202/2883 +f 3433/3202/2883 2582/3203/2884 2850/3204/2885 +f 3433/3202/2883 2570/3153/2836 2769/3151/2834 +f 2850/3204/2885 2847/3155/2838 2570/3153/2836 +f 2850/3204/2885 3138/3205/2886 3434/3206/2887 +f 3434/3206/2887 2583/3207/2315 2922/3208/2888 +f 3434/3206/2887 2571/3157/2840 2847/3155/2838 +f 2571/3160/2840 3435/3209/2889 2919/3162/2843 +f 2583/3210/2315 3435/3209/2889 2922/3211/2888 +f 3208/3212/2890 2988/3213/2891 3435/3209/2889 +f 2919/3162/2843 2988/3213/2891 2572/3165/2846 +f 2572/3165/2846 3436/3214/2892 2985/3166/2847 +f 2584/3215/2893 3436/3214/2892 2988/3213/2891 +f 3274/3216/2894 3061/3217/2895 3436/3214/2892 +f 2985/3166/2847 3061/3217/2895 2573/3169/2850 +f 2573/3169/2850 3437/3218/2896 3057/3170/2851 +f 2585/3219/2897 3437/3218/2896 3061/3217/2895 +f 2773/3220/2898 3139/3221/2899 3437/3218/2896 +f 3057/3170/2851 3139/3221/2899 2574/3173/2854 +f 2574/3173/2854 3438/3222/2900 3136/3174/2855 +f 2586/3223/2901 3438/3222/2900 3139/3221/2899 +f 2851/3224/2902 3209/3225/2903 3438/3222/2900 +f 3136/3174/2855 3209/3225/2903 2575/3177/2858 +f 2575/3177/2858 3439/3226/2904 3206/3178/2859 +f 2587/3227/2905 3439/3226/2904 3209/3225/2903 +f 2923/3228/2906 3275/3229/2907 3439/3226/2904 +f 3206/3178/2859 3275/3229/2907 2576/3181/2862 +f 2576/3181/2862 3440/3230/2908 3058/3182/2863 +f 2588/3231/2909 3440/3230/2908 3275/3229/2907 +f 2774/3232/2910 3059/3183/2864 3440/3230/2908 +f 3058/3182/2863 3059/3183/2864 2565/3184/2865 +f 2775/3233/2349 2771/3234/2866 2577/3235/2350 +f 2775/3233/2349 3062/3236/2911 3441/3237/2912 +f 3441/3237/2912 2590/3238/2913 2852/3239/2914 +f 3441/3237/2912 2578/3240/2868 2771/3234/2866 +f 2852/3239/2914 2849/3241/2870 2578/3240/2868 +f 2852/3239/2914 3140/3242/2915 3442/3243/2916 +f 3442/3243/2916 2591/3244/2917 2924/3245/2918 +f 3442/3243/2916 2579/3246/2872 2849/3241/2870 +f 2924/3245/2918 2921/3247/2874 2579/3246/2872 +f 2924/3245/2918 3210/3248/2919 3443/3249/2920 +f 3443/3249/2920 2592/3250/2921 2989/3251/2922 +f 3443/3249/2920 2580/3252/2876 2921/3247/2874 +f 2989/3251/2922 2987/3253/2878 2580/3252/2876 +f 2989/3251/2922 3276/3254/2923 3444/3255/2924 +f 3444/3255/2924 2593/3256/2925 3064/3257/2926 +f 3444/3255/2924 2581/3258/2880 2987/3253/2878 +f 3064/3257/2926 3060/3259/2882 2581/3258/2880 +f 3064/3257/2926 2776/3260/2927 3445/3261/2928 +f 3445/3261/2928 2594/3262/2929 3141/3263/2930 +f 3445/3261/2928 2582/3264/2884 3060/3259/2882 +f 3141/3263/2930 3138/3265/2886 2582/3264/2884 +f 3141/3263/2930 2854/3266/2931 3446/3267/2932 +f 3446/3267/2932 2595/3268/2385 3211/3269/2313 +f 3446/3267/2932 2583/3270/2315 3138/3265/2886 +f 2583/3271/2315 3447/3272/2933 3208/3273/2890 +f 2595/3274/2385 3447/3272/2933 3211/3275/2313 +f 2925/3276/2934 3277/3277/2935 3447/3272/2933 +f 3208/3273/2890 3277/3277/2935 2584/3278/2893 +f 2584/3278/2893 3448/3279/2936 3274/3280/2894 +f 2596/3281/2937 3448/3279/2936 3277/3277/2935 +f 2990/3282/2938 2777/3283/2939 3448/3279/2936 +f 3274/3280/2894 2777/3283/2939 2585/3284/2897 +f 2585/3284/2897 3449/3285/2940 2773/3286/2898 +f 2597/3287/2941 3449/3285/2940 2777/3283/2939 +f 3065/3288/2942 2855/3289/2943 3449/3285/2940 +f 2773/3286/2898 2855/3289/2943 2586/3290/2901 +f 2586/3290/2901 3450/3291/2944 2851/3292/2902 +f 2598/3293/2945 3450/3291/2944 2855/3289/2943 +f 3142/3294/2946 2926/3295/2947 3450/3291/2944 +f 2851/3292/2902 2926/3295/2947 2587/3296/2905 +f 2587/3296/2905 3451/3297/2948 2923/3298/2906 +f 2599/3299/2949 3451/3297/2948 2926/3295/2947 +f 3212/3300/2950 2991/3301/2951 3451/3297/2948 +f 2923/3298/2906 2991/3301/2951 2588/3302/2909 +f 2588/3302/2909 3452/3303/2952 2774/3304/2910 +f 2600/3305/2953 3452/3303/2952 2991/3301/2951 +f 3066/3306/2954 2775/3233/2349 3452/3303/2952 +f 2774/3304/2910 2775/3233/2349 2577/3235/2350 +f 3067/3307/2409 3062/3236/2911 2589/3308/2348 +f 3067/3307/2409 2778/3309/2955 3453/3310/2956 +f 3453/3310/2956 2602/3311/2957 3143/3312/2958 +f 3453/3310/2956 2590/3238/2913 3062/3236/2911 +f 3143/3312/2958 3140/3242/2915 2590/3238/2913 +f 3143/3312/2958 2856/3313/2959 3454/3314/2960 +f 3454/3314/2960 2603/3315/2961 3213/3316/2962 +f 3454/3314/2960 2591/3244/2917 3140/3242/2915 +f 3213/3316/2962 3210/3248/2919 2591/3244/2917 +f 3213/3316/2962 2927/3317/2963 3455/3318/2964 +f 3455/3318/2964 2604/3319/2965 3278/3320/2966 +f 3455/3318/2964 2592/3250/2921 3210/3248/2919 +f 3278/3320/2966 3276/3254/2923 2592/3250/2921 +f 3278/3320/2966 2992/3321/2967 3456/3322/2968 +f 3456/3322/2968 2605/3323/2969 2779/3324/2970 +f 3456/3322/2968 2593/3256/2925 3276/3254/2923 +f 2779/3324/2970 2776/3260/2927 2593/3256/2925 +f 2779/3324/2970 3068/3325/2971 3457/3326/2972 +f 3457/3326/2972 2606/3327/2973 2857/3328/2974 +f 3457/3326/2972 2594/3262/2929 2776/3260/2927 +f 2857/3328/2974 2854/3266/2931 2594/3262/2929 +f 2857/3328/2974 3144/3329/2975 3458/3330/2976 +f 3458/3330/2976 2607/3331/2433 2928/3332/2384 +f 3458/3330/2976 2595/3268/2385 2854/3266/2931 +f 2595/3274/2385 3459/3333/2977 2925/3276/2934 +f 2607/3334/2433 3459/3333/2977 2928/3335/2384 +f 3214/3336/2978 2993/3337/2979 3459/3333/2977 +f 2925/3276/2934 2993/3337/2979 2596/3281/2937 +f 2596/3281/2937 3460/3338/2980 2990/3282/2938 +f 2608/3339/2981 3460/3338/2980 2993/3337/2979 +f 3279/3340/2982 3069/3341/2983 3460/3338/2980 +f 2990/3282/2938 3069/3341/2983 2597/3287/2941 +f 2597/3287/2941 3461/3342/2984 3065/3288/2942 +f 2609/3343/2985 3461/3342/2984 3069/3341/2983 +f 2780/3344/2986 3145/3345/2987 3461/3342/2984 +f 3065/3288/2942 3145/3345/2987 2598/3293/2945 +f 2598/3293/2945 3462/3346/2988 3142/3294/2946 +f 2610/3347/2989 3462/3346/2988 3145/3345/2987 +f 2858/3348/2990 3215/3349/2991 3462/3346/2988 +f 3142/3294/2946 3215/3349/2991 2599/3299/2949 +f 2599/3299/2949 3463/3350/2992 3212/3300/2950 +f 2611/3351/2993 3463/3350/2992 3215/3349/2991 +f 2929/3352/2994 3280/3353/2995 3463/3350/2992 +f 3212/3300/2950 3280/3353/2995 2600/3305/2953 +f 2600/3305/2953 3464/3354/2996 3066/3306/2954 +f 2612/3355/2997 3464/3354/2996 3280/3353/2995 +f 2781/3356/2998 3067/3307/2409 3464/3354/2996 +f 3066/3306/2954 3067/3307/2409 2589/3308/2348 +f 2782/3357/2999 2778/3309/2955 2601/3358/2408 +f 2782/3357/2999 3070/3359/3000 3465/3360/3001 +f 3465/3360/3001 2614/3361/3002 2859/3362/3003 +f 3465/3360/3001 2602/3311/2957 2778/3309/2955 +f 2859/3362/3003 2856/3313/2959 2602/3311/2957 +f 2859/3362/3003 3146/3363/3004 3466/3364/3005 +f 3466/3364/3005 2615/3365/3006 2930/3366/3007 +f 3466/3364/3005 2603/3315/2961 2856/3313/2959 +f 2930/3366/3007 2927/3317/2963 2603/3315/2961 +f 2930/3366/3007 3216/3367/3008 3467/3368/3009 +f 3467/3368/3009 2616/3369/3010 2994/3370/3011 +f 3467/3368/3009 2604/3319/2965 2927/3317/2963 +f 2994/3370/3011 2992/3321/2967 2604/3319/2965 +f 2994/3370/3011 3281/3371/3012 3468/3372/3013 +f 3468/3372/3013 2617/3373/3014 3071/3374/3015 +f 3468/3372/3013 2605/3323/2969 2992/3321/2967 +f 3071/3374/3015 3068/3325/2971 2605/3323/2969 +f 3071/3374/3015 2783/3375/3016 3469/3376/3017 +f 3469/3376/3017 2618/3377/3018 3147/3378/3019 +f 3469/3376/3017 2606/3327/2973 3068/3325/2971 +f 3147/3378/3019 3144/3329/2975 2606/3327/2973 +f 3147/3378/3019 2860/3379/3020 3470/3380/3021 +f 3470/3380/3021 2619/3381/2481 3218/3382/2432 +f 3470/3380/3021 2607/3331/2433 3144/3329/2975 +f 2607/3334/2433 3471/3383/3022 3214/3336/2978 +f 2619/3384/2481 3471/3383/3022 3218/3385/2432 +f 2931/3386/3023 3282/3387/3024 3471/3383/3022 +f 3214/3336/2978 3282/3387/3024 2608/3339/2981 +f 2608/3339/2981 3472/3388/3025 3279/3340/2982 +f 2620/3389/3026 3472/3388/3025 3282/3387/3024 +f 2996/3390/3027 2784/3391/3028 3472/3388/3025 +f 3279/3340/2982 2784/3391/3028 2609/3343/2985 +f 2609/3343/2985 3473/3392/3029 2780/3344/2986 +f 2621/3393/3030 3473/3392/3029 2784/3391/3028 +f 3072/3394/3031 2861/3395/3032 3473/3392/3029 +f 2780/3344/2986 2861/3395/3032 2610/3347/2989 +f 2610/3347/2989 3474/3396/3033 2858/3348/2990 +f 2622/3397/3034 3474/3396/3033 2861/3395/3032 +f 3148/3398/3035 2932/3399/3036 3474/3396/3033 +f 2858/3348/2990 2932/3399/3036 2611/3351/2993 +f 2611/3351/2993 3475/3400/3037 2929/3352/2994 +f 2623/3401/3038 3475/3400/3037 2932/3399/3036 +f 3219/3402/3039 2997/3403/3040 3475/3400/3037 +f 2929/3352/2994 2997/3403/3040 2612/3355/2997 +f 2612/3355/2997 3476/3404/3041 2781/3356/2998 +f 2624/3405/3042 3476/3404/3041 2997/3403/3040 +f 3073/3406/3043 2782/3357/2999 3476/3404/3041 +f 2781/3356/2998 2782/3357/2999 2601/3358/2408 +f 3074/3407/2505 3070/3359/3000 2613/3408/2456 +f 3074/3407/2505 2785/3409/3044 3477/3410/3045 +f 3477/3410/3045 2626/3411/3046 3149/3412/3047 +f 3477/3410/3045 2614/3361/3002 3070/3359/3000 +f 3149/3412/3047 3146/3363/3004 2614/3361/3002 +f 3149/3412/3047 2862/3413/3048 3478/3414/3049 +f 3478/3414/3049 2627/3415/3050 3220/3416/3051 +f 3478/3414/3049 2615/3365/3006 3146/3363/3004 +f 3220/3416/3051 3216/3367/3008 2615/3365/3006 +f 3220/3416/3051 2933/3417/3052 3479/3418/3053 +f 3479/3418/3053 2628/3419/3054 3283/3420/3055 +f 3479/3418/3053 2616/3369/3010 3216/3367/3008 +f 3283/3420/3055 3281/3371/3012 2616/3369/3010 +f 3283/3420/3055 2998/3421/3056 3480/3422/3057 +f 3480/3422/3057 2629/3423/3058 2786/3424/3059 +f 3480/3422/3057 2617/3373/3014 3281/3371/3012 +f 2786/3424/3059 2783/3375/3016 2617/3373/3014 +f 2786/3424/3059 3075/3425/3060 3481/3426/3061 +f 3481/3426/3061 2630/3427/3062 2863/3428/3063 +f 3481/3426/3061 2618/3377/3018 2783/3375/3016 +f 2863/3428/3063 2860/3379/3020 2618/3377/3018 +f 2863/3428/3063 3150/3429/3064 3482/3430/3065 +f 3482/3430/3065 2631/3431/2529 2934/3432/2480 +f 3482/3430/3065 2619/3381/2481 2860/3379/3020 +f 2619/3384/2481 3483/3433/3066 2931/3386/3023 +f 2631/3434/2529 3483/3433/3066 2934/3435/2480 +f 3221/3436/3067 2999/3437/3068 3483/3433/3066 +f 2931/3386/3023 2999/3437/3068 2620/3389/3026 +f 2620/3389/3026 3484/3438/3069 2996/3390/3027 +f 2632/3439/3070 3484/3438/3069 2999/3437/3068 +f 3284/3440/3071 3076/3441/3072 3484/3438/3069 +f 2996/3390/3027 3076/3441/3072 2621/3393/3030 +f 2621/3393/3030 3485/3442/3073 3072/3394/3031 +f 2633/3443/3074 3485/3442/3073 3076/3441/3072 +f 2787/3444/3075 3151/3445/3076 3485/3442/3073 +f 3072/3394/3031 3151/3445/3076 2622/3397/3034 +f 2622/3397/3034 3486/3446/3077 3148/3398/3035 +f 2634/3447/3078 3486/3446/3077 3151/3445/3076 +f 2864/3448/3079 3222/3449/3080 3486/3446/3077 +f 3148/3398/3035 3222/3449/3080 2623/3401/3038 +f 2623/3401/3038 3487/3450/3081 3219/3402/3039 +f 2635/3451/3082 3487/3450/3081 3222/3449/3080 +f 2935/3452/3083 3285/3453/3084 3487/3450/3081 +f 3219/3402/3039 3285/3453/3084 2624/3405/3042 +f 2624/3405/3042 3488/3454/3085 3073/3406/3043 +f 2636/3455/3086 3488/3454/3085 3285/3453/3084 +f 2788/3456/3087 3074/3407/2505 3488/3454/3085 +f 3073/3406/3043 3074/3407/2505 2613/3408/2456 +f 2789/3457/2553 2785/3409/3044 2625/3458/2504 +f 2789/3457/2553 3077/3459/3088 3489/3460/3089 +f 3489/3460/3089 2638/3461/3090 2865/3462/3091 +f 3489/3460/3089 2626/3411/3046 2785/3409/3044 +f 2865/3462/3091 2862/3413/3048 2626/3411/3046 +f 2865/3462/3091 3152/3463/3092 3490/3464/3093 +f 3490/3464/3093 2639/3465/3094 2936/3466/3095 +f 3490/3464/3093 2627/3415/3050 2862/3413/3048 +f 2936/3466/3095 2933/3417/3052 2627/3415/3050 +f 2936/3466/3095 3223/3467/3096 3491/3468/3097 +f 3491/3468/3097 2640/3469/3098 3000/3470/3099 +f 3491/3468/3097 2628/3419/3054 2933/3417/3052 +f 3000/3470/3099 2998/3421/3056 2628/3419/3054 +f 3000/3470/3099 3286/3471/3100 3492/3472/3101 +f 3492/3472/3101 2641/3473/3102 3078/3474/3103 +f 3492/3472/3101 2629/3423/3058 2998/3421/3056 +f 3078/3474/3103 3075/3425/3060 2629/3423/3058 +f 3078/3474/3103 2790/3475/3104 3493/3476/3105 +f 3493/3476/3105 2642/3477/3106 3153/3478/3107 +f 3493/3476/3105 2630/3427/3062 3075/3425/3060 +f 3153/3478/3107 3150/3429/3064 2630/3427/3062 +f 3153/3478/3107 2866/3479/3108 3494/3480/3109 +f 3494/3480/3109 2643/3481/2577 3224/3482/2528 +f 3494/3480/3109 2631/3431/2529 3150/3429/3064 +f 2631/3434/2529 3495/3483/3110 3221/3436/3067 +f 2643/3484/2577 3495/3483/3110 3224/3485/2528 +f 2937/3486/3111 3287/3487/3112 3495/3483/3110 +f 3221/3436/3067 3287/3487/3112 2632/3439/3070 +f 2632/3439/3070 3496/3488/3113 3284/3440/3071 +f 2644/3489/3114 3496/3488/3113 3287/3487/3112 +f 3001/3490/3115 2792/3491/3116 3496/3488/3113 +f 3284/3440/3071 2792/3491/3116 2633/3443/3074 +f 2633/3443/3074 3497/3492/3117 2787/3444/3075 +f 2645/3493/3118 3497/3492/3117 2792/3491/3116 +f 3079/3494/3119 2867/3495/3120 3497/3492/3117 +f 2787/3444/3075 2867/3495/3120 2634/3447/3078 +f 2634/3447/3078 3498/3496/3121 2864/3448/3079 +f 2646/3497/3122 3498/3496/3121 2867/3495/3120 +f 3155/3498/3123 2938/3499/3124 3498/3496/3121 +f 2864/3448/3079 2938/3499/3124 2635/3451/3082 +f 2635/3451/3082 3499/3500/3125 2935/3452/3083 +f 2647/3501/3126 3499/3500/3125 2938/3499/3124 +f 3225/3502/3127 3002/3503/3128 3499/3500/3125 +f 2935/3452/3083 3002/3503/3128 2636/3455/3086 +f 2636/3455/3086 3500/3504/3129 2788/3456/3087 +f 2648/3505/3130 3500/3504/3129 3002/3503/3128 +f 3080/3506/3131 2789/3457/2553 3500/3504/3129 +f 2788/3456/3087 2789/3457/2553 2625/3458/2504 +f 3081/3507/2601 3077/3459/3088 2637/3508/2552 +f 3081/3507/2601 2793/3509/3132 3501/3510/3133 +f 3501/3510/3133 2650/3511/3134 3156/3512/3135 +f 3501/3510/3133 2638/3461/3090 3077/3459/3088 +f 3156/3512/3135 3152/3463/3092 2638/3461/3090 +f 3156/3512/3135 2868/3513/3136 3502/3514/3137 +f 3502/3514/3137 2651/3515/3138 3226/3516/3139 +f 3502/3514/3137 2639/3465/3094 3152/3463/3092 +f 3226/3516/3139 3223/3467/3096 2639/3465/3094 +f 3226/3516/3139 2939/3517/3140 3503/3518/3141 +f 3503/3518/3141 2652/3519/3142 3288/3520/3143 +f 3503/3518/3141 2640/3469/3098 3223/3467/3096 +f 3288/3520/3143 3286/3471/3100 2640/3469/3098 +f 3288/3520/3143 3003/3521/3144 3504/3522/3145 +f 3504/3522/3145 2653/3523/3146 2794/3524/3147 +f 3504/3522/3145 2641/3473/3102 3286/3471/3100 +f 2794/3524/3147 2790/3475/3104 2641/3473/3102 +f 2794/3524/3147 3082/3525/3148 3505/3526/3149 +f 3505/3526/3149 2654/3527/3150 2869/3528/3151 +f 3505/3526/3149 2642/3477/3106 2790/3475/3104 +f 2869/3528/3151 2866/3479/3108 2642/3477/3106 +f 2869/3528/3151 3157/3529/3152 3506/3530/3153 +f 3506/3530/3153 2655/3531/2625 2940/3532/2576 +f 3506/3530/3153 2643/3481/2577 2866/3479/3108 +f 2643/3484/2577 3507/3533/3154 2937/3486/3111 +f 2655/3534/2625 3507/3533/3154 2940/3535/2576 +f 3227/3536/3155 3004/3537/3156 3507/3533/3154 +f 2937/3486/3111 3004/3537/3156 2644/3489/3114 +f 2644/3489/3114 3508/3538/3157 3001/3490/3115 +f 2656/3539/3158 3508/3538/3157 3004/3537/3156 +f 3289/3540/3159 3083/3541/3160 3508/3538/3157 +f 3001/3490/3115 3083/3541/3160 2645/3493/3118 +f 2645/3493/3118 3509/3542/3161 3079/3494/3119 +f 2657/3543/3162 3509/3542/3161 3083/3541/3160 +f 2795/3544/3163 3158/3545/3164 3509/3542/3161 +f 3079/3494/3119 3158/3545/3164 2646/3497/3122 +f 2646/3497/3122 3510/3546/3165 3155/3498/3123 +f 2658/3547/3166 3510/3546/3165 3158/3545/3164 +f 2870/3548/3167 3228/3549/3168 3510/3546/3165 +f 3155/3498/3123 3228/3549/3168 2647/3501/3126 +f 2647/3501/3126 3511/3550/3169 3225/3502/3127 +f 2659/3551/3170 3511/3550/3169 3228/3549/3168 +f 2941/3552/3171 3290/3553/3172 3511/3550/3169 +f 3225/3502/3127 3290/3553/3172 2648/3505/3130 +f 2648/3505/3130 3512/3554/3173 3080/3506/3131 +f 2660/3555/3174 3512/3554/3173 3290/3553/3172 +f 2796/3556/3175 3081/3507/2601 3512/3554/3173 +f 3080/3506/3131 3081/3507/2601 2637/3508/2552 +f 2797/3557/2649 2793/3509/3132 2649/3558/2600 +f 2797/3557/2649 3084/3559/3176 3513/3560/3177 +f 3513/3560/3177 2662/3561/3178 2871/3562/3179 +f 3513/3560/3177 2650/3511/3134 2793/3509/3132 +f 2871/3562/3179 2868/3513/3136 2650/3511/3134 +f 2871/3562/3179 3159/3563/3180 3514/3564/3181 +f 3514/3564/3181 2663/3565/3182 2942/3566/3183 +f 3514/3564/3181 2651/3515/3138 2868/3513/3136 +f 2942/3566/3183 2939/3517/3140 2651/3515/3138 +f 2942/3566/3183 3229/3567/3184 3515/3568/3185 +f 3515/3568/3185 2664/3569/3186 3005/3570/3187 +f 3515/3568/3185 2652/3519/3142 2939/3517/3140 +f 3005/3570/3187 3003/3521/3144 2652/3519/3142 +f 3005/3570/3187 3291/3571/3188 3516/3572/3189 +f 3516/3572/3189 2665/3573/3190 3085/3574/3191 +f 3516/3572/3189 2653/3523/3146 3003/3521/3144 +f 3085/3574/3191 3082/3525/3148 2653/3523/3146 +f 3085/3574/3191 2798/3575/3192 3517/3576/3193 +f 3517/3576/3193 2666/3577/3194 3160/3578/3195 +f 3517/3576/3193 2654/3527/3150 3082/3525/3148 +f 3160/3578/3195 3157/3529/3152 2654/3527/3150 +f 3160/3578/3195 2872/3579/3196 3518/3580/3197 +f 3518/3580/3197 2667/3581/2673 3230/3582/2624 +f 3518/3580/3197 2655/3531/2625 3157/3529/3152 +f 2655/3534/2625 3519/3583/3198 3227/3536/3155 +f 2667/3584/2673 3519/3583/3198 3230/3585/2624 +f 2943/3586/3199 3292/3587/3200 3519/3583/3198 +f 3227/3536/3155 3292/3587/3200 2656/3539/3158 +f 2656/3539/3158 3520/3588/3201 3289/3540/3159 +f 2668/3589/3202 3520/3588/3201 3292/3587/3200 +f 3006/3590/3203 2799/3591/3204 3520/3588/3201 +f 3289/3540/3159 2799/3591/3204 2657/3543/3162 +f 2657/3543/3162 3521/3592/3205 2795/3544/3163 +f 2669/3593/3206 3521/3592/3205 2799/3591/3204 +f 3086/3594/3207 2873/3595/3208 3521/3592/3205 +f 2795/3544/3163 2873/3595/3208 2658/3547/3166 +f 2658/3547/3166 3522/3596/3209 2870/3548/3167 +f 2670/3597/3210 3522/3596/3209 2873/3595/3208 +f 3161/3598/3211 2945/3599/3212 3522/3596/3209 +f 2870/3548/3167 2945/3599/3212 2659/3551/3170 +f 2659/3551/3170 3523/3600/3213 2941/3552/3171 +f 2671/3601/3214 3523/3600/3213 2945/3599/3212 +f 3231/3602/3215 3007/3603/3216 3523/3600/3213 +f 2941/3552/3171 3007/3603/3216 2660/3555/3174 +f 2660/3555/3174 3524/3604/3217 2796/3556/3175 +f 2672/3605/3218 3524/3604/3217 3007/3603/3216 +f 3087/3606/3219 2797/3557/2649 3524/3604/3217 +f 2796/3556/3175 2797/3557/2649 2649/3558/2600 +f 3088/3607/2697 3084/3559/3176 2661/3608/2648 +f 3088/3607/2697 2800/3609/3220 3525/3610/3221 +f 3525/3610/3221 2674/3611/3222 3162/3612/3223 +f 3525/3610/3221 2662/3561/3178 3084/3559/3176 +f 3162/3612/3223 3159/3563/3180 2662/3561/3178 +f 3162/3612/3223 2874/3613/3224 3526/3614/3225 +f 3526/3614/3225 2675/3615/3226 3232/3616/3227 +f 3526/3614/3225 2663/3565/3182 3159/3563/3180 +f 3232/3616/3227 3229/3567/3184 2663/3565/3182 +f 3232/3616/3227 2946/3617/3228 3527/3618/3229 +f 3527/3618/3229 2676/3619/3230 3294/3620/3231 +f 3527/3618/3229 2664/3569/3186 3229/3567/3184 +f 3294/3620/3231 3291/3571/3188 2664/3569/3186 +f 3294/3620/3231 3008/3621/3232 3528/3622/3233 +f 3528/3622/3233 2677/3623/3234 2801/3624/3235 +f 3528/3622/3233 2665/3573/3190 3291/3571/3188 +f 2801/3624/3235 2798/3575/3192 2665/3573/3190 +f 2801/3624/3235 3089/3625/3236 3529/3626/3237 +f 3529/3626/3237 2678/3627/3238 2875/3628/3239 +f 3529/3626/3237 2666/3577/3194 2798/3575/3192 +f 2875/3628/3239 2872/3579/3196 2666/3577/3194 +f 2875/3628/3239 3163/3629/3240 3530/3630/3241 +f 3530/3630/3241 2679/3631/2721 2947/3632/2672 +f 3530/3630/3241 2667/3581/2673 2872/3579/3196 +f 2667/3584/2673 3531/3633/3242 2943/3586/3199 +f 2679/3634/2721 3531/3633/3242 2947/3635/2672 +f 3233/3636/3243 3009/3637/3244 3531/3633/3242 +f 2943/3586/3199 3009/3637/3244 2668/3589/3202 +f 2668/3589/3202 3532/3638/3245 3006/3590/3203 +f 2680/3639/3246 3532/3638/3245 3009/3637/3244 +f 3295/3640/3247 3090/3641/3248 3532/3638/3245 +f 3006/3590/3203 3090/3641/3248 2669/3593/3206 +f 2669/3593/3206 3533/3642/3249 3086/3594/3207 +f 2681/3643/3250 3533/3642/3249 3090/3641/3248 +f 2802/3644/3251 3164/3645/3252 3533/3642/3249 +f 3086/3594/3207 3164/3645/3252 2670/3597/3210 +f 2670/3597/3210 3534/3646/3253 3161/3598/3211 +f 2682/3647/3254 3534/3646/3253 3164/3645/3252 +f 2876/3648/3255 3234/3649/3256 3534/3646/3253 +f 3161/3598/3211 3234/3649/3256 2671/3601/3214 +f 2671/3601/3214 3535/3650/3257 3231/3602/3215 +f 2683/3651/3258 3535/3650/3257 3234/3649/3256 +f 2948/3652/3259 3296/3653/3260 3535/3650/3257 +f 3231/3602/3215 3296/3653/3260 2672/3605/3218 +f 2672/3605/3218 3536/3654/3261 3087/3606/3219 +f 2684/3655/3262 3536/3654/3261 3296/3653/3260 +f 2803/3656/3263 3088/3607/2697 3536/3654/3261 +f 3087/3606/3219 3088/3607/2697 2661/3608/2648 +f 2804/3657/2745 2800/3609/3220 2673/3658/2696 +f 2804/3657/2745 3091/3659/3264 3537/3660/3265 +f 3537/3660/3265 2686/3661/3266 2877/3662/3267 +f 3537/3660/3265 2674/3611/3222 2800/3609/3220 +f 2877/3662/3267 2874/3613/3224 2674/3611/3222 +f 2877/3662/3267 3165/3663/3268 3538/3664/3269 +f 3538/3664/3269 2687/3665/3270 2949/3666/3271 +f 3538/3664/3269 2675/3615/3226 2874/3613/3224 +f 2949/3666/3271 2946/3617/3228 2675/3615/3226 +f 2949/3666/3271 3235/3667/3272 3539/3668/3273 +f 3539/3668/3273 2688/3669/3274 3010/3670/3275 +f 3539/3668/3273 2676/3619/3230 2946/3617/3228 +f 3010/3670/3275 3008/3621/3232 2676/3619/3230 +f 3010/3670/3275 3166/3671/3276 3540/3672/3277 +f 3540/3672/3277 2689/3673/3278 3092/3674/3279 +f 3540/3672/3277 2677/3623/3234 3008/3621/3232 +f 3092/3674/3279 3089/3625/3236 2677/3623/3234 +f 3092/3674/3279 2805/3675/3280 3541/3676/3281 +f 3541/3676/3281 2690/3677/3282 3011/3678/3283 +f 3541/3676/3281 2678/3627/3238 3089/3625/3236 +f 3011/3678/3283 3163/3629/3240 2678/3627/3238 +f 3011/3678/3283 2722/3679/3284 3542/3680/3285 +f 3542/3680/3285 2691/3681/2769 3236/3682/2720 +f 3542/3680/3285 2679/3631/2721 3163/3629/3240 +f 2679/3634/2721 3543/3683/3286 3233/3636/3243 +f 2691/3684/2769 3543/3683/3286 3236/3685/2720 +f 2950/3686/3287 3167/3687/3288 3543/3683/3286 +f 3233/3636/3243 3167/3687/3288 2680/3639/3246 +f 2680/3639/3246 3544/3688/3289 3295/3640/3247 +f 2692/3689/3290 3544/3688/3289 3167/3687/3288 +f 2879/3690/3291 2807/3691/3292 3544/3688/3289 +f 3295/3640/3247 2807/3691/3292 2681/3643/3250 +f 2681/3643/3250 3545/3692/3293 2802/3644/3251 +f 2693/3693/3294 3545/3692/3293 2807/3691/3292 +f 3093/3694/3295 2723/3695/3296 3545/3692/3293 +f 2802/3644/3251 2723/3695/3296 2682/3647/3254 +f 2682/3647/3254 3546/3696/3297 2876/3648/3255 +f 2694/3697/3298 3546/3696/3297 2723/3695/3296 +f 3013/3698/3299 2952/3699/3300 3546/3696/3297 +f 2876/3648/3255 2952/3699/3300 2683/3651/3258 +f 2683/3651/3258 3547/3700/3301 2948/3652/3259 +f 2695/3701/3302 3547/3700/3301 2952/3699/3300 +f 3237/3702/3303 2880/3703/3304 3547/3700/3301 +f 2948/3652/3259 2880/3703/3304 2684/3655/3262 +f 2684/3655/3262 3548/3704/3305 2803/3656/3263 +f 2696/3705/3306 3548/3704/3305 2880/3703/3304 +f 3095/3706/3307 2804/3657/2745 3548/3704/3305 +f 2803/3656/3263 2804/3657/2745 2673/3658/2696 +f 3096/3707/2793 3091/3659/3264 2685/3708/2744 +f 3096/3707/2793 2808/3709/3308 3549/3710/3309 +f 3549/3710/3309 2698/3711/3310 3014/3712/3311 +f 3549/3710/3309 2686/3661/3266 3091/3659/3264 +f 3014/3712/3311 3165/3663/3268 2686/3661/3266 +f 3014/3712/3311 2725/3713/3312 3550/3714/3313 +f 3550/3714/3313 2699/3715/3314 3239/3716/3315 +f 3550/3714/3313 2687/3665/3270 3165/3663/3268 +f 3239/3716/3315 3235/3667/3272 2687/3665/3270 +f 3239/3716/3315 2953/3717/3316 3551/3718/3317 +f 3551/3718/3317 2700/3719/3318 3169/3720/3319 +f 3551/3718/3317 2688/3669/3274 3235/3667/3272 +f 3169/3720/3319 3166/3671/3276 2688/3669/3274 +f 3169/3720/3319 2882/3721/3320 3552/3722/3321 +f 3552/3722/3321 2701/3723/3322 2810/3724/3323 +f 3552/3722/3321 2689/3673/3278 3166/3671/3276 +f 2810/3724/3323 2805/3675/3280 2689/3673/3278 +f 2810/3724/3323 3097/3725/3324 3553/3726/3325 +f 3553/3726/3325 2702/3727/3326 2728/3728/3327 +f 3553/3726/3325 2690/3677/3282 2805/3675/3280 +f 2728/3728/3327 2722/3679/3284 2690/3677/3282 +f 2728/3728/3327 3016/3729/3328 3554/3730/3329 +f 3554/3730/3329 2703/3731/2817 2954/3732/2768 +f 3554/3730/3329 2691/3681/2769 2722/3679/3284 +f 2691/3684/2769 3555/3733/3330 2950/3686/3287 +f 2703/3734/2817 3555/3733/3330 2954/3735/2768 +f 3240/3736/3331 2884/3737/3332 3555/3733/3330 +f 2950/3686/3287 2884/3737/3332 2692/3689/3290 +f 2692/3689/3290 3556/3738/3333 2879/3690/3291 +f 2704/3739/3334 3556/3738/3333 2884/3737/3332 +f 3171/3740/3335 3099/3741/3336 3556/3738/3333 +f 2879/3690/3291 3099/3741/3336 2693/3693/3294 +f 2693/3693/3294 3557/3742/3337 3093/3694/3295 +f 2705/3743/3338 3557/3742/3337 3099/3741/3336 +f 2812/3744/3339 3018/3745/3340 3557/3742/3337 +f 3093/3694/3295 3018/3745/3340 2694/3697/3298 +f 2694/3697/3298 3558/3746/3341 3013/3698/3299 +f 2706/3747/3342 3558/3746/3341 3018/3745/3340 +f 2730/3748/3343 3242/3749/3344 3558/3746/3341 +f 3013/3698/3299 3242/3749/3344 2695/3701/3302 +f 2695/3701/3302 3559/3750/3345 3237/3702/3303 +f 2707/3751/3346 3559/3750/3345 3242/3749/3344 +f 2956/3752/3347 3173/3753/3348 3559/3750/3345 +f 3237/3702/3303 3173/3753/3348 2696/3705/3306 +f 2696/3705/3306 3560/3754/3349 3095/3706/3307 +f 2708/3755/3350 3560/3754/3349 3173/3753/3348 +f 2814/3756/3351 3096/3707/2793 3560/3754/3349 +f 3095/3706/3307 3096/3707/2793 2685/3708/2744 +f 2815/3757/2841 2808/3709/3308 2697/3758/2792 +f 2815/3757/2841 3101/3759/3352 3561/3760/3353 +f 3561/3760/3353 2710/3761/3354 2732/3762/3355 +f 3561/3760/3353 2698/3711/3310 2808/3709/3308 +f 2732/3762/3355 2725/3713/3312 2698/3711/3310 +f 2732/3762/3355 3020/3763/3356 3562/3764/3357 +f 3562/3764/3357 2711/3765/3358 2958/3766/3359 +f 3562/3764/3357 2699/3715/3314 2725/3713/3312 +f 2958/3766/3359 2953/3717/3316 2699/3715/3314 +f 2958/3766/3359 3244/3767/3360 3563/3768/3361 +f 3563/3768/3361 2712/3769/3362 2887/3770/3363 +f 3563/3768/3361 2700/3719/3318 2953/3717/3316 +f 2887/3770/3363 2882/3721/3320 2700/3719/3318 +f 2887/3770/3363 3175/3771/3364 3564/3772/3365 +f 3564/3772/3365 2713/3773/3366 3103/3774/3367 +f 3564/3772/3365 2701/3723/3322 2882/3721/3320 +f 3103/3774/3367 3097/3725/3324 2701/3723/3322 +f 3103/3774/3367 2817/3775/3368 3565/3776/3369 +f 3565/3776/3369 2714/3777/3370 3023/3778/3371 +f 3565/3776/3369 2702/3727/3326 3097/3725/3324 +f 3023/3778/3371 3016/3729/3328 2702/3727/3326 +f 3023/3778/3371 2734/3779/3372 3566/3780/3373 +f 3566/3780/3373 2715/3781/2865 3245/3782/2816 +f 3566/3780/3373 2703/3731/2817 3016/3729/3328 +f 2703/3734/2817 3567/3783/3374 3240/3736/3331 +f 2715/3784/2865 3567/3783/3374 3245/3785/2816 +f 2960/3786/3375 3177/3787/3376 3567/3783/3374 +f 3240/3736/3331 3177/3787/3376 2704/3739/3334 +f 2704/3739/3334 3568/3788/3377 3171/3740/3335 +f 2716/3789/3378 3568/3788/3377 3177/3787/3376 +f 2889/3790/3379 2819/3791/3380 3568/3788/3377 +f 3171/3740/3335 2819/3791/3380 2705/3743/3338 +f 2705/3743/3338 3569/3792/3381 2812/3744/3339 +f 2717/3793/3382 3569/3792/3381 2819/3791/3380 +f 3105/3794/3383 2736/3795/3384 3569/3792/3381 +f 2812/3744/3339 2736/3795/3384 2706/3747/3342 +f 2706/3747/3342 3570/3796/3385 2730/3748/3343 +f 2718/3797/3386 3570/3796/3385 2736/3795/3384 +f 3025/3798/3387 2962/3799/3388 3570/3796/3385 +f 2730/3748/3343 2962/3799/3388 2707/3751/3346 +f 2707/3751/3346 3571/3800/3389 2956/3752/3347 +f 2719/3801/3390 3571/3800/3389 2962/3799/3388 +f 3247/3802/3391 2891/3803/3392 3571/3800/3389 +f 2956/3752/3347 2891/3803/3392 2708/3755/3350 +f 2708/3755/3350 3572/3804/3393 2814/3756/3351 +f 2720/3805/3394 3572/3804/3393 2891/3803/3392 +f 3107/3806/3395 2815/3757/2841 3572/3804/3393 +f 2814/3756/3351 2815/3757/2841 2697/3758/2792 +f 3127/3807/2888 3101/3759/3352 2709/3808/2840 +f 3127/3807/2888 2721/2610/2314 3573/3809/3396 +f 3573/3809/3396 2434/2616/2320 2759/3810/3397 +f 3573/3809/3396 2710/3761/3354 3101/3759/3352 +f 2759/3810/3397 3020/3763/3356 2710/3761/3354 +f 2759/3810/3397 2806/2617/2321 3574/3811/3398 +f 3574/3811/3398 2435/2622/2326 3270/3812/3399 +f 3574/3811/3398 2711/3765/3358 3020/3763/3356 +f 3270/3812/3399 3244/3767/3360 2711/3765/3358 +f 3270/3812/3399 2878/2623/2327 3575/3813/3400 +f 3575/3813/3400 2436/2628/2332 2917/3814/3401 +f 3575/3813/3400 2712/3769/3362 3244/3767/3360 +f 2917/3814/3401 3175/3771/3364 2712/3769/3362 +f 2917/3814/3401 2951/2629/2333 3576/3815/3402 +f 3576/3815/3402 2437/2634/2338 2853/3816/3403 +f 3576/3815/3402 2713/3773/3366 3175/3771/3364 +f 2853/3816/3403 2817/3775/3368 2713/3773/3366 +f 2853/3816/3403 3012/2635/2339 3577/3817/3404 +f 3577/3817/3404 2438/2640/2344 3063/3818/3405 +f 3577/3817/3404 2714/3777/3370 2817/3775/3368 +f 3063/3818/3405 2734/3779/3372 2714/3777/3370 +f 3063/3818/3405 3094/2641/2345 3578/3819/3406 +f 3578/3819/3406 2439/2646/2350 2995/3820/2864 +f 3578/3819/3406 2715/3781/2865 2734/3779/3372 +f 2715/3784/2865 3579/3821/3407 2960/3786/3375 +f 2439/2647/2350 3579/3821/3407 2995/3822/2864 +f 3168/2649/2352 3217/3823/3408 3579/3821/3407 +f 2960/3786/3375 3217/3823/3408 2716/3789/3378 +f 2716/3789/3378 3580/3824/3409 2889/3790/3379 +f 2440/2654/2355 3580/3824/3409 3217/3823/3408 +f 3238/2656/2357 3154/3825/3410 3580/3824/3409 +f 2889/3790/3379 3154/3825/3410 2717/3793/3382 +f 2717/3793/3382 3581/3826/3411 3105/3794/3383 +f 2441/2660/2361 3581/3826/3411 3154/3825/3410 +f 2724/2662/2363 2791/3827/3412 3581/3826/3411 +f 3105/3794/3383 2791/3827/3412 2718/3797/3386 +f 2718/3797/3386 3582/3828/3413 3025/3798/3387 +f 2442/2666/2367 3582/3828/3413 2791/3827/3412 +f 2809/2668/2369 3293/3829/3414 3582/3828/3413 +f 3025/3798/3387 3293/3829/3414 2719/3801/3390 +f 2719/3801/3390 3583/3830/3415 3247/3802/3391 +f 2443/2672/2373 3583/3830/3415 3293/3829/3414 +f 2881/2674/2375 2944/3831/3416 3583/3830/3415 +f 3247/3802/3391 2944/3831/3416 2720/3805/3394 +f 2720/3805/3394 3584/3832/3417 3107/3806/3395 +f 2444/2678/2379 3584/3832/3417 2944/3831/3416 +f 2726/2680/2381 3127/3807/2888 3584/3832/3417 +f 3107/3806/3395 3127/3807/2888 2709/3808/2840 +f 2727/2609/2313 3297/2613/2317 2721/2610/2314 +f 2727/2609/2313 2445/2684/2385 3015/2612/2316 +f 3297/2613/2317 3015/2612/2316 2446/2614/2318 +f 3297/2613/2317 2811/2615/2319 2434/2616/2320 +f 2811/2615/2319 3298/2619/2323 2806/2617/2321 +f 2811/2615/2319 2446/2614/2318 3098/2618/2322 +f 3298/2619/2323 3098/2618/2322 2447/2620/2324 +f 3298/2619/2323 2883/2621/2325 2435/2622/2326 +f 2883/2621/2325 3299/2625/2329 2878/2623/2327 +f 2883/2621/2325 2447/2620/2324 3170/2624/2328 +f 3299/2625/2329 3170/2624/2328 2448/2626/2330 +f 3299/2625/2329 2955/2627/2331 2436/2628/2332 +f 2955/2627/2331 3300/2631/2335 2951/2629/2333 +f 2955/2627/2331 2448/2626/2330 3241/2630/2334 +f 3300/2631/2335 3241/2630/2334 2449/2632/2336 +f 3300/2631/2335 3017/2633/2337 2437/2634/2338 +f 3017/2633/2337 3301/2637/2341 3012/2635/2339 +f 3017/2633/2337 2449/2632/2336 2729/2636/2340 +f 3301/2637/2341 2729/2636/2340 2450/2638/2342 +f 3301/2637/2341 3100/2639/2343 2438/2640/2344 +f 3100/2639/2343 3302/2643/2347 3094/2641/2345 +f 3100/2639/2343 2450/2638/2342 2813/2642/2346 +f 3302/2643/2347 2813/2642/2346 2451/2644/2348 +f 3302/2643/2347 3172/2645/2349 2439/2646/2350 +f 2439/2647/2350 3172/2651/2349 3303/2648/2351 +f 2451/2650/2348 2885/2652/2353 3303/2648/2351 +f 2885/2652/2353 2452/2657/2358 3243/2653/2354 +f 3168/2649/2352 3303/2648/2351 3243/2653/2354 +f 2440/2654/2355 3243/2653/2354 3304/2655/2356 +f 2452/2657/2358 2957/2658/2359 3304/2655/2356 +f 2957/2658/2359 2453/2663/2364 2731/2659/2360 +f 3238/2656/2357 3304/2655/2356 2731/2659/2360 +f 2441/2660/2361 2731/2659/2360 3305/2661/2362 +f 2453/2663/2364 3019/2664/2365 3305/2661/2362 +f 3019/2664/2365 2454/2669/2370 2816/2665/2366 +f 2724/2662/2363 3305/2661/2362 2816/2665/2366 +f 2442/2666/2367 2816/2665/2366 3306/2667/2368 +f 2454/2669/2370 3102/2670/2371 3306/2667/2368 +f 3102/2670/2371 2455/2675/2376 2886/2671/2372 +f 2809/2668/2369 3306/2667/2368 2886/2671/2372 +f 2443/2672/2373 2886/2671/2372 3307/2673/2374 +f 2455/2675/2376 3174/2676/2377 3307/2673/2374 +f 3174/2676/2377 2456/2681/2382 2959/2677/2378 +f 2881/2674/2375 3307/2673/2374 2959/2677/2378 +f 2444/2678/2379 2959/2677/2378 3308/2679/2380 +f 2456/2681/2382 3021/2682/2383 3308/2679/2380 +f 3021/2682/2383 2445/2684/2385 2727/2609/2313 +f 2726/2680/2381 3308/2679/2380 2727/2609/2313 +f 3022/2683/2384 3309/2686/2387 3015/2612/2316 +f 3022/2683/2384 2457/2734/2433 2733/2685/2386 +f 3309/2686/2387 2733/2685/2386 2458/2687/2388 +f 3309/2686/2387 3104/2688/2389 2446/2614/2318 +f 3104/2688/2389 3310/2690/2391 3098/2618/2322 +f 3104/2688/2389 2458/2687/2388 2818/2689/2390 +f 3310/2690/2391 2818/2689/2390 2459/2691/2392 +f 3310/2690/2391 3176/2692/2393 2447/2620/2324 +f 3176/2692/2393 3311/2694/2395 3170/2624/2328 +f 3176/2692/2393 2459/2691/2392 2888/2693/2394 +f 3311/2694/2395 2888/2693/2394 2460/2695/2396 +f 3311/2694/2395 3246/2696/2397 2448/2626/2330 +f 3246/2696/2397 3312/2698/2399 3241/2630/2334 +f 3246/2696/2397 2460/2695/2396 2961/2697/2398 +f 3312/2698/2399 2961/2697/2398 2461/2699/2400 +f 3312/2698/2399 2735/2700/2401 2449/2632/2336 +f 2735/2700/2401 3313/2702/2403 2729/2636/2340 +f 2735/2700/2401 2461/2699/2400 3024/2701/2402 +f 3313/2702/2403 3024/2701/2402 2462/2703/2404 +f 3313/2702/2403 2820/2704/2405 2450/2638/2342 +f 2820/2704/2405 3314/2706/2407 2813/2642/2346 +f 2820/2704/2405 2462/2703/2404 3106/2705/2406 +f 3314/2706/2407 3106/2705/2406 2463/2707/2408 +f 3314/2706/2407 2890/2708/2409 2451/2644/2348 +f 2451/2650/2348 2890/2711/2409 3315/2709/2410 +f 2463/2710/2408 3178/2712/2411 3315/2709/2410 +f 3178/2712/2411 2464/2715/2414 2963/2713/2412 +f 2885/2652/2353 3315/2709/2410 2963/2713/2412 +f 2452/2657/2358 2963/2713/2412 3316/2714/2413 +f 2464/2715/2414 3248/2716/2415 3316/2714/2413 +f 3248/2716/2415 2465/2719/2418 3026/2717/2416 +f 2957/2658/2359 3316/2714/2413 3026/2717/2416 +f 2453/2663/2364 3026/2717/2416 3317/2718/2417 +f 2465/2719/2418 2737/2720/2419 3317/2718/2417 +f 2737/2720/2419 2466/2723/2422 3108/2721/2420 +f 3019/2664/2365 3317/2718/2417 3108/2721/2420 +f 2454/2669/2370 3108/2721/2420 3318/2722/2421 +f 2466/2723/2422 2821/2724/2423 3318/2722/2421 +f 2821/2724/2423 2467/2727/2426 3179/2725/2424 +f 3102/2670/2371 3318/2722/2421 3179/2725/2424 +f 2455/2675/2376 3179/2725/2424 3319/2726/2425 +f 2467/2727/2426 2892/2728/2427 3319/2726/2425 +f 2892/2728/2427 2468/2731/2430 3249/2729/2428 +f 3174/2676/2377 3319/2726/2425 3249/2729/2428 +f 2456/2681/2382 3249/2729/2428 3320/2730/2429 +f 2468/2731/2430 2738/2732/2431 3320/2730/2429 +f 2738/2732/2431 2457/2734/2433 3022/2683/2384 +f 3021/2682/2383 3320/2730/2429 3022/2683/2384 +f 2739/2733/2432 3321/2736/2435 2733/2685/2386 +f 2739/2733/2432 2469/2784/2481 3027/2735/2434 +f 3321/2736/2435 3027/2735/2434 2470/2737/2436 +f 3321/2736/2435 2822/2738/2437 2458/2687/2388 +f 2822/2738/2437 3322/2740/2439 2818/2689/2390 +f 2822/2738/2437 2470/2737/2436 3109/2739/2438 +f 3322/2740/2439 3109/2739/2438 2471/2741/2440 +f 3322/2740/2439 2893/2742/2441 2459/2691/2392 +f 2893/2742/2441 3323/2744/2443 2888/2693/2394 +f 2893/2742/2441 2471/2741/2440 3180/2743/2442 +f 3323/2744/2443 3180/2743/2442 2472/2745/2444 +f 3323/2744/2443 2964/2746/2445 2460/2695/2396 +f 2964/2746/2445 3324/2748/2447 2961/2697/2398 +f 2964/2746/2445 2472/2745/2444 3250/2747/2446 +f 3324/2748/2447 3250/2747/2446 2473/2749/2448 +f 3324/2748/2447 3028/2750/2449 2461/2699/2400 +f 3028/2750/2449 3325/2752/2451 3024/2701/2402 +f 3028/2750/2449 2473/2749/2448 2740/2751/2450 +f 3325/2752/2451 2740/2751/2450 2474/2753/2452 +f 3325/2752/2451 3110/2754/2453 2462/2703/2404 +f 3110/2754/2453 3326/2756/2455 3106/2705/2406 +f 3110/2754/2453 2474/2753/2452 2823/2755/2454 +f 3326/2756/2455 2823/2755/2454 2475/2757/2456 +f 3326/2756/2455 3181/2758/2457 2463/2707/2408 +f 2463/2710/2408 3181/2761/2457 3327/2759/2458 +f 2475/2760/2456 2894/2762/2459 3327/2759/2458 +f 2894/2762/2459 2476/2765/2462 3251/2763/2460 +f 3178/2712/2411 3327/2759/2458 3251/2763/2460 +f 2464/2715/2414 3251/2763/2460 3328/2764/2461 +f 2476/2765/2462 2965/2766/2463 3328/2764/2461 +f 2965/2766/2463 2477/2769/2466 2741/2767/2464 +f 3248/2716/2415 3328/2764/2461 2741/2767/2464 +f 2465/2719/2418 2741/2767/2464 3329/2768/2465 +f 2477/2769/2466 3029/2770/2467 3329/2768/2465 +f 3029/2770/2467 2478/2773/2470 2824/2771/2468 +f 2737/2720/2419 3329/2768/2465 2824/2771/2468 +f 2466/2723/2422 2824/2771/2468 3330/2772/2469 +f 2478/2773/2470 3111/2774/2471 3330/2772/2469 +f 3111/2774/2471 2479/2777/2474 2895/2775/2472 +f 2821/2724/2423 3330/2772/2469 2895/2775/2472 +f 2467/2727/2426 2895/2775/2472 3331/2776/2473 +f 2479/2777/2474 3182/2778/2475 3331/2776/2473 +f 3182/2778/2475 2480/2781/2478 2966/2779/2476 +f 2892/2728/2427 3331/2776/2473 2966/2779/2476 +f 2468/2731/2430 2966/2779/2476 3332/2780/2477 +f 2480/2781/2478 3030/2782/2479 3332/2780/2477 +f 3030/2782/2479 2469/2784/2481 2739/2733/2432 +f 2738/2732/2431 3332/2780/2477 2739/2733/2432 +f 3031/2783/2480 3333/2786/2483 3027/2735/2434 +f 3031/2783/2480 2481/2834/2529 2742/2785/2482 +f 3333/2786/2483 2742/2785/2482 2482/2787/2484 +f 3333/2786/2483 3112/2788/2485 2470/2737/2436 +f 3112/2788/2485 3334/2790/2487 3109/2739/2438 +f 3112/2788/2485 2482/2787/2484 2825/2789/2486 +f 3334/2790/2487 2825/2789/2486 2483/2791/2488 +f 3334/2790/2487 3183/2792/2489 2471/2741/2440 +f 3183/2792/2489 3335/2794/2491 3180/2743/2442 +f 3183/2792/2489 2483/2791/2488 2896/2793/2490 +f 3335/2794/2491 2896/2793/2490 2484/2795/2492 +f 3335/2794/2491 3252/2796/2493 2472/2745/2444 +f 3252/2796/2493 3336/2798/2495 3250/2747/2446 +f 3252/2796/2493 2484/2795/2492 2967/2797/2494 +f 3336/2798/2495 2967/2797/2494 2485/2799/2496 +f 3336/2798/2495 2743/2800/2497 2473/2749/2448 +f 2743/2800/2497 3337/2802/2499 2740/2751/2450 +f 2743/2800/2497 2485/2799/2496 3032/2801/2498 +f 3337/2802/2499 3032/2801/2498 2486/2803/2500 +f 3337/2802/2499 2826/2804/2501 2474/2753/2452 +f 2826/2804/2501 3338/2806/2503 2823/2755/2454 +f 2826/2804/2501 2486/2803/2500 3113/2805/2502 +f 3338/2806/2503 3113/2805/2502 2487/2807/2504 +f 3338/2806/2503 2897/2808/2505 2475/2757/2456 +f 2475/2760/2456 2897/2811/2505 3339/2809/2506 +f 2487/2810/2504 3184/2812/2507 3339/2809/2506 +f 3184/2812/2507 2488/2815/2510 2968/2813/2508 +f 2894/2762/2459 3339/2809/2506 2968/2813/2508 +f 2476/2765/2462 2968/2813/2508 3340/2814/2509 +f 2488/2815/2510 3253/2816/2511 3340/2814/2509 +f 3253/2816/2511 2489/2819/2514 3033/2817/2512 +f 2965/2766/2463 3340/2814/2509 3033/2817/2512 +f 2477/2769/2466 3033/2817/2512 3341/2818/2513 +f 2489/2819/2514 2744/2820/2515 3341/2818/2513 +f 2744/2820/2515 2490/2823/2518 3114/2821/2516 +f 3029/2770/2467 3341/2818/2513 3114/2821/2516 +f 2478/2773/2470 3114/2821/2516 3342/2822/2517 +f 2490/2823/2518 2827/2824/2519 3342/2822/2517 +f 2827/2824/2519 2491/2827/2522 3185/2825/2520 +f 3111/2774/2471 3342/2822/2517 3185/2825/2520 +f 2479/2777/2474 3185/2825/2520 3343/2826/2521 +f 2491/2827/2522 2898/2828/2523 3343/2826/2521 +f 2898/2828/2523 2492/2831/2526 3254/2829/2524 +f 3182/2778/2475 3343/2826/2521 3254/2829/2524 +f 2480/2781/2478 3254/2829/2524 3344/2830/2525 +f 2492/2831/2526 2745/2832/2527 3344/2830/2525 +f 2745/2832/2527 2481/2834/2529 3031/2783/2480 +f 3030/2782/2479 3344/2830/2525 3031/2783/2480 +f 2746/2833/2528 3345/2836/2531 2742/2785/2482 +f 2746/2833/2528 2493/2884/2577 3034/2835/2530 +f 3345/2836/2531 3034/2835/2530 2494/2837/2532 +f 3345/2836/2531 2828/2838/2533 2482/2787/2484 +f 2828/2838/2533 3346/2840/2535 2825/2789/2486 +f 2828/2838/2533 2494/2837/2532 3115/2839/2534 +f 3346/2840/2535 3115/2839/2534 2495/2841/2536 +f 3346/2840/2535 2899/2842/2537 2483/2791/2488 +f 2899/2842/2537 3347/2844/2539 2896/2793/2490 +f 2899/2842/2537 2495/2841/2536 3186/2843/2538 +f 3347/2844/2539 3186/2843/2538 2496/2845/2540 +f 3347/2844/2539 2969/2846/2541 2484/2795/2492 +f 2969/2846/2541 3348/2848/2543 2967/2797/2494 +f 2969/2846/2541 2496/2845/2540 3255/2847/2542 +f 3348/2848/2543 3255/2847/2542 2497/2849/2544 +f 3348/2848/2543 3035/2850/2545 2485/2799/2496 +f 3035/2850/2545 3349/2852/2547 3032/2801/2498 +f 3035/2850/2545 2497/2849/2544 2747/2851/2546 +f 3349/2852/2547 2747/2851/2546 2498/2853/2548 +f 3349/2852/2547 3116/2854/2549 2486/2803/2500 +f 3116/2854/2549 3350/2856/2551 3113/2805/2502 +f 3116/2854/2549 2498/2853/2548 2829/2855/2550 +f 3350/2856/2551 2829/2855/2550 2499/2857/2552 +f 3350/2856/2551 3187/2858/2553 2487/2807/2504 +f 2487/2810/2504 3187/2861/2553 3351/2859/2554 +f 2499/2860/2552 2900/2862/2555 3351/2859/2554 +f 2900/2862/2555 2500/2865/2558 3256/2863/2556 +f 3184/2812/2507 3351/2859/2554 3256/2863/2556 +f 2488/2815/2510 3256/2863/2556 3352/2864/2557 +f 2500/2865/2558 2970/2866/2559 3352/2864/2557 +f 2970/2866/2559 2501/2869/2562 2748/2867/2560 +f 3253/2816/2511 3352/2864/2557 2748/2867/2560 +f 2489/2819/2514 2748/2867/2560 3353/2868/2561 +f 2501/2869/2562 3036/2870/2563 3353/2868/2561 +f 3036/2870/2563 2502/2873/2566 2830/2871/2564 +f 2744/2820/2515 3353/2868/2561 2830/2871/2564 +f 2490/2823/2518 2830/2871/2564 3354/2872/2565 +f 2502/2873/2566 3117/2874/2567 3354/2872/2565 +f 3117/2874/2567 2503/2877/2570 2901/2875/2568 +f 2827/2824/2519 3354/2872/2565 2901/2875/2568 +f 2491/2827/2522 2901/2875/2568 3355/2876/2569 +f 2503/2877/2570 3188/2878/2571 3355/2876/2569 +f 3188/2878/2571 2504/2881/2574 2971/2879/2572 +f 2898/2828/2523 3355/2876/2569 2971/2879/2572 +f 2492/2831/2526 2971/2879/2572 3356/2880/2573 +f 2504/2881/2574 3037/2882/2575 3356/2880/2573 +f 3037/2882/2575 2493/2884/2577 2746/2833/2528 +f 2745/2832/2527 3356/2880/2573 2746/2833/2528 +f 3038/2883/2576 3357/2886/2579 3034/2835/2530 +f 3038/2883/2576 2505/2934/2625 2749/2885/2578 +f 3357/2886/2579 2749/2885/2578 2506/2887/2580 +f 3357/2886/2579 3118/2888/2581 2494/2837/2532 +f 3118/2888/2581 3358/2890/2583 3115/2839/2534 +f 3118/2888/2581 2506/2887/2580 2831/2889/2582 +f 3358/2890/2583 2831/2889/2582 2507/2891/2584 +f 3358/2890/2583 3189/2892/2585 2495/2841/2536 +f 3189/2892/2585 3359/2894/2587 3186/2843/2538 +f 3189/2892/2585 2507/2891/2584 2902/2893/2586 +f 3359/2894/2587 2902/2893/2586 2508/2895/2588 +f 3359/2894/2587 3257/2896/2589 2496/2845/2540 +f 3257/2896/2589 3360/2898/2591 3255/2847/2542 +f 3257/2896/2589 2508/2895/2588 2972/2897/2590 +f 3360/2898/2591 2972/2897/2590 2509/2899/2592 +f 3360/2898/2591 2750/2900/2593 2497/2849/2544 +f 2750/2900/2593 3361/2902/2595 2747/2851/2546 +f 2750/2900/2593 2509/2899/2592 3039/2901/2594 +f 3361/2902/2595 3039/2901/2594 2510/2903/2596 +f 3361/2902/2595 2832/2904/2597 2498/2853/2548 +f 2832/2904/2597 3362/2906/2599 2829/2855/2550 +f 2832/2904/2597 2510/2903/2596 3119/2905/2598 +f 3362/2906/2599 3119/2905/2598 2511/2907/2600 +f 3362/2906/2599 2903/2908/2601 2499/2857/2552 +f 2499/2860/2552 2903/2911/2601 3363/2909/2602 +f 2511/2910/2600 3190/2912/2603 3363/2909/2602 +f 3190/2912/2603 2512/2915/2606 2973/2913/2604 +f 2900/2862/2555 3363/2909/2602 2973/2913/2604 +f 2500/2865/2558 2973/2913/2604 3364/2914/2605 +f 2512/2915/2606 3258/2916/2607 3364/2914/2605 +f 3258/2916/2607 2513/2919/2610 3040/2917/2608 +f 2970/2866/2559 3364/2914/2605 3040/2917/2608 +f 2501/2869/2562 3040/2917/2608 3365/2918/2609 +f 2513/2919/2610 2751/2920/2611 3365/2918/2609 +f 2751/2920/2611 2514/2923/2614 3120/2921/2612 +f 3036/2870/2563 3365/2918/2609 3120/2921/2612 +f 2502/2873/2566 3120/2921/2612 3366/2922/2613 +f 2514/2923/2614 2833/2924/2615 3366/2922/2613 +f 2833/2924/2615 2515/2927/2618 3191/2925/2616 +f 3117/2874/2567 3366/2922/2613 3191/2925/2616 +f 2503/2877/2570 3191/2925/2616 3367/2926/2617 +f 2515/2927/2618 2904/2928/2619 3367/2926/2617 +f 2904/2928/2619 2516/2931/2622 3259/2929/2620 +f 3188/2878/2571 3367/2926/2617 3259/2929/2620 +f 2504/2881/2574 3259/2929/2620 3368/2930/2621 +f 2516/2931/2622 2752/2932/2623 3368/2930/2621 +f 2752/2932/2623 2505/2934/2625 3038/2883/2576 +f 3037/2882/2575 3368/2930/2621 3038/2883/2576 +f 2753/2933/2624 3369/2936/2627 2749/2885/2578 +f 2753/2933/2624 2517/2984/2673 3041/2935/2626 +f 3369/2936/2627 3041/2935/2626 2518/2937/2628 +f 3369/2936/2627 2834/2938/2629 2506/2887/2580 +f 2834/2938/2629 3370/2940/2631 2831/2889/2582 +f 2834/2938/2629 2518/2937/2628 3121/2939/2630 +f 3370/2940/2631 3121/2939/2630 2519/2941/2632 +f 3370/2940/2631 2905/2942/2633 2507/2891/2584 +f 2905/2942/2633 3371/2944/2635 2902/2893/2586 +f 2905/2942/2633 2519/2941/2632 3192/2943/2634 +f 3371/2944/2635 3192/2943/2634 2520/2945/2636 +f 3371/2944/2635 2974/2946/2637 2508/2895/2588 +f 2974/2946/2637 3372/2948/2639 2972/2897/2590 +f 2974/2946/2637 2520/2945/2636 3260/2947/2638 +f 3372/2948/2639 3260/2947/2638 2521/2949/2640 +f 3372/2948/2639 3042/2950/2641 2509/2899/2592 +f 3042/2950/2641 3373/2952/2643 3039/2901/2594 +f 3042/2950/2641 2521/2949/2640 2754/2951/2642 +f 3373/2952/2643 2754/2951/2642 2522/2953/2644 +f 3373/2952/2643 3122/2954/2645 2510/2903/2596 +f 3122/2954/2645 3374/2956/2647 3119/2905/2598 +f 3122/2954/2645 2522/2953/2644 2835/2955/2646 +f 3374/2956/2647 2835/2955/2646 2523/2957/2648 +f 3374/2956/2647 3193/2958/2649 2511/2907/2600 +f 2511/2910/2600 3193/2961/2649 3375/2959/2650 +f 2523/2960/2648 2906/2962/2651 3375/2959/2650 +f 2906/2962/2651 2524/2965/2654 3261/2963/2652 +f 3190/2912/2603 3375/2959/2650 3261/2963/2652 +f 2512/2915/2606 3261/2963/2652 3376/2964/2653 +f 2524/2965/2654 2975/2966/2655 3376/2964/2653 +f 2975/2966/2655 2525/2969/2658 2755/2967/2656 +f 3258/2916/2607 3376/2964/2653 2755/2967/2656 +f 2513/2919/2610 2755/2967/2656 3377/2968/2657 +f 2525/2969/2658 3043/2970/2659 3377/2968/2657 +f 3043/2970/2659 2526/2973/2662 2836/2971/2660 +f 2751/2920/2611 3377/2968/2657 2836/2971/2660 +f 2514/2923/2614 2836/2971/2660 3378/2972/2661 +f 2526/2973/2662 3123/2974/2663 3378/2972/2661 +f 3123/2974/2663 2527/2977/2666 2907/2975/2664 +f 2833/2924/2615 3378/2972/2661 2907/2975/2664 +f 2515/2927/2618 2907/2975/2664 3379/2976/2665 +f 2527/2977/2666 3194/2978/2667 3379/2976/2665 +f 3194/2978/2667 2528/2981/2670 2976/2979/2668 +f 2904/2928/2619 3379/2976/2665 2976/2979/2668 +f 2516/2931/2622 2976/2979/2668 3380/2980/2669 +f 2528/2981/2670 3044/2982/2671 3380/2980/2669 +f 3044/2982/2671 2517/2984/2673 2753/2933/2624 +f 2752/2932/2623 3380/2980/2669 2753/2933/2624 +f 3045/2983/2672 3381/2986/2675 3041/2935/2626 +f 3045/2983/2672 2529/3034/2721 2756/2985/2674 +f 3381/2986/2675 2756/2985/2674 2530/2987/2676 +f 3381/2986/2675 3124/2988/2677 2518/2937/2628 +f 3124/2988/2677 3382/2990/2679 3121/2939/2630 +f 3124/2988/2677 2530/2987/2676 2837/2989/2678 +f 3382/2990/2679 2837/2989/2678 2531/2991/2680 +f 3382/2990/2679 3195/2992/2681 2519/2941/2632 +f 3195/2992/2681 3383/2994/2683 3192/2943/2634 +f 3195/2992/2681 2531/2991/2680 2908/2993/2682 +f 3383/2994/2683 2908/2993/2682 2532/2995/2684 +f 3383/2994/2683 3262/2996/2685 2520/2945/2636 +f 3262/2996/2685 3384/2998/2687 3260/2947/2638 +f 3262/2996/2685 2532/2995/2684 2977/2997/2686 +f 3384/2998/2687 2977/2997/2686 2533/2999/2688 +f 3384/2998/2687 2757/3000/2689 2521/2949/2640 +f 2757/3000/2689 3385/3002/2691 2754/2951/2642 +f 2757/3000/2689 2533/2999/2688 3046/3001/2690 +f 3385/3002/2691 3046/3001/2690 2534/3003/2692 +f 3385/3002/2691 2838/3004/2693 2522/2953/2644 +f 2838/3004/2693 3386/3006/2695 2835/2955/2646 +f 2838/3004/2693 2534/3003/2692 3125/3005/2694 +f 3386/3006/2695 3125/3005/2694 2535/3007/2696 +f 3386/3006/2695 2909/3008/2697 2523/2957/2648 +f 2523/2960/2648 2909/3011/2697 3387/3009/2698 +f 2535/3010/2696 3196/3012/2699 3387/3009/2698 +f 3196/3012/2699 2536/3015/2702 2978/3013/2700 +f 2906/2962/2651 3387/3009/2698 2978/3013/2700 +f 2524/2965/2654 2978/3013/2700 3388/3014/2701 +f 2536/3015/2702 3263/3016/2703 3388/3014/2701 +f 3263/3016/2703 2537/3019/2706 3047/3017/2704 +f 2975/2966/2655 3388/3014/2701 3047/3017/2704 +f 2525/2969/2658 3047/3017/2704 3389/3018/2705 +f 2537/3019/2706 2758/3020/2707 3389/3018/2705 +f 2758/3020/2707 2538/3023/2710 3126/3021/2708 +f 3043/2970/2659 3389/3018/2705 3126/3021/2708 +f 2526/2973/2662 3126/3021/2708 3390/3022/2709 +f 2538/3023/2710 2839/3024/2711 3390/3022/2709 +f 2839/3024/2711 2539/3027/2714 3197/3025/2712 +f 3123/2974/2663 3390/3022/2709 3197/3025/2712 +f 2527/2977/2666 3197/3025/2712 3391/3026/2713 +f 2539/3027/2714 2910/3028/2715 3391/3026/2713 +f 2910/3028/2715 2540/3031/2718 3264/3029/2716 +f 3194/2978/2667 3391/3026/2713 3264/3029/2716 +f 2528/2981/2670 3264/3029/2716 3392/3030/2717 +f 2540/3031/2718 2760/3032/2719 3392/3030/2717 +f 2760/3032/2719 2529/3034/2721 3045/2983/2672 +f 3044/2982/2671 3392/3030/2717 3045/2983/2672 +f 2761/3033/2720 3393/3036/2723 2756/2985/2674 +f 2761/3033/2720 2541/3084/2769 3048/3035/2722 +f 3393/3036/2723 3048/3035/2722 2542/3037/2724 +f 3393/3036/2723 2840/3038/2725 2530/2987/2676 +f 2840/3038/2725 3394/3040/2727 2837/2989/2678 +f 2840/3038/2725 2542/3037/2724 3128/3039/2726 +f 3394/3040/2727 3128/3039/2726 2543/3041/2728 +f 3394/3040/2727 2911/3042/2729 2531/2991/2680 +f 2911/3042/2729 3395/3044/2731 2908/2993/2682 +f 2911/3042/2729 2543/3041/2728 3198/3043/2730 +f 3395/3044/2731 3198/3043/2730 2544/3045/2732 +f 3395/3044/2731 2979/3046/2733 2532/2995/2684 +f 2979/3046/2733 3396/3048/2735 2977/2997/2686 +f 2979/3046/2733 2544/3045/2732 3265/3047/2734 +f 3396/3048/2735 3265/3047/2734 2545/3049/2736 +f 3396/3048/2735 3049/3050/2737 2533/2999/2688 +f 3049/3050/2737 3397/3052/2739 3046/3001/2690 +f 3049/3050/2737 2545/3049/2736 2762/3051/2738 +f 3397/3052/2739 2762/3051/2738 2546/3053/2740 +f 3397/3052/2739 3129/3054/2741 2534/3003/2692 +f 3129/3054/2741 3398/3056/2743 3125/3005/2694 +f 3129/3054/2741 2546/3053/2740 2841/3055/2742 +f 3398/3056/2743 2841/3055/2742 2547/3057/2744 +f 3398/3056/2743 3199/3058/2745 2535/3007/2696 +f 2535/3010/2696 3199/3061/2745 3399/3059/2746 +f 2547/3060/2744 2912/3062/2747 3399/3059/2746 +f 2912/3062/2747 2548/3065/2750 3266/3063/2748 +f 3196/3012/2699 3399/3059/2746 3266/3063/2748 +f 2536/3015/2702 3266/3063/2748 3400/3064/2749 +f 2548/3065/2750 2980/3066/2751 3400/3064/2749 +f 2980/3066/2751 2549/3069/2754 2763/3067/2752 +f 3263/3016/2703 3400/3064/2749 2763/3067/2752 +f 2537/3019/2706 2763/3067/2752 3401/3068/2753 +f 2549/3069/2754 3050/3070/2755 3401/3068/2753 +f 3050/3070/2755 2550/3073/2758 2842/3071/2756 +f 2758/3020/2707 3401/3068/2753 2842/3071/2756 +f 2538/3023/2710 2842/3071/2756 3402/3072/2757 +f 2550/3073/2758 3130/3074/2759 3402/3072/2757 +f 3130/3074/2759 2551/3077/2762 2913/3075/2760 +f 2839/3024/2711 3402/3072/2757 2913/3075/2760 +f 2539/3027/2714 2913/3075/2760 3403/3076/2761 +f 2551/3077/2762 3200/3078/2763 3403/3076/2761 +f 3200/3078/2763 2552/3081/2766 2981/3079/2764 +f 2910/3028/2715 3403/3076/2761 2981/3079/2764 +f 2540/3031/2718 2981/3079/2764 3404/3080/2765 +f 2552/3081/2766 3051/3082/2767 3404/3080/2765 +f 3051/3082/2767 2541/3084/2769 2761/3033/2720 +f 2760/3032/2719 3404/3080/2765 2761/3033/2720 +f 3052/3083/2768 3405/3086/2771 3048/3035/2722 +f 3052/3083/2768 2553/3134/2817 2764/3085/2770 +f 3405/3086/2771 2764/3085/2770 2554/3087/2772 +f 3405/3086/2771 3131/3088/2773 2542/3037/2724 +f 3131/3088/2773 3406/3090/2775 3128/3039/2726 +f 3131/3088/2773 2554/3087/2772 2843/3089/2774 +f 3406/3090/2775 2843/3089/2774 2555/3091/2776 +f 3406/3090/2775 3201/3092/2777 2543/3041/2728 +f 3201/3092/2777 3407/3094/2779 3198/3043/2730 +f 3201/3092/2777 2555/3091/2776 2914/3093/2778 +f 3407/3094/2779 2914/3093/2778 2556/3095/2780 +f 3407/3094/2779 3267/3096/2781 2544/3045/2732 +f 3267/3096/2781 3408/3098/2783 3265/3047/2734 +f 3267/3096/2781 2556/3095/2780 2982/3097/2782 +f 3408/3098/2783 2982/3097/2782 2557/3099/2784 +f 3408/3098/2783 2765/3100/2785 2545/3049/2736 +f 2765/3100/2785 3409/3102/2787 2762/3051/2738 +f 2765/3100/2785 2557/3099/2784 3053/3101/2786 +f 3409/3102/2787 3053/3101/2786 2558/3103/2788 +f 3409/3102/2787 2844/3104/2789 2546/3053/2740 +f 2844/3104/2789 3410/3106/2791 2841/3055/2742 +f 2844/3104/2789 2558/3103/2788 3132/3105/2790 +f 3410/3106/2791 3132/3105/2790 2559/3107/2792 +f 3410/3106/2791 2915/3108/2793 2547/3057/2744 +f 2547/3060/2744 2915/3111/2793 3411/3109/2794 +f 2559/3110/2792 3202/3112/2795 3411/3109/2794 +f 3202/3112/2795 2560/3115/2798 2983/3113/2796 +f 2912/3062/2747 3411/3109/2794 2983/3113/2796 +f 2548/3065/2750 2983/3113/2796 3412/3114/2797 +f 2560/3115/2798 3268/3116/2799 3412/3114/2797 +f 3268/3116/2799 2561/3119/2802 3054/3117/2800 +f 2980/3066/2751 3412/3114/2797 3054/3117/2800 +f 2549/3069/2754 3054/3117/2800 3413/3118/2801 +f 2561/3119/2802 2766/3120/2803 3413/3118/2801 +f 2766/3120/2803 2562/3123/2806 3133/3121/2804 +f 3050/3070/2755 3413/3118/2801 3133/3121/2804 +f 2550/3073/2758 3133/3121/2804 3414/3122/2805 +f 2562/3123/2806 2845/3124/2807 3414/3122/2805 +f 2845/3124/2807 2563/3127/2810 3203/3125/2808 +f 3130/3074/2759 3414/3122/2805 3203/3125/2808 +f 2551/3077/2762 3203/3125/2808 3415/3126/2809 +f 2563/3127/2810 2916/3128/2811 3415/3126/2809 +f 2916/3128/2811 2564/3131/2814 3269/3129/2812 +f 3200/3078/2763 3415/3126/2809 3269/3129/2812 +f 2552/3081/2766 3269/3129/2812 3416/3130/2813 +f 2564/3131/2814 2767/3132/2815 3416/3130/2813 +f 2767/3132/2815 2553/3134/2817 3052/3083/2768 +f 3051/3082/2767 3416/3130/2813 3052/3083/2768 +f 2768/3133/2816 3417/3136/2819 2764/3085/2770 +f 2768/3133/2816 2565/3184/2865 3055/3135/2818 +f 3417/3136/2819 3055/3135/2818 2566/3137/2820 +f 3417/3136/2819 2846/3138/2821 2554/3087/2772 +f 2846/3138/2821 3418/3140/2823 2843/3089/2774 +f 2846/3138/2821 2566/3137/2820 3134/3139/2822 +f 3418/3140/2823 3134/3139/2822 2567/3141/2824 +f 3418/3140/2823 2918/3142/2825 2555/3091/2776 +f 2918/3142/2825 3419/3144/2827 2914/3093/2778 +f 2918/3142/2825 2567/3141/2824 3204/3143/2826 +f 3419/3144/2827 3204/3143/2826 2568/3145/2828 +f 3419/3144/2827 2984/3146/2829 2556/3095/2780 +f 2984/3146/2829 3420/3148/2831 2982/3097/2782 +f 2984/3146/2829 2568/3145/2828 3271/3147/2830 +f 3420/3148/2831 3271/3147/2830 2569/3149/2832 +f 3420/3148/2831 3056/3150/2833 2557/3099/2784 +f 3056/3150/2833 3421/3152/2835 3053/3101/2786 +f 3056/3150/2833 2569/3149/2832 2769/3151/2834 +f 3421/3152/2835 2769/3151/2834 2570/3153/2836 +f 3421/3152/2835 3135/3154/2837 2558/3103/2788 +f 3135/3154/2837 3422/3156/2839 3132/3105/2790 +f 3135/3154/2837 2570/3153/2836 2847/3155/2838 +f 3422/3156/2839 2847/3155/2838 2571/3157/2840 +f 3422/3156/2839 3205/3158/2841 2559/3107/2792 +f 2559/3110/2792 3205/3161/2841 3423/3159/2842 +f 2571/3160/2840 2919/3162/2843 3423/3159/2842 +f 2919/3162/2843 2572/3165/2846 3272/3163/2844 +f 3202/3112/2795 3423/3159/2842 3272/3163/2844 +f 2560/3115/2798 3272/3163/2844 3424/3164/2845 +f 2572/3165/2846 2985/3166/2847 3424/3164/2845 +f 2985/3166/2847 2573/3169/2850 2770/3167/2848 +f 3268/3116/2799 3424/3164/2845 2770/3167/2848 +f 2561/3119/2802 2770/3167/2848 3425/3168/2849 +f 2573/3169/2850 3057/3170/2851 3425/3168/2849 +f 3057/3170/2851 2574/3173/2854 2848/3171/2852 +f 2766/3120/2803 3425/3168/2849 2848/3171/2852 +f 2562/3123/2806 2848/3171/2852 3426/3172/2853 +f 2574/3173/2854 3136/3174/2855 3426/3172/2853 +f 3136/3174/2855 2575/3177/2858 2920/3175/2856 +f 2845/3124/2807 3426/3172/2853 2920/3175/2856 +f 2563/3127/2810 2920/3175/2856 3427/3176/2857 +f 2575/3177/2858 3206/3178/2859 3427/3176/2857 +f 3206/3178/2859 2576/3181/2862 2986/3179/2860 +f 2916/3128/2811 3427/3176/2857 2986/3179/2860 +f 2564/3131/2814 2986/3179/2860 3428/3180/2861 +f 2576/3181/2862 3058/3182/2863 3428/3180/2861 +f 3058/3182/2863 2565/3184/2865 2768/3133/2816 +f 2767/3132/2815 3428/3180/2861 2768/3133/2816 +f 3059/3183/2864 3429/3186/2867 3055/3135/2818 +f 3059/3183/2864 2577/3833/2350 2771/3185/2866 +f 3429/3186/2867 2771/3185/2866 2578/3187/2868 +f 3429/3186/2867 3137/3188/2869 2566/3137/2820 +f 3137/3188/2869 3430/3190/2871 3134/3139/2822 +f 3137/3188/2869 2578/3187/2868 2849/3189/2870 +f 3430/3190/2871 2849/3189/2870 2579/3191/2872 +f 3430/3190/2871 3207/3192/2873 2567/3141/2824 +f 3207/3192/2873 3431/3194/2875 3204/3143/2826 +f 3207/3192/2873 2579/3191/2872 2921/3193/2874 +f 3431/3194/2875 2921/3193/2874 2580/3195/2876 +f 3431/3194/2875 3273/3196/2877 2568/3145/2828 +f 3273/3196/2877 3432/3198/2879 3271/3147/2830 +f 3273/3196/2877 2580/3195/2876 2987/3197/2878 +f 3432/3198/2879 2987/3197/2878 2581/3199/2880 +f 3432/3198/2879 2772/3200/2881 2569/3149/2832 +f 2772/3200/2881 3433/3202/2883 2769/3151/2834 +f 2772/3200/2881 2581/3199/2880 3060/3201/2882 +f 3433/3202/2883 3060/3201/2882 2582/3203/2884 +f 3433/3202/2883 2850/3204/2885 2570/3153/2836 +f 2850/3204/2885 3434/3206/2887 2847/3155/2838 +f 2850/3204/2885 2582/3203/2884 3138/3205/2886 +f 3434/3206/2887 3138/3205/2886 2583/3207/2315 +f 3434/3206/2887 2922/3208/2888 2571/3157/2840 +f 2571/3160/2840 2922/3211/2888 3435/3209/2889 +f 2583/3210/2315 3208/3212/2890 3435/3209/2889 +f 3208/3212/2890 2584/3215/2893 2988/3213/2891 +f 2919/3162/2843 3435/3209/2889 2988/3213/2891 +f 2572/3165/2846 2988/3213/2891 3436/3214/2892 +f 2584/3215/2893 3274/3216/2894 3436/3214/2892 +f 3274/3216/2894 2585/3219/2897 3061/3217/2895 +f 2985/3166/2847 3436/3214/2892 3061/3217/2895 +f 2573/3169/2850 3061/3217/2895 3437/3218/2896 +f 2585/3219/2897 2773/3220/2898 3437/3218/2896 +f 2773/3220/2898 2586/3223/2901 3139/3221/2899 +f 3057/3170/2851 3437/3218/2896 3139/3221/2899 +f 2574/3173/2854 3139/3221/2899 3438/3222/2900 +f 2586/3223/2901 2851/3224/2902 3438/3222/2900 +f 2851/3224/2902 2587/3227/2905 3209/3225/2903 +f 3136/3174/2855 3438/3222/2900 3209/3225/2903 +f 2575/3177/2858 3209/3225/2903 3439/3226/2904 +f 2587/3227/2905 2923/3228/2906 3439/3226/2904 +f 2923/3228/2906 2588/3231/2909 3275/3229/2907 +f 3206/3178/2859 3439/3226/2904 3275/3229/2907 +f 2576/3181/2862 3275/3229/2907 3440/3230/2908 +f 2588/3231/2909 2774/3232/2910 3440/3230/2908 +f 2774/3232/2910 2577/3833/2350 3059/3183/2864 +f 3058/3182/2863 3440/3230/2908 3059/3183/2864 +f 2775/3233/2349 3441/3237/2912 2771/3234/2866 +f 2775/3233/2349 2589/3308/2348 3062/3236/2911 +f 3441/3237/2912 3062/3236/2911 2590/3238/2913 +f 3441/3237/2912 2852/3239/2914 2578/3240/2868 +f 2852/3239/2914 3442/3243/2916 2849/3241/2870 +f 2852/3239/2914 2590/3238/2913 3140/3242/2915 +f 3442/3243/2916 3140/3242/2915 2591/3244/2917 +f 3442/3243/2916 2924/3245/2918 2579/3246/2872 +f 2924/3245/2918 3443/3249/2920 2921/3247/2874 +f 2924/3245/2918 2591/3244/2917 3210/3248/2919 +f 3443/3249/2920 3210/3248/2919 2592/3250/2921 +f 3443/3249/2920 2989/3251/2922 2580/3252/2876 +f 2989/3251/2922 3444/3255/2924 2987/3253/2878 +f 2989/3251/2922 2592/3250/2921 3276/3254/2923 +f 3444/3255/2924 3276/3254/2923 2593/3256/2925 +f 3444/3255/2924 3064/3257/2926 2581/3258/2880 +f 3064/3257/2926 3445/3261/2928 3060/3259/2882 +f 3064/3257/2926 2593/3256/2925 2776/3260/2927 +f 3445/3261/2928 2776/3260/2927 2594/3262/2929 +f 3445/3261/2928 3141/3263/2930 2582/3264/2884 +f 3141/3263/2930 3446/3267/2932 3138/3265/2886 +f 3141/3263/2930 2594/3262/2929 2854/3266/2931 +f 3446/3267/2932 2854/3266/2931 2595/3268/2385 +f 3446/3267/2932 3211/3269/2313 2583/3270/2315 +f 2583/3271/2315 3211/3275/2313 3447/3272/2933 +f 2595/3274/2385 2925/3276/2934 3447/3272/2933 +f 2925/3276/2934 2596/3281/2937 3277/3277/2935 +f 3208/3273/2890 3447/3272/2933 3277/3277/2935 +f 2584/3278/2893 3277/3277/2935 3448/3279/2936 +f 2596/3281/2937 2990/3282/2938 3448/3279/2936 +f 2990/3282/2938 2597/3287/2941 2777/3283/2939 +f 3274/3280/2894 3448/3279/2936 2777/3283/2939 +f 2585/3284/2897 2777/3283/2939 3449/3285/2940 +f 2597/3287/2941 3065/3288/2942 3449/3285/2940 +f 3065/3288/2942 2598/3293/2945 2855/3289/2943 +f 2773/3286/2898 3449/3285/2940 2855/3289/2943 +f 2586/3290/2901 2855/3289/2943 3450/3291/2944 +f 2598/3293/2945 3142/3294/2946 3450/3291/2944 +f 3142/3294/2946 2599/3299/2949 2926/3295/2947 +f 2851/3292/2902 3450/3291/2944 2926/3295/2947 +f 2587/3296/2905 2926/3295/2947 3451/3297/2948 +f 2599/3299/2949 3212/3300/2950 3451/3297/2948 +f 3212/3300/2950 2600/3305/2953 2991/3301/2951 +f 2923/3298/2906 3451/3297/2948 2991/3301/2951 +f 2588/3302/2909 2991/3301/2951 3452/3303/2952 +f 2600/3305/2953 3066/3306/2954 3452/3303/2952 +f 3066/3306/2954 2589/3308/2348 2775/3233/2349 +f 2774/3304/2910 3452/3303/2952 2775/3233/2349 +f 3067/3307/2409 3453/3310/2956 3062/3236/2911 +f 3067/3307/2409 2601/3358/2408 2778/3309/2955 +f 3453/3310/2956 2778/3309/2955 2602/3311/2957 +f 3453/3310/2956 3143/3312/2958 2590/3238/2913 +f 3143/3312/2958 3454/3314/2960 3140/3242/2915 +f 3143/3312/2958 2602/3311/2957 2856/3313/2959 +f 3454/3314/2960 2856/3313/2959 2603/3315/2961 +f 3454/3314/2960 3213/3316/2962 2591/3244/2917 +f 3213/3316/2962 3455/3318/2964 3210/3248/2919 +f 3213/3316/2962 2603/3315/2961 2927/3317/2963 +f 3455/3318/2964 2927/3317/2963 2604/3319/2965 +f 3455/3318/2964 3278/3320/2966 2592/3250/2921 +f 3278/3320/2966 3456/3322/2968 3276/3254/2923 +f 3278/3320/2966 2604/3319/2965 2992/3321/2967 +f 3456/3322/2968 2992/3321/2967 2605/3323/2969 +f 3456/3322/2968 2779/3324/2970 2593/3256/2925 +f 2779/3324/2970 3457/3326/2972 2776/3260/2927 +f 2779/3324/2970 2605/3323/2969 3068/3325/2971 +f 3457/3326/2972 3068/3325/2971 2606/3327/2973 +f 3457/3326/2972 2857/3328/2974 2594/3262/2929 +f 2857/3328/2974 3458/3330/2976 2854/3266/2931 +f 2857/3328/2974 2606/3327/2973 3144/3329/2975 +f 3458/3330/2976 3144/3329/2975 2607/3331/2433 +f 3458/3330/2976 2928/3332/2384 2595/3268/2385 +f 2595/3274/2385 2928/3335/2384 3459/3333/2977 +f 2607/3334/2433 3214/3336/2978 3459/3333/2977 +f 3214/3336/2978 2608/3339/2981 2993/3337/2979 +f 2925/3276/2934 3459/3333/2977 2993/3337/2979 +f 2596/3281/2937 2993/3337/2979 3460/3338/2980 +f 2608/3339/2981 3279/3340/2982 3460/3338/2980 +f 3279/3340/2982 2609/3343/2985 3069/3341/2983 +f 2990/3282/2938 3460/3338/2980 3069/3341/2983 +f 2597/3287/2941 3069/3341/2983 3461/3342/2984 +f 2609/3343/2985 2780/3344/2986 3461/3342/2984 +f 2780/3344/2986 2610/3347/2989 3145/3345/2987 +f 3065/3288/2942 3461/3342/2984 3145/3345/2987 +f 2598/3293/2945 3145/3345/2987 3462/3346/2988 +f 2610/3347/2989 2858/3348/2990 3462/3346/2988 +f 2858/3348/2990 2611/3351/2993 3215/3349/2991 +f 3142/3294/2946 3462/3346/2988 3215/3349/2991 +f 2599/3299/2949 3215/3349/2991 3463/3350/2992 +f 2611/3351/2993 2929/3352/2994 3463/3350/2992 +f 2929/3352/2994 2612/3355/2997 3280/3353/2995 +f 3212/3300/2950 3463/3350/2992 3280/3353/2995 +f 2600/3305/2953 3280/3353/2995 3464/3354/2996 +f 2612/3355/2997 2781/3356/2998 3464/3354/2996 +f 2781/3356/2998 2601/3358/2408 3067/3307/2409 +f 3066/3306/2954 3464/3354/2996 3067/3307/2409 +f 2782/3357/2999 3465/3360/3001 2778/3309/2955 +f 2782/3357/2999 2613/3408/2456 3070/3359/3000 +f 3465/3360/3001 3070/3359/3000 2614/3361/3002 +f 3465/3360/3001 2859/3362/3003 2602/3311/2957 +f 2859/3362/3003 3466/3364/3005 2856/3313/2959 +f 2859/3362/3003 2614/3361/3002 3146/3363/3004 +f 3466/3364/3005 3146/3363/3004 2615/3365/3006 +f 3466/3364/3005 2930/3366/3007 2603/3315/2961 +f 2930/3366/3007 3467/3368/3009 2927/3317/2963 +f 2930/3366/3007 2615/3365/3006 3216/3367/3008 +f 3467/3368/3009 3216/3367/3008 2616/3369/3010 +f 3467/3368/3009 2994/3370/3011 2604/3319/2965 +f 2994/3370/3011 3468/3372/3013 2992/3321/2967 +f 2994/3370/3011 2616/3369/3010 3281/3371/3012 +f 3468/3372/3013 3281/3371/3012 2617/3373/3014 +f 3468/3372/3013 3071/3374/3015 2605/3323/2969 +f 3071/3374/3015 3469/3376/3017 3068/3325/2971 +f 3071/3374/3015 2617/3373/3014 2783/3375/3016 +f 3469/3376/3017 2783/3375/3016 2618/3377/3018 +f 3469/3376/3017 3147/3378/3019 2606/3327/2973 +f 3147/3378/3019 3470/3380/3021 3144/3329/2975 +f 3147/3378/3019 2618/3377/3018 2860/3379/3020 +f 3470/3380/3021 2860/3379/3020 2619/3381/2481 +f 3470/3380/3021 3218/3382/2432 2607/3331/2433 +f 2607/3334/2433 3218/3385/2432 3471/3383/3022 +f 2619/3384/2481 2931/3386/3023 3471/3383/3022 +f 2931/3386/3023 2620/3389/3026 3282/3387/3024 +f 3214/3336/2978 3471/3383/3022 3282/3387/3024 +f 2608/3339/2981 3282/3387/3024 3472/3388/3025 +f 2620/3389/3026 2996/3390/3027 3472/3388/3025 +f 2996/3390/3027 2621/3393/3030 2784/3391/3028 +f 3279/3340/2982 3472/3388/3025 2784/3391/3028 +f 2609/3343/2985 2784/3391/3028 3473/3392/3029 +f 2621/3393/3030 3072/3394/3031 3473/3392/3029 +f 3072/3394/3031 2622/3397/3034 2861/3395/3032 +f 2780/3344/2986 3473/3392/3029 2861/3395/3032 +f 2610/3347/2989 2861/3395/3032 3474/3396/3033 +f 2622/3397/3034 3148/3398/3035 3474/3396/3033 +f 3148/3398/3035 2623/3401/3038 2932/3399/3036 +f 2858/3348/2990 3474/3396/3033 2932/3399/3036 +f 2611/3351/2993 2932/3399/3036 3475/3400/3037 +f 2623/3401/3038 3219/3402/3039 3475/3400/3037 +f 3219/3402/3039 2624/3405/3042 2997/3403/3040 +f 2929/3352/2994 3475/3400/3037 2997/3403/3040 +f 2612/3355/2997 2997/3403/3040 3476/3404/3041 +f 2624/3405/3042 3073/3406/3043 3476/3404/3041 +f 3073/3406/3043 2613/3408/2456 2782/3357/2999 +f 2781/3356/2998 3476/3404/3041 2782/3357/2999 +f 3074/3407/2505 3477/3410/3045 3070/3359/3000 +f 3074/3407/2505 2625/3458/2504 2785/3409/3044 +f 3477/3410/3045 2785/3409/3044 2626/3411/3046 +f 3477/3410/3045 3149/3412/3047 2614/3361/3002 +f 3149/3412/3047 3478/3414/3049 3146/3363/3004 +f 3149/3412/3047 2626/3411/3046 2862/3413/3048 +f 3478/3414/3049 2862/3413/3048 2627/3415/3050 +f 3478/3414/3049 3220/3416/3051 2615/3365/3006 +f 3220/3416/3051 3479/3418/3053 3216/3367/3008 +f 3220/3416/3051 2627/3415/3050 2933/3417/3052 +f 3479/3418/3053 2933/3417/3052 2628/3419/3054 +f 3479/3418/3053 3283/3420/3055 2616/3369/3010 +f 3283/3420/3055 3480/3422/3057 3281/3371/3012 +f 3283/3420/3055 2628/3419/3054 2998/3421/3056 +f 3480/3422/3057 2998/3421/3056 2629/3423/3058 +f 3480/3422/3057 2786/3424/3059 2617/3373/3014 +f 2786/3424/3059 3481/3426/3061 2783/3375/3016 +f 2786/3424/3059 2629/3423/3058 3075/3425/3060 +f 3481/3426/3061 3075/3425/3060 2630/3427/3062 +f 3481/3426/3061 2863/3428/3063 2618/3377/3018 +f 2863/3428/3063 3482/3430/3065 2860/3379/3020 +f 2863/3428/3063 2630/3427/3062 3150/3429/3064 +f 3482/3430/3065 3150/3429/3064 2631/3431/2529 +f 3482/3430/3065 2934/3432/2480 2619/3381/2481 +f 2619/3384/2481 2934/3435/2480 3483/3433/3066 +f 2631/3434/2529 3221/3436/3067 3483/3433/3066 +f 3221/3436/3067 2632/3439/3070 2999/3437/3068 +f 2931/3386/3023 3483/3433/3066 2999/3437/3068 +f 2620/3389/3026 2999/3437/3068 3484/3438/3069 +f 2632/3439/3070 3284/3440/3071 3484/3438/3069 +f 3284/3440/3071 2633/3443/3074 3076/3441/3072 +f 2996/3390/3027 3484/3438/3069 3076/3441/3072 +f 2621/3393/3030 3076/3441/3072 3485/3442/3073 +f 2633/3443/3074 2787/3444/3075 3485/3442/3073 +f 2787/3444/3075 2634/3447/3078 3151/3445/3076 +f 3072/3394/3031 3485/3442/3073 3151/3445/3076 +f 2622/3397/3034 3151/3445/3076 3486/3446/3077 +f 2634/3447/3078 2864/3448/3079 3486/3446/3077 +f 2864/3448/3079 2635/3451/3082 3222/3449/3080 +f 3148/3398/3035 3486/3446/3077 3222/3449/3080 +f 2623/3401/3038 3222/3449/3080 3487/3450/3081 +f 2635/3451/3082 2935/3452/3083 3487/3450/3081 +f 2935/3452/3083 2636/3455/3086 3285/3453/3084 +f 3219/3402/3039 3487/3450/3081 3285/3453/3084 +f 2624/3405/3042 3285/3453/3084 3488/3454/3085 +f 2636/3455/3086 2788/3456/3087 3488/3454/3085 +f 2788/3456/3087 2625/3458/2504 3074/3407/2505 +f 3073/3406/3043 3488/3454/3085 3074/3407/2505 +f 2789/3457/2553 3489/3460/3089 2785/3409/3044 +f 2789/3457/2553 2637/3508/2552 3077/3459/3088 +f 3489/3460/3089 3077/3459/3088 2638/3461/3090 +f 3489/3460/3089 2865/3462/3091 2626/3411/3046 +f 2865/3462/3091 3490/3464/3093 2862/3413/3048 +f 2865/3462/3091 2638/3461/3090 3152/3463/3092 +f 3490/3464/3093 3152/3463/3092 2639/3465/3094 +f 3490/3464/3093 2936/3466/3095 2627/3415/3050 +f 2936/3466/3095 3491/3468/3097 2933/3417/3052 +f 2936/3466/3095 2639/3465/3094 3223/3467/3096 +f 3491/3468/3097 3223/3467/3096 2640/3469/3098 +f 3491/3468/3097 3000/3470/3099 2628/3419/3054 +f 3000/3470/3099 3492/3472/3101 2998/3421/3056 +f 3000/3470/3099 2640/3469/3098 3286/3471/3100 +f 3492/3472/3101 3286/3471/3100 2641/3473/3102 +f 3492/3472/3101 3078/3474/3103 2629/3423/3058 +f 3078/3474/3103 3493/3476/3105 3075/3425/3060 +f 3078/3474/3103 2641/3473/3102 2790/3475/3104 +f 3493/3476/3105 2790/3475/3104 2642/3477/3106 +f 3493/3476/3105 3153/3478/3107 2630/3427/3062 +f 3153/3478/3107 3494/3480/3109 3150/3429/3064 +f 3153/3478/3107 2642/3477/3106 2866/3479/3108 +f 3494/3480/3109 2866/3479/3108 2643/3481/2577 +f 3494/3480/3109 3224/3482/2528 2631/3431/2529 +f 2631/3434/2529 3224/3485/2528 3495/3483/3110 +f 2643/3484/2577 2937/3486/3111 3495/3483/3110 +f 2937/3486/3111 2644/3489/3114 3287/3487/3112 +f 3221/3436/3067 3495/3483/3110 3287/3487/3112 +f 2632/3439/3070 3287/3487/3112 3496/3488/3113 +f 2644/3489/3114 3001/3490/3115 3496/3488/3113 +f 3001/3490/3115 2645/3493/3118 2792/3491/3116 +f 3284/3440/3071 3496/3488/3113 2792/3491/3116 +f 2633/3443/3074 2792/3491/3116 3497/3492/3117 +f 2645/3493/3118 3079/3494/3119 3497/3492/3117 +f 3079/3494/3119 2646/3497/3122 2867/3495/3120 +f 2787/3444/3075 3497/3492/3117 2867/3495/3120 +f 2634/3447/3078 2867/3495/3120 3498/3496/3121 +f 2646/3497/3122 3155/3498/3123 3498/3496/3121 +f 3155/3498/3123 2647/3501/3126 2938/3499/3124 +f 2864/3448/3079 3498/3496/3121 2938/3499/3124 +f 2635/3451/3082 2938/3499/3124 3499/3500/3125 +f 2647/3501/3126 3225/3502/3127 3499/3500/3125 +f 3225/3502/3127 2648/3505/3130 3002/3503/3128 +f 2935/3452/3083 3499/3500/3125 3002/3503/3128 +f 2636/3455/3086 3002/3503/3128 3500/3504/3129 +f 2648/3505/3130 3080/3506/3131 3500/3504/3129 +f 3080/3506/3131 2637/3508/2552 2789/3457/2553 +f 2788/3456/3087 3500/3504/3129 2789/3457/2553 +f 3081/3507/2601 3501/3510/3133 3077/3459/3088 +f 3081/3507/2601 2649/3558/2600 2793/3509/3132 +f 3501/3510/3133 2793/3509/3132 2650/3511/3134 +f 3501/3510/3133 3156/3512/3135 2638/3461/3090 +f 3156/3512/3135 3502/3514/3137 3152/3463/3092 +f 3156/3512/3135 2650/3511/3134 2868/3513/3136 +f 3502/3514/3137 2868/3513/3136 2651/3515/3138 +f 3502/3514/3137 3226/3516/3139 2639/3465/3094 +f 3226/3516/3139 3503/3518/3141 3223/3467/3096 +f 3226/3516/3139 2651/3515/3138 2939/3517/3140 +f 3503/3518/3141 2939/3517/3140 2652/3519/3142 +f 3503/3518/3141 3288/3520/3143 2640/3469/3098 +f 3288/3520/3143 3504/3522/3145 3286/3471/3100 +f 3288/3520/3143 2652/3519/3142 3003/3521/3144 +f 3504/3522/3145 3003/3521/3144 2653/3523/3146 +f 3504/3522/3145 2794/3524/3147 2641/3473/3102 +f 2794/3524/3147 3505/3526/3149 2790/3475/3104 +f 2794/3524/3147 2653/3523/3146 3082/3525/3148 +f 3505/3526/3149 3082/3525/3148 2654/3527/3150 +f 3505/3526/3149 2869/3528/3151 2642/3477/3106 +f 2869/3528/3151 3506/3530/3153 2866/3479/3108 +f 2869/3528/3151 2654/3527/3150 3157/3529/3152 +f 3506/3530/3153 3157/3529/3152 2655/3531/2625 +f 3506/3530/3153 2940/3532/2576 2643/3481/2577 +f 2643/3484/2577 2940/3535/2576 3507/3533/3154 +f 2655/3534/2625 3227/3536/3155 3507/3533/3154 +f 3227/3536/3155 2656/3539/3158 3004/3537/3156 +f 2937/3486/3111 3507/3533/3154 3004/3537/3156 +f 2644/3489/3114 3004/3537/3156 3508/3538/3157 +f 2656/3539/3158 3289/3540/3159 3508/3538/3157 +f 3289/3540/3159 2657/3543/3162 3083/3541/3160 +f 3001/3490/3115 3508/3538/3157 3083/3541/3160 +f 2645/3493/3118 3083/3541/3160 3509/3542/3161 +f 2657/3543/3162 2795/3544/3163 3509/3542/3161 +f 2795/3544/3163 2658/3547/3166 3158/3545/3164 +f 3079/3494/3119 3509/3542/3161 3158/3545/3164 +f 2646/3497/3122 3158/3545/3164 3510/3546/3165 +f 2658/3547/3166 2870/3548/3167 3510/3546/3165 +f 2870/3548/3167 2659/3551/3170 3228/3549/3168 +f 3155/3498/3123 3510/3546/3165 3228/3549/3168 +f 2647/3501/3126 3228/3549/3168 3511/3550/3169 +f 2659/3551/3170 2941/3552/3171 3511/3550/3169 +f 2941/3552/3171 2660/3555/3174 3290/3553/3172 +f 3225/3502/3127 3511/3550/3169 3290/3553/3172 +f 2648/3505/3130 3290/3553/3172 3512/3554/3173 +f 2660/3555/3174 2796/3556/3175 3512/3554/3173 +f 2796/3556/3175 2649/3558/2600 3081/3507/2601 +f 3080/3506/3131 3512/3554/3173 3081/3507/2601 +f 2797/3557/2649 3513/3560/3177 2793/3509/3132 +f 2797/3557/2649 2661/3608/2648 3084/3559/3176 +f 3513/3560/3177 3084/3559/3176 2662/3561/3178 +f 3513/3560/3177 2871/3562/3179 2650/3511/3134 +f 2871/3562/3179 3514/3564/3181 2868/3513/3136 +f 2871/3562/3179 2662/3561/3178 3159/3563/3180 +f 3514/3564/3181 3159/3563/3180 2663/3565/3182 +f 3514/3564/3181 2942/3566/3183 2651/3515/3138 +f 2942/3566/3183 3515/3568/3185 2939/3517/3140 +f 2942/3566/3183 2663/3565/3182 3229/3567/3184 +f 3515/3568/3185 3229/3567/3184 2664/3569/3186 +f 3515/3568/3185 3005/3570/3187 2652/3519/3142 +f 3005/3570/3187 3516/3572/3189 3003/3521/3144 +f 3005/3570/3187 2664/3569/3186 3291/3571/3188 +f 3516/3572/3189 3291/3571/3188 2665/3573/3190 +f 3516/3572/3189 3085/3574/3191 2653/3523/3146 +f 3085/3574/3191 3517/3576/3193 3082/3525/3148 +f 3085/3574/3191 2665/3573/3190 2798/3575/3192 +f 3517/3576/3193 2798/3575/3192 2666/3577/3194 +f 3517/3576/3193 3160/3578/3195 2654/3527/3150 +f 3160/3578/3195 3518/3580/3197 3157/3529/3152 +f 3160/3578/3195 2666/3577/3194 2872/3579/3196 +f 3518/3580/3197 2872/3579/3196 2667/3581/2673 +f 3518/3580/3197 3230/3582/2624 2655/3531/2625 +f 2655/3534/2625 3230/3585/2624 3519/3583/3198 +f 2667/3584/2673 2943/3586/3199 3519/3583/3198 +f 2943/3586/3199 2668/3589/3202 3292/3587/3200 +f 3227/3536/3155 3519/3583/3198 3292/3587/3200 +f 2656/3539/3158 3292/3587/3200 3520/3588/3201 +f 2668/3589/3202 3006/3590/3203 3520/3588/3201 +f 3006/3590/3203 2669/3593/3206 2799/3591/3204 +f 3289/3540/3159 3520/3588/3201 2799/3591/3204 +f 2657/3543/3162 2799/3591/3204 3521/3592/3205 +f 2669/3593/3206 3086/3594/3207 3521/3592/3205 +f 3086/3594/3207 2670/3597/3210 2873/3595/3208 +f 2795/3544/3163 3521/3592/3205 2873/3595/3208 +f 2658/3547/3166 2873/3595/3208 3522/3596/3209 +f 2670/3597/3210 3161/3598/3211 3522/3596/3209 +f 3161/3598/3211 2671/3601/3214 2945/3599/3212 +f 2870/3548/3167 3522/3596/3209 2945/3599/3212 +f 2659/3551/3170 2945/3599/3212 3523/3600/3213 +f 2671/3601/3214 3231/3602/3215 3523/3600/3213 +f 3231/3602/3215 2672/3605/3218 3007/3603/3216 +f 2941/3552/3171 3523/3600/3213 3007/3603/3216 +f 2660/3555/3174 3007/3603/3216 3524/3604/3217 +f 2672/3605/3218 3087/3606/3219 3524/3604/3217 +f 3087/3606/3219 2661/3608/2648 2797/3557/2649 +f 2796/3556/3175 3524/3604/3217 2797/3557/2649 +f 3088/3607/2697 3525/3610/3221 3084/3559/3176 +f 3088/3607/2697 2673/3658/2696 2800/3609/3220 +f 3525/3610/3221 2800/3609/3220 2674/3611/3222 +f 3525/3610/3221 3162/3612/3223 2662/3561/3178 +f 3162/3612/3223 3526/3614/3225 3159/3563/3180 +f 3162/3612/3223 2674/3611/3222 2874/3613/3224 +f 3526/3614/3225 2874/3613/3224 2675/3615/3226 +f 3526/3614/3225 3232/3616/3227 2663/3565/3182 +f 3232/3616/3227 3527/3618/3229 3229/3567/3184 +f 3232/3616/3227 2675/3615/3226 2946/3617/3228 +f 3527/3618/3229 2946/3617/3228 2676/3619/3230 +f 3527/3618/3229 3294/3620/3231 2664/3569/3186 +f 3294/3620/3231 3528/3622/3233 3291/3571/3188 +f 3294/3620/3231 2676/3619/3230 3008/3621/3232 +f 3528/3622/3233 3008/3621/3232 2677/3623/3234 +f 3528/3622/3233 2801/3624/3235 2665/3573/3190 +f 2801/3624/3235 3529/3626/3237 2798/3575/3192 +f 2801/3624/3235 2677/3623/3234 3089/3625/3236 +f 3529/3626/3237 3089/3625/3236 2678/3627/3238 +f 3529/3626/3237 2875/3628/3239 2666/3577/3194 +f 2875/3628/3239 3530/3630/3241 2872/3579/3196 +f 2875/3628/3239 2678/3627/3238 3163/3629/3240 +f 3530/3630/3241 3163/3629/3240 2679/3631/2721 +f 3530/3630/3241 2947/3632/2672 2667/3581/2673 +f 2667/3584/2673 2947/3635/2672 3531/3633/3242 +f 2679/3634/2721 3233/3636/3243 3531/3633/3242 +f 3233/3636/3243 2680/3639/3246 3009/3637/3244 +f 2943/3586/3199 3531/3633/3242 3009/3637/3244 +f 2668/3589/3202 3009/3637/3244 3532/3638/3245 +f 2680/3639/3246 3295/3640/3247 3532/3638/3245 +f 3295/3640/3247 2681/3643/3250 3090/3641/3248 +f 3006/3590/3203 3532/3638/3245 3090/3641/3248 +f 2669/3593/3206 3090/3641/3248 3533/3642/3249 +f 2681/3643/3250 2802/3644/3251 3533/3642/3249 +f 2802/3644/3251 2682/3647/3254 3164/3645/3252 +f 3086/3594/3207 3533/3642/3249 3164/3645/3252 +f 2670/3597/3210 3164/3645/3252 3534/3646/3253 +f 2682/3647/3254 2876/3648/3255 3534/3646/3253 +f 2876/3648/3255 2683/3651/3258 3234/3649/3256 +f 3161/3598/3211 3534/3646/3253 3234/3649/3256 +f 2671/3601/3214 3234/3649/3256 3535/3650/3257 +f 2683/3651/3258 2948/3652/3259 3535/3650/3257 +f 2948/3652/3259 2684/3655/3262 3296/3653/3260 +f 3231/3602/3215 3535/3650/3257 3296/3653/3260 +f 2672/3605/3218 3296/3653/3260 3536/3654/3261 +f 2684/3655/3262 2803/3656/3263 3536/3654/3261 +f 2803/3656/3263 2673/3658/2696 3088/3607/2697 +f 3087/3606/3219 3536/3654/3261 3088/3607/2697 +f 2804/3657/2745 3537/3660/3265 2800/3609/3220 +f 2804/3657/2745 2685/3708/2744 3091/3659/3264 +f 3537/3660/3265 3091/3659/3264 2686/3661/3266 +f 3537/3660/3265 2877/3662/3267 2674/3611/3222 +f 2877/3662/3267 3538/3664/3269 2874/3613/3224 +f 2877/3662/3267 2686/3661/3266 3165/3663/3268 +f 3538/3664/3269 3165/3663/3268 2687/3665/3270 +f 3538/3664/3269 2949/3666/3271 2675/3615/3226 +f 2949/3666/3271 3539/3668/3273 2946/3617/3228 +f 2949/3666/3271 2687/3665/3270 3235/3667/3272 +f 3539/3668/3273 3235/3667/3272 2688/3669/3274 +f 3539/3668/3273 3010/3670/3275 2676/3619/3230 +f 3010/3670/3275 3540/3672/3277 3008/3621/3232 +f 3010/3670/3275 2688/3669/3274 3166/3671/3276 +f 3540/3672/3277 3166/3671/3276 2689/3673/3278 +f 3540/3672/3277 3092/3674/3279 2677/3623/3234 +f 3092/3674/3279 3541/3676/3281 3089/3625/3236 +f 3092/3674/3279 2689/3673/3278 2805/3675/3280 +f 3541/3676/3281 2805/3675/3280 2690/3677/3282 +f 3541/3676/3281 3011/3678/3283 2678/3627/3238 +f 3011/3678/3283 3542/3680/3285 3163/3629/3240 +f 3011/3678/3283 2690/3677/3282 2722/3679/3284 +f 3542/3680/3285 2722/3679/3284 2691/3681/2769 +f 3542/3680/3285 3236/3682/2720 2679/3631/2721 +f 2679/3634/2721 3236/3685/2720 3543/3683/3286 +f 2691/3684/2769 2950/3686/3287 3543/3683/3286 +f 2950/3686/3287 2692/3689/3290 3167/3687/3288 +f 3233/3636/3243 3543/3683/3286 3167/3687/3288 +f 2680/3639/3246 3167/3687/3288 3544/3688/3289 +f 2692/3689/3290 2879/3690/3291 3544/3688/3289 +f 2879/3690/3291 2693/3693/3294 2807/3691/3292 +f 3295/3640/3247 3544/3688/3289 2807/3691/3292 +f 2681/3643/3250 2807/3691/3292 3545/3692/3293 +f 2693/3693/3294 3093/3694/3295 3545/3692/3293 +f 3093/3694/3295 2694/3697/3298 2723/3695/3296 +f 2802/3644/3251 3545/3692/3293 2723/3695/3296 +f 2682/3647/3254 2723/3695/3296 3546/3696/3297 +f 2694/3697/3298 3013/3698/3299 3546/3696/3297 +f 3013/3698/3299 2695/3701/3302 2952/3699/3300 +f 2876/3648/3255 3546/3696/3297 2952/3699/3300 +f 2683/3651/3258 2952/3699/3300 3547/3700/3301 +f 2695/3701/3302 3237/3702/3303 3547/3700/3301 +f 3237/3702/3303 2696/3705/3306 2880/3703/3304 +f 2948/3652/3259 3547/3700/3301 2880/3703/3304 +f 2684/3655/3262 2880/3703/3304 3548/3704/3305 +f 2696/3705/3306 3095/3706/3307 3548/3704/3305 +f 3095/3706/3307 2685/3708/2744 2804/3657/2745 +f 2803/3656/3263 3548/3704/3305 2804/3657/2745 +f 3096/3707/2793 3549/3710/3309 3091/3659/3264 +f 3096/3707/2793 2697/3758/2792 2808/3709/3308 +f 3549/3710/3309 2808/3709/3308 2698/3711/3310 +f 3549/3710/3309 3014/3712/3311 2686/3661/3266 +f 3014/3712/3311 3550/3714/3313 3165/3663/3268 +f 3014/3712/3311 2698/3711/3310 2725/3713/3312 +f 3550/3714/3313 2725/3713/3312 2699/3715/3314 +f 3550/3714/3313 3239/3716/3315 2687/3665/3270 +f 3239/3716/3315 3551/3718/3317 3235/3667/3272 +f 3239/3716/3315 2699/3715/3314 2953/3717/3316 +f 3551/3718/3317 2953/3717/3316 2700/3719/3318 +f 3551/3718/3317 3169/3720/3319 2688/3669/3274 +f 3169/3720/3319 3552/3722/3321 3166/3671/3276 +f 3169/3720/3319 2700/3719/3318 2882/3721/3320 +f 3552/3722/3321 2882/3721/3320 2701/3723/3322 +f 3552/3722/3321 2810/3724/3323 2689/3673/3278 +f 2810/3724/3323 3553/3726/3325 2805/3675/3280 +f 2810/3724/3323 2701/3723/3322 3097/3725/3324 +f 3553/3726/3325 3097/3725/3324 2702/3727/3326 +f 3553/3726/3325 2728/3728/3327 2690/3677/3282 +f 2728/3728/3327 3554/3730/3329 2722/3679/3284 +f 2728/3728/3327 2702/3727/3326 3016/3729/3328 +f 3554/3730/3329 3016/3729/3328 2703/3731/2817 +f 3554/3730/3329 2954/3732/2768 2691/3681/2769 +f 2691/3684/2769 2954/3735/2768 3555/3733/3330 +f 2703/3734/2817 3240/3736/3331 3555/3733/3330 +f 3240/3736/3331 2704/3739/3334 2884/3737/3332 +f 2950/3686/3287 3555/3733/3330 2884/3737/3332 +f 2692/3689/3290 2884/3737/3332 3556/3738/3333 +f 2704/3739/3334 3171/3740/3335 3556/3738/3333 +f 3171/3740/3335 2705/3743/3338 3099/3741/3336 +f 2879/3690/3291 3556/3738/3333 3099/3741/3336 +f 2693/3693/3294 3099/3741/3336 3557/3742/3337 +f 2705/3743/3338 2812/3744/3339 3557/3742/3337 +f 2812/3744/3339 2706/3747/3342 3018/3745/3340 +f 3093/3694/3295 3557/3742/3337 3018/3745/3340 +f 2694/3697/3298 3018/3745/3340 3558/3746/3341 +f 2706/3747/3342 2730/3748/3343 3558/3746/3341 +f 2730/3748/3343 2707/3751/3346 3242/3749/3344 +f 3013/3698/3299 3558/3746/3341 3242/3749/3344 +f 2695/3701/3302 3242/3749/3344 3559/3750/3345 +f 2707/3751/3346 2956/3752/3347 3559/3750/3345 +f 2956/3752/3347 2708/3755/3350 3173/3753/3348 +f 3237/3702/3303 3559/3750/3345 3173/3753/3348 +f 2696/3705/3306 3173/3753/3348 3560/3754/3349 +f 2708/3755/3350 2814/3756/3351 3560/3754/3349 +f 2814/3756/3351 2697/3758/2792 3096/3707/2793 +f 3095/3706/3307 3560/3754/3349 3096/3707/2793 +f 2815/3757/2841 3561/3760/3353 2808/3709/3308 +f 2815/3757/2841 2709/3808/2840 3101/3759/3352 +f 3561/3760/3353 3101/3759/3352 2710/3761/3354 +f 3561/3760/3353 2732/3762/3355 2698/3711/3310 +f 2732/3762/3355 3562/3764/3357 2725/3713/3312 +f 2732/3762/3355 2710/3761/3354 3020/3763/3356 +f 3562/3764/3357 3020/3763/3356 2711/3765/3358 +f 3562/3764/3357 2958/3766/3359 2699/3715/3314 +f 2958/3766/3359 3563/3768/3361 2953/3717/3316 +f 2958/3766/3359 2711/3765/3358 3244/3767/3360 +f 3563/3768/3361 3244/3767/3360 2712/3769/3362 +f 3563/3768/3361 2887/3770/3363 2700/3719/3318 +f 2887/3770/3363 3564/3772/3365 2882/3721/3320 +f 2887/3770/3363 2712/3769/3362 3175/3771/3364 +f 3564/3772/3365 3175/3771/3364 2713/3773/3366 +f 3564/3772/3365 3103/3774/3367 2701/3723/3322 +f 3103/3774/3367 3565/3776/3369 3097/3725/3324 +f 3103/3774/3367 2713/3773/3366 2817/3775/3368 +f 3565/3776/3369 2817/3775/3368 2714/3777/3370 +f 3565/3776/3369 3023/3778/3371 2702/3727/3326 +f 3023/3778/3371 3566/3780/3373 3016/3729/3328 +f 3023/3778/3371 2714/3777/3370 2734/3779/3372 +f 3566/3780/3373 2734/3779/3372 2715/3781/2865 +f 3566/3780/3373 3245/3782/2816 2703/3731/2817 +f 2703/3734/2817 3245/3785/2816 3567/3783/3374 +f 2715/3784/2865 2960/3786/3375 3567/3783/3374 +f 2960/3786/3375 2716/3789/3378 3177/3787/3376 +f 3240/3736/3331 3567/3783/3374 3177/3787/3376 +f 2704/3739/3334 3177/3787/3376 3568/3788/3377 +f 2716/3789/3378 2889/3790/3379 3568/3788/3377 +f 2889/3790/3379 2717/3793/3382 2819/3791/3380 +f 3171/3740/3335 3568/3788/3377 2819/3791/3380 +f 2705/3743/3338 2819/3791/3380 3569/3792/3381 +f 2717/3793/3382 3105/3794/3383 3569/3792/3381 +f 3105/3794/3383 2718/3797/3386 2736/3795/3384 +f 2812/3744/3339 3569/3792/3381 2736/3795/3384 +f 2706/3747/3342 2736/3795/3384 3570/3796/3385 +f 2718/3797/3386 3025/3798/3387 3570/3796/3385 +f 3025/3798/3387 2719/3801/3390 2962/3799/3388 +f 2730/3748/3343 3570/3796/3385 2962/3799/3388 +f 2707/3751/3346 2962/3799/3388 3571/3800/3389 +f 2719/3801/3390 3247/3802/3391 3571/3800/3389 +f 3247/3802/3391 2720/3805/3394 2891/3803/3392 +f 2956/3752/3347 3571/3800/3389 2891/3803/3392 +f 2708/3755/3350 2891/3803/3392 3572/3804/3393 +f 2720/3805/3394 3107/3806/3395 3572/3804/3393 +f 3107/3806/3395 2709/3808/2840 2815/3757/2841 +f 2814/3756/3351 3572/3804/3393 2815/3757/2841 +f 3127/3807/2888 3573/3809/3396 3101/3759/3352 +f 3127/3807/2888 2433/2611/2315 2721/2610/2314 +f 3573/3809/3396 2721/2610/2314 2434/2616/2320 +f 3573/3809/3396 2759/3810/3397 2710/3761/3354 +f 2759/3810/3397 3574/3811/3398 3020/3763/3356 +f 2759/3810/3397 2434/2616/2320 2806/2617/2321 +f 3574/3811/3398 2806/2617/2321 2435/2622/2326 +f 3574/3811/3398 3270/3812/3399 2711/3765/3358 +f 3270/3812/3399 3575/3813/3400 3244/3767/3360 +f 3270/3812/3399 2435/2622/2326 2878/2623/2327 +f 3575/3813/3400 2878/2623/2327 2436/2628/2332 +f 3575/3813/3400 2917/3814/3401 2712/3769/3362 +f 2917/3814/3401 3576/3815/3402 3175/3771/3364 +f 2917/3814/3401 2436/2628/2332 2951/2629/2333 +f 3576/3815/3402 2951/2629/2333 2437/2634/2338 +f 3576/3815/3402 2853/3816/3403 2713/3773/3366 +f 2853/3816/3403 3577/3817/3404 2817/3775/3368 +f 2853/3816/3403 2437/2634/2338 3012/2635/2339 +f 3577/3817/3404 3012/2635/2339 2438/2640/2344 +f 3577/3817/3404 3063/3818/3405 2714/3777/3370 +f 3063/3818/3405 3578/3819/3406 2734/3779/3372 +f 3063/3818/3405 2438/2640/2344 3094/2641/2345 +f 3578/3819/3406 3094/2641/2345 2439/2646/2350 +f 3578/3819/3406 2995/3820/2864 2715/3781/2865 +f 2715/3784/2865 2995/3822/2864 3579/3821/3407 +f 2439/2647/2350 3168/2649/2352 3579/3821/3407 +f 3168/2649/2352 2440/2654/2355 3217/3823/3408 +f 2960/3786/3375 3579/3821/3407 3217/3823/3408 +f 2716/3789/3378 3217/3823/3408 3580/3824/3409 +f 2440/2654/2355 3238/2656/2357 3580/3824/3409 +f 3238/2656/2357 2441/2660/2361 3154/3825/3410 +f 2889/3790/3379 3580/3824/3409 3154/3825/3410 +f 2717/3793/3382 3154/3825/3410 3581/3826/3411 +f 2441/2660/2361 2724/2662/2363 3581/3826/3411 +f 2724/2662/2363 2442/2666/2367 2791/3827/3412 +f 3105/3794/3383 3581/3826/3411 2791/3827/3412 +f 2718/3797/3386 2791/3827/3412 3582/3828/3413 +f 2442/2666/2367 2809/2668/2369 3582/3828/3413 +f 2809/2668/2369 2443/2672/2373 3293/3829/3414 +f 3025/3798/3387 3582/3828/3413 3293/3829/3414 +f 2719/3801/3390 3293/3829/3414 3583/3830/3415 +f 2443/2672/2373 2881/2674/2375 3583/3830/3415 +f 2881/2674/2375 2444/2678/2379 2944/3831/3416 +f 3247/3802/3391 3583/3830/3415 2944/3831/3416 +f 2720/3805/3394 2944/3831/3416 3584/3832/3417 +f 2444/2678/2379 2726/2680/2381 3584/3832/3417 +f 2726/2680/2381 2433/2611/2315 3127/3807/2888 +f 3107/3806/3395 3584/3832/3417 3127/3807/2888 +g torus_Torus.001_torus-stand +usemtl torus-stand +s off +f 3729/3834/3418 3783/3835/3418 3733/3836/3418 +f 3730/3837/3419 3784/3838/3419 3732/3839/3419 +f 3729/3834/3418 3785/3840/3418 3735/3841/3418 +f 3730/3837/3419 3786/3842/3419 3734/3843/3419 +f 3729/3834/3418 3787/3844/3418 3737/3845/3418 +f 3730/3837/3419 3788/3846/3419 3736/3847/3419 +f 3729/3834/3418 3789/3848/3418 3739/3849/3418 +f 3730/3837/3419 3790/3850/3419 3738/3851/3419 +f 3729/3834/3418 3791/3852/3418 3741/3853/3418 +f 3730/3837/3419 3792/3854/3419 3740/3855/3419 +f 3729/3834/3418 3793/3856/3418 3743/3857/3418 +f 3730/3837/3419 3794/3858/3419 3742/3859/3419 +f 3729/3834/3418 3795/3860/3418 3745/3861/3418 +f 3730/3837/3419 3796/3862/3419 3744/3863/3419 +f 3729/3834/3418 3797/3864/3418 3731/3865/3418 +f 3730/3837/3419 3798/3866/3419 3746/3867/3419 +f 3747/3868/3418 3799/3869/3418 3751/3870/3418 +f 3748/3871/3419 3800/3872/3419 3750/3873/3419 +f 3747/3868/3418 3801/3874/3418 3753/3875/3418 +f 3748/3871/3419 3802/3876/3419 3752/3877/3419 +f 3747/3868/3418 3803/3878/3418 3755/3879/3418 +f 3748/3871/3419 3804/3880/3419 3754/3881/3419 +f 3747/3868/3418 3805/3882/3418 3757/3883/3418 +f 3748/3871/3419 3806/3884/3419 3756/3885/3419 +f 3747/3868/3418 3807/3886/3418 3759/3887/3418 +f 3748/3871/3419 3808/3888/3419 3758/3889/3419 +f 3747/3868/3418 3809/3890/3418 3761/3891/3418 +f 3748/3871/3419 3810/3892/3419 3760/3893/3419 +f 3747/3868/3418 3811/3894/3418 3763/3895/3418 +f 3748/3871/3419 3812/3896/3419 3762/3897/3419 +f 3747/3868/3418 3813/3898/3418 3749/3899/3418 +f 3748/3871/3419 3814/3900/3419 3764/3901/3419 +f 3765/3902/3418 3815/3903/3418 3769/3904/3418 +f 3766/3905/3419 3816/3906/3419 3768/3907/3419 +f 3765/3902/3418 3817/3908/3418 3771/3909/3418 +f 3766/3905/3419 3818/3910/3419 3770/3911/3419 +f 3765/3902/3418 3819/3912/3418 3773/3913/3418 +f 3766/3905/3419 3820/3914/3419 3772/3915/3419 +f 3765/3902/3418 3821/3916/3418 3775/3917/3418 +f 3766/3905/3419 3822/3918/3419 3774/3919/3419 +f 3765/3902/3418 3823/3920/3418 3777/3921/3418 +f 3766/3905/3419 3824/3922/3419 3776/3923/3419 +f 3765/3902/3418 3825/3924/3418 3779/3925/3418 +f 3766/3905/3419 3826/3926/3419 3778/3927/3419 +f 3765/3902/3418 3827/3928/3418 3781/3929/3418 +f 3766/3905/3419 3828/3930/3419 3780/3931/3419 +f 3765/3902/3418 3829/3932/3418 3767/3933/3418 +f 3766/3905/3419 3830/3934/3419 3782/3935/3419 +f 3729/3834/3418 3731/3865/3418 3783/3835/3418 +f 3730/3837/3419 3734/3843/3419 3784/3838/3419 +f 3729/3834/3418 3733/3836/3418 3785/3840/3418 +f 3730/3837/3419 3736/3847/3419 3786/3842/3419 +f 3729/3834/3418 3735/3841/3418 3787/3844/3418 +f 3730/3837/3419 3738/3851/3419 3788/3846/3419 +f 3729/3834/3418 3737/3845/3418 3789/3848/3418 +f 3730/3837/3419 3740/3855/3419 3790/3850/3419 +f 3729/3834/3418 3739/3849/3418 3791/3852/3418 +f 3730/3837/3419 3742/3859/3419 3792/3854/3419 +f 3729/3834/3418 3741/3853/3418 3793/3856/3418 +f 3730/3837/3419 3744/3863/3419 3794/3858/3419 +f 3729/3834/3418 3743/3857/3418 3795/3860/3418 +f 3730/3837/3419 3746/3867/3419 3796/3862/3419 +f 3729/3834/3418 3745/3861/3418 3797/3864/3418 +f 3730/3837/3419 3732/3839/3419 3798/3866/3419 +f 3747/3868/3418 3749/3899/3418 3799/3869/3418 +f 3748/3871/3419 3752/3877/3419 3800/3872/3419 +f 3747/3868/3418 3751/3870/3418 3801/3874/3418 +f 3748/3871/3419 3754/3881/3419 3802/3876/3419 +f 3747/3868/3418 3753/3875/3418 3803/3878/3418 +f 3748/3871/3419 3756/3885/3419 3804/3880/3419 +f 3747/3868/3418 3755/3879/3418 3805/3882/3418 +f 3748/3871/3419 3758/3889/3419 3806/3884/3419 +f 3747/3868/3418 3757/3883/3418 3807/3886/3418 +f 3748/3871/3419 3760/3893/3419 3808/3888/3419 +f 3747/3868/3418 3759/3887/3418 3809/3890/3418 +f 3748/3871/3419 3762/3897/3419 3810/3892/3419 +f 3747/3868/3418 3761/3891/3418 3811/3894/3418 +f 3748/3871/3419 3764/3901/3419 3812/3896/3419 +f 3747/3868/3418 3763/3895/3418 3813/3898/3418 +f 3748/3871/3419 3750/3873/3419 3814/3900/3419 +f 3765/3902/3418 3767/3933/3418 3815/3903/3418 +f 3766/3905/3419 3770/3911/3419 3816/3906/3419 +f 3765/3902/3418 3769/3904/3418 3817/3908/3418 +f 3766/3905/3419 3772/3915/3419 3818/3910/3419 +f 3765/3902/3418 3771/3909/3418 3819/3912/3418 +f 3766/3905/3419 3774/3919/3419 3820/3914/3419 +f 3765/3902/3418 3773/3913/3418 3821/3916/3418 +f 3766/3905/3419 3776/3923/3419 3822/3918/3419 +f 3765/3902/3418 3775/3917/3418 3823/3920/3418 +f 3766/3905/3419 3778/3927/3419 3824/3922/3419 +f 3765/3902/3418 3777/3921/3418 3825/3924/3418 +f 3766/3905/3419 3780/3931/3419 3826/3926/3419 +f 3765/3902/3418 3779/3925/3418 3827/3928/3418 +f 3766/3905/3419 3782/3935/3419 3828/3930/3419 +f 3765/3902/3418 3781/3929/3418 3829/3932/3418 +f 3766/3905/3419 3768/3907/3419 3830/3934/3419 +s 1 +f 3728/3936/1424 3588/3937/1377 3636/3938/1377 +f 3638/3939/1280 3639/3940/1211 3727/3941/1280 +f 3641/3942/1737 3642/3943/1640 3726/3944/1737 +f 3725/3945/1593 3594/3946/1496 3645/3947/1496 +f 3724/3948/1449 3596/3949/1352 3648/3950/1352 +f 3723/3951/1305 3598/3952/1246 3651/3953/1246 +f 3722/3954/1712 3600/3955/1665 3654/3956/1665 +f 3656/3957/1568 3635/3958/1521 3721/3959/1568 +f 3720/3960/1424 3604/3961/1377 3660/3962/1377 +f 3719/3963/1280 3606/3964/1211 3663/3965/1211 +f 3665/3966/1737 3666/3967/1640 3718/3968/1737 +f 3717/3969/1593 3610/3970/1496 3669/3971/1496 +f 3716/3972/1449 3612/3973/1352 3672/3974/1352 +f 3674/3975/1305 3675/3976/1246 3715/3977/1305 +f 3677/3978/1712 3678/3979/1665 3714/3980/1712 +f 3713/3981/1568 3602/3982/1521 3659/3983/1521 +f 3682/3984/1424 3684/3985/1377 3712/3986/1424 +f 3686/3987/1280 3687/3988/1211 3711/3989/1280 +f 3710/3990/1737 3624/3991/1640 3690/3992/1640 +f 3692/3993/1593 3693/3994/1496 3709/3995/1593 +f 3708/3996/1449 3628/3997/1352 3696/3998/1352 +f 3698/3999/1305 3699/4000/1246 3707/4001/1305 +f 3706/4002/1712 3632/4003/1665 3702/4004/1665 +f 3705/4005/1568 3618/4006/1521 3683/4007/1521 +f 3705/4005/1568 3617/4008/1521 3703/4009/1568 +f 3631/4010/1665 3705/4005/1568 3703/4009/1568 +f 3702/4004/1665 3704/4011/1568 3705/4005/1568 +f 3700/4012/1712 3702/4004/1665 3631/4010/1665 +f 3699/4000/1246 3700/4012/1712 3629/4013/1246 +f 3699/4000/1246 3701/4014/1712 3706/4002/1712 +f 3707/4001/1305 3629/4013/1246 3697/4015/1305 +f 3696/3998/1352 3697/4015/1305 3627/4016/1352 +f 3628/3997/1352 3707/4001/1305 3696/3998/1352 +f 3694/4017/1449 3696/3998/1352 3627/4016/1352 +f 3625/4018/1496 3708/3996/1449 3694/4017/1449 +f 3626/4019/1496 3708/3996/1449 3693/3994/1496 +f 3709/3995/1593 3625/4018/1496 3691/4020/1593 +f 3623/4021/1640 3709/3995/1593 3691/4020/1593 +f 3624/3991/1640 3709/3995/1593 3690/3992/1640 +f 3688/4022/1737 3690/3992/1640 3623/4021/1640 +f 3621/4023/1211 3710/3990/1737 3688/4022/1737 +f 3687/3988/1211 3689/4024/1737 3710/3990/1737 +f 3711/3989/1280 3621/4023/1211 3685/4025/1280 +f 3619/4026/1377 3711/3989/1280 3685/4025/1280 +f 3620/4027/1377 3711/3989/1280 3684/3985/1377 +f 3712/3986/1424 3619/4026/1377 3681/4028/1424 +f 3617/4029/1521 3712/3986/1424 3681/4028/1424 +f 3683/4030/1521 3682/3984/1424 3712/3986/1424 +f 3713/3981/1568 3601/4031/1521 3679/4032/1568 +f 3615/4033/1665 3713/3981/1568 3679/4032/1568 +f 3616/4034/1665 3713/3981/1568 3678/3979/1665 +f 3714/3980/1712 3615/4033/1665 3676/4035/1712 +f 3675/3976/1246 3676/4035/1712 3613/4036/1246 +f 3614/4037/1246 3714/3980/1712 3675/3976/1246 +f 3715/3977/1305 3613/4036/1246 3673/4038/1305 +f 3672/3974/1352 3673/4038/1305 3611/4039/1352 +f 3612/3973/1352 3715/3977/1305 3672/3974/1352 +f 3670/4040/1449 3672/3974/1352 3611/4039/1352 +f 3669/3971/1496 3670/4040/1449 3609/4041/1496 +f 3610/3970/1496 3716/3972/1449 3669/3971/1496 +f 3667/4042/1593 3669/3971/1496 3609/4041/1496 +f 3666/3967/1640 3667/4042/1593 3607/4043/1640 +f 3608/4044/1640 3717/3969/1593 3666/3967/1640 +f 3718/3968/1737 3607/4043/1640 3664/4045/1737 +f 3663/3965/1211 3664/4045/1737 3605/4046/1211 +f 3606/3964/1211 3718/3968/1737 3663/3965/1211 +f 3719/3963/1280 3605/4046/1211 3661/4047/1280 +f 3660/3962/1377 3661/4047/1280 3603/4048/1377 +f 3604/3961/1377 3719/3963/1280 3660/3962/1377 +f 3657/4049/1424 3660/3962/1377 3603/4048/1377 +f 3601/4050/1521 3720/3960/1424 3657/4049/1424 +f 3602/4051/1521 3720/3960/1424 3659/4052/1521 +f 3721/3959/1568 3585/4053/1521 3655/4054/1568 +f 3654/3956/1665 3655/4054/1568 3599/4055/1665 +f 3600/3955/1665 3721/3959/1568 3654/3956/1665 +f 3722/3954/1712 3599/4055/1665 3652/4056/1712 +f 3651/3953/1246 3652/4056/1712 3597/4057/1246 +f 3651/3953/1246 3653/4058/1712 3722/3954/1712 +f 3723/3951/1305 3597/4057/1246 3649/4059/1305 +f 3648/3950/1352 3649/4059/1305 3595/4060/1352 +f 3648/3950/1352 3650/4061/1305 3723/3951/1305 +f 3646/4062/1449 3648/3950/1352 3595/4060/1352 +f 3593/4063/1496 3724/3948/1449 3646/4062/1449 +f 3645/3947/1496 3647/4064/1449 3724/3948/1449 +f 3725/3945/1593 3593/4063/1496 3643/4065/1593 +f 3591/4066/1640 3725/3945/1593 3643/4065/1593 +f 3592/4067/1640 3725/3945/1593 3642/3943/1640 +f 3726/3944/1737 3591/4066/1640 3640/4068/1737 +f 3639/3940/1211 3640/4068/1737 3589/4069/1211 +f 3639/3940/1211 3641/3942/1737 3726/3944/1737 +f 3637/4070/1280 3639/3940/1211 3589/4069/1211 +f 3636/3938/1377 3637/4070/1280 3587/4071/1377 +f 3588/3937/1377 3727/3941/1280 3636/3938/1377 +f 3633/4072/1424 3636/3938/1377 3587/4071/1377 +f 3585/4073/1521 3728/3936/1424 3633/4072/1424 +f 3635/4074/1521 3634/4075/1424 3728/3936/1424 +f 3728/3936/1424 3634/4075/1424 3588/3937/1377 +f 3638/3939/1280 3590/4076/1211 3639/3940/1211 +f 3641/3942/1737 3592/4067/1640 3642/3943/1640 +f 3725/3945/1593 3644/4077/1593 3594/3946/1496 +f 3724/3948/1449 3647/4064/1449 3596/3949/1352 +f 3723/3951/1305 3650/4061/1305 3598/3952/1246 +f 3722/3954/1712 3653/4058/1712 3600/3955/1665 +f 3656/3957/1568 3586/4078/1521 3635/3958/1521 +f 3720/3960/1424 3658/4079/1424 3604/3961/1377 +f 3719/3963/1280 3662/4080/1280 3606/3964/1211 +f 3665/3966/1737 3608/4044/1640 3666/3967/1640 +f 3717/3969/1593 3668/4081/1593 3610/3970/1496 +f 3716/3972/1449 3671/4082/1449 3612/3973/1352 +f 3674/3975/1305 3614/4037/1246 3675/3976/1246 +f 3677/3978/1712 3616/4034/1665 3678/3979/1665 +f 3713/3981/1568 3680/4083/1568 3602/3982/1521 +f 3682/3984/1424 3620/4027/1377 3684/3985/1377 +f 3686/3987/1280 3622/4084/1211 3687/3988/1211 +f 3710/3990/1737 3689/4024/1737 3624/3991/1640 +f 3692/3993/1593 3626/4019/1496 3693/3994/1496 +f 3708/3996/1449 3695/4085/1449 3628/3997/1352 +f 3698/3999/1305 3630/4086/1246 3699/4000/1246 +f 3706/4002/1712 3701/4014/1712 3632/4003/1665 +f 3705/4005/1568 3704/4011/1568 3618/4006/1521 +f 3705/4005/1568 3683/4007/1521 3617/4008/1521 +f 3631/4010/1665 3702/4004/1665 3705/4005/1568 +f 3702/4004/1665 3632/4003/1665 3704/4011/1568 +f 3700/4012/1712 3706/4002/1712 3702/4004/1665 +f 3699/4000/1246 3706/4002/1712 3700/4012/1712 +f 3699/4000/1246 3630/4086/1246 3701/4014/1712 +f 3707/4001/1305 3699/4000/1246 3629/4013/1246 +f 3696/3998/1352 3707/4001/1305 3697/4015/1305 +f 3628/3997/1352 3698/3999/1305 3707/4001/1305 +f 3694/4017/1449 3708/3996/1449 3696/3998/1352 +f 3625/4018/1496 3693/3994/1496 3708/3996/1449 +f 3626/4019/1496 3695/4085/1449 3708/3996/1449 +f 3709/3995/1593 3693/3994/1496 3625/4018/1496 +f 3623/4021/1640 3690/3992/1640 3709/3995/1593 +f 3624/3991/1640 3692/3993/1593 3709/3995/1593 +f 3688/4022/1737 3710/3990/1737 3690/3992/1640 +f 3621/4023/1211 3687/3988/1211 3710/3990/1737 +f 3687/3988/1211 3622/4084/1211 3689/4024/1737 +f 3711/3989/1280 3687/3988/1211 3621/4023/1211 +f 3619/4026/1377 3684/3985/1377 3711/3989/1280 +f 3620/4027/1377 3686/3987/1280 3711/3989/1280 +f 3712/3986/1424 3684/3985/1377 3619/4026/1377 +f 3617/4029/1521 3683/4030/1521 3712/3986/1424 +f 3683/4030/1521 3618/4087/1521 3682/3984/1424 +f 3713/3981/1568 3659/3983/1521 3601/4031/1521 +f 3615/4033/1665 3678/3979/1665 3713/3981/1568 +f 3616/4034/1665 3680/4083/1568 3713/3981/1568 +f 3714/3980/1712 3678/3979/1665 3615/4033/1665 +f 3675/3976/1246 3714/3980/1712 3676/4035/1712 +f 3614/4037/1246 3677/3978/1712 3714/3980/1712 +f 3715/3977/1305 3675/3976/1246 3613/4036/1246 +f 3672/3974/1352 3715/3977/1305 3673/4038/1305 +f 3612/3973/1352 3674/3975/1305 3715/3977/1305 +f 3670/4040/1449 3716/3972/1449 3672/3974/1352 +f 3669/3971/1496 3716/3972/1449 3670/4040/1449 +f 3610/3970/1496 3671/4082/1449 3716/3972/1449 +f 3667/4042/1593 3717/3969/1593 3669/3971/1496 +f 3666/3967/1640 3717/3969/1593 3667/4042/1593 +f 3608/4044/1640 3668/4081/1593 3717/3969/1593 +f 3718/3968/1737 3666/3967/1640 3607/4043/1640 +f 3663/3965/1211 3718/3968/1737 3664/4045/1737 +f 3606/3964/1211 3665/3966/1737 3718/3968/1737 +f 3719/3963/1280 3663/3965/1211 3605/4046/1211 +f 3660/3962/1377 3719/3963/1280 3661/4047/1280 +f 3604/3961/1377 3662/4080/1280 3719/3963/1280 +f 3657/4049/1424 3720/3960/1424 3660/3962/1377 +f 3601/4050/1521 3659/4052/1521 3720/3960/1424 +f 3602/4051/1521 3658/4079/1424 3720/3960/1424 +f 3721/3959/1568 3635/3958/1521 3585/4053/1521 +f 3654/3956/1665 3721/3959/1568 3655/4054/1568 +f 3600/3955/1665 3656/3957/1568 3721/3959/1568 +f 3722/3954/1712 3654/3956/1665 3599/4055/1665 +f 3651/3953/1246 3722/3954/1712 3652/4056/1712 +f 3651/3953/1246 3598/3952/1246 3653/4058/1712 +f 3723/3951/1305 3651/3953/1246 3597/4057/1246 +f 3648/3950/1352 3723/3951/1305 3649/4059/1305 +f 3648/3950/1352 3596/3949/1352 3650/4061/1305 +f 3646/4062/1449 3724/3948/1449 3648/3950/1352 +f 3593/4063/1496 3645/3947/1496 3724/3948/1449 +f 3645/3947/1496 3594/3946/1496 3647/4064/1449 +f 3725/3945/1593 3645/3947/1496 3593/4063/1496 +f 3591/4066/1640 3642/3943/1640 3725/3945/1593 +f 3592/4067/1640 3644/4077/1593 3725/3945/1593 +f 3726/3944/1737 3642/3943/1640 3591/4066/1640 +f 3639/3940/1211 3726/3944/1737 3640/4068/1737 +f 3639/3940/1211 3590/4076/1211 3641/3942/1737 +f 3637/4070/1280 3727/3941/1280 3639/3940/1211 +f 3636/3938/1377 3727/3941/1280 3637/4070/1280 +f 3588/3937/1377 3638/3939/1280 3727/3941/1280 +f 3633/4072/1424 3728/3936/1424 3636/3938/1377 +f 3585/4073/1521 3635/4074/1521 3728/3936/1424 +f 3635/4074/1521 3586/4088/1521 3634/4075/1424 +g bubble_Icosphere +v -3.910440 7.243722 -0.615227 +v -3.201336 7.703301 -0.100412 +v -4.211912 7.661933 0.292689 +v -4.857645 7.671463 -0.612080 +v -4.223453 7.639643 -1.577276 +v -3.163540 7.678376 -1.161784 +v -3.642030 8.583762 0.216006 +v -4.756935 8.658118 -0.003795 +v -4.756377 8.660480 -1.227637 +v -3.605032 8.647757 -1.580369 +v -2.974994 8.617176 -0.613802 +v -3.914599 9.223416 -0.616767 +v -4.164034 7.447568 0.151319 +v -4.070670 7.317980 -0.125794 +v -3.983463 7.233162 -0.388561 +v -3.723780 7.240955 -0.477033 +v -3.483391 7.291190 -0.305424 +v -3.300778 7.485984 -0.174473 +v -3.394794 7.654524 0.043369 +v -3.658648 7.625340 0.175478 +v -3.949268 7.623285 0.274093 +v -3.055349 7.610032 -0.925613 +v -2.976351 7.558912 -0.615258 +v -3.063703 7.615659 -0.308595 +v -3.722471 7.229332 -0.755215 +v -3.495508 7.314173 -0.917362 +v -3.284846 7.471306 -1.070881 +v -4.672318 7.491829 -0.610418 +v -4.383763 7.391759 -0.610825 +v -4.119821 7.323750 -0.613664 +v -4.465440 7.574185 0.200031 +v -4.706625 7.544286 -0.038183 +v -4.839616 7.586730 -0.345299 +v -4.163995 7.432624 -1.397647 +v -4.075972 7.273959 -1.131909 +v -3.981925 7.228599 -0.844425 +v -4.775189 7.628238 -0.861121 +v -4.627439 7.604704 -1.135239 +v -4.430741 7.605898 -1.390622 +v -3.947964 7.572552 -1.603554 +v -3.616220 7.551620 -1.532735 +v -3.329839 7.592972 -1.366157 +v -2.979689 8.393785 -0.474698 +v -3.021018 8.140388 -0.326318 +v -3.062661 7.888713 -0.176863 +v -3.035102 7.883244 -1.069364 +v -2.957141 8.142517 -0.928098 +v -2.962012 8.395979 -0.761070 +v -3.768878 8.378463 0.268313 +v -3.915938 8.141392 0.341711 +v -4.072481 7.886427 0.339384 +v -3.243969 7.894766 0.043277 +v -3.380040 8.141891 0.115360 +v -3.513452 8.379501 0.180710 +v -4.939075 8.443170 -0.083959 +v -5.014828 8.143350 -0.252330 +v -4.959911 7.866831 -0.449367 +v -4.382789 7.869448 0.304096 +v -4.572649 8.141458 0.277816 +v -4.727230 8.438441 0.183574 +v -4.713746 8.437027 -1.405812 +v -4.584701 8.143202 -1.539802 +v -4.407471 7.856671 -1.602163 +v -4.926367 7.877499 -0.771769 +v -5.004040 8.145787 -0.971767 +v -4.924760 8.439850 -1.136290 +v -3.438228 8.418950 -1.572048 +v -3.275757 8.140603 -1.500751 +v -3.186752 7.873656 -1.339893 +v -4.094153 7.848507 -1.735888 +v -3.912477 8.143428 -1.826901 +v -3.730050 8.442506 -1.757203 +v -3.057128 8.663520 -0.376620 +v -3.244105 8.657756 -0.130202 +v -3.445369 8.635522 0.084612 +v -3.881276 8.620824 0.204047 +v -4.180747 8.668531 0.191927 +v -4.503071 8.690061 0.129948 +v -4.859770 8.723556 -0.269802 +v -4.894769 8.747117 -0.615000 +v -4.855133 8.720813 -0.957984 +v -4.534060 8.728189 -1.410346 +v -4.222616 8.765841 -1.571724 +v -3.878246 8.735287 -1.637458 +v -3.413363 8.666314 -1.366775 +v -3.214442 8.676700 -1.123606 +v -3.074574 8.650928 -0.850193 +v -3.835098 9.121226 -0.380561 +v -3.749032 8.989410 -0.117113 +v -3.674003 8.809993 0.113963 +v -3.071250 8.878141 -0.613868 +v -3.321826 9.100352 -0.615242 +v -3.632369 9.217830 -0.616006 +v -4.135466 9.194731 -0.459912 +v -4.373130 9.060289 -0.284994 +v -4.573186 8.845446 -0.138714 +v -4.147886 9.248606 -0.785979 +v -4.414576 9.154005 -0.983506 +v -4.587294 8.868633 -1.106935 +v -3.834860 9.167236 -0.864889 +v -3.744441 9.053460 -1.154250 +v -3.657747 8.876256 -1.421478 +v -3.519209 9.104383 -0.896153 +v -3.250142 8.903658 -0.886977 +v -3.448943 8.898089 -1.158734 +v -4.085379 9.201805 -1.128026 +v -3.984206 9.007936 -1.433801 +v -4.336196 9.010196 -1.316790 +v -4.422236 9.149897 -0.618615 +v -4.669489 8.962987 -0.793975 +v -4.663819 8.952697 -0.439420 +v -4.059371 9.055500 -0.178877 +v -4.288350 8.895963 -0.005591 +v -3.968408 8.856212 0.057863 +v -3.523851 9.088589 -0.339147 +v -3.453930 8.888485 -0.080273 +v -3.249360 8.903189 -0.343631 +v -3.034218 8.422057 -1.054589 +v -3.069695 8.146727 -1.230392 +v -3.215436 8.425258 -1.327926 +v -4.082248 8.471704 -1.759730 +v -4.272877 8.148554 -1.732719 +v -4.420714 8.458061 -1.594030 +v -5.023703 8.464585 -0.801562 +v -5.034943 8.151823 -0.614656 +v -5.012327 8.461555 -0.430132 +v -4.381785 8.427765 0.268000 +v -4.225759 8.145213 0.332634 +v -4.052530 8.406552 0.299339 +v -3.283018 8.401770 0.026355 +v -3.154452 8.143608 -0.064495 +v -3.105265 8.403063 -0.214488 +v -3.552780 8.135790 -1.738938 +v -3.406602 7.827311 -1.598413 +v -3.743949 7.818596 -1.747906 +v -4.849920 8.138680 -1.294364 +v -4.664735 7.840643 -1.379598 +v -4.881904 7.838295 -1.100130 +v -4.890118 8.136151 0.093477 +v -4.940287 7.816206 -0.097836 +v -4.716495 7.817013 0.195127 +v -3.634416 8.139048 0.249707 +v -3.781707 7.877988 0.291363 +v -3.503465 7.886722 0.168549 +v -2.944006 8.137750 -0.617036 +v -2.955720 7.859093 -0.455799 +v -2.947210 7.858263 -0.776796 +v -3.537307 7.381373 -1.239087 +v -3.772089 7.233151 -1.057386 +v -3.852505 7.360165 -1.360108 +v -4.355726 7.426010 -1.139045 +v -4.238871 7.339962 -0.859828 +v -4.509919 7.469900 -0.864806 +v -4.579892 7.392220 -0.332775 +v -4.259017 7.303434 -0.359332 +v -4.381057 7.398511 -0.071537 +v -3.178566 7.353819 -0.784422 +v -3.185027 7.358926 -0.446785 +v -3.454948 7.251359 -0.613982 +v -3.857706 7.403812 0.086128 +v -3.774512 7.263211 -0.189668 +v -3.556965 7.418922 -0.029542 +v -3.960412 7.235164 -0.458497 +v -3.944137 7.239310 -0.508802 +v -3.928446 7.243525 -0.557594 +v -3.266700 7.551614 -0.148950 +v -3.244606 7.599764 -0.132441 +v -3.224245 7.646862 -0.117455 +v -4.029162 7.631300 0.287062 +v -4.087246 7.639387 0.292410 +v -4.143999 7.649034 0.293884 +v -3.102798 7.641274 -0.239979 +v -3.133810 7.661053 -0.193878 +v -3.165188 7.680740 -0.150823 +v -3.242228 7.530840 -1.103518 +v -3.214315 7.576123 -1.124432 +v -3.189302 7.621549 -1.142936 +v -4.054599 7.298048 -0.614406 +v -4.008761 7.278296 -0.614746 +v -3.964436 7.259654 -0.614956 +v -4.850911 7.610058 -0.429191 +v -4.855392 7.628693 -0.488776 +v -4.856993 7.648260 -0.545819 +v -3.959268 7.232695 -0.772312 +v -3.943357 7.237282 -0.721497 +v -3.927957 7.241956 -0.672667 +v -4.371298 7.611441 -1.453406 +v -4.326334 7.617749 -1.496254 +v -4.280582 7.626388 -1.535068 +v -3.273095 7.616250 -1.306104 +v -3.236376 7.635544 -1.260284 +v -3.202955 7.655534 -1.214699 +v -3.095380 7.827747 -0.147354 +v -3.125724 7.786360 -0.130019 +v -3.158939 7.747642 -0.115581 +v -2.964758 8.462854 -0.715743 +v -2.965656 8.512104 -0.683235 +v -2.968562 8.560013 -0.651605 +v -4.115105 7.816794 0.331393 +v -4.146010 7.766683 0.322972 +v -4.176086 7.718505 0.311304 +v -3.550833 8.443419 0.196450 +v -3.578337 8.489713 0.207146 +v -3.606366 8.533670 0.214052 +v -4.931762 7.802156 -0.501143 +v -4.910496 7.757762 -0.537390 +v -4.887975 7.716761 -0.571765 +v -4.747538 8.512492 0.136948 +v -4.755811 8.562814 0.096720 +v -4.758633 8.608266 0.052509 +v -4.353328 7.786314 -1.601721 +v -4.312964 7.737422 -1.597439 +v -4.272440 7.691800 -1.589808 +v -4.882097 8.513120 -1.170385 +v -4.846704 8.563620 -1.192032 +v -4.807777 8.609822 -1.210017 +v -3.175666 7.810071 -1.287136 +v -3.170027 7.766337 -1.248006 +v -3.166251 7.725248 -1.209222 +v -3.687745 8.511721 -1.711813 +v -3.659182 8.558263 -1.673582 +v -3.633401 8.600671 -1.632262 +v -3.503677 8.623875 0.133384 +v -3.546457 8.613955 0.165760 +v -3.589337 8.602040 0.192353 +v -4.586189 8.685571 0.098241 +v -4.643942 8.679731 0.070334 +v -4.697166 8.671149 0.038697 +v -4.830213 8.705069 -1.043712 +v -4.809624 8.692443 -1.104306 +v -4.786576 8.678363 -1.161478 +v -3.789370 8.713412 -1.630419 +v -3.727524 8.694963 -1.619608 +v -3.669840 8.674661 -1.604381 +v -3.036720 8.644922 -0.776836 +v -3.010503 8.639540 -0.724588 +v -2.989575 8.631935 -0.674009 +v -3.660869 8.746117 0.156046 +v -3.653022 8.696527 0.181087 +v -3.647093 8.645581 0.199742 +v -3.718382 9.223434 -0.616135 +v -3.780888 9.223888 -0.616199 +v -3.842147 9.222006 -0.616395 +v -4.631087 8.790370 -0.096171 +v -4.673805 8.751063 -0.064805 +v -4.713830 8.710892 -0.035546 +v -4.639846 8.802388 -1.144014 +v -4.679793 8.758488 -1.172538 +v -4.717303 8.715726 -1.199534 +v -3.638991 8.811543 -1.476077 +v -3.626808 8.761408 -1.511980 +v -3.616459 8.710238 -1.544172 +v -4.204045 7.599140 0.268545 +v -4.195119 7.549623 0.241904 +v -4.183760 7.503110 0.208168 +v -4.138783 7.402919 0.078617 +v -4.118581 7.375177 0.018656 +v -4.097957 7.350445 -0.043431 +v -4.045167 7.284201 -0.203424 +v -4.026739 7.261338 -0.259551 +v -4.008248 7.243996 -0.315067 +v -3.865204 7.238849 -0.580399 +v -3.825973 7.237762 -0.551165 +v -3.784243 7.238187 -0.520675 +v -3.656340 7.247363 -0.428458 +v -3.604093 7.254580 -0.390875 +v -3.551727 7.265681 -0.353525 +v -3.422432 7.335207 -0.262197 +v -3.381733 7.375869 -0.232949 +v -3.344509 7.421135 -0.206190 +v -3.249137 7.689660 -0.060658 +v -3.289454 7.678373 -0.028273 +v -3.332111 7.667528 0.003223 +v -3.465694 7.643607 0.083250 +v -3.521426 7.636731 0.112472 +v -3.579058 7.631178 0.140075 +v -3.740506 7.620927 0.210446 +v -3.802709 7.619116 0.234182 +v -3.865638 7.619398 0.253948 +v -3.136061 7.662124 -1.101392 +v -3.111920 7.647261 -1.051436 +v -3.087723 7.631726 -0.999582 +v -3.021655 7.587935 -0.842488 +v -2.999558 7.573852 -0.776425 +v -2.984144 7.563943 -0.708301 +v -2.986285 7.565727 -0.522334 +v -3.003083 7.576637 -0.454584 +v -3.026783 7.591729 -0.389371 +v -3.864510 7.235854 -0.650725 +v -3.824549 7.231108 -0.680587 +v -3.782358 7.228232 -0.711614 +v -3.659315 7.243888 -0.800785 +v -3.611544 7.261574 -0.835125 +v -3.562752 7.282381 -0.869973 +v -3.429992 7.353023 -0.963694 +v -3.383360 7.384895 -0.997353 +v -3.338662 7.419106 -1.030212 +v -4.819929 7.617529 -0.612114 +v -4.782291 7.576433 -0.612038 +v -4.738966 7.538053 -0.611516 +v -4.593247 7.456004 -0.610129 +v -4.530540 7.434556 -0.610223 +v -4.467326 7.415415 -0.610273 +v -4.303429 7.373820 -0.612121 +v -4.245978 7.361749 -0.612778 +v -4.190729 7.347348 -0.613121 +v -4.277548 7.635176 0.277187 +v -4.333467 7.613697 0.261028 +v -4.389923 7.594651 0.239249 +v -4.540984 7.558609 0.145407 +v -4.594758 7.550377 0.096250 +v -4.644792 7.546040 0.041161 +v -4.759699 7.547159 -0.122316 +v -4.792086 7.554110 -0.187991 +v -4.817209 7.565843 -0.255451 +v -4.210320 7.580709 -1.537063 +v -4.198368 7.533864 -1.500462 +v -4.184692 7.489180 -1.459404 +v -4.141225 7.378390 -1.327715 +v -4.123008 7.341279 -1.271862 +v -4.103426 7.309215 -1.213204 +v -4.048988 7.248229 -1.049302 +v -4.028793 7.235593 -0.986998 +v -4.008273 7.229362 -0.924684 +v -4.838237 7.658437 -0.676768 +v -4.821489 7.647984 -0.730545 +v -4.802806 7.638812 -0.785397 +v -4.741387 7.618371 -0.940288 +v -4.711199 7.612451 -0.999440 +v -4.677250 7.608484 -1.057886 +v -4.574151 7.601549 -1.211392 +v -4.532836 7.600876 -1.267072 +v -4.489927 7.602198 -1.321279 +v -4.155668 7.618181 -1.591143 +v -4.097009 7.602138 -1.599246 +v -4.035273 7.588206 -1.603626 +v -3.853932 7.560145 -1.594443 +v -3.782188 7.553853 -1.581827 +v -3.710668 7.550972 -1.563979 +v -3.525153 7.556479 -1.493803 +v -3.460620 7.563292 -1.460474 +v -3.400654 7.573865 -1.422654 +v -2.967097 8.561699 -0.577099 +v -2.966465 8.513676 -0.546638 +v -2.970603 8.463357 -0.515914 +v -2.990427 8.322112 -0.432666 +v -2.999824 8.268097 -0.401117 +v -3.009704 8.213779 -0.369538 +v -3.028347 8.066711 -0.281124 +v -3.034280 8.012036 -0.247568 +v -3.043131 7.958045 -0.215510 +v -3.126081 7.728652 -1.139990 +v -3.096949 7.772000 -1.120860 +v -3.069319 7.817713 -1.100203 +v -3.004998 7.955121 -1.032980 +v -2.985828 8.010532 -1.003472 +v -2.970608 8.066646 -0.972346 +v -2.952003 8.217669 -0.881124 +v -2.952048 8.272612 -0.845314 +v -2.955294 8.326413 -0.809130 +v -3.673311 8.532031 0.233117 +v -3.700555 8.487627 0.243905 +v -3.729293 8.441440 0.252986 +v -3.809553 8.313274 0.292221 +v -3.840650 8.263106 0.310645 +v -3.872397 8.211900 0.326474 +v -3.960447 8.068672 0.348539 +v -3.994017 8.013949 0.349056 +v -4.027781 7.959134 0.346052 +v -3.208246 7.751204 -0.058598 +v -3.214490 7.791398 -0.024545 +v -3.223667 7.833615 0.007186 +v -3.277000 7.963021 0.069683 +v -3.306652 8.016146 0.084769 +v -3.338401 8.070017 0.097506 +v -3.418259 8.211638 0.136147 +v -3.446386 8.262693 0.151122 +v -3.474839 8.313181 0.164734 +v -4.814042 8.610983 -0.016409 +v -4.856741 8.566516 -0.031568 +v -4.894965 8.516802 -0.051192 +v -4.973186 8.360875 -0.125972 +v -4.992031 8.296605 -0.161423 +v -5.005135 8.231171 -0.199226 +v -5.011332 8.058981 -0.308204 +v -5.001084 7.998590 -0.350824 +v -4.985794 7.940261 -0.393474 +v -4.256752 7.711808 0.301124 +v -4.293313 7.755923 0.304579 +v -4.330688 7.802714 0.305291 +v -4.437764 7.943248 0.302048 +v -4.479120 8.000838 0.298647 +v -4.519891 8.059711 0.292070 +v -4.623836 8.227795 0.259512 +v -4.660377 8.292787 0.242840 +v -4.692952 8.356619 0.221041 +v -4.754755 8.609752 -1.280716 +v -4.747988 8.562983 -1.321276 +v -4.736192 8.511646 -1.358978 +v -4.683698 8.355461 -1.449764 +v -4.657432 8.292524 -1.479964 +v -4.627985 8.228853 -1.507143 +v -4.538165 8.058072 -1.567269 +v -4.501333 7.995480 -1.583259 +v -4.462178 7.934419 -1.594468 +v -4.876396 7.721745 -0.652154 +v -4.889953 7.765681 -0.685802 +v -4.903808 7.812061 -0.720961 +v -4.955191 7.949085 -0.828591 +v -4.976340 8.005411 -0.872318 +v -4.993372 8.063781 -0.915677 +v -4.996076 8.231630 -1.024230 +v -4.981860 8.295767 -1.061043 +v -4.960953 8.358916 -1.095247 +v -3.559998 8.590981 -1.583335 +v -3.523340 8.542306 -1.582766 +v -3.487123 8.491053 -1.579556 +v -3.387696 8.342014 -1.559377 +v -3.351300 8.282636 -1.546182 +v -3.317331 8.222198 -1.529451 +v -3.241477 8.060760 -1.461971 +v -3.220813 8.002648 -1.428323 +v -3.204023 7.945850 -1.391753 +v -4.193808 7.687989 -1.624182 +v -4.166962 7.731500 -1.660526 +v -4.137534 7.778920 -1.694268 +v -4.045123 7.927430 -1.773901 +v -4.006433 7.990052 -1.797642 +v -3.966694 8.054669 -1.814883 +v -3.857767 8.233029 -1.824051 +v -3.817472 8.298823 -1.812991 +v -3.778529 8.362617 -1.793632 +v -2.981435 8.637374 -0.552397 +v -2.995494 8.649458 -0.500459 +v -3.017570 8.657795 -0.447728 +v -3.105955 8.663830 -0.304451 +v -3.145900 8.662485 -0.251320 +v -3.187854 8.660447 -0.199302 +v -3.299071 8.654308 -0.062799 +v -3.341289 8.650317 -0.015134 +v -3.385171 8.644973 0.029659 +v -3.699932 8.597667 0.220833 +v -3.750912 8.605688 0.218333 +v -3.804937 8.612087 0.212173 +v -3.963627 8.633319 0.201262 +v -4.027182 8.644269 0.200352 +v -4.091823 8.655240 0.198320 +v -4.273708 8.679837 0.181054 +v -4.343886 8.686417 0.170040 +v -4.413267 8.690075 0.155282 +v -4.789376 8.678450 -0.068075 +v -4.814075 8.694085 -0.124162 +v -4.835565 8.707633 -0.184136 +v -4.878501 8.736813 -0.363640 +v -4.887743 8.743190 -0.437288 +v -4.892574 8.746191 -0.512734 +v -4.892708 8.745744 -0.716818 +v -4.886812 8.741975 -0.791675 +v -4.876051 8.734812 -0.864748 +v -4.703153 8.679293 -1.277509 +v -4.656737 8.694641 -1.318282 +v -4.606467 8.709084 -1.357971 +v -4.453184 8.745687 -1.462591 +v -4.387670 8.755219 -1.498865 +v -4.318638 8.761457 -1.531775 +v -4.124045 8.764724 -1.603788 +v -4.049676 8.760080 -1.621092 +v -3.975288 8.751834 -1.632245 +v -3.551913 8.656060 -1.528868 +v -3.510130 8.660374 -1.482899 +v -3.469047 8.663202 -1.434160 +v -3.354512 8.670533 -1.298487 +v -3.310445 8.673846 -1.247446 +v -3.267818 8.676269 -1.195670 +v -3.169368 8.671444 -1.047175 +v -3.139878 8.665162 -0.988425 +v -3.111944 8.658463 -0.928894 +v -3.892985 9.206944 -0.555299 +v -3.875860 9.184830 -0.504572 +v -3.858669 9.158602 -0.452668 +v -3.810678 9.083812 -0.304776 +v -3.792235 9.057022 -0.247849 +v -3.773692 9.030057 -0.191451 +v -3.724965 8.943520 -0.043355 +v -3.707684 8.907797 0.009963 +v -3.691783 8.868779 0.058823 +v -2.988599 8.688069 -0.613397 +v -3.004270 8.747635 -0.613336 +v -3.027749 8.805182 -0.613415 +v -3.129051 8.950282 -0.614517 +v -3.180786 9.000708 -0.614815 +v -3.239268 9.045466 -0.615002 +v -3.405683 9.151640 -0.615414 +v -3.471609 9.182399 -0.615512 +v -3.540419 9.203219 -0.615683 +v -3.972095 9.222857 -0.577549 +v -4.019964 9.219489 -0.543608 +v -4.068764 9.211776 -0.508607 +v -4.204753 9.168045 -0.408107 +v -4.256617 9.141676 -0.369714 +v -4.307470 9.109746 -0.332688 +v -4.433161 9.002936 -0.240645 +v -4.475272 8.956230 -0.209683 +v -4.516752 8.907969 -0.179585 +v -3.973459 9.233446 -0.657088 +v -4.023536 9.241207 -0.692870 +v -4.075357 9.246239 -0.731020 +v -4.226840 9.241946 -0.845577 +v -4.286637 9.227630 -0.889851 +v -4.344116 9.203205 -0.932109 +v -4.471067 9.081351 -1.023937 +v -4.506557 9.017645 -1.049285 +v -4.540092 8.951355 -1.073362 +v -3.893290 9.219911 -0.678790 +v -3.875989 9.207691 -0.731313 +v -3.858623 9.191458 -0.786462 +v -3.809303 9.138495 -0.947315 +v -3.789722 9.115622 -1.009166 +v -3.770293 9.091727 -1.071277 +v -3.717687 9.007366 -1.236291 +v -3.697945 8.971922 -1.296464 +v -3.679584 8.933999 -1.353704 +v -3.682055 9.213587 -0.689324 +v -3.724606 9.199320 -0.742682 +v -3.770319 9.182097 -0.795320 +v -3.581634 9.087657 -0.969719 +v -3.629519 9.074342 -1.023740 +v -3.678425 9.062245 -1.078153 +v -3.369698 9.118130 -0.696816 +v -3.411593 9.121525 -0.758151 +v -3.456961 9.117370 -0.818488 +v -3.507386 8.893820 -1.234208 +v -3.551363 8.891022 -1.291386 +v -3.596382 8.886638 -1.347708 +v -3.109731 8.900057 -0.690281 +v -3.148047 8.905502 -0.748828 +v -3.191602 8.905392 -0.807769 +v -3.304984 8.904050 -0.966996 +v -3.346792 8.903944 -1.026278 +v -3.389984 8.902528 -1.084016 +v -3.592249 9.204640 -0.694557 +v -3.566877 9.182757 -0.755321 +v -3.544767 9.152425 -0.816080 +v -3.743205 9.149566 -0.874938 +v -3.674725 9.139936 -0.882575 +v -3.607119 9.129104 -0.889605 +v -3.288293 9.061560 -0.695035 +v -3.271534 9.020085 -0.754055 +v -3.260259 8.971818 -0.812056 +v -3.436283 9.058681 -0.897447 +v -3.377148 9.016021 -0.895963 +v -3.320551 8.969205 -0.892823 +v -3.496798 9.050666 -0.974615 +v -3.481139 9.006655 -1.031915 +v -3.466633 8.960223 -1.087460 +v -3.654525 9.014084 -1.157421 +v -3.589791 8.983139 -1.159920 +v -3.527500 8.949498 -1.161234 +v -3.061343 8.826468 -0.685602 +v -3.063945 8.776760 -0.737188 +v -3.070285 8.722458 -0.787009 +v -3.191648 8.833984 -0.879017 +v -3.153569 8.779738 -0.871698 +v -3.118206 8.724859 -0.863327 +v -3.240165 8.837738 -0.958376 +v -3.231927 8.789694 -1.010215 +v -3.224072 8.741686 -1.060196 +v -3.376169 8.838684 -1.151097 +v -3.324273 8.792035 -1.144014 +v -3.275221 8.743675 -1.135784 +v -3.434477 8.835425 -1.223444 +v -3.425962 8.786185 -1.268095 +v -3.419334 8.735394 -1.310839 +v -3.580453 8.824745 -1.407547 +v -3.527002 8.780264 -1.394904 +v -3.476633 8.732260 -1.381714 +v -3.926120 9.194753 -0.850725 +v -3.994136 9.217324 -0.836077 +v -4.061201 9.236729 -0.817941 +v -4.185503 9.211307 -1.097467 +v -4.259274 9.205668 -1.068286 +v -4.329360 9.188986 -1.034371 +v -3.839338 9.099355 -1.152074 +v -3.912344 9.136661 -1.149601 +v -3.986179 9.170182 -1.144158 +v -4.415645 8.978444 -1.260739 +v -4.468204 8.946947 -1.213997 +v -4.518586 8.912907 -1.166347 +v -3.744517 8.921075 -1.432797 +v -3.813724 8.952017 -1.438825 +v -3.885502 8.978805 -1.440265 +v -4.087035 9.025133 -1.414365 +v -4.164946 9.029037 -1.391793 +v -4.241158 9.025363 -1.362805 +v -3.903847 9.176037 -0.938455 +v -3.957305 9.189836 -0.996315 +v -4.011636 9.201324 -1.054045 +v -4.135341 9.247370 -0.884395 +v -4.122613 9.242415 -0.959206 +v -4.107930 9.230033 -1.032735 +v -3.811202 9.052359 -1.238216 +v -3.862166 9.048642 -1.302389 +v -3.914034 9.038292 -1.363269 +v -4.058293 9.160676 -1.222312 +v -4.036488 9.121496 -1.290938 +v -4.014236 9.075032 -1.355201 +v -4.161096 9.172014 -1.194065 +v -4.217231 9.134100 -1.237478 +v -4.270721 9.085374 -1.275047 +v -4.396630 9.126654 -1.082556 +v -4.380684 9.097925 -1.155594 +v -4.362219 9.062813 -1.226265 +v -3.720380 8.852619 -1.491896 +v -3.768285 8.825446 -1.540540 +v -3.816317 8.791068 -1.584758 +v -3.954019 8.937501 -1.502753 +v -3.931658 8.879842 -1.548055 +v -3.909366 8.818364 -1.588203 +v -4.054716 8.952679 -1.486788 +v -4.107099 8.901855 -1.518326 +v -4.158196 8.845548 -1.544001 +v -4.308684 8.950291 -1.400468 +v -4.284979 8.899452 -1.457497 +v -4.258810 8.844076 -1.509220 +v -4.396147 8.931245 -1.350835 +v -4.439138 8.871019 -1.372844 +v -4.480177 8.809495 -1.391117 +v -4.569872 8.835087 -1.197972 +v -4.560279 8.808552 -1.266589 +v -4.550959 8.778857 -1.332562 +v -4.151832 9.245574 -0.690433 +v -4.150643 9.237078 -0.619229 +v -4.146411 9.222140 -0.549280 +v -4.413922 9.133284 -0.518073 +v -4.404873 9.116398 -0.444956 +v -4.393065 9.094882 -0.374363 +v -4.425813 9.166559 -0.881924 +v -4.428533 9.167609 -0.803224 +v -4.427226 9.162282 -0.723487 +v -4.643164 8.929279 -0.348342 +v -4.622885 8.906469 -0.283817 +v -4.601057 8.881031 -0.221080 +v -4.612121 8.900437 -1.018597 +v -4.632320 8.923421 -0.953124 +v -4.651280 8.944132 -0.886981 +v -4.676096 8.968611 -0.692905 +v -4.676736 8.968491 -0.615524 +v -4.673787 8.964646 -0.538624 +v -4.230202 9.236674 -0.742379 +v -4.289923 9.218093 -0.706500 +v -4.347813 9.192513 -0.669449 +v -4.218515 9.196030 -0.499908 +v -4.280472 9.189241 -0.533381 +v -4.341735 9.176198 -0.568953 +v -4.491301 9.107405 -0.929517 +v -4.546142 9.066467 -0.888496 +v -4.599001 9.021878 -0.847215 +v -4.499699 9.109691 -0.669996 +v -4.554760 9.071735 -0.708561 +v -4.606402 9.028031 -0.746240 +v -4.494703 9.099876 -0.565928 +v -4.547927 9.058844 -0.526645 +v -4.599072 9.014549 -0.488500 +v -4.458372 9.039514 -0.326525 +v -4.521791 9.018555 -0.359131 +v -4.583743 8.993015 -0.393048 +v -4.663498 8.828918 -1.058457 +v -4.723714 8.800230 -1.026820 +v -4.783043 8.769794 -0.997195 +v -4.727767 8.895106 -0.840245 +v -4.769559 8.844078 -0.875221 +v -4.808483 8.791930 -0.910222 +v -4.740706 8.906877 -0.743335 +v -4.791386 8.862521 -0.704936 +v -4.838352 8.815092 -0.666208 +v -4.739045 8.903557 -0.487515 +v -4.791061 8.861447 -0.525144 +v -4.838488 8.814972 -0.563612 +v -4.726242 8.890964 -0.390719 +v -4.770927 8.843408 -0.354311 +v -4.811840 8.793356 -0.318386 +v -4.658690 8.820245 -0.177142 +v -4.723798 8.797851 -0.204590 +v -4.786232 8.770794 -0.231935 +v -4.051454 9.177773 -0.429395 +v -3.987302 9.159264 -0.411410 +v -3.922356 9.140318 -0.396555 +v -3.969861 9.037032 -0.159379 +v -3.903388 9.022091 -0.146112 +v -3.837185 9.006982 -0.133632 +v -4.286193 9.070768 -0.247857 +v -4.218904 9.072438 -0.223645 +v -4.150510 9.068469 -0.202588 +v -3.881145 8.845266 0.075628 +v -3.817009 8.838167 0.089995 +v -3.754326 8.828965 0.102348 +v -4.492448 8.866264 -0.097361 +v -4.432937 8.879659 -0.066562 +v -4.372703 8.889946 -0.037853 +v -4.197781 8.890429 0.017980 +v -4.128407 8.882042 0.032190 +v -4.059012 8.871334 0.043882 +v -4.117021 9.161597 -0.375878 +v -4.100757 9.133209 -0.314891 +v -4.083455 9.101304 -0.255637 +v -3.898865 9.102000 -0.321151 +v -3.946702 9.091040 -0.277139 +v -3.994675 9.079126 -0.234108 +v -4.350199 9.019899 -0.200519 +v -4.332376 8.986092 -0.139152 +v -4.313783 8.949011 -0.080164 +v -4.125827 9.018831 -0.125600 +v -4.175924 8.986141 -0.087025 +v -4.225129 8.949399 -0.050687 +v -4.033792 9.004815 -0.105738 +v -4.014174 8.962585 -0.053540 +v -3.994558 8.917679 -0.003805 +v -3.812027 8.958627 -0.061962 +v -3.858804 8.931711 -0.022975 +v -3.905643 8.901552 0.013551 +v -4.550888 8.808093 -0.056379 +v -4.536792 8.777811 0.004520 +v -4.523300 8.743954 0.062256 +v -4.350162 8.840555 0.037817 +v -4.396311 8.797647 0.068806 +v -4.441843 8.752575 0.096843 +v -4.260746 8.837801 0.061371 +v -4.237903 8.790220 0.106207 +v -4.213793 8.739466 0.146122 +v -4.030568 8.805637 0.098914 +v -4.076550 8.766361 0.128864 +v -4.121930 8.725728 0.157180 +v -3.943006 8.792025 0.108757 +v -3.924648 8.741723 0.141159 +v -3.906438 8.690356 0.170238 +v -3.735043 8.766179 0.148003 +v -3.780401 8.725691 0.166965 +v -3.825053 8.681280 0.182684 +v -3.772122 9.153315 -0.443063 +v -3.726409 9.180628 -0.492498 +v -3.683296 9.203714 -0.543845 +v -3.460545 9.107204 -0.414542 +v -3.414131 9.114944 -0.473735 +v -3.371049 9.114787 -0.534238 +v -3.684434 9.018998 -0.175995 +v -3.635649 9.042047 -0.222102 +v -3.587264 9.063641 -0.270375 +v -3.187624 8.907478 -0.421208 +v -3.143332 8.908302 -0.479509 +v -3.105713 8.902514 -0.537761 +v -3.610392 8.841127 0.068156 +v -3.562213 8.859515 0.028348 +v -3.515123 8.873715 -0.016142 +v -3.393796 8.897818 -0.149850 +v -3.349966 8.900803 -0.205998 +v -3.307221 8.901636 -0.264714 +v -3.746504 9.113865 -0.366931 +v -3.679346 9.110964 -0.357053 +v -3.612213 9.106071 -0.348201 +v -3.593909 9.197827 -0.537808 +v -3.569798 9.172061 -0.477782 +v -3.548724 9.138683 -0.418020 +v -3.660723 8.972137 -0.100302 +v -3.595293 8.954629 -0.089437 +v -3.532113 8.931298 -0.082152 +v -3.500578 9.037182 -0.260260 +v -3.483999 8.995924 -0.202441 +v -3.469357 8.951252 -0.147593 +v -3.439618 9.048897 -0.335402 +v -3.379352 9.009889 -0.335613 +v -3.321630 8.965979 -0.338048 +v -3.288796 9.060242 -0.535338 +v -3.271954 9.018598 -0.476258 +v -3.260189 8.970644 -0.418216 +v -3.600510 8.774858 0.115753 +v -3.549571 8.738894 0.110430 +v -3.502311 8.696948 0.100560 +v -3.444971 8.821509 -0.023275 +v -3.441907 8.767452 0.013406 +v -3.441756 8.711020 0.045846 +v -3.386054 8.829714 -0.088815 +v -3.339892 8.780186 -0.099287 +v -3.297025 8.728094 -0.112121 +v -3.243074 8.834860 -0.275520 +v -3.240813 8.782751 -0.228182 +v -3.240751 8.729821 -0.183966 +v -3.184520 8.837705 -0.350174 +v -3.140162 8.787548 -0.355823 +v -3.100536 8.735893 -0.363164 +v -3.051880 8.832257 -0.540625 +v -3.047207 8.787107 -0.487562 +v -3.049443 8.735692 -0.437200 +v -2.985388 8.468176 -0.793173 +v -3.009251 8.522194 -0.813607 +v -3.036024 8.576841 -0.831350 +v -3.078121 8.498191 -1.079459 +v -3.115828 8.553624 -1.095366 +v -3.157001 8.607271 -1.108909 +v -2.968498 8.222538 -0.968856 +v -2.981706 8.283279 -0.997408 +v -3.000460 8.343517 -1.023734 +v -3.268776 8.497601 -1.342076 +v -3.310588 8.549459 -1.349923 +v -3.353817 8.600000 -1.356799 +v -3.038081 7.957119 -1.116875 +v -3.042697 8.012877 -1.152955 +v -3.051081 8.069457 -1.187673 +v -3.100921 8.226810 -1.266044 +v -3.131021 8.287494 -1.288399 +v -3.165480 8.347630 -1.307307 +v -2.975341 8.402782 -0.844781 +v -2.988101 8.409184 -0.908159 +v -3.004715 8.415308 -0.971249 +v -3.064567 8.585799 -0.910393 +v -3.053175 8.538286 -0.954904 +v -3.042702 8.490070 -0.998433 +v -2.979035 8.145103 -1.016536 +v -3.000371 8.146111 -1.082706 +v -3.026779 8.146649 -1.147352 +v -3.034483 8.346730 -1.108917 +v -3.039787 8.287344 -1.148200 +v -3.050031 8.226897 -1.185234 +v -3.075917 8.426305 -1.136421 +v -3.113837 8.427606 -1.196077 +v -3.156039 8.427206 -1.253763 +v -3.208339 8.608974 -1.184189 +v -3.207350 8.555941 -1.228607 +v -3.209292 8.500948 -1.271804 +v -3.072414 7.885892 -1.147962 +v -3.103727 7.884993 -1.206284 +v -3.137721 7.881933 -1.263882 +v -3.096440 8.068311 -1.268181 +v -3.120972 8.010050 -1.292435 +v -3.148589 7.951938 -1.314034 +v -3.121264 8.145911 -1.310623 +v -3.164245 8.145040 -1.369235 +v -3.210674 8.143705 -1.426070 +v -3.225943 8.346527 -1.382113 +v -3.236801 8.285810 -1.420637 +v -3.251011 8.224073 -1.456666 +v -3.275757 8.423379 -1.399901 +v -3.322167 8.421824 -1.452796 +v -3.370413 8.420049 -1.504487 +v -3.412710 8.596478 -1.424524 +v -3.415786 8.543882 -1.469221 +v -3.422459 8.490909 -1.513946 +v -3.776475 8.527969 -1.736738 +v -3.809402 8.591605 -1.713266 +v -3.840803 8.653851 -1.683434 +v -4.125281 8.559468 -1.714587 +v -4.156164 8.623285 -1.675258 +v -4.185570 8.685200 -1.631802 +v -3.962977 8.238005 -1.823441 +v -4.000162 8.309548 -1.813029 +v -4.036296 8.380240 -1.794648 +v -4.458034 8.541448 -1.546966 +v -4.484222 8.601876 -1.510499 +v -4.507834 8.659361 -1.471041 +v -4.145768 7.931784 -1.748063 +v -4.185103 7.995517 -1.750662 +v -4.223550 8.060461 -1.747179 +v -4.319027 8.237702 -1.703276 +v -4.351375 8.304653 -1.674060 +v -4.381855 8.371208 -1.640863 +v -3.827693 8.453664 -1.776365 +v -3.903492 8.461299 -1.781365 +v -3.980182 8.467098 -1.777693 +v -3.937305 8.668236 -1.683992 +v -3.981323 8.613475 -1.714411 +v -4.024939 8.555083 -1.738616 +v -4.017813 8.146631 -1.816056 +v -4.096399 8.147904 -1.798791 +v -4.173554 8.148597 -1.774116 +v -4.139145 8.381468 -1.765947 +v -4.181181 8.311375 -1.762683 +v -4.221757 8.240718 -1.752876 +v -4.182381 8.471585 -1.723735 +v -4.255895 8.468819 -1.688255 +v -4.327752 8.464442 -1.648311 +v -4.282114 8.681851 -1.588708 +v -4.325129 8.616251 -1.594752 +v -4.366836 8.548965 -1.596536 +v -4.188648 7.853944 -1.708996 +v -4.257670 7.856080 -1.682862 +v -4.324103 7.857358 -1.651374 +v -4.318838 8.061230 -1.705229 +v -4.349760 7.997779 -1.679385 +v -4.377158 7.936047 -1.648761 +v -4.367223 8.147252 -1.684134 +v -4.435337 8.146235 -1.643883 +v -4.500826 8.145206 -1.600358 +v -4.472312 8.367227 -1.585933 +v -4.509086 8.299383 -1.576896 +v -4.543492 8.231961 -1.564349 +v -4.509923 8.452363 -1.543112 +v -4.574539 8.447938 -1.504887 +v -4.636409 8.443184 -1.464651 +v -4.588810 8.647831 -1.421111 +v -4.628430 8.585475 -1.422810 +v -4.665903 8.521683 -1.418852 +v -4.921224 8.523872 -1.086229 +v -4.909872 8.586020 -1.048011 +v -4.891017 8.645823 -1.009105 +v -5.000406 8.550974 -0.748463 +v -4.974955 8.613154 -0.708058 +v -4.943387 8.672503 -0.667607 +v -5.023572 8.236321 -0.926115 +v -5.031848 8.305486 -0.890391 +v -5.032898 8.374495 -0.853139 +v -4.981095 8.544589 -0.380373 +v -4.951893 8.603782 -0.344948 +v -4.916790 8.658957 -0.311420 +v -4.961417 7.953402 -0.730245 +v -4.987634 8.010977 -0.697112 +v -5.011536 8.069852 -0.662885 +v -5.042622 8.239353 -0.562306 +v -5.040678 8.306670 -0.522202 +v -5.032489 8.373983 -0.482312 +v -4.964622 8.448066 -1.045986 +v -4.989291 8.454442 -0.975275 +v -5.007914 8.459718 -0.902163 +v -4.915928 8.657164 -0.916738 +v -4.955842 8.603677 -0.884204 +v -4.989468 8.546228 -0.849960 +v -5.021287 8.149411 -0.871529 +v -5.029346 8.150761 -0.794940 +v -5.033240 8.151649 -0.717648 +v -5.042264 8.376741 -0.749750 +v -5.047358 8.308639 -0.709466 +v -5.045472 8.240351 -0.668527 +v -5.029544 8.466693 -0.696747 +v -5.028447 8.466526 -0.616429 +v -5.022884 8.464866 -0.535886 +v -4.940961 8.672052 -0.563149 +v -4.969122 8.611822 -0.523325 +v -4.991453 8.548754 -0.483311 +v -4.936564 7.880448 -0.680236 +v -4.944850 7.879160 -0.611747 +v -4.952538 7.875660 -0.542875 +v -5.017257 8.068289 -0.564568 +v -5.000995 8.007397 -0.528739 +v -4.983187 7.947274 -0.493775 +v -5.035018 8.150136 -0.511636 +v -5.032413 8.148689 -0.433948 +v -5.026565 8.147043 -0.356147 +v -5.022648 8.371550 -0.377837 +v -5.025300 8.303091 -0.339539 +v -5.023313 8.234439 -0.301957 +v -5.000273 8.457836 -0.327462 +v -4.987666 8.454196 -0.252070 +v -4.970214 8.449599 -0.178565 +v -4.897131 8.649061 -0.217494 +v -4.917648 8.589357 -0.177339 +v -4.931030 8.527131 -0.137479 +v -4.667425 8.515527 0.182840 +v -4.619375 8.571266 0.173916 +v -4.569108 8.624122 0.158086 +v -4.323957 8.501600 0.252758 +v -4.280746 8.554614 0.238448 +v -4.237814 8.605316 0.220867 +v -4.521029 8.226372 0.284096 +v -4.480457 8.288464 0.283478 +v -4.438740 8.349334 0.278772 +v -4.004107 8.471043 0.274596 +v -3.968027 8.516797 0.253319 +v -3.931699 8.561518 0.231266 +v -4.340181 7.950574 0.317305 +v -4.306722 8.009572 0.324735 +v -4.272675 8.067887 0.329800 +v -4.176252 8.222124 0.330116 +v -4.138750 8.279290 0.325038 +v -4.101555 8.335331 0.316541 +v -4.635619 8.438027 0.221632 +v -4.561116 8.436139 0.240674 +v -4.483967 8.432875 0.254027 +v -4.474999 8.622667 0.181251 +v -4.449739 8.566922 0.212304 +v -4.421964 8.508229 0.238488 +v -4.471411 8.143785 0.299921 +v -4.396220 8.144667 0.312277 +v -4.321970 8.145099 0.321891 +v -4.338157 8.346448 0.291955 +v -4.304654 8.285285 0.307111 +v -4.270957 8.224458 0.319737 +v -4.284163 8.423027 0.281213 +v -4.212644 8.419051 0.289653 +v -4.142588 8.414207 0.295664 +v -4.145700 8.595512 0.229625 +v -4.118218 8.539685 0.254249 +v -4.090322 8.482852 0.275473 +v -4.291399 7.879615 0.319445 +v -4.224436 7.884140 0.328686 +v -4.158517 7.886512 0.335344 +v -4.180645 8.069632 0.340444 +v -4.147356 8.014236 0.343456 +v -4.114708 7.959399 0.343624 +v -4.134151 8.144762 0.342374 +v -4.067096 8.144241 0.347281 +v -4.001303 8.143405 0.348195 +v -4.013559 8.330668 0.319151 +v -3.984236 8.273593 0.330849 +v -3.955080 8.216499 0.338389 +v -3.968056 8.398018 0.296176 +v -3.906866 8.391364 0.290114 +v -3.846955 8.384973 0.281700 +v -3.852549 8.550700 0.229509 +v -3.828916 8.498560 0.245056 +v -3.803998 8.446934 0.257808 +v -3.486261 8.451213 0.158756 +v -3.469588 8.506228 0.139645 +v -3.456450 8.561598 0.117905 +v -3.267011 8.475546 -0.012564 +v -3.257948 8.530399 -0.045547 +v -3.251015 8.584927 -0.080972 +v -3.349094 8.215491 0.093558 +v -3.326618 8.271500 0.076462 +v -3.305931 8.327496 0.057228 +v -3.089304 8.478039 -0.258074 +v -3.077186 8.534626 -0.291099 +v -3.067036 8.590545 -0.325782 +v -3.210482 7.963420 0.021341 +v -3.189945 8.016362 -0.000895 +v -3.173217 8.070432 -0.027004 +v -3.138003 8.217596 -0.104327 +v -3.127311 8.273310 -0.136357 +v -3.117914 8.329003 -0.169706 +v -3.445241 8.385880 0.142601 +v -3.394639 8.391398 0.111693 +v -3.345454 8.396590 0.077797 +v -3.394591 8.570765 0.070219 +v -3.358648 8.521264 0.059249 +v -3.324922 8.470814 0.046454 +v -3.309980 8.143160 0.071701 +v -3.259310 8.143594 0.035475 +v -3.211403 8.143730 -0.004292 +v -3.243224 8.329677 0.003496 +v -3.214771 8.274172 -0.015584 +v -3.188149 8.218099 -0.036386 +v -3.226439 8.403835 -0.035621 +v -3.187480 8.404119 -0.087052 +v -3.151032 8.403778 -0.141122 +v -3.197771 8.586967 -0.150163 +v -3.166696 8.532763 -0.167613 +v -3.138434 8.477682 -0.186812 +v -3.183458 7.896217 -0.010031 +v -3.142425 7.895788 -0.056100 +v -3.105863 7.894112 -0.106398 +v -3.121793 8.070137 -0.092343 +v -3.099643 8.015450 -0.115157 +v -3.081156 7.961139 -0.140376 +v -3.109436 8.143253 -0.134756 +v -3.080435 8.142876 -0.190728 +v -3.053890 8.142157 -0.248282 +v -3.078231 8.327852 -0.244689 +v -3.060105 8.271622 -0.268333 +v -3.043022 8.215471 -0.292662 +v -3.063142 8.401422 -0.287499 +v -3.034165 8.399406 -0.342547 +v -3.008154 8.397051 -0.398369 +v -3.026350 8.586769 -0.397358 +v -3.008422 8.528167 -0.417284 +v -2.994348 8.469664 -0.440337 +v -3.513412 8.422903 -1.636917 +v -3.574500 8.427881 -1.681369 +v -3.639092 8.433526 -1.719494 +v -3.650538 8.137158 -1.782469 +v -3.727713 8.138422 -1.805977 +v -3.806725 8.140022 -1.820625 +v -3.345611 8.137721 -1.576366 +v -3.402625 8.136560 -1.631071 +v -3.464089 8.135844 -1.681202 +v -3.845541 7.824274 -1.759979 +v -3.921324 7.830631 -1.760123 +v -3.996365 7.838436 -1.753237 +v -3.240584 7.859561 -1.417717 +v -3.284476 7.848217 -1.476008 +v -3.332896 7.837971 -1.531428 +v -3.494399 7.820246 -1.655336 +v -3.566389 7.817063 -1.691408 +v -3.641745 7.816333 -1.720335 +v -3.463115 8.343004 -1.628218 +v -3.485756 8.283475 -1.667900 +v -3.512007 8.221827 -1.702772 +v -3.678807 8.356919 -1.765169 +v -3.639684 8.291623 -1.764435 +v -3.601701 8.225237 -1.757085 +v -3.306268 8.052993 -1.539415 +v -3.332026 7.985084 -1.564149 +v -3.361455 7.916967 -1.583432 +v -3.504904 8.045330 -1.711537 +v -3.471272 7.977460 -1.684343 +v -3.441259 7.911055 -1.650700 +v -3.601793 8.044158 -1.759401 +v -3.642452 7.974341 -1.765673 +v -3.685393 7.905684 -1.763367 +v -3.862311 8.049150 -1.819173 +v -3.825477 7.978179 -1.805953 +v -3.789560 7.908360 -1.785265 +v -3.223501 7.791688 -1.359841 +v -3.252102 7.729372 -1.369684 +v -3.283337 7.668761 -1.373565 +v -3.377430 7.751237 -1.540124 +v -3.359313 7.698279 -1.492247 +v -3.345023 7.649714 -1.440101 +v -3.459817 7.741033 -1.595786 +v -3.504210 7.679692 -1.584547 +v -3.551550 7.622174 -1.566222 +v -3.702629 7.734428 -1.698629 +v -3.673930 7.675056 -1.654383 +v -3.647434 7.619554 -1.604481 +v -3.802204 7.739530 -1.718126 +v -3.845869 7.684671 -1.688747 +v -3.889596 7.633886 -1.654088 +v -4.047361 7.766150 -1.711248 +v -4.014738 7.705313 -1.685668 +v -3.984098 7.646565 -1.654135 +v -4.783994 8.434247 -1.337636 +v -4.832295 8.434277 -1.281348 +v -4.875566 8.435550 -1.221167 +v -4.908707 8.138887 -1.209056 +v -4.945714 8.139750 -1.140797 +v -4.975475 8.141541 -1.069522 +v -4.666235 8.141110 -1.476946 +v -4.725418 8.140110 -1.426437 +v -4.781331 8.139370 -1.372154 +v -4.907855 7.846825 -1.009108 +v -4.916571 7.856018 -0.938196 +v -4.920599 7.866312 -0.866250 +v -4.485080 7.851542 -1.545567 +v -4.540970 7.847257 -1.499347 +v -4.594731 7.843928 -1.449677 +v -4.735945 7.836698 -1.305907 +v -4.787429 7.834531 -1.247636 +v -4.833330 7.834620 -1.186159 +v -4.759884 8.353467 -1.383509 +v -4.791645 8.290041 -1.361785 +v -4.819382 8.225775 -1.335557 +v -4.914792 8.355437 -1.186002 +v -4.901237 8.291229 -1.221710 +v -4.882382 8.226229 -1.254756 +v -4.617206 8.054905 -1.503703 +v -4.636532 7.988800 -1.471472 +v -4.651680 7.923855 -1.434893 +v -4.807136 8.050499 -1.327407 +v -4.768988 7.984916 -1.347735 +v -4.726295 7.921067 -1.363876 +v -4.873315 8.049214 -1.246257 +v -4.885181 7.982288 -1.206293 +v -4.889362 7.917745 -1.162676 +v -4.979555 8.055737 -1.014770 +v -4.957316 7.988037 -1.044531 +v -4.929006 7.921985 -1.071078 +v -4.426169 7.780795 -1.548264 +v -4.433529 7.725637 -1.503546 +v -4.435727 7.672552 -1.456030 +v -4.600492 7.767375 -1.388162 +v -4.551010 7.715717 -1.390956 +v -4.500070 7.666931 -1.391336 +v -4.665269 7.764406 -1.315654 +v -4.659301 7.711617 -1.263728 +v -4.648725 7.662832 -1.209412 +v -4.820988 7.762558 -1.118454 +v -4.766872 7.710785 -1.126885 +v -4.707639 7.663222 -1.131905 +v -4.859900 7.769133 -1.034127 +v -4.837115 7.722316 -0.982896 +v -4.810402 7.679718 -0.930504 +v -4.890517 7.801927 -0.805918 +v -4.861365 7.746208 -0.827329 +v -4.828683 7.692851 -0.845166 +v -4.895204 8.440023 0.005606 +v -4.853755 8.439230 0.068117 +v -4.804492 8.438670 0.123773 +v -4.813744 8.136986 0.164974 +v -4.746550 8.137927 0.208187 +v -4.673731 8.139067 0.243143 +v -4.995671 8.139431 -0.147720 +v -4.974001 8.137733 -0.070307 +v -4.944281 8.136691 0.003737 +v -4.626088 7.828635 0.242179 +v -4.553828 7.840413 0.266911 +v -4.479705 7.853422 0.285163 +v -4.964738 7.851488 -0.350346 +v -4.966005 7.838870 -0.273843 +v -4.961247 7.827547 -0.197522 +v -4.895967 7.810283 -0.001957 +v -4.851057 7.809049 0.065593 +v -4.797434 7.810853 0.126663 +v -4.937286 8.358607 -0.028251 +v -4.930229 8.293576 0.012381 +v -4.916893 8.227036 0.049644 +v -4.783071 8.357298 0.170804 +v -4.820988 8.293341 0.153879 +v -4.853580 8.227101 0.130741 +v -5.003472 8.050031 -0.203301 +v -4.992050 7.978648 -0.168022 +v -4.974670 7.907932 -0.135348 +v -4.919806 8.042111 0.048799 +v -4.935476 7.971302 0.009592 +v -4.942830 7.902332 -0.034370 +v -4.852755 8.042527 0.132329 +v -4.818060 7.972157 0.157552 +v -4.777284 7.903481 0.177090 +v -4.621277 8.050733 0.264678 +v -4.655496 7.980252 0.250861 +v -4.685719 7.909678 0.231359 +v -4.936110 7.783870 -0.411638 +v -4.914411 7.721568 -0.387185 +v -4.887222 7.661396 -0.366028 +v -4.924044 7.739984 -0.165258 +v -4.904279 7.688105 -0.218054 +v -4.878455 7.641153 -0.272367 +v -4.889198 7.729116 -0.070528 +v -4.841274 7.667876 -0.055429 +v -4.786262 7.611412 -0.044940 +v -4.730324 7.728676 0.142940 +v -4.731518 7.666966 0.094772 +v -4.725249 7.610585 0.040196 +v -4.651412 7.737891 0.206299 +v -4.599241 7.682723 0.209694 +v -4.543393 7.632532 0.207616 +v -4.418781 7.782532 0.286108 +v -4.440861 7.716162 0.268365 +v -4.457202 7.651999 0.244627 +v -3.693246 8.375884 0.250337 +v -3.637697 8.375476 0.233232 +v -3.583399 8.376255 0.213014 +v -3.559844 8.139820 0.213966 +v -3.505336 8.140311 0.185360 +v -3.451474 8.140757 0.155669 +v -3.833305 8.139683 0.324074 +v -3.772290 8.139170 0.305343 +v -3.712317 8.138926 0.282836 +v -3.425418 7.888814 0.135715 +v -3.367399 7.890107 0.111734 +v -3.311985 7.891787 0.085278 +v -3.988438 7.883379 0.335062 +v -3.925926 7.880966 0.326925 +v -3.863841 7.879036 0.314534 +v -3.700517 7.879418 0.260089 +v -3.640382 7.881345 0.233636 +v -3.581149 7.883646 0.205669 +v -3.730866 8.310405 0.269341 +v -3.701639 8.259553 0.266894 +v -3.672589 8.208412 0.261765 +v -3.545524 8.310575 0.201078 +v -3.570933 8.259576 0.216347 +v -3.597414 8.208467 0.231002 +v -3.876498 8.066834 0.335993 +v -3.847441 8.010295 0.326551 +v -3.818981 7.953524 0.313108 +v -3.674114 8.066282 0.266819 +v -3.705380 8.010180 0.277342 +v -3.737656 7.953539 0.285095 +v -3.596470 8.067772 0.230265 +v -3.568264 8.013567 0.213027 +v -3.540417 7.959028 0.194436 +v -3.412305 8.069540 0.134964 +v -3.437812 8.015039 0.147331 +v -3.464691 7.960254 0.157821 +v -4.033200 7.811205 0.329732 +v -4.005699 7.753716 0.318787 +v -3.980058 7.696795 0.303218 +v -3.827087 7.802432 0.293814 +v -3.862156 7.746409 0.292815 +v -3.898376 7.692026 0.287809 +v -3.744737 7.803264 0.265601 +v -3.717537 7.748188 0.242792 +v -3.691437 7.694428 0.216358 +v -3.545538 7.811761 0.175538 +v -3.578056 7.755089 0.179088 +v -3.611638 7.698842 0.180102 +v -3.468073 7.816500 0.139897 +v -3.443589 7.765336 0.115541 +v -3.421233 7.715973 0.087774 +v -3.283734 7.826438 0.053619 +v -3.316284 7.774799 0.055099 +v -3.350383 7.723349 0.051947 +v -2.962881 8.391992 -0.554673 +v -2.956670 8.392007 -0.616245 +v -2.955626 8.392987 -0.678348 +v -2.939317 8.138362 -0.705862 +v -2.939797 8.139047 -0.773000 +v -2.944240 8.140019 -0.839868 +v -2.992373 8.138979 -0.406511 +v -2.973722 8.138494 -0.468160 +v -2.958098 8.138065 -0.531023 +v -2.965295 7.865079 -0.864056 +v -2.982865 7.870680 -0.927318 +v -3.003516 7.876359 -0.989045 +v -3.024646 7.879751 -0.250838 +v -2.999845 7.872989 -0.309398 +v -2.978864 7.866619 -0.370629 +v -2.941215 7.854847 -0.545809 +v -2.936892 7.853848 -0.615304 +v -2.938059 7.854510 -0.685195 +v -2.967286 8.321198 -0.512861 +v -2.959136 8.267085 -0.543077 +v -2.952271 8.212449 -0.574294 +v -2.950601 8.323112 -0.722303 +v -2.945824 8.268296 -0.691420 +v -2.943743 8.212978 -0.659914 +v -2.998491 8.062842 -0.361200 +v -2.982147 8.002919 -0.387991 +v -2.968284 7.942018 -0.415932 +v -2.944685 8.059606 -0.571557 +v -2.945602 7.999662 -0.536534 +v -2.948359 7.939189 -0.501699 +v -2.937852 8.059539 -0.661979 +v -2.936390 7.999431 -0.696676 +v -2.938412 7.938744 -0.731366 +v -2.950142 8.062960 -0.885721 +v -2.947195 8.002384 -0.853645 +v -2.946601 7.941213 -0.821042 +v -3.052482 7.812689 -0.214012 +v -3.050160 7.753710 -0.242080 +v -3.052935 7.694534 -0.270781 +v -2.972018 7.782555 -0.410670 +v -2.991530 7.728044 -0.378181 +v -3.017840 7.676736 -0.347446 +v -2.949311 7.771503 -0.499489 +v -2.948797 7.704859 -0.533751 +v -2.955153 7.640128 -0.568651 +v -2.945929 7.770862 -0.731405 +v -2.947158 7.704361 -0.696633 +v -2.954381 7.639747 -0.661624 +v -2.966246 7.781218 -0.821128 +v -2.986504 7.726083 -0.853561 +v -3.012087 7.673638 -0.884953 +v -3.034531 7.806865 -1.026204 +v -3.036715 7.748007 -0.995416 +v -3.042245 7.688932 -0.965056 +v -3.300842 7.499634 -1.156937 +v -3.308995 7.522444 -1.222665 +v -3.317145 7.549084 -1.286484 +v -3.555040 7.419098 -1.328761 +v -3.571176 7.453320 -1.393787 +v -3.589458 7.492431 -1.455643 +v -3.509271 7.331097 -1.007417 +v -3.517210 7.342824 -1.077035 +v -3.524824 7.356281 -1.147002 +v -3.878269 7.413326 -1.437670 +v -3.898136 7.457057 -1.492175 +v -3.918574 7.504488 -1.542707 +v -3.734468 7.225872 -0.838707 +v -3.744606 7.223388 -0.903548 +v -3.755593 7.224221 -0.969121 +v -3.792424 7.255725 -1.146953 +v -3.809580 7.280922 -1.213295 +v -3.827673 7.312331 -1.277670 +v -3.354885 7.444464 -1.119129 +v -3.407326 7.423866 -1.156231 +v -3.461100 7.404278 -1.192759 +v -3.382679 7.524528 -1.340603 +v -3.426018 7.477414 -1.314472 +v -3.472515 7.434334 -1.283996 +v -3.574895 7.290854 -0.959159 +v -3.632928 7.269600 -0.990671 +v -3.691341 7.250292 -1.021030 +v -3.603190 7.330521 -1.190709 +v -3.653600 7.295145 -1.152547 +v -3.704807 7.264757 -1.112672 +v -3.622247 7.365367 -1.280657 +v -3.689817 7.358489 -1.308623 +v -3.759253 7.356366 -1.333210 +v -3.681951 7.488688 -1.490320 +v -3.732699 7.445661 -1.454632 +v -3.784175 7.406585 -1.415695 +v -3.795316 7.220114 -0.787592 +v -3.851194 7.216139 -0.808315 +v -3.907396 7.217221 -0.826299 +v -3.835852 7.215388 -0.999253 +v -3.882345 7.210969 -0.953903 +v -3.927231 7.214241 -0.907379 +v -3.858379 7.230161 -1.086162 +v -3.924564 7.235720 -1.104002 +v -3.990420 7.248365 -1.118464 +v -3.919408 7.321830 -1.300531 +v -3.968573 7.299092 -1.252907 +v -4.016206 7.283129 -1.202531 +v -3.944649 7.371473 -1.378846 +v -4.012609 7.384375 -1.388651 +v -4.078951 7.401923 -1.394686 +v -4.008461 7.520564 -1.550285 +v -4.055257 7.487288 -1.507451 +v -4.102234 7.459674 -1.461715 +v -4.244634 7.473340 -1.396760 +v -4.302991 7.509208 -1.394983 +v -4.359135 7.548985 -1.392586 +v -4.434070 7.473961 -1.138409 +v -4.492651 7.511021 -1.137826 +v -4.550481 7.550034 -1.136885 +v -4.158353 7.309185 -1.138009 +v -4.218760 7.341112 -1.139822 +v -4.277901 7.376812 -1.139951 +v -4.589937 7.509259 -0.865725 +v -4.649088 7.540798 -0.866143 +v -4.706014 7.575331 -0.865714 +v -4.055666 7.253168 -0.852671 +v -4.110508 7.276889 -0.855753 +v -4.165152 7.303566 -0.857896 +v -4.314808 7.375669 -0.860556 +v -4.372564 7.403305 -0.861429 +v -4.430920 7.431668 -0.862911 +v -4.222991 7.419772 -1.329071 +v -4.265063 7.416836 -1.274260 +v -4.305157 7.418579 -1.217106 +v -4.415751 7.546535 -1.322731 +v -4.400656 7.506177 -1.269672 +v -4.382913 7.469324 -1.214845 +v -4.128270 7.281961 -1.056202 +v -4.163814 7.295555 -0.996962 +v -4.197119 7.313630 -0.937248 +v -4.324436 7.392581 -1.059423 +v -4.299399 7.372498 -0.998637 +v -4.273583 7.355968 -0.938182 +v -4.402177 7.437317 -1.059905 +v -4.435160 7.447073 -1.000309 +v -4.467247 7.457407 -0.941258 +v -4.597250 7.557906 -1.058999 +v -4.571984 7.528068 -1.000586 +v -4.545689 7.501403 -0.941951 +v -4.026486 7.256024 -0.780214 +v -4.056056 7.280925 -0.731069 +v -4.083935 7.304184 -0.681213 +v -4.204011 7.335350 -0.786363 +v -4.177938 7.335213 -0.733521 +v -4.152504 7.333446 -0.681824 +v -4.278040 7.362411 -0.787288 +v -4.307504 7.376079 -0.734512 +v -4.338380 7.386349 -0.682099 +v -4.472631 7.444848 -0.790745 +v -4.444477 7.428536 -0.736592 +v -4.417449 7.412897 -0.682832 +v -4.554677 7.477073 -0.791889 +v -4.589440 7.480728 -0.738024 +v -4.624647 7.484670 -0.683995 +v -4.745064 7.582507 -0.792378 +v -4.722582 7.551764 -0.739378 +v -4.699924 7.524460 -0.684927 +v -4.723049 7.506047 -0.534185 +v -4.761304 7.522951 -0.476523 +v -4.797109 7.545907 -0.419418 +v -4.624454 7.421633 -0.247769 +v -4.653557 7.451746 -0.183352 +v -4.678560 7.488179 -0.120041 +v -4.438591 7.386161 -0.534657 +v -4.483105 7.381489 -0.475188 +v -4.526905 7.380936 -0.414684 +v -4.412238 7.438892 0.014315 +v -4.433842 7.472822 0.076880 +v -4.451871 7.511774 0.134729 +v -4.157198 7.322104 -0.543683 +v -4.187096 7.314157 -0.489754 +v -4.217933 7.305925 -0.434754 +v -4.296824 7.319131 -0.279792 +v -4.323082 7.338492 -0.218351 +v -4.348360 7.362377 -0.155989 +v -4.650112 7.458753 -0.532785 +v -4.633207 7.434529 -0.473032 +v -4.613447 7.413600 -0.412747 +v -4.777164 7.519564 -0.335800 +v -4.723950 7.474110 -0.332293 +v -4.665195 7.434805 -0.330992 +v -4.350985 7.366045 -0.538556 +v -4.325840 7.344493 -0.484398 +v -4.299436 7.324085 -0.430317 +v -4.489329 7.358908 -0.338981 +v -4.419540 7.338467 -0.344848 +v -4.349140 7.322381 -0.351090 +v -4.532283 7.382829 -0.255267 +v -4.489659 7.383368 -0.198749 +v -4.443655 7.388749 -0.143443 +v -4.619644 7.490839 -0.041482 +v -4.549571 7.458157 -0.048282 +v -4.477160 7.430359 -0.057485 +v -4.085897 7.299191 -0.546448 +v -4.058461 7.275316 -0.497061 +v -4.028818 7.252545 -0.449158 +v -4.177463 7.280262 -0.366760 +v -4.118323 7.263010 -0.372172 +v -4.059804 7.248612 -0.378125 +v -4.209392 7.297328 -0.291397 +v -4.169362 7.299936 -0.241429 +v -4.127940 7.306455 -0.191688 +v -4.289288 7.372179 -0.086978 +v -4.222418 7.354733 -0.099019 +v -4.156743 7.338570 -0.110841 +v -4.319598 7.406951 -0.001845 +v -4.273735 7.414414 0.048541 +v -4.227424 7.425283 0.095709 +v -4.383797 7.526430 0.190897 +v -4.319282 7.496518 0.181240 +v -4.252684 7.472390 0.168572 +v -3.112871 7.559565 -0.965950 +v -3.162004 7.528186 -0.996312 +v -3.213997 7.501162 -1.027196 +v -3.265148 7.333312 -0.824766 +v -3.335114 7.326683 -0.852371 +v -3.406239 7.323153 -0.879308 +v -3.015244 7.485195 -0.663918 +v -3.054715 7.436054 -0.701519 +v -3.103224 7.394811 -0.738336 +v -3.535274 7.243457 -0.656434 +v -3.593143 7.239244 -0.686998 +v -3.649521 7.235881 -0.716959 +v -3.084253 7.535488 -0.344800 +v -3.106404 7.476938 -0.373054 +v -3.135330 7.422597 -0.403386 +v -3.251497 7.310827 -0.493353 +v -3.309134 7.284436 -0.529840 +v -3.370904 7.266048 -0.566803 +v -3.076499 7.528757 -0.888213 +v -3.098243 7.469119 -0.859522 +v -3.127104 7.414716 -0.828818 +v -3.255075 7.436415 -0.990386 +v -3.228981 7.407638 -0.930847 +v -3.204507 7.381326 -0.869976 +v -3.017323 7.487293 -0.567162 +v -3.058912 7.440311 -0.530012 +v -3.109152 7.400599 -0.493449 +v -3.165095 7.339049 -0.690172 +v -3.163229 7.336703 -0.616058 +v -3.168704 7.342298 -0.541717 +v -3.248192 7.309852 -0.736607 +v -3.307954 7.285678 -0.699348 +v -3.371220 7.268218 -0.661670 +v -3.480081 7.292659 -0.830854 +v -3.469912 7.275908 -0.766371 +v -3.461350 7.261680 -0.701676 +v -3.123806 7.568107 -0.270288 +v -3.174561 7.538725 -0.241709 +v -3.228205 7.513589 -0.213409 +v -3.211650 7.386321 -0.361567 +v -3.236804 7.413197 -0.302229 +v -3.264619 7.443841 -0.245948 +v -3.267029 7.329640 -0.403137 +v -3.331439 7.313590 -0.372358 +v -3.397430 7.302412 -0.343223 +v -3.457165 7.253427 -0.524156 +v -3.461847 7.260029 -0.456938 +v -3.468978 7.271001 -0.390840 +v -3.533921 7.242467 -0.572255 +v -3.591913 7.240810 -0.542600 +v -3.649079 7.241396 -0.513662 +v -3.716341 7.231697 -0.675679 +v -3.715586 7.234713 -0.616370 +v -3.717311 7.238050 -0.556887 +v -4.099667 7.484265 0.196961 +v -4.052248 7.519879 0.226142 +v -4.006333 7.561323 0.250153 +v -3.797027 7.457362 0.123717 +v -3.752978 7.504000 0.145069 +v -3.710819 7.554506 0.161172 +v -4.010771 7.332848 -0.060023 +v -3.965153 7.347487 -0.011520 +v -3.919241 7.366910 0.034011 +v -3.505368 7.482320 -0.000871 +v -3.469911 7.532444 0.016436 +v -3.436879 7.584394 0.030115 +v -3.928323 7.230403 -0.330745 +v -3.883736 7.234542 -0.287783 +v -3.837667 7.244038 -0.245394 +v -3.709578 7.293450 -0.136678 +v -3.661372 7.324399 -0.100093 +v -3.614904 7.361786 -0.067068 +v -4.076994 7.428483 0.137290 +v -4.011296 7.417557 0.125193 +v -3.945337 7.410238 0.109983 +v -3.922204 7.553342 0.232918 +v -3.902749 7.503819 0.195323 +v -3.883560 7.458229 0.151841 +v -3.985635 7.296583 -0.140785 +v -3.921969 7.281431 -0.152983 +v -3.858545 7.269942 -0.166805 +v -3.832066 7.355276 0.012424 +v -3.813641 7.322371 -0.046477 +v -3.796048 7.293928 -0.107641 +v -3.769828 7.400894 0.058869 +v -3.703991 7.402637 0.035169 +v -3.639462 7.408040 0.008422 +v -3.627140 7.560213 0.126186 +v -3.604308 7.513997 0.084244 +v -3.583016 7.470847 0.038038 +v -3.909397 7.226533 -0.406787 +v -3.853769 7.228634 -0.424859 +v -3.797916 7.234265 -0.445578 +v -3.757127 7.246268 -0.271128 +v -3.745927 7.241524 -0.333020 +v -3.735652 7.240786 -0.395202 +v -3.690435 7.265460 -0.218793 +v -3.627530 7.270555 -0.242851 +v -3.565414 7.278765 -0.268692 +v -3.533294 7.374071 -0.103732 +v -3.517092 7.344294 -0.162253 +v -3.502176 7.318709 -0.222820 +v -3.480242 7.433701 -0.068646 +v -3.425327 7.447515 -0.099602 +v -3.371843 7.463252 -0.131854 +v -3.369919 7.600588 -0.012125 +v -3.350612 7.563506 -0.058081 +v -3.330528 7.528901 -0.106711 +v -3.875258 7.231993 -0.493191 +v -3.888937 7.236925 -0.540004 +v -3.852950 7.234953 -0.517441 +v -3.822161 7.234320 -0.486630 +v -3.866418 7.229985 -0.464484 +v -3.913483 7.229045 -0.454343 +v -3.905948 7.232946 -0.498450 +v -3.182945 7.597888 -0.189501 +v -3.190102 7.638554 -0.155048 +v -3.210414 7.597498 -0.165175 +v -3.223555 7.556102 -0.183993 +v -3.179089 7.573053 -0.211193 +v -3.137681 7.601446 -0.230675 +v -3.160289 7.624210 -0.192374 +v -4.004738 7.265665 -0.538538 +v -3.968750 7.257130 -0.567893 +v -3.979385 7.252525 -0.524189 +v -3.998632 7.250748 -0.484313 +v -4.027015 7.270368 -0.520834 +v -4.046063 7.288468 -0.564794 +v -4.007380 7.273567 -0.571371 +v -4.004243 7.266586 -0.690939 +v -3.968531 7.256960 -0.661970 +v -4.007133 7.274148 -0.658103 +v -4.045433 7.290195 -0.664053 +v -4.026030 7.272559 -0.708268 +v -3.997581 7.251498 -0.745498 +v -3.978874 7.252491 -0.705636 +v -3.873462 7.224456 -0.738119 +v -3.887848 7.232544 -0.690805 +v -3.904626 7.227959 -0.732385 +v -3.911843 7.222772 -0.777118 +v -3.864257 7.220496 -0.767400 +v -3.819877 7.223286 -0.745504 +v -3.851188 7.227165 -0.714001 +v -3.098552 7.732786 -0.188456 +v -3.137246 7.721076 -0.154007 +v -3.112035 7.700863 -0.191704 +v -3.083488 7.690886 -0.230326 +v -3.076763 7.740844 -0.210505 +v -3.081178 7.787884 -0.183006 +v -3.109594 7.757253 -0.163672 +v -4.077362 7.719255 0.316442 +v -4.128447 7.696780 0.309599 +v -4.080257 7.684157 0.307474 +v -4.030658 7.683641 0.305098 +v -4.046618 7.733636 0.318269 +v -4.074796 7.779101 0.326987 +v -4.106255 7.740572 0.320407 +v -4.897108 7.700760 -0.469808 +v -4.883147 7.688646 -0.525039 +v -4.880479 7.667966 -0.476294 +v -4.881083 7.658274 -0.423756 +v -4.904440 7.709227 -0.435409 +v -4.921276 7.758830 -0.461342 +v -4.904037 7.726427 -0.498237 +v -4.361586 7.692671 -1.534394 +v -4.309729 7.671141 -1.552827 +v -4.347803 7.659686 -1.517393 +v -4.389247 7.659972 -1.484573 +v -4.392257 7.706648 -1.521657 +v -4.380763 7.749802 -1.561296 +v -4.342443 7.712610 -1.562545 +v -3.217700 7.708969 -1.296121 +v -3.196532 7.697023 -1.244492 +v -3.225807 7.675867 -1.282789 +v -3.254799 7.665642 -1.325358 +v -3.231752 7.717120 -1.327226 +v -3.205508 7.766913 -1.314142 +v -3.196911 7.734943 -1.276385 +v -3.157418 7.826164 -0.066954 +v -3.173142 7.778794 -0.078799 +v -3.143046 7.810422 -0.094392 +v -3.119867 7.848469 -0.103765 +v -3.149733 7.855391 -0.061371 +v -3.184941 7.850747 -0.023641 +v -3.181742 7.812110 -0.047233 +v -4.221347 7.804663 0.321833 +v -4.218341 7.749226 0.313436 +v -4.188110 7.789341 0.323206 +v -4.167799 7.834912 0.330279 +v -4.222913 7.838527 0.325204 +v -4.278099 7.828456 0.316796 +v -4.253038 7.785133 0.315080 +v -4.916211 7.802474 -0.612047 +v -4.895797 7.750694 -0.612202 +v -4.914425 7.784523 -0.579082 +v -4.932927 7.825862 -0.555195 +v -4.928165 7.834728 -0.611852 +v -4.918573 7.830487 -0.668175 +v -4.905429 7.787644 -0.644963 +v -4.248140 7.775064 -1.652421 +v -4.239552 7.721636 -1.625849 +v -4.277909 7.759484 -1.629840 +v -4.306577 7.804319 -1.637982 +v -4.252457 7.808880 -1.666290 +v -4.194862 7.800994 -1.685603 +v -4.212630 7.757226 -1.657802 +v -3.122245 7.810149 -1.192171 +v -3.136730 7.758816 -1.181321 +v -3.142845 7.792742 -1.217045 +v -3.143536 7.833362 -1.245153 +v -3.114176 7.841714 -1.198399 +v -3.089134 7.836973 -1.149209 +v -3.110684 7.795033 -1.160760 +v -3.580249 8.687921 0.157523 +v -3.602907 8.649543 0.183917 +v -3.563908 8.656677 0.161558 +v -3.530393 8.671524 0.133332 +v -3.567233 8.709831 0.138321 +v -3.611375 8.736032 0.146228 +v -3.611279 8.694386 0.169159 +v -4.616765 8.739674 0.005454 +v -4.672443 8.710798 0.004085 +v -4.627728 8.715075 0.034743 +v -4.577523 8.725327 0.054071 +v -4.582340 8.755950 0.005086 +v -4.599724 8.777974 -0.046011 +v -4.640473 8.745897 -0.025021 +v -4.739191 8.752917 -1.099604 +v -4.748227 8.719286 -1.150207 +v -4.771338 8.728308 -1.100755 +v -4.783121 8.744317 -1.049426 +v -4.732584 8.772776 -1.068433 +v -4.683342 8.792402 -1.099716 +v -4.712569 8.756331 -1.130187 +v -3.707146 8.764950 -1.560127 +v -3.666800 8.721124 -1.570052 +v -3.717441 8.735851 -1.586354 +v -3.767679 8.758142 -1.591358 +v -3.732767 8.790593 -1.552307 +v -3.689047 8.809170 -1.513213 +v -3.671831 8.765726 -1.539629 +v -3.020528 8.727224 -0.693187 +v -2.998446 8.687038 -0.662742 +v -3.016347 8.689365 -0.708187 +v -3.040462 8.700586 -0.749743 +v -3.037663 8.749396 -0.711740 +v -3.032328 8.786503 -0.665829 +v -3.011405 8.739526 -0.658937 +v -3.790544 9.214393 -0.696940 +v -3.732130 9.220315 -0.668840 +v -3.762311 9.208768 -0.716102 +v -3.804994 9.196548 -0.756271 +v -3.826821 9.209824 -0.712914 +v -3.837831 9.220120 -0.666167 +v -3.784175 9.222008 -0.661861 +v -3.478630 9.173460 -0.710949 +v -3.418921 9.153390 -0.676577 +v -3.448647 9.153236 -0.731586 +v -3.491395 9.152728 -0.778844 +v -3.516419 9.179815 -0.730800 +v -3.532358 9.197368 -0.676006 +v -3.473708 9.180300 -0.669771 +v -3.192133 8.983720 -0.706479 +v -3.142246 8.950609 -0.672563 +v -3.171001 8.951107 -0.725329 +v -3.211410 8.956888 -0.772122 +v -3.225754 9.000030 -0.726860 +v -3.234512 9.031480 -0.674032 +v -3.184586 8.994900 -0.666918 +v -3.654972 9.177722 -0.793799 +v -3.643273 9.200374 -0.729475 +v -3.616952 9.181235 -0.777763 +v -3.604717 9.156123 -0.831594 +v -3.663195 9.161380 -0.832209 +v -3.719165 9.170061 -0.819742 +v -3.685395 9.187997 -0.771216 +v -3.696455 9.107487 -0.971426 +v -3.631359 9.108619 -0.945343 +v -3.667143 9.094572 -0.994310 +v -3.713529 9.087326 -1.036288 +v -3.736293 9.108395 -0.987214 +v -3.746406 9.128548 -0.933027 +v -3.686803 9.120666 -0.932954 +v -3.351546 9.056168 -0.803414 +v -3.335932 9.079763 -0.735637 +v -3.316929 9.040787 -0.781983 +v -3.312410 9.002666 -0.834643 +v -3.362606 9.039067 -0.843601 +v -3.410927 9.078068 -0.838398 +v -3.376683 9.085809 -0.784107 +v -3.400328 8.977713 -0.986811 +v -3.344517 8.952073 -0.951497 +v -3.376650 8.946066 -1.004356 +v -3.417354 8.949298 -1.050174 +v -3.434772 8.991446 -1.006891 +v -3.441651 9.027776 -0.955584 +v -3.390525 8.994106 -0.947869 +v -3.565723 9.024854 -1.072787 +v -3.548408 9.054940 -1.009870 +v -3.528704 9.018202 -1.055536 +v -3.521899 8.981560 -1.105858 +v -3.576379 9.006184 -1.110183 +v -3.629036 9.033875 -1.101134 +v -3.592889 9.048235 -1.052038 +v -3.610922 8.949671 -1.250149 +v -3.551130 8.932425 -1.217690 +v -3.584229 8.925459 -1.269244 +v -3.626962 8.925975 -1.314489 +v -3.647911 8.959312 -1.269541 +v -3.657846 8.988008 -1.216190 +v -3.601947 8.963377 -1.210939 +v -3.118654 8.822075 -0.786097 +v -3.094985 8.850012 -0.724161 +v -3.093751 8.802951 -0.764470 +v -3.102982 8.759872 -0.810792 +v -3.134611 8.803401 -0.823044 +v -3.163895 8.852324 -0.822550 +v -3.129847 8.858566 -0.770545 +v -3.175947 8.744305 -0.957827 +v -3.138347 8.710508 -0.919206 +v -3.160820 8.709962 -0.971564 +v -3.188695 8.720744 -1.018945 +v -3.199208 8.764363 -0.980546 +v -3.201216 8.801923 -0.933434 +v -3.167668 8.758810 -0.920643 +v -3.297923 8.830037 -1.062205 +v -3.280807 8.856177 -0.999926 +v -3.268134 8.813258 -1.039909 +v -3.266170 8.775609 -1.085608 +v -3.309032 8.813920 -1.098300 +v -3.350789 8.856210 -1.098058 +v -3.318386 8.862033 -1.047142 +v -3.351904 8.751622 -1.220152 +v -3.300251 8.725893 -1.186187 +v -3.333326 8.718280 -1.231870 +v -3.373458 8.721048 -1.273278 +v -3.383804 8.766498 -1.240420 +v -3.385086 8.806017 -1.199758 +v -3.339750 8.769391 -1.187802 +v -3.499923 8.821616 -1.320545 +v -3.480929 8.849691 -1.263530 +v -3.467852 8.806432 -1.297575 +v -3.466724 8.766596 -1.337084 +v -3.511779 8.803943 -1.353389 +v -3.555032 8.844614 -1.357959 +v -3.521230 8.852880 -1.309287 +v -3.551893 8.737948 -1.463667 +v -3.501137 8.713286 -1.428326 +v -3.532589 8.704813 -1.471162 +v -3.571002 8.705031 -1.509678 +v -3.583555 8.750253 -1.484548 +v -3.587444 8.790492 -1.450632 +v -3.541201 8.756527 -1.434622 +v -3.965685 9.221208 -0.754510 +v -3.919412 9.201747 -0.794950 +v -3.977816 9.218563 -0.788230 +v -4.031099 9.235047 -0.767363 +v -3.992140 9.231651 -0.729233 +v -3.945754 9.225142 -0.700784 +v -3.926603 9.213283 -0.745674 +v -3.886561 9.147933 -1.051805 +v -3.834782 9.114516 -1.089183 +v -3.897900 9.144398 -1.093527 +v -3.957692 9.174246 -1.082437 +v -3.917476 9.166942 -1.028702 +v -3.867581 9.152726 -0.982976 +v -3.844359 9.131782 -1.032970 +v -3.789865 8.993942 -1.348808 +v -3.739971 8.953725 -1.378115 +v -3.800220 8.977773 -1.389109 +v -3.858878 9.005073 -1.384292 +v -3.820792 9.016974 -1.329376 +v -3.773272 9.016843 -1.278601 +v -3.749556 8.984804 -1.325883 +v -4.024443 9.222088 -0.931918 +v -3.955227 9.199117 -0.908390 +v -3.995836 9.209618 -0.960805 +v -4.046732 9.221657 -1.003652 +v -4.066348 9.233481 -0.944798 +v -4.071079 9.237108 -0.881200 +v -4.011151 9.219681 -0.889188 +v -4.225036 9.236810 -0.975949 +v -4.175982 9.231611 -1.033853 +v -4.240196 9.225913 -1.016230 +v -4.297099 9.215231 -0.981814 +v -4.252781 9.234390 -0.939370 +v -4.197997 9.245713 -0.906928 +v -4.180595 9.242781 -0.970058 +v -3.936260 9.110135 -1.251517 +v -3.865880 9.089963 -1.216405 +v -3.904059 9.083459 -1.274217 +v -3.953488 9.079397 -1.321858 +v -3.979097 9.118206 -1.270378 +v -3.990416 9.149327 -1.210038 +v -3.926061 9.123843 -1.207437 +v -4.140333 9.104466 -1.313314 +v -4.083672 9.073792 -1.361395 +v -4.151232 9.073252 -1.348541 +v -4.214255 9.076320 -1.319050 +v -4.173861 9.118592 -1.281351 +v -4.121146 9.147975 -1.249243 +v -4.095249 9.115356 -1.305854 +v -4.290610 9.155787 -1.158097 +v -4.217602 9.182714 -1.151894 +v -4.259629 9.147824 -1.192941 +v -4.308969 9.107326 -1.218388 +v -4.331614 9.133276 -1.158640 +v -4.338530 9.161082 -1.096770 +v -4.277670 9.179767 -1.119843 +v -4.453534 9.024293 -1.141088 +v -4.413890 9.023552 -1.206983 +v -4.459308 8.990598 -1.172791 +v -4.500909 8.966128 -1.127324 +v -4.476282 9.022301 -1.100982 +v -4.442539 9.077111 -1.086462 +v -4.423784 9.057619 -1.148510 +v -3.836295 8.891960 -1.515706 +v -3.769886 8.890938 -1.484171 +v -3.806116 8.863020 -1.527439 +v -3.852607 8.838623 -1.562610 +v -3.877092 8.888747 -1.531371 +v -3.888561 8.936784 -1.490712 +v -3.826623 8.920188 -1.484256 +v -4.029622 8.851832 -1.567365 +v -3.974608 8.811263 -1.596166 +v -4.038848 8.812602 -1.590783 +v -4.100352 8.823627 -1.573114 +v -4.062775 8.874133 -1.547285 +v -4.013461 8.913137 -1.523994 +v -3.987102 8.865768 -1.560644 +v -4.187373 8.947497 -1.461208 +v -4.113974 8.975747 -1.456994 +v -4.152579 8.928533 -1.487069 +v -4.201361 8.883899 -1.504368 +v -4.230358 8.927508 -1.460492 +v -4.243843 8.974676 -1.412908 +v -4.178032 8.983453 -1.432426 +v -4.374903 8.847227 -1.448842 +v -4.321668 8.820629 -1.496102 +v -4.380693 8.808235 -1.472071 +v -4.434463 8.805278 -1.437267 +v -4.404326 8.859842 -1.417534 +v -4.362607 8.908560 -1.404709 +v -4.337106 8.870449 -1.453362 +v -4.490206 8.875805 -1.285957 +v -4.437876 8.926775 -1.299670 +v -4.469396 8.875589 -1.324563 +v -4.507129 8.824914 -1.334975 +v -4.520521 8.845369 -1.277049 +v -4.523719 8.873683 -1.220022 +v -4.479988 8.905911 -1.255114 +v -4.631317 8.755579 -1.253917 +v -4.598427 8.749108 -1.312887 +v -4.642265 8.730875 -1.283866 +v -4.681056 8.720419 -1.245223 +v -4.651165 8.757798 -1.218071 +v -4.613596 8.795024 -1.200984 +v -4.600575 8.777097 -1.258799 +v -4.067241 9.241273 -0.618268 +v -4.097270 9.247583 -0.677008 +v -4.102663 9.241182 -0.618811 +v -4.093383 9.228940 -0.561198 +v -4.047957 9.233579 -0.584512 +v -4.008885 9.235778 -0.617531 +v -4.049909 9.243957 -0.651777 +v -4.338351 9.211156 -0.800401 +v -4.369556 9.197671 -0.868446 +v -4.377939 9.194376 -0.802006 +v -4.370369 9.192216 -0.734683 +v -4.317799 9.215161 -0.759332 +v -4.270006 9.231472 -0.796508 +v -4.317210 9.219280 -0.839358 +v -4.562843 9.005105 -0.963284 +v -4.570595 8.954808 -1.014635 +v -4.592275 8.968771 -0.958064 +v -4.603005 8.992098 -0.902708 +v -4.557132 9.033528 -0.932013 +v -4.512546 9.063871 -0.972277 +v -4.538251 9.011251 -0.999825 +v -4.240661 9.220223 -0.618754 +v -4.209409 9.235817 -0.680273 +v -4.262017 9.220095 -0.655904 +v -4.306801 9.199469 -0.618619 +v -4.258373 9.207663 -0.581905 +v -4.204079 9.215423 -0.558796 +v -4.201123 9.229117 -0.619046 +v -4.315797 9.154050 -0.447589 +v -4.355617 9.156375 -0.507751 +v -4.354300 9.139022 -0.446430 +v -4.338286 9.123295 -0.387335 +v -4.290824 9.149786 -0.412988 +v -4.250694 9.173775 -0.450814 +v -4.301120 9.169964 -0.484558 +v -4.514107 9.108871 -0.802554 +v -4.481091 9.130053 -0.868974 +v -4.529843 9.093002 -0.840997 +v -4.571656 9.057912 -0.799764 +v -4.531985 9.093180 -0.761994 +v -4.483238 9.128280 -0.736106 +v -4.477833 9.136108 -0.803329 +v -4.595303 9.036032 -0.615932 +v -4.625204 9.013118 -0.681377 +v -4.630823 9.007213 -0.615688 +v -4.622357 9.008092 -0.550711 +v -4.575608 9.047258 -0.576954 +v -4.534063 9.080902 -0.616795 +v -4.577895 9.051417 -0.655680 +v -4.494482 9.069901 -0.441438 +v -4.469989 9.101495 -0.504374 +v -4.518357 9.066668 -0.477676 +v -4.557076 9.030041 -0.440092 +v -4.507384 9.048537 -0.405042 +v -4.452070 9.070134 -0.383074 +v -4.455887 9.091166 -0.442937 +v -4.540563 8.962769 -0.283361 +v -4.587314 8.962806 -0.338039 +v -4.575858 8.938502 -0.283939 +v -4.551747 8.920114 -0.230982 +v -4.512065 8.960774 -0.251352 +v -4.481174 9.001009 -0.282843 +v -4.533274 8.987369 -0.315435 +v -4.709041 8.854913 -0.951567 +v -4.663333 8.859849 -1.005813 +v -4.715353 8.830495 -0.984350 +v -4.764800 8.808601 -0.953243 +v -4.736022 8.851335 -0.919178 +v -4.697260 8.895909 -0.896133 +v -4.675212 8.883113 -0.951327 +v -4.820793 8.820851 -0.791872 +v -4.836362 8.786414 -0.852759 +v -4.850315 8.787712 -0.791448 +v -4.850832 8.796854 -0.728690 +v -4.808994 8.839572 -0.754692 +v -4.767805 8.873078 -0.792478 +v -4.800008 8.832534 -0.828733 +v -4.756079 8.899751 -0.615193 +v -4.727130 8.924644 -0.680469 +v -4.772115 8.884268 -0.654198 +v -4.809435 8.847208 -0.615020 +v -4.771708 8.883494 -0.576101 +v -4.725890 8.922497 -0.550349 +v -4.722247 8.929738 -0.615341 +v -4.822369 8.821239 -0.437272 +v -4.851654 8.797218 -0.500702 +v -4.852194 8.788775 -0.437457 +v -4.839283 8.787944 -0.375805 +v -4.801727 8.832634 -0.400451 +v -4.767611 8.871157 -0.437610 +v -4.809596 8.839140 -0.474898 +v -4.708001 8.851190 -0.279784 +v -4.694351 8.889606 -0.335902 +v -4.736361 8.849355 -0.311114 +v -4.767046 8.808731 -0.276213 +v -4.714969 8.827544 -0.246978 +v -4.658624 8.850969 -0.228816 +v -4.671165 8.875154 -0.281937 +v -4.739581 8.751523 -0.131644 +v -4.786341 8.745346 -0.179795 +v -4.773585 8.728546 -0.129148 +v -4.748300 8.717646 -0.081400 +v -4.710533 8.752668 -0.103111 +v -4.679695 8.786194 -0.135037 +v -4.732947 8.771042 -0.162858 +v -3.962392 9.187390 -0.483485 +v -4.024728 9.193033 -0.473290 +v -3.973274 9.175416 -0.452815 +v -3.917265 9.162204 -0.445615 +v -3.924906 9.184394 -0.491288 +v -3.944026 9.205104 -0.534398 +v -3.988354 9.202085 -0.507851 +v -4.192808 9.121628 -0.300132 +v -4.259050 9.103811 -0.292894 +v -4.204203 9.101125 -0.266951 +v -4.144938 9.100593 -0.254417 +v -4.152815 9.128622 -0.305897 +v -4.172981 9.151372 -0.357075 +v -4.220874 9.131406 -0.329198 +v -4.413601 8.943263 -0.137048 +v -4.470571 8.908257 -0.137846 +v -4.421591 8.915552 -0.106608 +v -4.369509 8.929352 -0.086890 +v -4.379154 8.962801 -0.137336 +v -4.400121 8.987780 -0.189060 +v -4.439902 8.949698 -0.168203 +v -4.011526 9.130058 -0.333774 +v -4.057567 9.156685 -0.376845 +v -4.049794 9.132830 -0.325166 +v -4.028805 9.106170 -0.277086 +v -3.983604 9.112996 -0.308994 +v -3.947835 9.124037 -0.349516 +v -4.001114 9.142973 -0.367842 +v -3.881162 9.056266 -0.222422 +v -3.945075 9.058151 -0.205581 +v -3.890885 9.042727 -0.189014 +v -3.833486 9.032516 -0.184165 +v -3.842850 9.055442 -0.233183 +v -3.864645 9.078220 -0.279278 +v -3.909575 9.070780 -0.245832 +v -4.244197 9.019422 -0.147115 +v -4.291744 9.037582 -0.194788 +v -4.283143 9.006339 -0.142865 +v -4.260959 8.976782 -0.094211 +v -4.214947 9.006006 -0.120296 +v -4.177535 9.036453 -0.156910 +v -4.233455 9.042942 -0.180021 +v -4.106415 8.946609 -0.033483 +v -4.173179 8.931015 -0.021426 +v -4.116222 8.919232 -0.004394 +v -4.056059 8.914498 0.001219 +v -4.066302 8.954155 -0.041955 +v -4.089550 8.989248 -0.084498 +v -4.136547 8.964434 -0.055818 +v -3.924837 8.974498 -0.073458 +v -3.973243 9.005310 -0.110312 +v -3.963112 8.969850 -0.064847 +v -3.940489 8.933969 -0.023616 +v -3.896127 8.955452 -0.051828 +v -3.861433 8.980495 -0.088579 +v -3.915596 8.996675 -0.104392 +v -3.794229 8.895425 0.029300 +v -3.856692 8.882235 0.040218 +v -3.804080 8.871956 0.057347 +v -3.749002 8.867919 0.063748 +v -3.756968 8.901736 0.021408 +v -3.777972 8.931301 -0.021673 +v -3.821936 8.910675 0.006838 +v -4.456140 8.819985 0.004765 +v -4.497247 8.830910 -0.046527 +v -4.491123 8.801454 0.004703 +v -4.473433 8.775751 0.053485 +v -4.431103 8.811693 0.033813 +v -4.396824 8.849577 0.002953 +v -4.445761 8.845510 -0.025928 +v -4.328069 8.762530 0.119993 +v -4.391791 8.738333 0.126020 +v -4.335243 8.730503 0.142946 +v -4.275227 8.730437 0.149200 +v -4.289250 8.775131 0.114383 +v -4.314635 8.812650 0.077242 +v -4.358553 8.779292 0.099530 +v -4.147593 8.814621 0.092229 +v -4.199522 8.846839 0.060230 +v -4.186600 8.804442 0.098398 +v -4.160288 8.763494 0.131042 +v -4.116481 8.794036 0.109153 +v -4.082516 8.830192 0.080231 +v -4.139604 8.844133 0.067068 +v -4.009794 8.717430 0.157546 +v -4.071221 8.700748 0.171194 +v -4.018025 8.686129 0.176534 +v -3.962876 8.682116 0.175245 +v -3.973018 8.727449 0.149436 +v -3.995137 8.768839 0.123970 +v -4.038210 8.738587 0.145952 +v -3.839566 8.770315 0.135130 +v -3.885057 8.801407 0.108853 +v -3.876251 8.757755 0.136919 +v -3.855865 8.717045 0.161460 +v -3.813248 8.751107 0.149469 +v -3.779036 8.789058 0.130679 +v -3.829805 8.800797 0.117317 +v -3.728035 8.680671 0.193706 +v -3.783129 8.659957 0.197099 +v -3.739132 8.648704 0.205235 +v -3.693694 8.645411 0.206387 +v -3.695404 8.690193 0.189576 +v -3.708569 8.730680 0.169643 +v -3.749895 8.700431 0.183085 +v -3.791435 9.200488 -0.536927 +v -3.806108 9.172066 -0.480427 +v -3.763546 9.192390 -0.518383 +v -3.732908 9.212006 -0.564068 +v -3.784727 9.214156 -0.571016 +v -3.838156 9.210857 -0.567144 +v -3.827509 9.192272 -0.521800 +v -3.702205 9.069262 -0.274831 +v -3.719187 9.041006 -0.217023 +v -3.673358 9.058537 -0.252117 +v -3.637241 9.079891 -0.296075 +v -3.692172 9.086554 -0.310068 +v -3.750458 9.086664 -0.313105 +v -3.741206 9.062861 -0.262932 +v -3.619820 8.911624 -0.012596 +v -3.638776 8.878094 0.037637 +v -3.593759 8.890817 0.006692 +v -3.557974 8.907594 -0.033773 +v -3.609146 8.929985 -0.045198 +v -3.665662 8.941856 -0.048958 +v -3.657768 8.911184 -0.002202 +v -3.658270 9.158269 -0.441645 +v -3.722120 9.142578 -0.418379 +v -3.667074 9.137743 -0.404788 +v -3.608907 9.137374 -0.403994 +v -3.620166 9.165980 -0.456520 +v -3.645440 9.187940 -0.504107 +v -3.688013 9.168463 -0.464204 +v -3.480715 9.167826 -0.520748 +v -3.494694 9.143122 -0.453955 +v -3.451038 9.146952 -0.500240 +v -3.420188 9.150236 -0.554548 +v -3.474925 9.177097 -0.561481 +v -3.533712 9.193233 -0.555626 +v -3.518916 9.172366 -0.501406 +v -3.570325 9.002560 -0.168811 +v -3.634696 8.999416 -0.148838 +v -3.581100 8.981595 -0.134155 +v -3.525528 8.965741 -0.133315 +v -3.532514 9.001643 -0.182367 +v -3.553127 9.035192 -0.228796 +v -3.598275 9.021347 -0.191648 +v -3.402100 8.972814 -0.244416 +v -3.419477 8.944239 -0.182213 +v -3.378409 8.942627 -0.226818 +v -3.345946 8.948932 -0.279375 +v -3.392464 8.988610 -0.283425 +v -3.444437 9.018997 -0.276937 +v -3.436899 8.984660 -0.225226 +v -3.353546 9.051020 -0.427944 +v -3.414018 9.069660 -0.393999 +v -3.364808 9.033194 -0.387955 +v -3.313545 8.999309 -0.396218 +v -3.318209 9.037412 -0.448873 +v -3.337312 9.076313 -0.495313 +v -3.379031 9.079786 -0.447554 +v -3.191476 8.983954 -0.523138 +v -3.210167 8.957213 -0.457533 +v -3.169275 8.952050 -0.503910 +v -3.141013 8.951355 -0.556510 +v -3.184248 8.995033 -0.562708 +v -3.234562 9.031155 -0.555950 +v -3.225522 8.999725 -0.503037 +v -3.515347 8.792986 0.055834 +v -3.571390 8.804498 0.081018 +v -3.530339 8.769553 0.080466 +v -3.487178 8.737771 0.068223 +v -3.483086 8.783085 0.038130 +v -3.491760 8.829501 0.010156 +v -3.534312 8.823448 0.045616 +v -3.372024 8.734580 -0.031348 +v -3.397255 8.699384 0.012999 +v -3.357979 8.698166 -0.024291 +v -3.324494 8.707621 -0.066006 +v -3.357962 8.754715 -0.059732 +v -3.398463 8.793372 -0.045569 +v -3.401732 8.749550 -0.011707 +v -3.307944 8.822858 -0.175250 +v -3.358589 8.849895 -0.138382 +v -3.321625 8.804783 -0.141446 +v -3.282602 8.763918 -0.157290 +v -3.278776 8.805516 -0.198404 +v -3.286402 8.851880 -0.234480 +v -3.324932 8.857163 -0.187628 +v -3.173774 8.744481 -0.276474 +v -3.198610 8.713405 -0.222218 +v -3.160688 8.709350 -0.264581 +v -3.128092 8.716660 -0.311588 +v -3.159480 8.762980 -0.310170 +v -3.198580 8.802417 -0.298925 +v -3.202574 8.760835 -0.255980 +v -3.104508 8.830674 -0.439692 +v -3.154597 8.857739 -0.405008 +v -3.119571 8.812467 -0.402933 +v -3.083807 8.771770 -0.414008 +v -3.077793 8.812753 -0.460653 +v -3.085018 8.856103 -0.502328 +v -3.120031 8.864494 -0.456366 +v -3.006876 8.735676 -0.532018 +v -3.020943 8.712965 -0.474452 +v -3.001125 8.698956 -0.516735 +v -2.990087 8.692288 -0.563368 +v -3.003231 8.744555 -0.567157 +v -3.023575 8.791858 -0.560259 +v -3.021959 8.759110 -0.513114 +v -2.993693 8.556443 -0.742451 +v -2.981047 8.498607 -0.750456 +v -3.001205 8.541394 -0.772435 +v -3.021056 8.590132 -0.781909 +v -3.001663 8.591672 -0.736185 +v -2.982971 8.581146 -0.693321 +v -2.979536 8.536811 -0.717808 +v -2.968951 8.322804 -0.918228 +v -2.961620 8.258142 -0.922862 +v -2.973530 8.306239 -0.952308 +v -2.988060 8.359336 -0.968869 +v -2.976038 8.360766 -0.914512 +v -2.964961 8.349424 -0.861056 +v -2.960474 8.300748 -0.887074 +v -3.005879 8.056501 -1.081489 +v -3.014549 7.993195 -1.077811 +v -3.020884 8.037764 -1.113043 +v -3.024997 8.088900 -1.136880 +v -3.002668 8.094832 -1.082674 +v -2.984776 8.087681 -1.027000 +v -2.996667 8.036969 -1.047615 +v -3.015118 8.490253 -0.892660 +v -2.992484 8.455762 -0.846228 +v -3.002657 8.455723 -0.899959 +v -3.019020 8.467032 -0.951393 +v -3.030550 8.510955 -0.919855 +v -3.037377 8.547542 -0.878957 +v -3.013433 8.503882 -0.857727 +v -3.099970 8.586704 -1.014550 +v -3.073159 8.528863 -1.030599 +v -3.105724 8.572935 -1.049612 +v -3.138776 8.620566 -1.055346 +v -3.117336 8.620674 -1.003829 +v -3.092229 8.609015 -0.955142 +v -3.078667 8.565837 -0.989158 +v -3.001458 8.239284 -1.078203 +v -2.981979 8.204337 -1.024781 +v -2.999907 8.198718 -1.080878 +v -3.022502 8.205997 -1.134956 +v -3.016401 8.260067 -1.109070 +v -3.009191 8.306660 -1.071426 +v -2.991832 8.258765 -1.043284 +v -3.090401 8.335307 -1.213198 +v -3.079032 8.266915 -1.222106 +v -3.107385 8.314783 -1.245922 +v -3.133631 8.368776 -1.256553 +v -3.099742 8.375694 -1.206324 +v -3.066095 8.368325 -1.156876 +v -3.067062 8.314682 -1.185772 +v -3.141893 8.515132 -1.175510 +v -3.099009 8.482816 -1.133569 +v -3.129116 8.477974 -1.184856 +v -3.166593 8.483792 -1.231532 +v -3.169713 8.533238 -1.199217 +v -3.166253 8.574887 -1.158037 +v -3.129324 8.532517 -1.141073 +v -3.274306 8.594055 -1.276052 +v -3.251411 8.534621 -1.296075 +v -3.289691 8.574755 -1.307913 +v -3.324120 8.620275 -1.308535 +v -3.289270 8.628832 -1.263616 +v -3.250526 8.625320 -1.222139 +v -3.245187 8.577861 -1.256102 +v -3.085739 7.968129 -1.218901 +v -3.065365 7.938321 -1.164803 +v -3.093167 7.931253 -1.213768 +v -3.120937 7.935407 -1.263633 +v -3.099925 7.986088 -1.250786 +v -3.076447 8.031445 -1.225526 +v -3.066343 7.987561 -1.191051 +v -3.164725 8.053118 -1.365541 +v -3.170891 7.987553 -1.358068 +v -3.188780 8.032125 -1.392660 +v -3.202049 8.084414 -1.416098 +v -3.163244 8.092602 -1.368301 +v -3.127501 8.087142 -1.318568 +v -3.144695 8.034416 -1.334154 +v -3.174059 8.239412 -1.362617 +v -3.132610 8.205728 -1.317015 +v -3.168576 8.198401 -1.366732 +v -3.208587 8.204359 -1.413647 +v -3.200819 8.259531 -1.388279 +v -3.186832 8.307671 -1.352299 +v -3.155045 8.260208 -1.330824 +v -3.300533 8.331366 -1.475076 +v -3.288995 8.263306 -1.487202 +v -3.321522 8.310300 -1.505698 +v -3.348921 8.363193 -1.511677 +v -3.309185 8.371185 -1.466195 +v -3.268267 8.365843 -1.422800 +v -3.272754 8.311850 -1.451999 +v -3.348478 8.506000 -1.425055 +v -3.299795 8.477757 -1.391469 +v -3.336578 8.470288 -1.437588 +v -3.378162 8.474486 -1.478818 +v -3.377922 8.522436 -1.444414 +v -3.370160 8.564404 -1.403346 +v -3.331834 8.524698 -1.392509 +v -3.479252 8.581800 -1.511460 +v -3.462467 8.524358 -1.534070 +v -3.496537 8.564044 -1.542462 +v -3.525802 8.608085 -1.539752 +v -3.491308 8.615807 -1.498180 +v -3.454044 8.612079 -1.459240 +v -3.452024 8.565453 -1.493478 +v -3.732414 8.616745 -1.675274 +v -3.731868 8.556096 -1.709102 +v -3.764489 8.606807 -1.692800 +v -3.784788 8.660050 -1.665689 +v -3.731866 8.651463 -1.652036 +v -3.681800 8.630513 -1.641699 +v -3.701070 8.590638 -1.677042 +v -3.907397 8.358030 -1.810903 +v -3.909375 8.280899 -1.822359 +v -3.947335 8.337635 -1.813920 +v -3.971337 8.400416 -1.798591 +v -3.905979 8.403317 -1.799619 +v -3.841451 8.390236 -1.797688 +v -3.868767 8.332144 -1.813580 +v -4.097311 8.044008 -1.788318 +v -4.096587 7.971587 -1.773185 +v -4.135961 8.022944 -1.772929 +v -4.162051 8.081886 -1.773055 +v -4.097157 8.088294 -1.794109 +v -4.031216 8.079659 -1.808185 +v -4.057963 8.021173 -1.793838 +v -3.897135 8.558515 -1.742892 +v -3.836526 8.516848 -1.754219 +v -3.900110 8.517326 -1.760747 +v -3.963777 8.529713 -1.755364 +v -3.933587 8.582490 -1.732063 +v -3.891703 8.624438 -1.707702 +v -3.858114 8.573827 -1.731425 +v -4.064009 8.667797 -1.676047 +v -4.071543 8.598988 -1.710844 +v -4.104048 8.649451 -1.677884 +v -4.122047 8.704782 -1.641243 +v -4.058510 8.707819 -1.652539 +v -3.996464 8.695304 -1.666554 +v -4.028559 8.644524 -1.693917 +v -4.093796 8.256882 -1.799798 +v -4.028747 8.216165 -1.815661 +v -4.095169 8.209365 -1.800875 +v -4.160124 8.217522 -1.779722 +v -4.132022 8.280804 -1.785653 +v -4.090402 8.335897 -1.790835 +v -4.053372 8.280065 -1.807518 +v -4.264620 8.362514 -1.712985 +v -4.269138 8.284676 -1.724476 +v -4.302598 8.337351 -1.696656 +v -4.322214 8.397704 -1.670843 +v -4.261009 8.408789 -1.703279 +v -4.199589 8.403687 -1.735568 +v -4.229078 8.340813 -1.735871 +v -4.246868 8.571832 -1.657054 +v -4.188487 8.537357 -1.698783 +v -4.250861 8.527817 -1.671436 +v -4.310782 8.531306 -1.636051 +v -4.281036 8.591330 -1.629997 +v -4.239165 8.643327 -1.629125 +v -4.207891 8.594875 -1.666875 +v -4.400553 8.659126 -1.537086 +v -4.408663 8.587480 -1.559398 +v -4.437060 8.634300 -1.525975 +v -4.451867 8.687367 -1.494139 +v -4.395013 8.701085 -1.521836 +v -4.337837 8.699295 -1.552849 +v -4.368403 8.640880 -1.561667 +v -4.266313 7.947948 -1.708771 +v -4.204375 7.912419 -1.722963 +v -4.262812 7.907033 -1.698349 +v -4.320495 7.914859 -1.673436 +v -4.302599 7.969528 -1.697295 +v -4.270335 8.018787 -1.721706 +v -4.232075 7.968314 -1.727540 +v -4.431934 8.046262 -1.640930 +v -4.425439 7.975985 -1.630642 +v -4.462947 8.024561 -1.616737 +v -4.488484 8.081165 -1.606740 +v -4.434081 8.089084 -1.643879 +v -4.376863 8.082669 -1.677174 +v -4.396747 8.025441 -1.658764 +v -4.434221 8.249476 -1.634182 +v -4.377645 8.213090 -1.673335 +v -4.435265 8.204511 -1.639754 +v -4.490718 8.210855 -1.602626 +v -4.466903 8.271243 -1.609286 +v -4.430462 8.325055 -1.621503 +v -4.398975 8.272981 -1.651626 +v -4.582207 8.346933 -1.523050 +v -4.585276 8.273359 -1.532169 +v -4.615149 8.323155 -1.505479 +v -4.632267 8.380129 -1.482791 +v -4.579164 8.390785 -1.515842 +v -4.525277 8.386857 -1.549762 +v -4.550921 8.326666 -1.546124 +v -4.565384 8.546677 -1.481947 +v -4.514810 8.515614 -1.522455 +v -4.569684 8.504400 -1.492575 +v -4.620805 8.506626 -1.457769 +v -4.593810 8.564191 -1.456715 +v -4.555901 8.615147 -1.460580 +v -4.530757 8.570390 -1.494688 +v -4.681155 8.617355 -1.361025 +v -4.695068 8.554338 -1.380831 +v -4.710323 8.592968 -1.345572 +v -4.712447 8.635546 -1.312060 +v -4.671053 8.652667 -1.345220 +v -4.629828 8.657562 -1.381548 +v -4.659706 8.604518 -1.388369 +v -4.862327 8.616858 -1.116102 +v -4.889599 8.555317 -1.124608 +v -4.883194 8.604206 -1.087687 +v -4.863634 8.655413 -1.059969 +v -4.841887 8.651305 -1.110503 +v -4.824041 8.635064 -1.160338 +v -4.857730 8.593158 -1.148952 +v -5.008219 8.352959 -0.977245 +v -5.011960 8.277903 -0.976579 +v -5.020065 8.332908 -0.940217 +v -5.018898 8.394219 -0.915019 +v -5.001832 8.397353 -0.976686 +v -4.982111 8.385212 -1.036944 +v -4.998057 8.327964 -1.013633 +v -5.000153 8.055511 -0.788034 +v -4.973717 7.989862 -0.782440 +v -4.994723 8.036417 -0.748125 +v -5.015565 8.089970 -0.726174 +v -5.014268 8.095775 -0.791183 +v -5.006310 8.087619 -0.855024 +v -4.989692 8.034607 -0.824716 +v -4.957301 8.550538 -0.971501 +v -4.950346 8.510528 -1.032257 +v -4.972792 8.509786 -0.973431 +v -4.986078 8.521453 -0.911985 +v -4.958003 8.573691 -0.934089 +v -4.925285 8.615468 -0.966898 +v -4.937200 8.566484 -1.005555 +v -4.945049 8.655971 -0.795371 +v -4.979141 8.589190 -0.798319 +v -4.959183 8.638115 -0.758193 +v -4.930024 8.690787 -0.730357 +v -4.921103 8.694047 -0.793431 +v -4.916238 8.682567 -0.855877 +v -4.950992 8.633671 -0.833930 +v -5.043575 8.254424 -0.799920 +v -5.033146 8.215230 -0.863063 +v -5.039554 8.208776 -0.798095 +v -5.043462 8.217004 -0.732858 +v -5.046369 8.277922 -0.761240 +v -5.042673 8.331331 -0.801586 +v -5.040105 8.276795 -0.839442 +v -5.044268 8.361695 -0.616200 +v -5.045975 8.284696 -0.615746 +v -5.043106 8.337984 -0.575364 +v -5.035776 8.398669 -0.548354 +v -5.039423 8.407491 -0.616361 +v -5.041577 8.400298 -0.684176 +v -5.046581 8.338980 -0.656754 +v -4.996515 8.566261 -0.616160 +v -5.010850 8.530990 -0.683807 +v -5.012297 8.523891 -0.616336 +v -5.005284 8.529513 -0.548634 +v -4.985150 8.586235 -0.575682 +v -4.964044 8.634237 -0.615717 +v -4.988362 8.587050 -0.656324 +v -4.940768 8.655765 -0.434556 +v -4.971108 8.587642 -0.432448 +v -4.946358 8.633508 -0.395789 +v -4.915647 8.683798 -0.372973 +v -4.919401 8.694637 -0.435987 +v -4.927317 8.690661 -0.499712 +v -4.953399 8.637167 -0.472401 +v -4.978212 7.964616 -0.612437 +v -4.959319 7.934187 -0.670842 +v -4.963402 7.926685 -0.612026 +v -4.971922 7.930633 -0.553161 +v -4.988864 7.982948 -0.576905 +v -5.001915 8.030126 -0.613241 +v -4.981927 7.984817 -0.648392 +v -5.015120 8.051438 -0.438636 +v -4.996660 7.983570 -0.442173 +v -5.008755 8.029456 -0.400771 +v -5.018993 8.084019 -0.371464 +v -5.024016 8.092817 -0.436513 +v -5.023887 8.087502 -0.501732 +v -5.010237 8.032250 -0.478271 +v -5.037200 8.252064 -0.430814 +v -5.039989 8.215311 -0.497586 +v -5.036738 8.206747 -0.431917 +v -5.031303 8.213069 -0.366193 +v -5.032976 8.274238 -0.391135 +v -5.032686 8.328404 -0.429867 +v -5.038907 8.275557 -0.469973 +v -5.006850 8.352178 -0.250291 +v -5.013375 8.276916 -0.250297 +v -5.001357 8.327996 -0.212101 +v -4.986851 8.386049 -0.187931 +v -4.999924 8.396707 -0.250846 +v -5.011705 8.392174 -0.314559 +v -5.015842 8.331263 -0.288563 +v -4.957870 8.551707 -0.255668 +v -4.980587 8.520612 -0.317037 +v -4.972216 8.510271 -0.253781 +v -4.955568 8.512567 -0.192947 +v -4.941481 8.568806 -0.220601 +v -4.927904 8.617661 -0.260308 +v -4.956193 8.574337 -0.294067 +v -4.870590 8.620014 -0.109750 +v -4.900142 8.558841 -0.099272 +v -4.866557 8.596100 -0.076229 +v -4.830062 8.636808 -0.066850 +v -4.848549 8.653948 -0.116507 +v -4.870784 8.658700 -0.166668 +v -4.892014 8.607736 -0.137695 +v -4.677122 8.608046 0.122445 +v -4.698443 8.549702 0.149659 +v -4.654013 8.593122 0.146325 +v -4.615582 8.639277 0.128973 +v -4.662595 8.640483 0.101844 +v -4.710329 8.629202 0.077055 +v -4.711990 8.588186 0.114030 +v -4.569293 8.340213 0.261168 +v -4.571784 8.268997 0.269947 +v -4.530942 8.317713 0.271512 +v -4.501553 8.372739 0.265975 +v -4.566489 8.382137 0.253268 +v -4.630763 8.376957 0.238751 +v -4.609030 8.320041 0.255157 +v -4.393753 8.052468 0.314689 +v -4.390476 7.986230 0.312391 +v -4.355557 8.033743 0.319349 +v -4.332716 8.086573 0.322729 +v -4.395313 8.092125 0.314466 +v -4.458256 8.083924 0.304274 +v -4.430509 8.031161 0.308396 +v -4.546730 8.527595 0.213782 +v -4.614883 8.496584 0.209010 +v -4.553781 8.488757 0.226383 +v -4.488149 8.492362 0.235641 +v -4.504594 8.544946 0.213635 +v -4.532237 8.589423 0.187851 +v -4.579755 8.547278 0.197957 +v -4.357852 8.604479 0.210158 +v -4.367218 8.542076 0.233505 +v -4.324603 8.582971 0.222921 +v -4.293336 8.629257 0.205721 +v -4.351970 8.640558 0.193997 +v -4.412487 8.638354 0.185277 +v -4.396945 8.588539 0.211288 +v -4.393759 8.239210 0.303412 +v -4.458633 8.204894 0.297473 +v -4.395342 8.198096 0.308066 +v -4.332287 8.204690 0.315337 +v -4.355005 8.259396 0.305340 +v -4.390274 8.307950 0.292801 +v -4.430917 8.260193 0.295085 +v -4.218164 8.328599 0.309496 +v -4.221331 8.262134 0.320029 +v -4.183499 8.307071 0.316529 +v -4.157226 8.358124 0.308440 +v -4.216118 8.368041 0.301636 +v -4.276810 8.364454 0.295853 +v -4.255221 8.310232 0.308747 +v -4.203505 8.506075 0.263990 +v -4.267013 8.478911 0.266931 +v -4.207815 8.468943 0.275902 +v -4.148270 8.470422 0.278987 +v -4.166106 8.521266 0.260564 +v -4.195902 8.566339 0.240802 +v -4.236847 8.526976 0.253400 +v -4.037719 8.567984 0.238883 +v -4.043416 8.510928 0.263006 +v -4.007340 8.545639 0.245864 +v -3.981004 8.586642 0.225221 +v -4.033849 8.601365 0.222865 +v -4.088927 8.604889 0.224404 +v -4.072037 8.556304 0.246179 +v -4.225451 7.968771 0.333794 +v -4.282238 7.934761 0.324607 +v -4.225178 7.931622 0.331845 +v -4.169150 7.939729 0.338150 +v -4.191658 7.988647 0.338280 +v -4.225905 8.031753 0.335276 +v -4.259935 7.986187 0.330074 +v -4.069238 8.057709 0.350509 +v -4.070325 7.995703 0.348324 +v -4.036412 8.038957 0.351057 +v -4.013271 8.088314 0.351007 +v -4.068560 8.094931 0.349908 +v -4.124878 8.088932 0.345979 +v -4.102985 8.039132 0.348041 +v -4.062423 8.232559 0.338297 +v -4.120787 8.201393 0.338214 +v -4.064645 8.194237 0.343009 +v -4.008904 8.199453 0.343293 +v -4.028143 8.250771 0.336184 +v -4.058881 8.296293 0.326864 +v -4.095044 8.252498 0.333109 +v -3.910191 8.310084 0.314808 +v -3.912192 8.249687 0.327914 +v -3.880136 8.289357 0.314210 +v -3.858403 8.334809 0.298412 +v -3.908996 8.345681 0.304775 +v -3.960870 8.344883 0.311866 +v -3.941754 8.294807 0.322810 +v -3.900757 8.468711 0.262712 +v -3.954429 8.447295 0.277662 +v -3.903697 8.435643 0.274747 +v -3.853066 8.435318 0.267077 +v -3.869244 8.481446 0.253953 +v -3.895184 8.523636 0.242011 +v -3.929569 8.489127 0.259160 +v -3.761231 8.530030 0.238281 +v -3.764766 8.475531 0.249831 +v -3.735274 8.511201 0.242562 +v -3.714618 8.552093 0.233106 +v -3.758093 8.562671 0.230183 +v -3.804313 8.562190 0.227488 +v -3.790030 8.516317 0.240373 +v -3.528143 8.536739 0.173555 +v -3.521264 8.480086 0.177005 +v -3.503201 8.523854 0.159149 +v -3.496660 8.572320 0.144069 +v -3.534343 8.570346 0.170324 +v -3.570464 8.556631 0.193896 +v -3.548717 8.515715 0.189119 +v -3.387857 8.308685 0.114891 +v -3.384965 8.248645 0.115351 +v -3.361331 8.293014 0.098762 +v -3.347819 8.342705 0.086036 +v -3.390278 8.344497 0.113828 +v -3.432927 8.334337 0.139991 +v -3.412832 8.288419 0.130826 +v -3.249611 8.058347 0.042675 +v -3.244447 7.998029 0.046308 +v -3.222972 8.040203 0.024806 +v -3.212466 8.088987 0.006753 +v -3.253958 8.094968 0.039190 +v -3.296280 8.088747 0.069837 +v -3.273561 8.040133 0.062046 +v -3.406072 8.473587 0.106122 +v -3.443338 8.438871 0.134992 +v -3.400500 8.438151 0.108942 +v -3.360372 8.448733 0.079683 +v -3.384956 8.494306 0.087021 +v -3.417745 8.532349 0.099424 +v -3.433933 8.487942 0.120699 +v -3.316379 8.567928 0.002425 +v -3.302324 8.508472 0.013070 +v -3.290569 8.552086 -0.017597 +v -3.289291 8.600757 -0.043678 +v -3.326394 8.603343 -0.005136 +v -3.361725 8.593339 0.033409 +v -3.333957 8.547911 0.028169 +v -3.265417 8.230356 0.034276 +v -3.305759 8.198309 0.065232 +v -3.263068 8.192767 0.034294 +v -3.223147 8.199172 0.000610 +v -3.242547 8.249372 0.013996 +v -3.270321 8.292811 0.033130 +v -3.291730 8.248581 0.053052 +v -3.173129 8.317528 -0.076699 +v -3.165380 8.254575 -0.071521 +v -3.152370 8.298432 -0.102024 +v -3.147724 8.348487 -0.125777 +v -3.178997 8.355073 -0.080875 +v -3.210831 8.348913 -0.036965 +v -3.190018 8.298847 -0.048988 +v -3.203106 8.489666 -0.098656 +v -3.229973 8.458487 -0.050548 +v -3.196166 8.452834 -0.093435 +v -3.165941 8.458857 -0.139654 +v -3.187650 8.508147 -0.128505 +v -3.216146 8.550667 -0.108793 +v -3.226385 8.507629 -0.075113 +v -3.126901 8.577595 -0.234851 +v -3.117813 8.514815 -0.226655 +v -3.104309 8.559421 -0.258854 +v -3.099777 8.609529 -0.284539 +v -3.134042 8.614647 -0.241003 +v -3.167614 8.606980 -0.196182 +v -3.144234 8.558109 -0.205855 +v -3.138258 7.974319 -0.052777 +v -3.173104 7.945559 -0.013722 +v -3.138602 7.939358 -0.053173 +v -3.107743 7.944297 -0.095868 +v -3.120309 7.991941 -0.078813 +v -3.142236 8.034593 -0.055637 +v -3.159383 7.992439 -0.029220 +v -3.069334 8.057188 -0.182938 +v -3.063444 7.995657 -0.179003 +v -3.053791 8.038117 -0.210599 +v -3.051147 8.087247 -0.234231 +v -3.074208 8.094153 -0.186188 +v -3.097644 8.088471 -0.138388 +v -3.081563 8.039134 -0.153102 +v -3.088505 8.229331 -0.198192 +v -3.110119 8.198374 -0.148099 +v -3.085323 8.191881 -0.195006 +v -3.063188 8.197513 -0.243815 +v -3.076280 8.247751 -0.228634 +v -3.094135 8.291979 -0.203825 +v -3.104568 8.248314 -0.171277 +v -3.030383 8.312664 -0.336681 +v -3.027597 8.250722 -0.332950 +v -3.016458 8.293211 -0.364030 +v -3.010037 8.342062 -0.386071 +v -3.032155 8.349905 -0.339131 +v -3.055552 8.345415 -0.291983 +v -3.043275 8.295033 -0.307286 +v -3.036846 8.488317 -0.349318 +v -3.060795 8.457830 -0.300707 +v -3.035529 8.449740 -0.346159 +v -3.013260 8.453728 -0.393176 +v -3.023907 8.506009 -0.378722 +v -3.041537 8.552318 -0.356386 +v -3.053123 8.508695 -0.323877 +v -2.985648 8.563687 -0.484623 +v -2.982033 8.502161 -0.479577 +v -2.976010 8.541327 -0.510499 +v -2.976350 8.586377 -0.533823 +v -2.989621 8.600544 -0.489697 +v -3.006939 8.601030 -0.444030 +v -2.994492 8.548870 -0.455463 +v -3.583183 8.509464 -1.651070 +v -3.529656 8.476542 -1.625327 +v -3.579496 8.475328 -1.664515 +v -3.633253 8.486486 -1.694362 +v -3.616110 8.529579 -1.663154 +v -3.590641 8.563623 -1.625776 +v -3.555560 8.523076 -1.622318 +v -3.410134 8.234696 -1.618795 +v -3.359171 8.200375 -1.578453 +v -3.406542 8.192945 -1.625329 +v -3.458167 8.199695 -1.667153 +v -3.442338 8.255389 -1.640867 +v -3.418559 8.302895 -1.604070 +v -3.383644 8.255366 -1.587605 +v -3.276311 7.944573 -1.492327 +v -3.241410 7.918105 -1.437805 +v -3.279533 7.902557 -1.486383 +v -3.319558 7.901417 -1.535159 +v -3.299289 7.961291 -1.523760 +v -3.273585 8.015438 -1.498569 +v -3.252177 7.970362 -1.464799 +v -3.563963 8.336120 -1.710226 +v -3.515207 8.366275 -1.662673 +v -3.529766 8.313072 -1.693069 +v -3.558182 8.265485 -1.725283 +v -3.595392 8.317330 -1.735494 +v -3.623057 8.374306 -1.733031 +v -3.568528 8.376925 -1.698311 +v -3.726083 8.243727 -1.802790 +v -3.661757 8.204677 -1.785105 +v -3.726474 8.198704 -1.805540 +v -3.792729 8.207706 -1.818319 +v -3.765534 8.267140 -1.808931 +v -3.726889 8.317393 -1.791278 +v -3.687579 8.264800 -1.788434 +v -3.397125 8.032792 -1.632732 +v -3.350508 8.072295 -1.587327 +v -3.367716 8.011430 -1.603896 +v -3.397677 7.957181 -1.625300 +v -3.427747 8.009026 -1.656747 +v -3.450621 8.069551 -1.675690 +v -3.398977 8.078137 -1.633546 +v -3.556410 7.921108 -1.721720 +v -3.498705 7.885189 -1.681292 +v -3.560182 7.875376 -1.710335 +v -3.623205 7.882131 -1.737520 +v -3.593022 7.943756 -1.742085 +v -3.552999 7.998986 -1.733463 +v -3.518346 7.945393 -1.707568 +v -3.731086 8.029566 -1.800473 +v -3.664070 8.068205 -1.784762 +v -3.692541 8.005488 -1.786874 +v -3.734891 7.951407 -1.787122 +v -3.771985 8.006886 -1.804983 +v -3.796301 8.070444 -1.815937 +v -3.729411 8.076844 -1.804226 +v -3.917506 7.931348 -1.795612 +v -3.854235 7.889247 -1.784185 +v -3.918871 7.887032 -1.781589 +v -3.982690 7.900268 -1.777919 +v -3.955686 7.957067 -1.798152 +v -3.915593 8.007169 -1.812334 +v -3.878031 7.951001 -1.802093 +v -3.294042 7.755850 -1.450298 +v -3.253567 7.799226 -1.412433 +v -3.274792 7.743577 -1.415077 +v -3.304836 7.693429 -1.424617 +v -3.320745 7.730644 -1.470240 +v -3.330722 7.779265 -1.506560 +v -3.289481 7.795108 -1.462699 +v -3.437065 7.643190 -1.518301 +v -3.394793 7.621670 -1.465800 +v -3.447063 7.607438 -1.494668 +v -3.499843 7.607585 -1.527619 +v -3.464956 7.658282 -1.547375 +v -3.423397 7.706929 -1.552068 +v -3.401953 7.666458 -1.509052 +v -3.579300 7.720330 -1.649412 +v -3.513338 7.757100 -1.636669 +v -3.545959 7.702151 -1.621931 +v -3.591287 7.656079 -1.610936 +v -3.620202 7.700095 -1.653168 +v -3.637461 7.753695 -1.690117 +v -3.573316 7.761104 -1.669060 +v -3.766243 7.634337 -1.647660 +v -3.710667 7.601857 -1.609616 +v -3.772507 7.598533 -1.619940 +v -3.832469 7.609378 -1.634945 +v -3.800306 7.655615 -1.667083 +v -3.757223 7.697887 -1.688806 +v -3.726595 7.651248 -1.652071 +v -3.927882 7.737192 -1.716875 +v -3.862101 7.764196 -1.733468 +v -3.892240 7.714156 -1.706382 +v -3.933739 7.674720 -1.679137 +v -3.966431 7.722736 -1.703937 +v -3.987609 7.777355 -1.728471 +v -3.924766 7.776606 -1.736618 +v -4.091855 7.678063 -1.653180 +v -4.039653 7.638642 -1.639443 +v -4.092624 7.644206 -1.630812 +v -4.143499 7.661762 -1.626380 +v -4.123623 7.701997 -1.658194 +v -4.092253 7.737371 -1.686372 +v -4.059564 7.689257 -1.667537 +v -4.813841 8.519567 -1.268311 +v -4.781338 8.490047 -1.320367 +v -4.822540 8.483742 -1.274407 +v -4.857012 8.491006 -1.223529 +v -4.830039 8.537634 -1.235562 +v -4.795341 8.576180 -1.255298 +v -4.785794 8.537182 -1.292691 +v -4.729079 8.240817 -1.427279 +v -4.678748 8.205498 -1.469916 +v -4.728636 8.197506 -1.427886 +v -4.775983 8.204103 -1.382568 +v -4.757115 8.262009 -1.399698 +v -4.725948 8.312587 -1.422309 +v -4.698790 8.262898 -1.451360 +v -4.562613 7.942219 -1.521707 +v -4.507759 7.910526 -1.553801 +v -4.554284 7.900303 -1.513195 +v -4.601939 7.904482 -1.473003 +v -4.594450 7.961998 -1.500491 +v -4.573196 8.014069 -1.531751 +v -4.537129 7.965369 -1.548902 +v -4.846369 8.339901 -1.291778 +v -4.800915 8.374475 -1.336636 +v -4.823845 8.318354 -1.322680 +v -4.851162 8.268277 -1.295402 +v -4.871129 8.318968 -1.262535 +v -4.879129 8.375576 -1.237283 +v -4.841023 8.381673 -1.287762 +v -4.948113 8.242212 -1.143968 +v -4.916892 8.204655 -1.200854 +v -4.947873 8.198240 -1.143148 +v -4.974083 8.206942 -1.083495 +v -4.963746 8.264962 -1.108425 +v -4.943742 8.314860 -1.142900 +v -4.929072 8.263405 -1.178485 +v -4.713099 8.037701 -1.418733 +v -4.669049 8.075716 -1.465332 +v -4.679961 8.016332 -1.442010 +v -4.698785 7.964462 -1.407866 +v -4.737793 8.015013 -1.388772 +v -4.765870 8.073942 -1.376653 +v -4.719487 8.082055 -1.422978 +v -4.820331 7.931316 -1.271675 +v -4.765930 7.897117 -1.313267 +v -4.807780 7.888272 -1.262430 +v -4.849409 7.895082 -1.211940 +v -4.849867 7.952989 -1.244437 +v -4.835203 8.005749 -1.282927 +v -4.799139 7.954332 -1.305328 +v -4.937973 8.035070 -1.133655 +v -4.911036 8.072102 -1.194432 +v -4.916917 8.012012 -1.165939 +v -4.923572 7.961148 -1.124371 +v -4.949124 8.013934 -1.095561 +v -4.966114 8.074708 -1.076800 +v -4.942446 8.080348 -1.137366 +v -4.955093 7.948073 -0.953717 +v -4.934828 7.906561 -1.009346 +v -4.939127 7.907386 -0.947692 +v -4.944871 7.922292 -0.887067 +v -4.964450 7.973432 -0.919021 +v -4.977203 8.018188 -0.961698 +v -4.958376 7.964539 -0.993169 +v -4.511125 7.760331 -1.468302 +v -4.477077 7.794750 -1.519553 +v -4.477149 7.744997 -1.484216 +v -4.484714 7.702176 -1.441162 +v -4.529407 7.740683 -1.435610 +v -4.566960 7.787896 -1.438610 +v -4.525027 7.796904 -1.482765 +v -4.582757 7.673610 -1.308997 +v -4.528251 7.647902 -1.339458 +v -4.561851 7.641173 -1.291018 +v -4.601388 7.646402 -1.247229 +v -4.615173 7.690004 -1.289810 +v -4.615123 7.731032 -1.337111 +v -4.569966 7.691373 -1.344943 +v -4.742399 7.748812 -1.215378 +v -4.717350 7.780239 -1.276910 +v -4.706254 7.732565 -1.236813 +v -4.703060 7.693443 -1.187813 +v -4.754527 7.731722 -1.177250 +v -4.798749 7.778619 -1.176717 +v -4.763306 7.784472 -1.230262 +v -4.778527 7.677378 -1.039086 +v -4.725942 7.649535 -1.075057 +v -4.749966 7.647829 -1.022638 +v -4.779068 7.657779 -0.974587 +v -4.806372 7.696015 -1.015931 +v -4.821076 7.731560 -1.063815 +v -4.775154 7.691091 -1.077066 +v -4.874987 7.772141 -0.917210 +v -4.883148 7.793353 -0.984209 +v -4.860826 7.750035 -0.946622 +v -4.841262 7.716804 -0.899009 +v -4.868383 7.760815 -0.877234 +v -4.894444 7.810698 -0.865972 +v -4.893431 7.807346 -0.926920 +v -4.858389 7.719205 -0.749600 +v -4.831997 7.684638 -0.791599 +v -4.843193 7.687302 -0.742874 +v -4.858500 7.700554 -0.697069 +v -4.872706 7.740119 -0.723128 +v -4.882582 7.774765 -0.758507 +v -4.858566 7.730948 -0.781960 +v -4.827822 8.523324 0.049327 +v -4.872618 8.495259 0.005013 +v -4.839666 8.488276 0.057939 +v -4.797274 8.493743 0.103144 +v -4.797790 8.539842 0.072237 +v -4.803904 8.577826 0.031491 +v -4.842199 8.540990 0.014526 +v -4.970836 8.243182 -0.070419 +v -4.991327 8.206748 -0.134920 +v -4.972651 8.198146 -0.069895 +v -4.947822 8.204771 -0.007458 +v -4.954972 8.264935 -0.033507 +v -4.963305 8.317018 -0.073659 +v -4.981069 8.266082 -0.109705 +v -4.991226 7.937367 -0.262856 +v -4.982232 7.910980 -0.331432 +v -4.981292 7.894143 -0.266784 +v -4.979436 7.892285 -0.201053 +v -4.993528 7.954292 -0.221881 +v -5.003250 8.011084 -0.258059 +v -4.995496 7.964557 -0.300742 +v -4.876055 8.344092 0.084427 +v -4.904162 8.379740 0.025738 +v -4.901338 8.322390 0.054907 +v -4.885075 8.270685 0.090645 +v -4.854627 8.322240 0.116304 +v -4.826905 8.379073 0.126947 +v -4.867276 8.386436 0.078021 +v -4.747797 8.242771 0.208139 +v -4.804488 8.204899 0.172369 +v -4.747686 8.198034 0.208178 +v -4.686446 8.205734 0.237551 +v -4.710835 8.264734 0.225267 +v -4.743940 8.315554 0.203559 +v -4.781473 8.264658 0.186643 +v -4.975467 8.028109 -0.073384 +v -4.993309 8.069868 -0.137212 +v -4.985016 8.005848 -0.113968 +v -4.968719 7.949468 -0.079447 +v -4.960436 8.003448 -0.036689 +v -4.951101 8.066818 -0.008837 +v -4.975582 8.075762 -0.071518 +v -4.877504 7.915423 0.084724 +v -4.907830 7.876955 0.021900 +v -4.867690 7.868649 0.077622 +v -4.823694 7.877596 0.130265 +v -4.853980 7.939722 0.118457 +v -4.886581 7.995292 0.091155 +v -4.904927 7.939299 0.053600 +v -4.744306 8.029130 0.211964 +v -4.802680 8.067454 0.174322 +v -4.777736 8.004500 0.190709 +v -4.738194 7.950877 0.210181 +v -4.706526 8.007071 0.230544 +v -4.684146 8.070419 0.240512 +v -4.745653 8.076406 0.210345 +v -4.564877 7.939998 0.276976 +v -4.623798 7.894463 0.254030 +v -4.561001 7.896746 0.273113 +v -4.498300 7.913874 0.288783 +v -4.528026 7.967141 0.287355 +v -4.569005 8.012731 0.279788 +v -4.604218 7.956492 0.267199 +v -4.934049 7.746613 -0.292199 +v -4.945713 7.790764 -0.348321 +v -4.925814 7.735137 -0.334406 +v -4.903989 7.685056 -0.309033 +v -4.923531 7.721013 -0.259459 +v -4.942651 7.768799 -0.221268 +v -4.948928 7.785597 -0.283426 +v -4.853900 7.632071 -0.150749 +v -4.852875 7.612234 -0.221182 +v -4.827925 7.597085 -0.165896 +v -4.805323 7.596730 -0.107125 +v -4.850357 7.646568 -0.109434 +v -4.890962 7.695167 -0.128772 +v -4.878293 7.655670 -0.178888 +v -4.814357 7.710342 0.039352 +v -4.866996 7.746162 -0.006916 +v -4.827856 7.691069 -0.001133 +v -4.779551 7.645781 0.014507 +v -4.779122 7.690970 0.064383 +v -4.784751 7.746351 0.102020 +v -4.831605 7.751854 0.051651 +v -4.648064 7.627598 0.141659 +v -4.673552 7.594164 0.080227 +v -4.626786 7.592173 0.123281 +v -4.583685 7.604933 0.166892 +v -4.629019 7.650430 0.173905 +v -4.677463 7.692585 0.165912 +v -4.684463 7.643844 0.122780 +v -4.534543 7.743466 0.254421 +v -4.602318 7.767407 0.238270 +v -4.564223 7.716604 0.237760 +v -4.514332 7.677896 0.239245 +v -4.493154 7.730939 0.260982 +v -4.481155 7.789953 0.275599 +v -4.544015 7.784800 0.260487 +v -4.358654 7.693781 0.281615 +v -4.401037 7.647783 0.258454 +v -4.350047 7.657883 0.273609 +v -4.302346 7.680611 0.287796 +v -4.331331 7.721753 0.292475 +v -4.369118 7.756221 0.291557 +v -4.393029 7.702874 0.276128 +v -3.637671 8.450060 0.232376 +v -3.683987 8.423695 0.245765 +v -3.637759 8.418133 0.232584 +v -3.592594 8.424336 0.216006 +v -3.611066 8.466426 0.222532 +v -3.638376 8.501969 0.229162 +v -3.664971 8.465808 0.239375 +v -3.770758 8.220679 0.297250 +v -3.822375 8.192364 0.316619 +v -3.771330 8.185884 0.301512 +v -3.720885 8.191219 0.282452 +v -3.740476 8.237505 0.284130 +v -3.770194 8.278123 0.287671 +v -3.800954 8.238555 0.304132 +v -3.921597 7.968590 0.338082 +v -3.975931 7.938850 0.340974 +v -3.923324 7.930858 0.333475 +v -3.870672 7.935482 0.324077 +v -3.889394 7.986470 0.334131 +v -3.919291 8.031306 0.342626 +v -3.952569 7.988359 0.344041 +v -3.636044 8.298429 0.239226 +v -3.683886 8.326695 0.252268 +v -3.663985 8.281605 0.250904 +v -3.634975 8.241755 0.244231 +v -3.607740 8.281624 0.230139 +v -3.590556 8.326824 0.219193 +v -3.636900 8.331988 0.236075 +v -3.506919 8.220733 0.186249 +v -3.551899 8.191468 0.210039 +v -3.506205 8.186233 0.186245 +v -3.461294 8.192568 0.161253 +v -3.480527 8.238459 0.171254 +v -3.508662 8.278098 0.184865 +v -3.534455 8.237529 0.200098 +v -3.774390 8.053460 0.307176 +v -3.825001 8.085059 0.323491 +v -3.805800 8.034675 0.316567 +v -3.776651 7.990224 0.303536 +v -3.744459 8.034606 0.295052 +v -3.722782 8.084745 0.288064 +v -3.773379 8.090951 0.307284 +v -3.636964 7.968457 0.243218 +v -3.688561 7.935521 0.262702 +v -3.638334 7.930855 0.239555 +v -3.588432 7.938758 0.216440 +v -3.606784 7.988106 0.230429 +v -3.635434 8.030880 0.247356 +v -3.666420 7.986336 0.258420 +v -3.503570 8.057075 0.181989 +v -3.550390 8.086967 0.207737 +v -3.531119 8.038476 0.195482 +v -3.502768 7.995714 0.178241 +v -3.475514 8.038936 0.166494 +v -3.458368 8.087668 0.158823 +v -3.504327 8.093395 0.183706 +v -3.368738 7.973380 0.117412 +v -3.416417 7.942416 0.136608 +v -3.367459 7.937180 0.115965 +v -3.320501 7.944068 0.094010 +v -3.341303 7.991915 0.104380 +v -3.372564 8.034224 0.117347 +v -3.398728 7.991283 0.130125 +v -3.931238 7.792476 0.316137 +v -3.981466 7.826868 0.327525 +v -3.963702 7.775218 0.317978 +v -3.936166 7.729760 0.304812 +v -3.901412 7.772277 0.307076 +v -3.876969 7.822604 0.309787 +v -3.928804 7.830688 0.320997 +v -3.792680 7.702900 0.261414 +v -3.848552 7.672249 0.269503 +v -3.796368 7.666245 0.250981 +v -3.743552 7.673711 0.232801 +v -3.759914 7.722249 0.254120 +v -3.788027 7.765554 0.274571 +v -3.822647 7.721321 0.276099 +v -3.644336 7.794203 0.220395 +v -3.693498 7.823750 0.248138 +v -3.675733 7.774248 0.230480 +v -3.648377 7.732171 0.207322 +v -3.615436 7.777021 0.202679 +v -3.592816 7.827839 0.202047 +v -3.642501 7.831792 0.226656 +v -3.513708 7.718331 0.137730 +v -3.564865 7.684184 0.152993 +v -3.516968 7.682702 0.128161 +v -3.469039 7.693622 0.105724 +v -3.483516 7.738946 0.127838 +v -3.509103 7.778749 0.150693 +v -3.541248 7.733903 0.155758 +v -3.372319 7.808925 0.097214 +v -3.418459 7.836373 0.123591 +v -3.402985 7.790374 0.105009 +v -3.379758 7.752009 0.081032 +v -3.346672 7.793397 0.079879 +v -3.323493 7.840056 0.081520 +v -3.369357 7.843710 0.104631 +v -3.272193 7.747634 0.005902 +v -3.315303 7.714114 0.021317 +v -3.280478 7.717334 -0.007558 +v -3.244969 7.730627 -0.033809 +v -3.247147 7.767387 -0.005781 +v -3.259259 7.799416 0.023634 +v -3.289978 7.758630 0.028106 +v -2.957407 8.471771 -0.615620 +v -2.961696 8.443629 -0.564632 +v -2.957103 8.437620 -0.615970 +v -2.957360 8.443951 -0.667353 +v -2.958547 8.488826 -0.645663 +v -2.961364 8.527540 -0.614932 +v -2.960016 8.489032 -0.585169 +v -2.975695 8.225076 -0.470202 +v -2.991394 8.194545 -0.418114 +v -2.975407 8.188134 -0.469574 +v -2.962018 8.193947 -0.522162 +v -2.967544 8.243226 -0.501629 +v -2.976604 8.286065 -0.471419 +v -2.985330 8.243566 -0.439815 +v -3.001851 7.962618 -0.313775 +v -3.020390 7.935044 -0.262204 +v -2.999725 7.923872 -0.311697 +v -2.982379 7.925645 -0.363453 +v -2.992762 7.979591 -0.345618 +v -3.008402 8.027218 -0.318124 +v -3.015355 7.984412 -0.284908 +v -2.951733 8.309497 -0.616289 +v -2.959247 8.339275 -0.563850 +v -2.953793 8.291121 -0.584596 +v -2.948397 8.248582 -0.616541 +v -2.948724 8.291718 -0.648348 +v -2.951839 8.340281 -0.669281 +v -2.954260 8.345469 -0.616283 +v -2.943015 8.226794 -0.769956 +v -2.941118 8.194779 -0.714837 +v -2.941329 8.189305 -0.771320 +v -2.944932 8.196521 -0.827318 +v -2.946003 8.246146 -0.802751 +v -2.948132 8.288609 -0.767353 +v -2.943694 8.244784 -0.735703 +v -2.965351 8.047335 -0.463322 +v -2.984131 8.081325 -0.412957 +v -2.972240 8.027757 -0.430621 +v -2.959657 7.979841 -0.459897 +v -2.955655 8.026780 -0.494307 +v -2.955783 8.080187 -0.518590 +v -2.969467 8.087232 -0.465631 +v -2.936587 7.951734 -0.615532 +v -2.940327 7.917367 -0.557049 +v -2.936627 7.910012 -0.615392 +v -2.936578 7.917118 -0.674233 +v -2.936126 7.972362 -0.650757 +v -2.938385 8.020163 -0.616049 +v -2.939125 7.972486 -0.580796 +v -2.937820 8.047165 -0.775529 +v -2.937296 8.080163 -0.717856 +v -2.936833 8.026535 -0.741771 +v -2.939429 7.979372 -0.776475 +v -2.940474 8.027485 -0.809675 +v -2.942255 8.081542 -0.831051 +v -2.938345 8.087320 -0.774557 +v -2.968361 7.961083 -0.928393 +v -2.959083 7.924328 -0.874446 +v -2.974121 7.921943 -0.927828 +v -2.989928 7.932491 -0.980617 +v -2.975477 7.982816 -0.960552 +v -2.961759 8.026584 -0.928960 +v -2.957800 7.978558 -0.896469 +v -3.009159 7.783853 -0.306569 +v -3.025694 7.822819 -0.258472 +v -3.025774 7.769802 -0.277367 +v -3.023973 7.721146 -0.306913 +v -3.001313 7.760267 -0.336828 +v -2.986092 7.809429 -0.358654 +v -3.003598 7.822207 -0.307440 +v -2.974112 7.667243 -0.454560 +v -3.002176 7.645493 -0.399648 +v -2.984601 7.627403 -0.454949 +v -2.968491 7.625029 -0.511846 +v -2.961290 7.682369 -0.488434 +v -2.963332 7.735953 -0.454300 +v -2.981086 7.693772 -0.421043 +v -2.937652 7.751617 -0.615125 +v -2.940246 7.789830 -0.556378 +v -2.940687 7.730367 -0.579775 +v -2.945094 7.679397 -0.615098 +v -2.939869 7.730174 -0.650497 +v -2.938357 7.789526 -0.674197 +v -2.936721 7.795976 -0.615199 +v -2.971425 7.665904 -0.776111 +v -2.966751 7.623972 -0.718582 +v -2.981798 7.625633 -0.775811 +v -2.998092 7.643045 -0.831752 +v -2.977543 7.692194 -0.809987 +v -2.959792 7.734923 -0.776631 +v -2.959078 7.681465 -0.742064 +v -3.000089 7.781063 -0.927345 +v -2.977577 7.807597 -0.874412 +v -2.994355 7.757885 -0.895921 +v -3.016222 7.717639 -0.926677 +v -3.015333 7.766066 -0.957718 +v -3.011220 7.819081 -0.978640 +v -2.992203 7.819643 -0.927327 +v -3.077418 7.721490 -1.055496 +v -3.067767 7.682056 -1.009451 +v -3.090435 7.688337 -1.052953 +v -3.109715 7.704964 -1.096042 +v -3.085017 7.744481 -1.083174 +v -3.059978 7.778769 -1.060438 +v -3.059243 7.732226 -1.030336 +v -3.253011 7.574808 -1.205045 +v -3.264805 7.536412 -1.158083 +v -3.275959 7.552046 -1.213424 +v -3.278702 7.578251 -1.264443 +v -3.246027 7.599607 -1.230996 +v -3.217415 7.613763 -1.189263 +v -3.237546 7.574584 -1.169226 +v -3.437802 7.385052 -1.076373 +v -3.458829 7.358884 -1.018604 +v -3.471906 7.367158 -1.076964 +v -3.472517 7.381577 -1.135736 +v -3.424796 7.401161 -1.111021 +v -3.381110 7.414879 -1.074982 +v -3.415960 7.386535 -1.041325 +v -3.663520 7.249597 -0.910245 +v -3.684618 7.239710 -0.853290 +v -3.698646 7.236902 -0.908156 +v -3.701378 7.239831 -0.964265 +v -3.650627 7.257255 -0.944667 +v -3.604162 7.273138 -0.912775 +v -3.641054 7.256062 -0.877687 +v -3.377033 7.470723 -1.233625 +v -3.345119 7.470546 -1.173830 +v -3.389791 7.449273 -1.200707 +v -3.432423 7.436546 -1.237488 +v -3.397269 7.472548 -1.268811 +v -3.358141 7.510864 -1.285529 +v -3.346147 7.492757 -1.229733 +v -3.483093 7.493239 -1.393435 +v -3.501244 7.449465 -1.339621 +v -3.520486 7.475432 -1.394417 +v -3.529134 7.511239 -1.446392 +v -3.473357 7.522217 -1.423504 +v -3.424012 7.526608 -1.387708 +v -3.457402 7.485147 -1.359795 +v -3.599697 7.298408 -1.074262 +v -3.563289 7.305804 -1.016773 +v -3.614207 7.284776 -1.037887 +v -3.661264 7.270182 -1.069993 +v -3.622103 7.295547 -1.108421 +v -3.576180 7.325215 -1.134607 +v -3.563595 7.317429 -1.075919 +v -3.716112 7.305468 -1.227340 +v -3.736021 7.274102 -1.166672 +v -3.756502 7.293617 -1.222088 +v -3.764758 7.321735 -1.277770 +v -3.704692 7.327497 -1.262694 +v -3.649897 7.330168 -1.233476 +v -3.688115 7.299188 -1.195592 +v -3.663286 7.415857 -1.388810 +v -3.615389 7.399586 -1.336688 +v -3.674692 7.390460 -1.354490 +v -3.731565 7.392761 -1.380972 +v -3.693008 7.427915 -1.418169 +v -3.645278 7.461693 -1.443414 +v -3.623058 7.431597 -1.391668 +v -3.803564 7.481256 -1.513129 +v -3.820966 7.434601 -1.459915 +v -3.844638 7.469898 -1.504791 +v -3.855531 7.511913 -1.549573 +v -3.793748 7.511575 -1.543260 +v -3.735296 7.503978 -1.523455 +v -3.772778 7.465035 -1.488859 +v -3.825496 7.210962 -0.888865 +v -3.787091 7.216815 -0.841042 +v -3.836904 7.212408 -0.853029 +v -3.883533 7.211741 -0.874910 +v -3.849299 7.209868 -0.917153 +v -3.806263 7.213791 -0.949586 +v -3.790533 7.214424 -0.896095 +v -3.946052 7.219580 -1.017068 +v -3.960169 7.218170 -0.953966 +v -3.982720 7.224705 -1.005246 +v -3.993227 7.234683 -1.060227 +v -3.936998 7.224664 -1.054535 +v -3.883436 7.218462 -1.033923 +v -3.917905 7.214452 -0.990125 +v -3.901467 7.265617 -1.192598 +v -3.853416 7.248460 -1.145400 +v -3.911627 7.250960 -1.154321 +v -3.966219 7.263145 -1.173268 +v -3.930410 7.279286 -1.219368 +v -3.884015 7.296111 -1.254752 +v -3.862033 7.270857 -1.202396 +v -4.035992 7.336058 -1.307633 +v -4.051679 7.308454 -1.245817 +v -4.074214 7.336541 -1.292913 +v -4.083395 7.368024 -1.342695 +v -4.025939 7.355857 -1.343133 +v -3.970599 7.340940 -1.329123 +v -4.006941 7.319441 -1.284761 +v -3.989801 7.439315 -1.466552 +v -3.940620 7.408182 -1.431068 +v -3.999603 7.414706 -1.433443 +v -4.054020 7.432377 -1.443752 +v -4.018599 7.459749 -1.485419 +v -3.973500 7.484231 -1.518654 +v -3.950592 7.446060 -1.478314 +v -4.116301 7.535929 -1.538979 +v -4.133761 7.495054 -1.490674 +v -4.151889 7.533058 -1.522284 +v -4.157991 7.573966 -1.555863 +v -4.106565 7.563204 -1.565859 +v -4.056335 7.545912 -1.564509 +v -4.090413 7.514606 -1.526522 +v -4.278909 7.548515 -1.465029 +v -4.239238 7.503927 -1.442541 +v -4.289764 7.530728 -1.435925 +v -4.334613 7.567010 -1.438959 +v -4.300769 7.577524 -1.477932 +v -4.258977 7.581304 -1.510052 +v -4.244455 7.540252 -1.480090 +v -4.204597 7.360558 -1.231035 +v -4.158973 7.325471 -1.197025 +v -4.211362 7.350573 -1.192119 +v -4.260293 7.382281 -1.198562 +v -4.230998 7.384253 -1.250124 +v -4.191225 7.382718 -1.293594 +v -4.170024 7.350507 -1.249293 +v -4.102833 7.263677 -0.947149 +v -4.058878 7.247138 -0.910438 +v -4.106696 7.268022 -0.906929 +v -4.152671 7.290469 -0.915553 +v -4.128938 7.276470 -0.968812 +v -4.094599 7.262139 -1.014563 +v -4.071821 7.250128 -0.965337 +v -4.324194 7.475183 -1.315131 +v -4.267680 7.455807 -1.346421 +v -4.298872 7.449666 -1.297788 +v -4.337202 7.454681 -1.253047 +v -4.357282 7.488459 -1.295518 +v -4.364786 7.520160 -1.342742 +v -4.315404 7.489208 -1.350750 +v -4.477690 7.536276 -1.225461 +v -4.434752 7.494390 -1.194893 +v -4.485013 7.524376 -1.188006 +v -4.532063 7.559903 -1.193344 +v -4.502178 7.563196 -1.243424 +v -4.462867 7.559255 -1.286682 +v -4.444454 7.523203 -1.244451 +v -4.228168 7.333242 -1.045779 +v -4.175031 7.307510 -1.078778 +v -4.200056 7.316229 -1.024822 +v -4.232839 7.333417 -0.977388 +v -4.259176 7.350386 -1.025433 +v -4.274776 7.364678 -1.080121 +v -4.224612 7.335338 -1.086661 +v -4.369565 7.406744 -0.952357 +v -4.322128 7.380599 -0.918275 +v -4.371148 7.404923 -0.912413 +v -4.419884 7.430244 -0.920126 +v -4.397897 7.423521 -0.973127 +v -4.365931 7.411426 -1.020060 +v -4.339332 7.392497 -0.972159 +v -4.500974 7.493347 -1.046825 +v -4.449163 7.468537 -1.080223 +v -4.472587 7.472567 -1.026940 +v -4.504566 7.484064 -0.980307 +v -4.531607 7.508666 -1.026753 +v -4.547556 7.530759 -1.079397 +v -4.498060 7.500141 -1.086490 +v -4.644152 7.558733 -0.955396 +v -4.595835 7.524729 -0.922560 +v -4.646139 7.550991 -0.916429 +v -4.694812 7.581798 -0.922499 +v -4.672959 7.580766 -0.974805 +v -4.639984 7.573293 -1.020674 +v -4.612933 7.545745 -0.974850 +v -4.114380 7.297892 -0.772205 +v -4.068129 7.269514 -0.799810 +v -4.088463 7.290257 -0.754216 +v -4.116401 7.312438 -0.714712 +v -4.141810 7.314959 -0.755550 +v -4.158715 7.311444 -0.803110 +v -4.113023 7.288334 -0.807436 +v -4.242611 7.361641 -0.693783 +v -4.197296 7.350730 -0.664658 +v -4.243843 7.363786 -0.658925 +v -4.291376 7.374513 -0.664482 +v -4.270432 7.367101 -0.711304 +v -4.241336 7.354174 -0.752345 +v -4.214390 7.351659 -0.711098 +v -4.373798 7.401807 -0.776362 +v -4.324730 7.380479 -0.805793 +v -4.344952 7.389355 -0.758070 +v -4.375679 7.400463 -0.716944 +v -4.403840 7.414046 -0.759162 +v -4.422745 7.424744 -0.807752 +v -4.373301 7.402320 -0.812499 +v -4.519669 7.448513 -0.695804 +v -4.469832 7.427502 -0.665112 +v -4.523355 7.443254 -0.659339 +v -4.575685 7.461921 -0.665406 +v -4.549963 7.461657 -0.714030 +v -4.515431 7.456411 -0.756150 +v -4.486647 7.440528 -0.713628 +v -4.655985 7.521600 -0.780857 +v -4.603547 7.502884 -0.810831 +v -4.627776 7.502770 -0.762294 +v -4.660796 7.509534 -0.720040 +v -4.686043 7.533955 -0.762966 +v -4.701017 7.556685 -0.811379 +v -4.652896 7.529857 -0.817334 +v -4.777242 7.587685 -0.696916 +v -4.741135 7.550527 -0.666923 +v -4.778022 7.581917 -0.660696 +v -4.810440 7.617775 -0.664975 +v -4.797297 7.612342 -0.713077 +v -4.776395 7.600543 -0.756055 +v -4.755033 7.571344 -0.715513 +v -4.801972 7.572073 -0.524240 +v -4.757588 7.539219 -0.554903 +v -4.785510 7.550971 -0.503712 +v -4.817594 7.574182 -0.460378 +v -4.826416 7.594687 -0.507200 +v -4.825724 7.608780 -0.558110 +v -4.792190 7.573027 -0.562390 +v -4.549713 7.414152 -0.519629 +v -4.488281 7.405608 -0.553187 +v -4.521497 7.399830 -0.500011 +v -4.563771 7.401532 -0.452536 +v -4.586264 7.421222 -0.499397 +v -4.595356 7.440261 -0.552622 +v -4.540771 7.423293 -0.559315 +v -4.250946 7.343486 -0.529704 +v -4.201749 7.340191 -0.560637 +v -4.223349 7.331503 -0.512192 +v -4.255358 7.325367 -0.468541 +v -4.282024 7.343949 -0.510593 +v -4.298070 7.361439 -0.558932 +v -4.248573 7.353262 -0.565893 +v -4.711079 7.471582 -0.427730 +v -4.696955 7.476562 -0.494761 +v -4.678409 7.453421 -0.447140 +v -4.667769 7.438921 -0.392485 +v -4.717675 7.471386 -0.387025 +v -4.761237 7.508347 -0.396095 +v -4.734100 7.493596 -0.448929 +v -4.728434 7.486623 -0.232363 +v -4.677830 7.446924 -0.267783 +v -4.697660 7.470113 -0.210260 +v -4.724506 7.503753 -0.160924 +v -4.756367 7.514263 -0.212382 +v -4.773875 7.519717 -0.271679 +v -4.727725 7.479785 -0.275815 +v -4.411328 7.349637 -0.434991 +v -4.400729 7.365533 -0.499345 +v -4.373520 7.346421 -0.456757 +v -4.356899 7.330631 -0.407201 +v -4.416430 7.342595 -0.396158 +v -4.474015 7.359945 -0.398113 +v -4.442980 7.363003 -0.451935 +v -4.412890 7.347402 -0.253752 +v -4.356843 7.328156 -0.292668 +v -4.373900 7.342989 -0.238000 +v -4.402390 7.363666 -0.187907 +v -4.446024 7.361845 -0.230210 +v -4.476221 7.359411 -0.281063 +v -4.417409 7.341138 -0.293198 +v -4.567345 7.426735 -0.141972 +v -4.575894 7.408976 -0.210666 +v -4.533926 7.406956 -0.166532 +v -4.500277 7.414713 -0.115448 +v -4.560197 7.439970 -0.101376 +v -4.620546 7.464578 -0.102365 +v -4.605830 7.436342 -0.159012 +v -4.528757 7.489694 0.044418 +v -4.476003 7.453921 0.003370 +v -4.487518 7.482056 0.058841 +v -4.509730 7.516447 0.106582 +v -4.558615 7.514033 0.067505 +v -4.595613 7.505966 0.017428 +v -4.538254 7.475799 0.004785 +v -4.121594 7.281046 -0.452849 +v -4.121305 7.300420 -0.511112 +v -4.093342 7.278696 -0.472261 +v -4.072976 7.259692 -0.427909 +v -4.121076 7.270818 -0.417987 +v -4.170062 7.286825 -0.419901 +v -4.150179 7.295376 -0.468424 +v -4.106150 7.269343 -0.291167 +v -4.061255 7.252134 -0.325923 +v -4.072247 7.265511 -0.277068 +v -4.094002 7.284729 -0.232216 +v -4.133091 7.282156 -0.270140 +v -4.161747 7.279258 -0.315293 +v -4.112399 7.263739 -0.326243 +v -4.237292 7.330274 -0.186811 +v -4.247012 7.315406 -0.249403 +v -4.207359 7.317204 -0.210962 +v -4.177063 7.325268 -0.164739 +v -4.231098 7.340739 -0.149043 +v -4.288421 7.353317 -0.145558 +v -4.273846 7.333814 -0.200106 +v -4.205048 7.378988 -0.010289 +v -4.156039 7.356670 -0.052620 +v -4.167678 7.376748 0.002230 +v -4.191320 7.399613 0.051938 +v -4.234573 7.393553 0.015044 +v -4.267742 7.384884 -0.031770 +v -4.212843 7.368314 -0.048587 +v -4.343389 7.456815 0.107217 +v -4.357585 7.434189 0.044483 +v -4.313373 7.437387 0.082305 +v -4.278605 7.449698 0.124983 +v -4.333851 7.472708 0.141641 +v -4.391420 7.494230 0.144821 +v -4.382051 7.463350 0.094614 +v -4.286758 7.546497 0.233441 +v -4.244425 7.506799 0.206949 +v -4.246812 7.546134 0.236786 +v -4.259064 7.588854 0.259789 +v -4.309350 7.573761 0.246452 +v -4.352074 7.552766 0.224538 +v -4.301872 7.523540 0.213489 +v -3.162338 7.582975 -1.055557 +v -3.122262 7.590592 -1.009414 +v -3.162517 7.560411 -1.030408 +v -3.204269 7.540584 -1.061201 +v -3.186091 7.579437 -1.084026 +v -3.162302 7.619381 -1.096648 +v -3.138933 7.609681 -1.052886 +v -3.042556 7.486707 -0.781058 +v -3.011751 7.508314 -0.721478 +v -3.045763 7.463470 -0.747473 +v -3.085217 7.431857 -0.783796 +v -3.065417 7.477430 -0.815713 +v -3.044095 7.530123 -0.834922 +v -3.021880 7.523320 -0.778773 +v -3.048321 7.492292 -0.450453 +v -3.050222 7.535507 -0.397024 +v -3.072335 7.484091 -0.416198 +v -3.092241 7.438785 -0.448030 +v -3.051142 7.468832 -0.483978 +v -3.015331 7.511762 -0.509549 +v -3.026615 7.527648 -0.452514 +v -3.159125 7.463614 -0.931633 +v -3.117052 7.513283 -0.929731 +v -3.132271 7.464602 -0.901207 +v -3.161022 7.419233 -0.880921 +v -3.187482 7.437177 -0.931797 +v -3.205868 7.465700 -0.981010 +v -3.160233 7.492074 -0.960379 +v -3.313548 7.370333 -0.926842 +v -3.261669 7.359638 -0.877283 +v -3.321521 7.350529 -0.895001 +v -3.379531 7.349957 -0.923176 +v -3.345030 7.377774 -0.956525 +v -3.302725 7.405921 -0.979374 +v -3.275484 7.384500 -0.928848 +v -3.082952 7.396173 -0.615953 +v -3.036928 7.450327 -0.615695 +v -3.070601 7.413845 -0.578275 +v -3.115088 7.377414 -0.553257 +v -3.115745 7.368281 -0.616051 +v -3.111757 7.374149 -0.678717 +v -3.068548 7.411753 -0.653465 +v -3.255106 7.294056 -0.615616 +v -3.224548 7.311518 -0.553191 +v -3.277851 7.288848 -0.578024 +v -3.327195 7.274318 -0.614932 +v -3.276669 7.288351 -0.652661 +v -3.221961 7.309618 -0.678190 +v -3.214121 7.310318 -0.615889 +v -3.368958 7.291483 -0.774369 +v -3.296049 7.307750 -0.779457 +v -3.341796 7.287481 -0.742913 +v -3.398561 7.272840 -0.716280 +v -3.413489 7.284461 -0.770756 +v -3.415722 7.301215 -0.825502 +v -3.352953 7.305484 -0.808538 +v -3.559298 7.258690 -0.761493 +v -3.521119 7.253777 -0.709046 +v -3.573322 7.248754 -0.728854 +v -3.619392 7.246514 -0.759479 +v -3.581968 7.261418 -0.793101 +v -3.536143 7.277619 -0.817110 +v -3.522009 7.266373 -0.763169 +v -3.168843 7.472850 -0.302665 +v -3.126332 7.521593 -0.304545 +v -3.170674 7.501658 -0.275186 +v -3.216858 7.475689 -0.255654 +v -3.197030 7.445948 -0.302384 +v -3.169900 7.427518 -0.351927 +v -3.141376 7.473335 -0.332217 +v -3.313499 7.362685 -0.301109 +v -3.307242 7.405547 -0.253335 +v -3.343669 7.368218 -0.271749 +v -3.373468 7.333103 -0.301517 +v -3.319496 7.339736 -0.331098 +v -3.264644 7.357231 -0.351583 +v -3.279332 7.383260 -0.301582 +v -3.364895 7.279528 -0.450458 +v -3.296420 7.302548 -0.447830 +v -3.348709 7.292279 -0.415899 +v -3.407140 7.281622 -0.396873 +v -3.407140 7.269596 -0.453031 +v -3.395560 7.264745 -0.509871 +v -3.340572 7.280897 -0.483908 +v -3.552653 7.249923 -0.463715 +v -3.525800 7.260481 -0.405651 +v -3.574562 7.252462 -0.431968 +v -3.615818 7.246345 -0.468512 +v -3.569328 7.245470 -0.498350 +v -3.516689 7.247326 -0.517279 +v -3.514138 7.253361 -0.460824 +v -3.633672 7.234819 -0.615861 +v -3.570933 7.238187 -0.615090 +v -3.615369 7.236969 -0.584808 +v -3.665207 7.237389 -0.565236 +v -3.670161 7.234360 -0.616178 +v -3.664802 7.232910 -0.666745 +v -3.615434 7.235024 -0.646326 +v -3.787252 7.235874 -0.616171 +v -3.764035 7.237942 -0.567250 +v -3.802838 7.237597 -0.587384 +v -3.835350 7.237092 -0.615805 +v -3.802134 7.234181 -0.644725 +v -3.762969 7.232205 -0.665274 +v -3.757319 7.235360 -0.616326 +v -4.109763 7.565628 0.257060 +v -4.129738 7.518337 0.223951 +v -4.085421 7.545628 0.244640 +v -4.051031 7.583739 0.266237 +v -4.098735 7.596534 0.273777 +v -4.149446 7.600977 0.273542 +v -4.145838 7.557246 0.250052 +v -4.031842 7.376328 0.047196 +v -4.046072 7.353718 -0.014856 +v -4.002878 7.364122 0.021936 +v -3.968963 7.382408 0.064440 +v -4.023124 7.392335 0.082479 +v -4.080091 7.399186 0.087089 +v -4.069387 7.375026 0.035181 +v -3.943989 7.254178 -0.232493 +v -3.959437 7.241077 -0.289028 +v -3.917415 7.243847 -0.255839 +v -3.883223 7.253637 -0.215401 +v -3.934480 7.265068 -0.198567 +v -3.989125 7.276026 -0.194321 +v -3.980076 7.256878 -0.243630 +v -3.989346 7.475074 0.188245 +v -4.052262 7.461008 0.177127 +v -3.998962 7.448205 0.162966 +v -3.942109 7.447053 0.154334 +v -3.951751 7.486420 0.192282 +v -3.973511 7.525458 0.224148 +v -4.017122 7.493998 0.205703 +v -3.818305 7.539327 0.196155 +v -3.831955 7.486367 0.161054 +v -3.790253 7.523690 0.174618 +v -3.759256 7.568987 0.191273 +v -3.810941 7.573136 0.214017 +v -3.865514 7.567872 0.228061 +v -3.854466 7.523190 0.196684 +v -3.900151 7.313763 -0.069105 +v -3.962023 7.313759 -0.088910 +v -3.909539 7.299073 -0.105638 +v -3.854079 7.291717 -0.111585 +v -3.862966 7.316000 -0.058388 +v -3.884644 7.342141 -0.009676 +v -3.928044 7.328594 -0.044282 +v -3.725391 7.344182 -0.032983 +v -3.742460 7.309936 -0.088111 +v -3.697456 7.335053 -0.061759 +v -3.662661 7.368135 -0.029209 +v -3.715808 7.368065 -0.002166 +v -3.772901 7.363327 0.012307 +v -3.763596 7.333034 -0.037582 +v -3.685451 7.470517 0.091893 +v -3.747000 7.442854 0.093218 +v -3.693052 7.440113 0.068798 +v -3.637654 7.449640 0.049951 +v -3.649642 7.488932 0.089042 +v -3.674407 7.524518 0.125902 +v -3.714739 7.484603 0.115281 +v -3.529670 7.558680 0.074753 +v -3.537825 7.505754 0.040519 +v -3.503432 7.546553 0.050064 +v -3.479460 7.592740 0.064799 +v -3.525879 7.591854 0.092601 +v -3.575243 7.581305 0.113130 +v -3.561125 7.539161 0.079222 +v -3.828472 7.230259 -0.348186 +v -3.885844 7.226716 -0.360971 +v -3.839808 7.228672 -0.382142 +v -3.789861 7.234075 -0.393899 +v -3.793349 7.234795 -0.341284 +v -3.808905 7.237517 -0.290911 +v -3.851888 7.230339 -0.321512 +v -3.658728 7.252644 -0.320850 +v -3.682265 7.247031 -0.377998 +v -3.634738 7.253909 -0.350720 +v -3.595035 7.263536 -0.314098 +v -3.644938 7.258387 -0.286939 +v -3.699707 7.252821 -0.272324 +v -3.696824 7.247699 -0.325714 +v -3.599655 7.307247 -0.166661 +v -3.662425 7.287191 -0.173076 +v -3.611183 7.289066 -0.199232 +v -3.557190 7.299561 -0.215911 +v -3.563197 7.322251 -0.164138 +v -3.582472 7.343835 -0.114460 +v -3.625961 7.314090 -0.137890 +v -3.440799 7.386978 -0.162684 +v -3.454128 7.347908 -0.212387 +v -3.416194 7.382298 -0.193132 +v -3.388604 7.421234 -0.165989 +v -3.433751 7.412458 -0.134481 +v -3.481764 7.396568 -0.113221 +v -3.473090 7.367898 -0.161882 +v -3.412799 7.512518 -0.044562 +v -3.462352 7.477030 -0.037225 +v -3.417787 7.483878 -0.067350 +v -3.373144 7.501558 -0.090953 +v -3.384875 7.534623 -0.050189 +v -3.405967 7.562351 -0.009746 +v -3.437141 7.520380 -0.017824 +v -3.296489 7.612195 -0.071713 +v -3.298134 7.566165 -0.106849 +v -3.275141 7.605678 -0.098220 +v -3.259740 7.646812 -0.082244 +v -3.294603 7.640414 -0.052004 +v -3.331067 7.625484 -0.028404 +v -3.319154 7.591385 -0.065791 +vt 0.181819 0.016493 +vt 0.181819 0.026244 +vt 0.176907 0.023407 +vt 0.190105 0.031119 +vt 0.186731 0.023407 +vt 0.173533 0.031119 +vt 0.181819 0.031916 +vt 0.187501 0.009841 +vt 0.176137 0.009841 +vt 0.181819 0.000000 +vt 0.170455 0.019683 +vt 0.191585 0.039399 +vt 0.198864 0.029524 +vt 0.204546 0.039365 +vt 0.181819 0.039365 +vt 0.193183 0.019683 +vt 0.164774 0.029524 +vt 0.172053 0.039399 +vt 0.159092 0.039365 +vt 0.287169 0.149214 +vt 0.295455 0.144339 +vt 0.295455 0.150012 +vt 0.295534 0.134726 +vt 0.290543 0.141503 +vt 0.303662 0.149078 +vt 0.300368 0.141503 +vt 0.278410 0.147620 +vt 0.285690 0.157495 +vt 0.272728 0.157461 +vt 0.295455 0.157461 +vt 0.301966 0.129304 +vt 0.289773 0.127937 +vt 0.295455 0.118096 +vt 0.284092 0.137778 +vt 0.305201 0.157461 +vt 0.311692 0.146219 +vt 0.318183 0.157461 +vt 0.306819 0.137778 +vt 0.909091 0.016493 +vt 0.909091 0.026244 +vt 0.904179 0.023407 +vt 0.909091 0.031916 +vt 0.914003 0.023407 +vt 0.917377 0.031119 +vt 0.900805 0.031119 +vt 0.914773 0.009841 +vt 0.903409 0.009841 +vt 0.909091 0.000000 +vt 0.897727 0.019683 +vt 0.918857 0.039399 +vt 0.926137 0.029524 +vt 0.931818 0.039365 +vt 0.909091 0.039365 +vt 0.920455 0.019683 +vt 0.892046 0.029524 +vt 0.899325 0.039399 +vt 0.886364 0.039365 +vt 0.727273 0.016493 +vt 0.727273 0.026244 +vt 0.722361 0.023407 +vt 0.735559 0.031119 +vt 0.732185 0.023407 +vt 0.727273 0.031916 +vt 0.718987 0.031119 +vt 0.732955 0.009841 +vt 0.721591 0.009841 +vt 0.727273 0.000000 +vt 0.715909 0.019683 +vt 0.737039 0.039399 +vt 0.744318 0.029524 +vt 0.750000 0.039365 +vt 0.727273 0.039365 +vt 0.738637 0.019683 +vt 0.710228 0.029524 +vt 0.717507 0.039399 +vt 0.704546 0.039365 +vt 0.545455 0.016493 +vt 0.545455 0.026244 +vt 0.540543 0.023407 +vt 0.553741 0.031119 +vt 0.550367 0.023407 +vt 0.537169 0.031119 +vt 0.545455 0.031916 +vt 0.551137 0.009841 +vt 0.539773 0.009841 +vt 0.545455 0.000000 +vt 0.556819 0.019683 +vt 0.534091 0.019683 +vt 0.555221 0.039399 +vt 0.562500 0.029524 +vt 0.568182 0.039365 +vt 0.545455 0.039365 +vt 0.528410 0.029524 +vt 0.535689 0.039399 +vt 0.522728 0.039365 +vt 0.287248 0.165844 +vt 0.295455 0.170583 +vt 0.290543 0.173419 +vt 0.303662 0.165844 +vt 0.295455 0.164910 +vt 0.295455 0.180059 +vt 0.300368 0.173419 +vt 0.279219 0.168703 +vt 0.284092 0.177144 +vt 0.311692 0.168703 +vt 0.306819 0.177144 +vt 0.288965 0.185584 +vt 0.301946 0.185584 +vt 0.295455 0.196826 +vt 0.105430 0.165844 +vt 0.113637 0.170583 +vt 0.108725 0.173419 +vt 0.121844 0.165844 +vt 0.113637 0.164910 +vt 0.113637 0.180059 +vt 0.118550 0.173419 +vt 0.103872 0.157495 +vt 0.097420 0.168669 +vt 0.090910 0.157461 +vt 0.113637 0.157461 +vt 0.102274 0.177144 +vt 0.129874 0.168703 +vt 0.123383 0.157461 +vt 0.136365 0.157461 +vt 0.125001 0.177144 +vt 0.107147 0.185584 +vt 0.120128 0.185584 +vt 0.113637 0.196826 +vt 0.832702 0.165844 +vt 0.840909 0.170583 +vt 0.835997 0.173419 +vt 0.849116 0.165844 +vt 0.840909 0.164910 +vt 0.840909 0.180059 +vt 0.845822 0.173419 +vt 0.831144 0.157495 +vt 0.824673 0.168703 +vt 0.818182 0.157461 +vt 0.840909 0.157461 +vt 0.829546 0.177144 +vt 0.857146 0.168703 +vt 0.850655 0.157461 +vt 0.863637 0.157461 +vt 0.852273 0.177144 +vt 0.834419 0.185584 +vt 0.847400 0.185584 +vt 0.840909 0.196826 +vt 0.650884 0.165844 +vt 0.659091 0.170583 +vt 0.654179 0.173419 +vt 0.667298 0.165844 +vt 0.659091 0.164910 +vt 0.659091 0.180059 +vt 0.664004 0.173419 +vt 0.649326 0.157495 +vt 0.642855 0.168703 +vt 0.636364 0.157461 +vt 0.647728 0.177144 +vt 0.675328 0.168703 +vt 0.668837 0.157461 +vt 0.681819 0.157461 +vt 0.670455 0.177144 +vt 0.659091 0.157461 +vt 0.652601 0.185584 +vt 0.665582 0.185584 +vt 0.659091 0.196826 +vt 0.469066 0.165844 +vt 0.477273 0.170583 +vt 0.472361 0.173419 +vt 0.485480 0.165844 +vt 0.477273 0.164910 +vt 0.477273 0.180059 +vt 0.482186 0.173419 +vt 0.467508 0.157495 +vt 0.461037 0.168703 +vt 0.454546 0.157461 +vt 0.465910 0.177144 +vt 0.493510 0.168703 +vt 0.487019 0.157461 +vt 0.500001 0.157461 +vt 0.488637 0.177144 +vt 0.477273 0.157461 +vt 0.470783 0.185584 +vt 0.483764 0.185584 +vt 0.477273 0.196826 +vt 0.272728 0.174228 +vt 0.272728 0.183704 +vt 0.267816 0.180868 +vt 0.280935 0.188443 +vt 0.277640 0.180868 +vt 0.264521 0.188443 +vt 0.272728 0.189377 +vt 0.266237 0.168703 +vt 0.261364 0.177144 +vt 0.282474 0.196826 +vt 0.272728 0.196826 +vt 0.256491 0.185584 +vt 0.262982 0.196826 +vt 0.250001 0.196826 +vt 0.090989 0.174091 +vt 0.090910 0.183704 +vt 0.085998 0.180868 +vt 0.099117 0.188443 +vt 0.095822 0.180868 +vt 0.082624 0.188579 +vt 0.090910 0.189377 +vt 0.085228 0.167302 +vt 0.079546 0.177144 +vt 0.100656 0.196826 +vt 0.090910 0.196826 +vt 0.073864 0.186985 +vt 0.081144 0.196860 +vt 0.068182 0.196826 +vt 0.818182 0.174228 +vt 0.818182 0.183704 +vt 0.813270 0.180868 +vt 0.826389 0.188443 +vt 0.823094 0.180868 +vt 0.809975 0.188443 +vt 0.818182 0.189377 +vt 0.811692 0.168703 +vt 0.806818 0.177144 +vt 0.827928 0.196826 +vt 0.818182 0.196826 +vt 0.801946 0.185584 +vt 0.808436 0.196826 +vt 0.795455 0.196826 +vt 0.636364 0.174228 +vt 0.636364 0.183704 +vt 0.631452 0.180868 +vt 0.644571 0.188443 +vt 0.641276 0.180868 +vt 0.628157 0.188443 +vt 0.636364 0.189377 +vt 0.629873 0.168703 +vt 0.625000 0.177144 +vt 0.646110 0.196826 +vt 0.636364 0.196826 +vt 0.620127 0.185584 +vt 0.626618 0.196826 +vt 0.613637 0.196826 +vt 0.454546 0.174228 +vt 0.454546 0.183704 +vt 0.449634 0.180868 +vt 0.462753 0.188443 +vt 0.459458 0.180868 +vt 0.446339 0.188443 +vt 0.454546 0.189377 +vt 0.448055 0.168703 +vt 0.443182 0.177144 +vt 0.464292 0.196826 +vt 0.454546 0.196826 +vt 0.438310 0.185584 +vt 0.444800 0.196826 +vt 0.431819 0.196826 +vt 0.196260 0.323168 +vt 0.204546 0.328043 +vt 0.199634 0.330879 +vt 0.212753 0.323304 +vt 0.204546 0.322370 +vt 0.204625 0.337656 +vt 0.209459 0.330879 +vt 0.194781 0.314887 +vt 0.187501 0.324762 +vt 0.181819 0.314921 +vt 0.193183 0.334604 +vt 0.220783 0.326163 +vt 0.214292 0.314921 +vt 0.227274 0.314921 +vt 0.215910 0.334604 +vt 0.204546 0.314921 +vt 0.198864 0.344445 +vt 0.211057 0.343078 +vt 0.204546 0.354286 +vt 0.014441 0.323168 +vt 0.022727 0.328043 +vt 0.017815 0.330879 +vt 0.030935 0.323304 +vt 0.022727 0.322370 +vt 0.022806 0.337656 +vt 0.027640 0.330879 +vt 0.012942 0.314921 +vt 0.005682 0.324762 +vt 0.000000 0.314921 +vt 0.022727 0.314921 +vt 0.011364 0.334604 +vt 0.038964 0.326163 +vt 0.032473 0.314921 +vt 0.045455 0.314921 +vt 0.017046 0.344445 +vt 0.029238 0.343078 +vt 0.022727 0.354286 +vt 0.034091 0.334604 +vt 0.741714 0.323168 +vt 0.750000 0.328043 +vt 0.745088 0.330879 +vt 0.758207 0.323304 +vt 0.750000 0.322370 +vt 0.750079 0.337656 +vt 0.754913 0.330879 +vt 0.740235 0.314887 +vt 0.732955 0.324762 +vt 0.727273 0.314921 +vt 0.738637 0.334604 +vt 0.766237 0.326163 +vt 0.759746 0.314921 +vt 0.772728 0.314921 +vt 0.761364 0.334604 +vt 0.750000 0.314921 +vt 0.744318 0.344445 +vt 0.756511 0.343078 +vt 0.750000 0.354286 +vt 0.559896 0.323168 +vt 0.568182 0.328043 +vt 0.563270 0.330879 +vt 0.576389 0.323304 +vt 0.568182 0.322370 +vt 0.568261 0.337656 +vt 0.573095 0.330879 +vt 0.558417 0.314887 +vt 0.551137 0.324762 +vt 0.545455 0.314921 +vt 0.556819 0.334604 +vt 0.584419 0.326163 +vt 0.577928 0.314921 +vt 0.590910 0.314921 +vt 0.579546 0.334604 +vt 0.568182 0.314921 +vt 0.562500 0.344445 +vt 0.574693 0.343078 +vt 0.568182 0.354286 +vt 0.378078 0.323168 +vt 0.386364 0.328043 +vt 0.381452 0.330879 +vt 0.394571 0.323304 +vt 0.386364 0.322370 +vt 0.391277 0.330879 +vt 0.386443 0.337656 +vt 0.376599 0.314887 +vt 0.369319 0.324762 +vt 0.363637 0.314921 +vt 0.375001 0.334604 +vt 0.402601 0.326163 +vt 0.396110 0.314921 +vt 0.409092 0.314921 +vt 0.397728 0.334604 +vt 0.386364 0.314921 +vt 0.380682 0.344445 +vt 0.392875 0.343078 +vt 0.386364 0.354286 +vt 0.446260 0.441263 +vt 0.454546 0.446139 +vt 0.449634 0.448975 +vt 0.462832 0.441263 +vt 0.454546 0.440466 +vt 0.454546 0.455889 +vt 0.459458 0.448975 +vt 0.444780 0.432983 +vt 0.437501 0.442858 +vt 0.431819 0.433017 +vt 0.454546 0.433017 +vt 0.443182 0.452699 +vt 0.471592 0.442858 +vt 0.464312 0.432983 +vt 0.477273 0.433017 +vt 0.465910 0.452699 +vt 0.448864 0.462541 +vt 0.460228 0.462541 +vt 0.454546 0.472382 +vt 0.423533 0.401898 +vt 0.431819 0.406773 +vt 0.426906 0.409610 +vt 0.440026 0.402035 +vt 0.431819 0.401101 +vt 0.431898 0.416387 +vt 0.436731 0.409609 +vt 0.422053 0.393617 +vt 0.414773 0.403493 +vt 0.409091 0.393651 +vt 0.431819 0.393652 +vt 0.420455 0.413334 +vt 0.448055 0.404894 +vt 0.441565 0.393652 +vt 0.454546 0.393652 +vt 0.443182 0.413334 +vt 0.426137 0.423175 +vt 0.438329 0.421809 +vt 0.400806 0.362533 +vt 0.409091 0.367408 +vt 0.404179 0.370244 +vt 0.417299 0.362670 +vt 0.409092 0.361736 +vt 0.409170 0.377021 +vt 0.414004 0.370244 +vt 0.399326 0.354252 +vt 0.392046 0.364128 +vt 0.397728 0.373969 +vt 0.425328 0.365529 +vt 0.418837 0.354286 +vt 0.431819 0.354286 +vt 0.420455 0.373969 +vt 0.409092 0.354286 +vt 0.403410 0.383810 +vt 0.415602 0.382443 +vt 0.446339 0.424633 +vt 0.454546 0.419895 +vt 0.454546 0.425567 +vt 0.454546 0.410418 +vt 0.449634 0.417059 +vt 0.462753 0.424633 +vt 0.459458 0.417059 +vt 0.461037 0.404894 +vt 0.470763 0.421809 +vt 0.465910 0.413334 +vt 0.469066 0.402035 +vt 0.477273 0.406773 +vt 0.472361 0.409610 +vt 0.485559 0.401898 +vt 0.477273 0.401101 +vt 0.477194 0.416387 +vt 0.482186 0.409610 +vt 0.467527 0.393652 +vt 0.477273 0.393652 +vt 0.494319 0.403493 +vt 0.487039 0.393617 +vt 0.500000 0.393651 +vt 0.488637 0.413334 +vt 0.482955 0.423175 +vt 0.423612 0.385268 +vt 0.431819 0.380530 +vt 0.431819 0.386202 +vt 0.431819 0.371053 +vt 0.426906 0.377694 +vt 0.440026 0.385268 +vt 0.436731 0.377694 +vt 0.438309 0.365529 +vt 0.443182 0.373969 +vt 0.448055 0.382409 +vt 0.446339 0.362670 +vt 0.454546 0.367408 +vt 0.449634 0.370244 +vt 0.462753 0.362670 +vt 0.454546 0.361736 +vt 0.454546 0.376885 +vt 0.459458 0.370244 +vt 0.444800 0.354286 +vt 0.454546 0.354286 +vt 0.470783 0.365529 +vt 0.464292 0.354286 +vt 0.477273 0.354286 +vt 0.465910 0.373969 +vt 0.461037 0.382409 +vt 0.469066 0.385268 +vt 0.477273 0.380530 +vt 0.477273 0.386202 +vt 0.477273 0.371053 +vt 0.472361 0.377694 +vt 0.485480 0.385268 +vt 0.482186 0.377694 +vt 0.483764 0.365529 +vt 0.488637 0.373969 +vt 0.493490 0.382443 +vt 0.491793 0.362670 +vt 0.500000 0.367408 +vt 0.495088 0.370244 +vt 0.508286 0.362533 +vt 0.500000 0.361736 +vt 0.499922 0.377022 +vt 0.504913 0.370244 +vt 0.490255 0.354286 +vt 0.500001 0.354286 +vt 0.517046 0.364128 +vt 0.509766 0.354252 +vt 0.522728 0.354286 +vt 0.511364 0.373969 +vt 0.505682 0.383810 +vt 0.400884 0.345903 +vt 0.409092 0.341165 +vt 0.409091 0.346837 +vt 0.409092 0.331688 +vt 0.404179 0.338328 +vt 0.417299 0.345903 +vt 0.414004 0.338328 +vt 0.415582 0.326163 +vt 0.420455 0.334604 +vt 0.425328 0.343044 +vt 0.423612 0.323304 +vt 0.431819 0.328043 +vt 0.426906 0.330879 +vt 0.440026 0.323304 +vt 0.431819 0.322370 +vt 0.431819 0.337520 +vt 0.436731 0.330879 +vt 0.422073 0.314921 +vt 0.448055 0.326163 +vt 0.441565 0.314921 +vt 0.454546 0.314921 +vt 0.443182 0.334604 +vt 0.431819 0.314921 +vt 0.438309 0.343044 +vt 0.446339 0.345903 +vt 0.454546 0.341165 +vt 0.454546 0.346837 +vt 0.454546 0.331688 +vt 0.449634 0.338328 +vt 0.462753 0.345903 +vt 0.459458 0.338328 +vt 0.461037 0.326163 +vt 0.465910 0.334604 +vt 0.470783 0.343044 +vt 0.469066 0.323304 +vt 0.477273 0.328043 +vt 0.472361 0.330879 +vt 0.485480 0.323304 +vt 0.477273 0.322370 +vt 0.477273 0.337520 +vt 0.482186 0.330879 +vt 0.467527 0.314921 +vt 0.477273 0.314921 +vt 0.493510 0.326163 +vt 0.487019 0.314921 +vt 0.500001 0.314921 +vt 0.488637 0.334604 +vt 0.483764 0.343044 +vt 0.491793 0.345903 +vt 0.500001 0.341165 +vt 0.500000 0.346837 +vt 0.500001 0.331688 +vt 0.495088 0.338328 +vt 0.508208 0.345903 +vt 0.504913 0.338328 +vt 0.506491 0.326163 +vt 0.516217 0.343078 +vt 0.511364 0.334604 +vt 0.514521 0.323304 +vt 0.522728 0.328043 +vt 0.517815 0.330879 +vt 0.531014 0.323168 +vt 0.522728 0.322370 +vt 0.522649 0.337656 +vt 0.527640 0.330879 +vt 0.512982 0.314921 +vt 0.522728 0.314921 +vt 0.539773 0.324762 +vt 0.532493 0.314887 +vt 0.528410 0.344445 +vt 0.534091 0.334604 +vt 0.628078 0.441263 +vt 0.636364 0.446139 +vt 0.631452 0.448975 +vt 0.641276 0.448975 +vt 0.636364 0.440466 +vt 0.644650 0.441263 +vt 0.636364 0.455889 +vt 0.626598 0.432983 +vt 0.619319 0.442858 +vt 0.613637 0.433017 +vt 0.625000 0.452699 +vt 0.653409 0.442858 +vt 0.646130 0.432983 +vt 0.659091 0.433017 +vt 0.647728 0.452699 +vt 0.636364 0.433017 +vt 0.630682 0.462541 +vt 0.642046 0.462541 +vt 0.636364 0.472382 +vt 0.605351 0.401898 +vt 0.613637 0.406773 +vt 0.608724 0.409610 +vt 0.618549 0.409610 +vt 0.613637 0.401101 +vt 0.621844 0.402035 +vt 0.613716 0.416387 +vt 0.603871 0.393617 +vt 0.596591 0.403493 +vt 0.590909 0.393651 +vt 0.602273 0.413334 +vt 0.629873 0.404894 +vt 0.623383 0.393652 +vt 0.636364 0.393652 +vt 0.625000 0.413334 +vt 0.613637 0.393652 +vt 0.607955 0.423175 +vt 0.620147 0.421809 +vt 0.582624 0.362533 +vt 0.590909 0.367408 +vt 0.585997 0.370244 +vt 0.599117 0.362670 +vt 0.590910 0.361736 +vt 0.590988 0.377021 +vt 0.595822 0.370244 +vt 0.581144 0.354252 +vt 0.573864 0.364128 +vt 0.579546 0.373969 +vt 0.607146 0.365529 +vt 0.600655 0.354286 +vt 0.613637 0.354286 +vt 0.602273 0.373969 +vt 0.590910 0.354286 +vt 0.585228 0.383810 +vt 0.597420 0.382443 +vt 0.628157 0.424633 +vt 0.636364 0.419895 +vt 0.636364 0.425567 +vt 0.636364 0.410418 +vt 0.631452 0.417059 +vt 0.644571 0.424633 +vt 0.641276 0.417059 +vt 0.642855 0.404894 +vt 0.647728 0.413334 +vt 0.652581 0.421809 +vt 0.650884 0.402035 +vt 0.659091 0.406773 +vt 0.654179 0.409610 +vt 0.667377 0.401898 +vt 0.659091 0.401101 +vt 0.659012 0.416387 +vt 0.664004 0.409610 +vt 0.649345 0.393652 +vt 0.659091 0.393652 +vt 0.676137 0.403493 +vt 0.668857 0.393617 +vt 0.681818 0.393651 +vt 0.670455 0.413334 +vt 0.664773 0.423175 +vt 0.605430 0.385268 +vt 0.613637 0.380530 +vt 0.613637 0.386202 +vt 0.613637 0.371053 +vt 0.608724 0.377694 +vt 0.621844 0.385268 +vt 0.618549 0.377694 +vt 0.620127 0.365529 +vt 0.625000 0.373969 +vt 0.629873 0.382409 +vt 0.628157 0.362670 +vt 0.636364 0.367408 +vt 0.631452 0.370244 +vt 0.644571 0.362670 +vt 0.636364 0.361736 +vt 0.636364 0.376885 +vt 0.641276 0.370244 +vt 0.626618 0.354286 +vt 0.636364 0.354286 +vt 0.652601 0.365529 +vt 0.646110 0.354286 +vt 0.659091 0.354286 +vt 0.647728 0.373969 +vt 0.642855 0.382409 +vt 0.650884 0.385268 +vt 0.659091 0.380530 +vt 0.659091 0.386202 +vt 0.659091 0.371053 +vt 0.654179 0.377694 +vt 0.667298 0.385268 +vt 0.664004 0.377694 +vt 0.665582 0.365529 +vt 0.670455 0.373969 +vt 0.675308 0.382443 +vt 0.673611 0.362670 +vt 0.681818 0.367408 +vt 0.676906 0.370244 +vt 0.690105 0.362533 +vt 0.681818 0.361736 +vt 0.681740 0.377022 +vt 0.686731 0.370244 +vt 0.672073 0.354286 +vt 0.681819 0.354286 +vt 0.698864 0.364128 +vt 0.691584 0.354252 +vt 0.704546 0.354286 +vt 0.693182 0.373969 +vt 0.687500 0.383810 +vt 0.582703 0.345903 +vt 0.590909 0.341165 +vt 0.590910 0.346837 +vt 0.590910 0.331688 +vt 0.585997 0.338328 +vt 0.599117 0.345903 +vt 0.595822 0.338328 +vt 0.597400 0.326163 +vt 0.602273 0.334604 +vt 0.607146 0.343044 +vt 0.605430 0.323304 +vt 0.613637 0.328043 +vt 0.608724 0.330879 +vt 0.621844 0.323304 +vt 0.613637 0.322370 +vt 0.613637 0.337520 +vt 0.618549 0.330879 +vt 0.603891 0.314921 +vt 0.613637 0.314921 +vt 0.629873 0.326163 +vt 0.623383 0.314921 +vt 0.636364 0.314921 +vt 0.625000 0.334604 +vt 0.620127 0.343044 +vt 0.628157 0.345903 +vt 0.636364 0.341165 +vt 0.636364 0.346837 +vt 0.636364 0.331688 +vt 0.631452 0.338328 +vt 0.644571 0.345903 +vt 0.641276 0.338328 +vt 0.642855 0.326163 +vt 0.647728 0.334604 +vt 0.652601 0.343044 +vt 0.650884 0.323304 +vt 0.659091 0.328043 +vt 0.654179 0.330879 +vt 0.667298 0.323304 +vt 0.659091 0.322370 +vt 0.659091 0.337520 +vt 0.664004 0.330879 +vt 0.649345 0.314921 +vt 0.659091 0.314921 +vt 0.675328 0.326163 +vt 0.668837 0.314921 +vt 0.681819 0.314921 +vt 0.670455 0.334604 +vt 0.665582 0.343044 +vt 0.673612 0.345903 +vt 0.681819 0.341165 +vt 0.681819 0.346837 +vt 0.681819 0.331688 +vt 0.676906 0.338328 +vt 0.690026 0.345903 +vt 0.686731 0.338328 +vt 0.688309 0.326163 +vt 0.693182 0.334604 +vt 0.698035 0.343078 +vt 0.696339 0.323304 +vt 0.704546 0.328043 +vt 0.699633 0.330879 +vt 0.712832 0.323168 +vt 0.704546 0.322370 +vt 0.704467 0.337656 +vt 0.709458 0.330879 +vt 0.694800 0.314921 +vt 0.704546 0.314921 +vt 0.721591 0.324762 +vt 0.714311 0.314887 +vt 0.710228 0.344445 +vt 0.715909 0.334604 +vt 0.809896 0.441263 +vt 0.818182 0.446139 +vt 0.813270 0.448975 +vt 0.826468 0.441263 +vt 0.818182 0.440466 +vt 0.818182 0.455889 +vt 0.823094 0.448975 +vt 0.808416 0.432983 +vt 0.801137 0.442858 +vt 0.795455 0.433017 +vt 0.818182 0.433017 +vt 0.806818 0.452699 +vt 0.835228 0.442858 +vt 0.827948 0.432983 +vt 0.840909 0.433017 +vt 0.829546 0.452699 +vt 0.812500 0.462541 +vt 0.823864 0.462541 +vt 0.818182 0.472382 +vt 0.787169 0.401898 +vt 0.795455 0.406773 +vt 0.790542 0.409610 +vt 0.803662 0.402035 +vt 0.795455 0.401101 +vt 0.795534 0.416387 +vt 0.800367 0.409609 +vt 0.785689 0.393617 +vt 0.778409 0.403493 +vt 0.772727 0.393651 +vt 0.795455 0.393652 +vt 0.784091 0.413334 +vt 0.811691 0.404894 +vt 0.805201 0.393652 +vt 0.818182 0.393652 +vt 0.806818 0.413334 +vt 0.789773 0.423175 +vt 0.801965 0.421809 +vt 0.764442 0.362533 +vt 0.772727 0.367408 +vt 0.767815 0.370244 +vt 0.780935 0.362670 +vt 0.772727 0.361736 +vt 0.772806 0.377021 +vt 0.777640 0.370244 +vt 0.762962 0.354252 +vt 0.755682 0.364128 +vt 0.761364 0.373969 +vt 0.788964 0.365529 +vt 0.782474 0.354286 +vt 0.795455 0.354286 +vt 0.772728 0.354286 +vt 0.767046 0.383810 +vt 0.779238 0.382443 +vt 0.784091 0.373969 +vt 0.809975 0.424633 +vt 0.818182 0.419895 +vt 0.818182 0.425567 +vt 0.818182 0.410418 +vt 0.813270 0.417059 +vt 0.826389 0.424633 +vt 0.823094 0.417059 +vt 0.824673 0.404894 +vt 0.834399 0.421809 +vt 0.829546 0.413334 +vt 0.832702 0.402035 +vt 0.840909 0.406773 +vt 0.835997 0.409610 +vt 0.849195 0.401898 +vt 0.840909 0.401101 +vt 0.840830 0.416387 +vt 0.845822 0.409610 +vt 0.831163 0.393652 +vt 0.840909 0.393652 +vt 0.857955 0.403493 +vt 0.850675 0.393617 +vt 0.863636 0.393651 +vt 0.852273 0.413334 +vt 0.846591 0.423175 +vt 0.787248 0.385268 +vt 0.795455 0.380530 +vt 0.795455 0.386202 +vt 0.795455 0.371053 +vt 0.790542 0.377694 +vt 0.803662 0.385268 +vt 0.800367 0.377694 +vt 0.801946 0.365529 +vt 0.806818 0.373969 +vt 0.811692 0.382409 +vt 0.809975 0.362670 +vt 0.818182 0.367408 +vt 0.813270 0.370244 +vt 0.826389 0.362670 +vt 0.818182 0.361736 +vt 0.818182 0.376885 +vt 0.823095 0.370244 +vt 0.808436 0.354286 +vt 0.818182 0.354286 +vt 0.834419 0.365529 +vt 0.827928 0.354286 +vt 0.840909 0.354286 +vt 0.829546 0.373969 +vt 0.824673 0.382409 +vt 0.832702 0.385268 +vt 0.840909 0.380530 +vt 0.840909 0.386202 +vt 0.840909 0.371053 +vt 0.835997 0.377694 +vt 0.849116 0.385268 +vt 0.845822 0.377694 +vt 0.847400 0.365529 +vt 0.852273 0.373969 +vt 0.857126 0.382443 +vt 0.855430 0.362670 +vt 0.863636 0.367408 +vt 0.858724 0.370244 +vt 0.871923 0.362533 +vt 0.863637 0.361736 +vt 0.863558 0.377022 +vt 0.868549 0.370244 +vt 0.853891 0.354286 +vt 0.863637 0.354286 +vt 0.880682 0.364128 +vt 0.873402 0.354252 +vt 0.886364 0.354286 +vt 0.875000 0.373969 +vt 0.869318 0.383810 +vt 0.764521 0.345903 +vt 0.772728 0.341165 +vt 0.772727 0.346837 +vt 0.772728 0.331688 +vt 0.767815 0.338328 +vt 0.780935 0.345903 +vt 0.777640 0.338328 +vt 0.779218 0.326163 +vt 0.784091 0.334604 +vt 0.788964 0.343044 +vt 0.787248 0.323304 +vt 0.795455 0.328043 +vt 0.790542 0.330879 +vt 0.803662 0.323304 +vt 0.795455 0.322370 +vt 0.795455 0.337520 +vt 0.800367 0.330879 +vt 0.785709 0.314921 +vt 0.795455 0.314921 +vt 0.811691 0.326163 +vt 0.805201 0.314921 +vt 0.818182 0.314921 +vt 0.806818 0.334604 +vt 0.801946 0.343044 +vt 0.809975 0.345903 +vt 0.818182 0.341165 +vt 0.818182 0.346837 +vt 0.818182 0.331688 +vt 0.813270 0.338328 +vt 0.826389 0.345903 +vt 0.823094 0.338328 +vt 0.824673 0.326163 +vt 0.829546 0.334604 +vt 0.834419 0.343044 +vt 0.832702 0.323304 +vt 0.840909 0.328043 +vt 0.835997 0.330879 +vt 0.849116 0.323304 +vt 0.840909 0.322370 +vt 0.840909 0.337520 +vt 0.845822 0.330879 +vt 0.831163 0.314921 +vt 0.840909 0.314921 +vt 0.857146 0.326163 +vt 0.850655 0.314921 +vt 0.863637 0.314921 +vt 0.852273 0.334604 +vt 0.847400 0.343044 +vt 0.855430 0.345903 +vt 0.863637 0.341165 +vt 0.863637 0.346837 +vt 0.863637 0.331688 +vt 0.858724 0.338328 +vt 0.871844 0.345903 +vt 0.868549 0.338328 +vt 0.870127 0.326163 +vt 0.875000 0.334604 +vt 0.879853 0.343078 +vt 0.878157 0.323304 +vt 0.886364 0.328043 +vt 0.881451 0.330879 +vt 0.894650 0.323168 +vt 0.886364 0.322370 +vt 0.886285 0.337656 +vt 0.891276 0.330879 +vt 0.876618 0.314921 +vt 0.886364 0.314921 +vt 0.903409 0.324762 +vt 0.896130 0.314887 +vt 0.909091 0.314921 +vt 0.892046 0.344445 +vt 0.897727 0.334604 +vt 0.082624 0.441263 +vt 0.090910 0.446139 +vt 0.085997 0.448975 +vt 0.099196 0.441263 +vt 0.090910 0.440466 +vt 0.090910 0.455889 +vt 0.095822 0.448975 +vt 0.081144 0.432983 +vt 0.073864 0.442858 +vt 0.068182 0.433017 +vt 0.090910 0.433017 +vt 0.079546 0.452699 +vt 0.107955 0.442858 +vt 0.100676 0.432983 +vt 0.113637 0.433017 +vt 0.102274 0.452699 +vt 0.085228 0.462541 +vt 0.096592 0.462541 +vt 0.090910 0.472382 +vt 0.059896 0.401898 +vt 0.068182 0.406773 +vt 0.063270 0.409610 +vt 0.076390 0.402035 +vt 0.068182 0.401101 +vt 0.068261 0.416387 +vt 0.073095 0.409609 +vt 0.058417 0.393617 +vt 0.051137 0.403493 +vt 0.045455 0.393651 +vt 0.068182 0.393652 +vt 0.056819 0.413334 +vt 0.084419 0.404894 +vt 0.077928 0.393652 +vt 0.090910 0.393652 +vt 0.079546 0.413334 +vt 0.062501 0.423175 +vt 0.074693 0.421809 +vt 0.037169 0.362533 +vt 0.045455 0.367408 +vt 0.040543 0.370244 +vt 0.053662 0.362670 +vt 0.045455 0.361736 +vt 0.045534 0.377021 +vt 0.050367 0.370244 +vt 0.035689 0.354252 +vt 0.028409 0.364128 +vt 0.045455 0.354286 +vt 0.034091 0.373969 +vt 0.061692 0.365529 +vt 0.055201 0.354286 +vt 0.068182 0.354286 +vt 0.056819 0.373969 +vt 0.039773 0.383810 +vt 0.051965 0.382443 +vt 0.082703 0.424633 +vt 0.090910 0.419895 +vt 0.090910 0.425567 +vt 0.090910 0.410418 +vt 0.085997 0.417059 +vt 0.099117 0.424633 +vt 0.095822 0.417059 +vt 0.097401 0.404894 +vt 0.107127 0.421809 +vt 0.102274 0.413334 +vt 0.105430 0.402035 +vt 0.113637 0.406773 +vt 0.108725 0.409610 +vt 0.121923 0.401898 +vt 0.113637 0.401101 +vt 0.113558 0.416387 +vt 0.118550 0.409610 +vt 0.103891 0.393652 +vt 0.113637 0.393652 +vt 0.130683 0.403493 +vt 0.123403 0.393617 +vt 0.136365 0.393651 +vt 0.125001 0.413334 +vt 0.119319 0.423175 +vt 0.059975 0.385268 +vt 0.068182 0.380530 +vt 0.068182 0.386202 +vt 0.068182 0.371053 +vt 0.063270 0.377694 +vt 0.076389 0.385268 +vt 0.073095 0.377694 +vt 0.074673 0.365529 +vt 0.079546 0.373969 +vt 0.084419 0.382409 +vt 0.082703 0.362670 +vt 0.090910 0.367408 +vt 0.085997 0.370244 +vt 0.099117 0.362670 +vt 0.090910 0.361736 +vt 0.090910 0.376885 +vt 0.095822 0.370244 +vt 0.081164 0.354286 +vt 0.090910 0.354286 +vt 0.107146 0.365529 +vt 0.100656 0.354286 +vt 0.113637 0.354286 +vt 0.102273 0.373969 +vt 0.097400 0.382409 +vt 0.105430 0.385268 +vt 0.113637 0.380530 +vt 0.113637 0.386202 +vt 0.113637 0.371053 +vt 0.108725 0.377694 +vt 0.121844 0.385268 +vt 0.118550 0.377694 +vt 0.120128 0.365529 +vt 0.125001 0.373969 +vt 0.129854 0.382443 +vt 0.128157 0.362670 +vt 0.136364 0.367408 +vt 0.131452 0.370244 +vt 0.144650 0.362533 +vt 0.136364 0.361736 +vt 0.136286 0.377022 +vt 0.141277 0.370244 +vt 0.126618 0.354286 +vt 0.136364 0.354286 +vt 0.153410 0.364128 +vt 0.146130 0.354252 +vt 0.159092 0.354286 +vt 0.147728 0.373969 +vt 0.142046 0.383810 +vt 0.037248 0.345903 +vt 0.045455 0.341165 +vt 0.045455 0.346837 +vt 0.045455 0.331688 +vt 0.040542 0.338328 +vt 0.053662 0.345903 +vt 0.050367 0.338328 +vt 0.051946 0.326163 +vt 0.056819 0.334604 +vt 0.061692 0.343044 +vt 0.059975 0.323304 +vt 0.068182 0.328043 +vt 0.063270 0.330879 +vt 0.076389 0.323304 +vt 0.068182 0.322370 +vt 0.068182 0.337520 +vt 0.073095 0.330879 +vt 0.058436 0.314921 +vt 0.068182 0.314921 +vt 0.084419 0.326163 +vt 0.077928 0.314921 +vt 0.090910 0.314921 +vt 0.079546 0.334604 +vt 0.074673 0.343044 +vt 0.082703 0.345903 +vt 0.090910 0.341165 +vt 0.090910 0.346837 +vt 0.090910 0.331688 +vt 0.085997 0.338328 +vt 0.099117 0.345903 +vt 0.095822 0.338328 +vt 0.097400 0.326163 +vt 0.107146 0.343044 +vt 0.102273 0.334604 +vt 0.105430 0.323304 +vt 0.113637 0.328043 +vt 0.108725 0.330879 +vt 0.121844 0.323304 +vt 0.113637 0.322370 +vt 0.113637 0.337520 +vt 0.118549 0.330879 +vt 0.103891 0.314921 +vt 0.113637 0.314921 +vt 0.129874 0.326163 +vt 0.123383 0.314921 +vt 0.136364 0.314921 +vt 0.120128 0.343044 +vt 0.125001 0.334604 +vt 0.128157 0.345903 +vt 0.136364 0.341165 +vt 0.136364 0.346837 +vt 0.136364 0.331688 +vt 0.131452 0.338328 +vt 0.144571 0.345903 +vt 0.141277 0.338328 +vt 0.142855 0.326163 +vt 0.147728 0.334604 +vt 0.152581 0.343078 +vt 0.150885 0.323304 +vt 0.159092 0.328043 +vt 0.154179 0.330879 +vt 0.167378 0.323168 +vt 0.159092 0.322370 +vt 0.159013 0.337656 +vt 0.164004 0.330879 +vt 0.149346 0.314921 +vt 0.159092 0.314921 +vt 0.176137 0.324762 +vt 0.168857 0.314887 +vt 0.164774 0.344445 +vt 0.170455 0.334604 +vt 0.264442 0.441263 +vt 0.272728 0.446139 +vt 0.267816 0.448975 +vt 0.281014 0.441263 +vt 0.272728 0.440466 +vt 0.272728 0.455889 +vt 0.277640 0.448975 +vt 0.262962 0.432983 +vt 0.255683 0.442858 +vt 0.250001 0.433017 +vt 0.272728 0.433017 +vt 0.261364 0.452699 +vt 0.289773 0.442858 +vt 0.282494 0.432983 +vt 0.295455 0.433017 +vt 0.284092 0.452699 +vt 0.267046 0.462541 +vt 0.278410 0.462541 +vt 0.272728 0.472382 +vt 0.241715 0.401898 +vt 0.250001 0.406773 +vt 0.245088 0.409610 +vt 0.258208 0.402035 +vt 0.250001 0.401101 +vt 0.250080 0.416387 +vt 0.254913 0.409609 +vt 0.240235 0.393617 +vt 0.232955 0.403493 +vt 0.227273 0.393651 +vt 0.250001 0.393652 +vt 0.238637 0.413334 +vt 0.266237 0.404894 +vt 0.259747 0.393652 +vt 0.272728 0.393652 +vt 0.261364 0.413334 +vt 0.244319 0.423175 +vt 0.256511 0.421809 +vt 0.218988 0.362533 +vt 0.227274 0.367408 +vt 0.222361 0.370244 +vt 0.235481 0.362670 +vt 0.227274 0.361736 +vt 0.227352 0.377021 +vt 0.232186 0.370244 +vt 0.217508 0.354252 +vt 0.210228 0.364128 +vt 0.227274 0.354286 +vt 0.215910 0.373969 +vt 0.243510 0.365529 +vt 0.237019 0.354286 +vt 0.250001 0.354286 +vt 0.238637 0.373969 +vt 0.221592 0.383810 +vt 0.233784 0.382443 +vt 0.264521 0.424633 +vt 0.272728 0.419895 +vt 0.272728 0.425567 +vt 0.272728 0.410418 +vt 0.267816 0.417059 +vt 0.280935 0.424633 +vt 0.277640 0.417059 +vt 0.279219 0.404894 +vt 0.288945 0.421809 +vt 0.284092 0.413334 +vt 0.287248 0.402035 +vt 0.295455 0.406773 +vt 0.290543 0.409610 +vt 0.303741 0.401898 +vt 0.295455 0.401101 +vt 0.295376 0.416387 +vt 0.300368 0.409610 +vt 0.285709 0.393652 +vt 0.295455 0.393652 +vt 0.312501 0.403493 +vt 0.305221 0.393617 +vt 0.318182 0.393651 +vt 0.306819 0.413334 +vt 0.301137 0.423175 +vt 0.241794 0.385268 +vt 0.250001 0.380530 +vt 0.250001 0.386202 +vt 0.250001 0.371053 +vt 0.245088 0.377694 +vt 0.258208 0.385268 +vt 0.254913 0.377694 +vt 0.256491 0.365529 +vt 0.261364 0.373969 +vt 0.266237 0.382409 +vt 0.264521 0.362670 +vt 0.272728 0.367408 +vt 0.267816 0.370244 +vt 0.280935 0.362670 +vt 0.272728 0.361736 +vt 0.272728 0.376885 +vt 0.277640 0.370244 +vt 0.262982 0.354286 +vt 0.272728 0.354286 +vt 0.288965 0.365529 +vt 0.282474 0.354286 +vt 0.295455 0.354286 +vt 0.284092 0.373969 +vt 0.279219 0.382409 +vt 0.287248 0.385268 +vt 0.295455 0.380530 +vt 0.295455 0.386202 +vt 0.295455 0.371053 +vt 0.290543 0.377694 +vt 0.303662 0.385268 +vt 0.300368 0.377694 +vt 0.301946 0.365529 +vt 0.306819 0.373969 +vt 0.311672 0.382443 +vt 0.309975 0.362670 +vt 0.318182 0.367408 +vt 0.313270 0.370244 +vt 0.326468 0.362533 +vt 0.318182 0.361736 +vt 0.318104 0.377022 +vt 0.323095 0.370244 +vt 0.308437 0.354286 +vt 0.318182 0.354286 +vt 0.335228 0.364128 +vt 0.327948 0.354252 +vt 0.340910 0.354286 +vt 0.329546 0.373969 +vt 0.323864 0.383810 +vt 0.219066 0.345903 +vt 0.227274 0.341165 +vt 0.227273 0.346837 +vt 0.227274 0.331688 +vt 0.222361 0.338328 +vt 0.235481 0.345903 +vt 0.232186 0.338328 +vt 0.233764 0.326163 +vt 0.238637 0.334604 +vt 0.243510 0.343044 +vt 0.241794 0.323304 +vt 0.250001 0.328043 +vt 0.245088 0.330879 +vt 0.258208 0.323304 +vt 0.250001 0.322370 +vt 0.250001 0.337520 +vt 0.254913 0.330879 +vt 0.240255 0.314921 +vt 0.250001 0.314921 +vt 0.266237 0.326163 +vt 0.259747 0.314921 +vt 0.272728 0.314921 +vt 0.261364 0.334604 +vt 0.256491 0.343044 +vt 0.264521 0.345903 +vt 0.272728 0.341165 +vt 0.272728 0.346837 +vt 0.272728 0.331688 +vt 0.267816 0.338328 +vt 0.280935 0.345903 +vt 0.277640 0.338328 +vt 0.279219 0.326163 +vt 0.284092 0.334604 +vt 0.288965 0.343044 +vt 0.287248 0.323304 +vt 0.295455 0.328043 +vt 0.290543 0.330879 +vt 0.303662 0.323304 +vt 0.295455 0.322370 +vt 0.295455 0.337520 +vt 0.300368 0.330879 +vt 0.285709 0.314921 +vt 0.295455 0.314921 +vt 0.311692 0.326163 +vt 0.305201 0.314921 +vt 0.318183 0.314921 +vt 0.301946 0.343044 +vt 0.306819 0.334604 +vt 0.309975 0.345903 +vt 0.318182 0.341165 +vt 0.318182 0.346837 +vt 0.318183 0.331688 +vt 0.313270 0.338328 +vt 0.326390 0.345903 +vt 0.323095 0.338328 +vt 0.324673 0.326163 +vt 0.329546 0.334604 +vt 0.334399 0.343078 +vt 0.332703 0.323304 +vt 0.340910 0.328043 +vt 0.335997 0.330879 +vt 0.349196 0.323168 +vt 0.340910 0.322370 +vt 0.345822 0.330879 +vt 0.340831 0.337656 +vt 0.331164 0.314921 +vt 0.340910 0.314921 +vt 0.357955 0.324762 +vt 0.350675 0.314887 +vt 0.346592 0.344445 +vt 0.352273 0.334604 +vt 0.386364 0.292323 +vt 0.386364 0.301799 +vt 0.381452 0.298963 +vt 0.394571 0.306538 +vt 0.391277 0.298963 +vt 0.378157 0.306538 +vt 0.386364 0.307472 +vt 0.392855 0.286798 +vt 0.379874 0.286798 +vt 0.386364 0.275556 +vt 0.397728 0.295239 +vt 0.375001 0.295239 +vt 0.402601 0.303679 +vt 0.370128 0.303679 +vt 0.409092 0.252958 +vt 0.409091 0.262434 +vt 0.404179 0.259598 +vt 0.417299 0.267173 +vt 0.414004 0.259598 +vt 0.400884 0.267173 +vt 0.409092 0.268107 +vt 0.415582 0.247433 +vt 0.402601 0.247433 +vt 0.409092 0.236191 +vt 0.420455 0.255874 +vt 0.397728 0.255874 +vt 0.418837 0.275556 +vt 0.425328 0.264314 +vt 0.431819 0.275556 +vt 0.409092 0.275556 +vt 0.392855 0.264314 +vt 0.399346 0.275556 +vt 0.431819 0.213593 +vt 0.431819 0.223069 +vt 0.426906 0.220233 +vt 0.440026 0.227808 +vt 0.436731 0.220233 +vt 0.423612 0.227808 +vt 0.431819 0.228742 +vt 0.438309 0.208068 +vt 0.425328 0.208068 +vt 0.420455 0.216509 +vt 0.441565 0.236191 +vt 0.448055 0.224949 +vt 0.454546 0.236191 +vt 0.431819 0.236191 +vt 0.443182 0.216509 +vt 0.415582 0.224949 +vt 0.422073 0.236191 +vt 0.400884 0.283939 +vt 0.409091 0.288678 +vt 0.404179 0.291514 +vt 0.417299 0.283939 +vt 0.409092 0.283005 +vt 0.409092 0.298154 +vt 0.414004 0.291514 +vt 0.425328 0.286798 +vt 0.420455 0.295239 +vt 0.415582 0.303679 +vt 0.431819 0.292323 +vt 0.431819 0.301799 +vt 0.426906 0.298963 +vt 0.440026 0.306538 +vt 0.436731 0.298963 +vt 0.423612 0.306538 +vt 0.431819 0.307472 +vt 0.438309 0.286798 +vt 0.443182 0.295239 +vt 0.448055 0.303679 +vt 0.423612 0.244574 +vt 0.431819 0.249313 +vt 0.426906 0.252149 +vt 0.440026 0.244574 +vt 0.431819 0.243640 +vt 0.431819 0.258789 +vt 0.436731 0.252149 +vt 0.448055 0.247433 +vt 0.443182 0.255874 +vt 0.438309 0.264314 +vt 0.454546 0.252958 +vt 0.454546 0.262434 +vt 0.449634 0.259598 +vt 0.462753 0.267173 +vt 0.459458 0.259598 +vt 0.446339 0.267173 +vt 0.454546 0.268107 +vt 0.461037 0.247433 +vt 0.465910 0.255874 +vt 0.464292 0.275556 +vt 0.470783 0.264314 +vt 0.477273 0.275556 +vt 0.454546 0.275556 +vt 0.444800 0.275556 +vt 0.446339 0.283939 +vt 0.454546 0.288678 +vt 0.449634 0.291514 +vt 0.462753 0.283939 +vt 0.454546 0.283005 +vt 0.454546 0.298154 +vt 0.459458 0.291514 +vt 0.470783 0.286798 +vt 0.465910 0.295239 +vt 0.461037 0.303679 +vt 0.477273 0.292323 +vt 0.477273 0.301799 +vt 0.472361 0.298963 +vt 0.485480 0.306538 +vt 0.482186 0.298963 +vt 0.469066 0.306538 +vt 0.477273 0.307472 +vt 0.483764 0.286798 +vt 0.488637 0.295239 +vt 0.493510 0.303679 +vt 0.446339 0.205209 +vt 0.454546 0.209948 +vt 0.449634 0.212784 +vt 0.462753 0.205209 +vt 0.454546 0.204275 +vt 0.454546 0.219424 +vt 0.459458 0.212784 +vt 0.470783 0.208068 +vt 0.465910 0.216509 +vt 0.461037 0.224949 +vt 0.477273 0.213593 +vt 0.477273 0.223069 +vt 0.472361 0.220233 +vt 0.485480 0.227808 +vt 0.482186 0.220233 +vt 0.469066 0.227808 +vt 0.477273 0.228742 +vt 0.483764 0.208068 +vt 0.487019 0.236191 +vt 0.493510 0.224949 +vt 0.500001 0.236191 +vt 0.477273 0.236191 +vt 0.488637 0.216509 +vt 0.467527 0.236191 +vt 0.469066 0.244574 +vt 0.477273 0.249313 +vt 0.472361 0.252149 +vt 0.485480 0.244574 +vt 0.477273 0.243640 +vt 0.477273 0.258789 +vt 0.482186 0.252149 +vt 0.493510 0.247433 +vt 0.488637 0.255874 +vt 0.483764 0.264314 +vt 0.500001 0.252958 +vt 0.500000 0.262434 +vt 0.495088 0.259598 +vt 0.508208 0.267173 +vt 0.504913 0.259598 +vt 0.491793 0.267173 +vt 0.500000 0.268107 +vt 0.506491 0.247433 +vt 0.511364 0.255874 +vt 0.509746 0.275556 +vt 0.516237 0.264314 +vt 0.522728 0.275556 +vt 0.490255 0.275556 +vt 0.500001 0.275556 +vt 0.491794 0.283939 +vt 0.500001 0.288678 +vt 0.495088 0.291514 +vt 0.508208 0.283939 +vt 0.500001 0.283005 +vt 0.500001 0.298154 +vt 0.504913 0.291514 +vt 0.516237 0.286798 +vt 0.511364 0.295239 +vt 0.506491 0.303679 +vt 0.522728 0.292323 +vt 0.522728 0.301799 +vt 0.517815 0.298963 +vt 0.530935 0.306538 +vt 0.527640 0.298963 +vt 0.514521 0.306538 +vt 0.522728 0.307472 +vt 0.529218 0.286798 +vt 0.534091 0.295239 +vt 0.538964 0.303679 +vt 0.568182 0.292323 +vt 0.568182 0.301799 +vt 0.563270 0.298963 +vt 0.576389 0.306538 +vt 0.573095 0.298963 +vt 0.559975 0.306538 +vt 0.568182 0.307472 +vt 0.574673 0.286798 +vt 0.561692 0.286798 +vt 0.568182 0.275556 +vt 0.579546 0.295239 +vt 0.556819 0.295239 +vt 0.584419 0.303679 +vt 0.551946 0.303679 +vt 0.590910 0.252958 +vt 0.590909 0.262434 +vt 0.585997 0.259598 +vt 0.599117 0.267173 +vt 0.595822 0.259598 +vt 0.582703 0.267173 +vt 0.590910 0.268107 +vt 0.597400 0.247433 +vt 0.584419 0.247433 +vt 0.590910 0.236191 +vt 0.602273 0.255874 +vt 0.579546 0.255874 +vt 0.600655 0.275556 +vt 0.607146 0.264314 +vt 0.613637 0.275556 +vt 0.590910 0.275556 +vt 0.574673 0.264314 +vt 0.581164 0.275556 +vt 0.613637 0.213593 +vt 0.613637 0.223069 +vt 0.608724 0.220233 +vt 0.621844 0.227808 +vt 0.618549 0.220233 +vt 0.605430 0.227808 +vt 0.613637 0.228742 +vt 0.620127 0.208068 +vt 0.607146 0.208068 +vt 0.602273 0.216509 +vt 0.623383 0.236191 +vt 0.629873 0.224949 +vt 0.636364 0.236191 +vt 0.613637 0.236191 +vt 0.625000 0.216509 +vt 0.597400 0.224949 +vt 0.603891 0.236191 +vt 0.582703 0.283939 +vt 0.590909 0.288678 +vt 0.585997 0.291514 +vt 0.599117 0.283939 +vt 0.590910 0.283005 +vt 0.590910 0.298154 +vt 0.595822 0.291514 +vt 0.607146 0.286798 +vt 0.597400 0.303679 +vt 0.602273 0.295239 +vt 0.613637 0.292323 +vt 0.613637 0.301799 +vt 0.608724 0.298963 +vt 0.621844 0.306538 +vt 0.618549 0.298963 +vt 0.605430 0.306538 +vt 0.613637 0.307472 +vt 0.620127 0.286798 +vt 0.625000 0.295239 +vt 0.629873 0.303679 +vt 0.605430 0.244574 +vt 0.613637 0.249313 +vt 0.608724 0.252149 +vt 0.621844 0.244574 +vt 0.613637 0.243640 +vt 0.613637 0.258789 +vt 0.618549 0.252149 +vt 0.629873 0.247433 +vt 0.625000 0.255874 +vt 0.620127 0.264314 +vt 0.636364 0.252958 +vt 0.636364 0.262434 +vt 0.631452 0.259598 +vt 0.644571 0.267173 +vt 0.641276 0.259598 +vt 0.628157 0.267173 +vt 0.636364 0.268107 +vt 0.642855 0.247433 +vt 0.647728 0.255874 +vt 0.646110 0.275556 +vt 0.652601 0.264314 +vt 0.659091 0.275556 +vt 0.636364 0.275556 +vt 0.626618 0.275556 +vt 0.628157 0.283939 +vt 0.636364 0.288678 +vt 0.631452 0.291514 +vt 0.644571 0.283939 +vt 0.636364 0.283005 +vt 0.636364 0.298154 +vt 0.641276 0.291514 +vt 0.652601 0.286798 +vt 0.647728 0.295239 +vt 0.642855 0.303679 +vt 0.659091 0.292323 +vt 0.659091 0.301799 +vt 0.654179 0.298963 +vt 0.667298 0.306538 +vt 0.664004 0.298963 +vt 0.650884 0.306538 +vt 0.659091 0.307472 +vt 0.665582 0.286798 +vt 0.670455 0.295239 +vt 0.675328 0.303679 +vt 0.628157 0.205209 +vt 0.636364 0.209948 +vt 0.631452 0.212784 +vt 0.644571 0.205209 +vt 0.636364 0.204275 +vt 0.636364 0.219424 +vt 0.641276 0.212784 +vt 0.652601 0.208068 +vt 0.647728 0.216509 +vt 0.642855 0.224949 +vt 0.659091 0.213593 +vt 0.659091 0.223069 +vt 0.654179 0.220233 +vt 0.667298 0.227808 +vt 0.664004 0.220233 +vt 0.650884 0.227808 +vt 0.659091 0.228742 +vt 0.665582 0.208068 +vt 0.670455 0.216509 +vt 0.668837 0.236191 +vt 0.675328 0.224949 +vt 0.681819 0.236191 +vt 0.659091 0.236191 +vt 0.649345 0.236191 +vt 0.650884 0.244574 +vt 0.659091 0.249313 +vt 0.654179 0.252149 +vt 0.667298 0.244574 +vt 0.659091 0.243640 +vt 0.659091 0.258789 +vt 0.664004 0.252149 +vt 0.675328 0.247433 +vt 0.670455 0.255874 +vt 0.665582 0.264314 +vt 0.681819 0.252958 +vt 0.681818 0.262434 +vt 0.676906 0.259598 +vt 0.690026 0.267173 +vt 0.686731 0.259598 +vt 0.673611 0.267173 +vt 0.681819 0.268107 +vt 0.688309 0.247433 +vt 0.693182 0.255874 +vt 0.691564 0.275556 +vt 0.698055 0.264314 +vt 0.704546 0.275556 +vt 0.681819 0.275556 +vt 0.672073 0.275556 +vt 0.673612 0.283939 +vt 0.681818 0.288678 +vt 0.676906 0.291514 +vt 0.690026 0.283939 +vt 0.681819 0.283005 +vt 0.681819 0.298154 +vt 0.686731 0.291514 +vt 0.698055 0.286798 +vt 0.693182 0.295239 +vt 0.688309 0.303679 +vt 0.704546 0.292323 +vt 0.704546 0.301799 +vt 0.699633 0.298963 +vt 0.712753 0.306538 +vt 0.709458 0.298963 +vt 0.696339 0.306538 +vt 0.704546 0.307472 +vt 0.711037 0.286798 +vt 0.715909 0.295239 +vt 0.720782 0.303679 +vt 0.750000 0.292323 +vt 0.750000 0.301799 +vt 0.745088 0.298963 +vt 0.758207 0.306538 +vt 0.754913 0.298963 +vt 0.741793 0.306538 +vt 0.750000 0.307472 +vt 0.756491 0.286798 +vt 0.743510 0.286798 +vt 0.750000 0.275556 +vt 0.761364 0.295239 +vt 0.738637 0.295239 +vt 0.766237 0.303679 +vt 0.733764 0.303679 +vt 0.772728 0.252958 +vt 0.772728 0.262434 +vt 0.767815 0.259598 +vt 0.780935 0.267173 +vt 0.777640 0.259598 +vt 0.764521 0.267173 +vt 0.772727 0.268107 +vt 0.779218 0.247433 +vt 0.766237 0.247433 +vt 0.772728 0.236191 +vt 0.784091 0.255874 +vt 0.761364 0.255874 +vt 0.782474 0.275556 +vt 0.788964 0.264314 +vt 0.795455 0.275556 +vt 0.772728 0.275556 +vt 0.756491 0.264314 +vt 0.762982 0.275556 +vt 0.795455 0.213593 +vt 0.795455 0.223069 +vt 0.790542 0.220233 +vt 0.803662 0.227808 +vt 0.800367 0.220233 +vt 0.787248 0.227808 +vt 0.795455 0.228742 +vt 0.801946 0.208068 +vt 0.788964 0.208068 +vt 0.806818 0.216509 +vt 0.784091 0.216509 +vt 0.805201 0.236191 +vt 0.811692 0.224949 +vt 0.818182 0.236191 +vt 0.795455 0.236191 +vt 0.779218 0.224949 +vt 0.785709 0.236191 +vt 0.764521 0.283939 +vt 0.772728 0.288678 +vt 0.767815 0.291514 +vt 0.780935 0.283939 +vt 0.772728 0.283005 +vt 0.772728 0.298154 +vt 0.777640 0.291514 +vt 0.788964 0.286798 +vt 0.784091 0.295239 +vt 0.779218 0.303679 +vt 0.795455 0.292323 +vt 0.795455 0.301799 +vt 0.790542 0.298963 +vt 0.803662 0.306538 +vt 0.800367 0.298963 +vt 0.787248 0.306538 +vt 0.795455 0.307472 +vt 0.801946 0.286798 +vt 0.806818 0.295239 +vt 0.811692 0.303679 +vt 0.787248 0.244574 +vt 0.795455 0.249313 +vt 0.790542 0.252149 +vt 0.803662 0.244574 +vt 0.795455 0.243640 +vt 0.795455 0.258789 +vt 0.800367 0.252149 +vt 0.811692 0.247433 +vt 0.806818 0.255874 +vt 0.801946 0.264314 +vt 0.818182 0.252958 +vt 0.818182 0.262434 +vt 0.813270 0.259598 +vt 0.826389 0.267173 +vt 0.823094 0.259598 +vt 0.809975 0.267173 +vt 0.818182 0.268107 +vt 0.824673 0.247433 +vt 0.829546 0.255874 +vt 0.827928 0.275556 +vt 0.834419 0.264314 +vt 0.840909 0.275556 +vt 0.818182 0.275556 +vt 0.808436 0.275556 +vt 0.809975 0.283939 +vt 0.818182 0.288678 +vt 0.813270 0.291514 +vt 0.826389 0.283939 +vt 0.818182 0.283005 +vt 0.818182 0.298154 +vt 0.823095 0.291514 +vt 0.834419 0.286798 +vt 0.829546 0.295239 +vt 0.824673 0.303679 +vt 0.840909 0.292323 +vt 0.840909 0.301799 +vt 0.835997 0.298963 +vt 0.849116 0.306538 +vt 0.845822 0.298963 +vt 0.832702 0.306538 +vt 0.840909 0.307472 +vt 0.847400 0.286798 +vt 0.852273 0.295239 +vt 0.857146 0.303679 +vt 0.809975 0.205209 +vt 0.818182 0.209948 +vt 0.813270 0.212784 +vt 0.826389 0.205209 +vt 0.818182 0.204275 +vt 0.818182 0.219424 +vt 0.823094 0.212784 +vt 0.834419 0.208068 +vt 0.829546 0.216509 +vt 0.824673 0.224949 +vt 0.840909 0.213593 +vt 0.840909 0.223069 +vt 0.835997 0.220233 +vt 0.849116 0.227808 +vt 0.845822 0.220233 +vt 0.832702 0.227808 +vt 0.840909 0.228742 +vt 0.847400 0.208068 +vt 0.850655 0.236191 +vt 0.857146 0.224949 +vt 0.863637 0.236191 +vt 0.840909 0.236191 +vt 0.852273 0.216509 +vt 0.831163 0.236191 +vt 0.832702 0.244574 +vt 0.840909 0.249313 +vt 0.835997 0.252149 +vt 0.849116 0.244574 +vt 0.840909 0.243640 +vt 0.840909 0.258789 +vt 0.845822 0.252149 +vt 0.857146 0.247433 +vt 0.852273 0.255874 +vt 0.847400 0.264314 +vt 0.863637 0.252958 +vt 0.863636 0.262434 +vt 0.858724 0.259598 +vt 0.871844 0.267173 +vt 0.868549 0.259598 +vt 0.855430 0.267173 +vt 0.863637 0.268107 +vt 0.870127 0.247433 +vt 0.875000 0.255874 +vt 0.873383 0.275556 +vt 0.879873 0.264314 +vt 0.886364 0.275556 +vt 0.853891 0.275556 +vt 0.863637 0.275556 +vt 0.855430 0.283939 +vt 0.863636 0.288678 +vt 0.858724 0.291514 +vt 0.871844 0.283939 +vt 0.863637 0.283005 +vt 0.863637 0.298154 +vt 0.868549 0.291514 +vt 0.879873 0.286798 +vt 0.875000 0.295239 +vt 0.870127 0.303679 +vt 0.886364 0.292323 +vt 0.886364 0.301799 +vt 0.881451 0.298963 +vt 0.894571 0.306538 +vt 0.891276 0.298963 +vt 0.878157 0.306538 +vt 0.886364 0.307472 +vt 0.892855 0.286798 +vt 0.897727 0.295239 +vt 0.902581 0.303713 +vt 0.022806 0.292186 +vt 0.022727 0.301799 +vt 0.017815 0.298963 +vt 0.030935 0.306538 +vt 0.027640 0.298963 +vt 0.014441 0.306674 +vt 0.022727 0.307472 +vt 0.029238 0.286764 +vt 0.017046 0.285397 +vt 0.022727 0.275556 +vt 0.034091 0.295239 +vt 0.011364 0.295239 +vt 0.038964 0.303679 +vt 0.005682 0.305080 +vt 0.045534 0.252821 +vt 0.045455 0.262434 +vt 0.040542 0.259598 +vt 0.053662 0.267173 +vt 0.050367 0.259598 +vt 0.037169 0.267309 +vt 0.045455 0.268107 +vt 0.051965 0.247399 +vt 0.039773 0.246032 +vt 0.045455 0.236191 +vt 0.034091 0.255874 +vt 0.055201 0.275556 +vt 0.061692 0.264314 +vt 0.068182 0.275556 +vt 0.045455 0.275556 +vt 0.056819 0.255874 +vt 0.028409 0.265715 +vt 0.035689 0.275590 +vt 0.068261 0.213456 +vt 0.068182 0.223069 +vt 0.063270 0.220233 +vt 0.076390 0.227808 +vt 0.073095 0.220233 +vt 0.059896 0.227944 +vt 0.068182 0.228742 +vt 0.074693 0.208034 +vt 0.062501 0.206667 +vt 0.056819 0.216509 +vt 0.077928 0.236191 +vt 0.084419 0.224949 +vt 0.090910 0.236191 +vt 0.068182 0.236191 +vt 0.079546 0.216509 +vt 0.051137 0.226350 +vt 0.058417 0.236225 +vt 0.037248 0.283939 +vt 0.045455 0.288678 +vt 0.040542 0.291514 +vt 0.053662 0.283939 +vt 0.045455 0.283005 +vt 0.045455 0.298154 +vt 0.050367 0.291514 +vt 0.061692 0.286798 +vt 0.056819 0.295239 +vt 0.051946 0.303679 +vt 0.068182 0.292323 +vt 0.068182 0.301799 +vt 0.063270 0.298963 +vt 0.076389 0.306538 +vt 0.073095 0.298963 +vt 0.059975 0.306538 +vt 0.068182 0.307472 +vt 0.074673 0.286798 +vt 0.084419 0.303679 +vt 0.079546 0.295239 +vt 0.059975 0.244574 +vt 0.068182 0.249313 +vt 0.063270 0.252149 +vt 0.076389 0.244574 +vt 0.068182 0.243640 +vt 0.068182 0.258789 +vt 0.073095 0.252149 +vt 0.084419 0.247433 +vt 0.079546 0.255874 +vt 0.074673 0.264314 +vt 0.090910 0.252958 +vt 0.090910 0.262434 +vt 0.085997 0.259598 +vt 0.099117 0.267173 +vt 0.095822 0.259598 +vt 0.082703 0.267173 +vt 0.090910 0.268107 +vt 0.097400 0.247433 +vt 0.102273 0.255874 +vt 0.100656 0.275556 +vt 0.107146 0.264314 +vt 0.113637 0.275556 +vt 0.090910 0.275556 +vt 0.081164 0.275556 +vt 0.082703 0.283939 +vt 0.090910 0.288678 +vt 0.085997 0.291514 +vt 0.099117 0.283939 +vt 0.090910 0.283005 +vt 0.090910 0.298154 +vt 0.095822 0.291514 +vt 0.107146 0.286798 +vt 0.102273 0.295239 +vt 0.097400 0.303679 +vt 0.113637 0.292323 +vt 0.113637 0.301799 +vt 0.108725 0.298963 +vt 0.121844 0.306538 +vt 0.118549 0.298963 +vt 0.105430 0.306538 +vt 0.113637 0.307472 +vt 0.120128 0.286798 +vt 0.125001 0.295239 +vt 0.129874 0.303679 +vt 0.082703 0.205209 +vt 0.090910 0.209948 +vt 0.085997 0.212784 +vt 0.099117 0.205209 +vt 0.090910 0.204275 +vt 0.090910 0.219424 +vt 0.095822 0.212784 +vt 0.107147 0.208068 +vt 0.102274 0.216509 +vt 0.097401 0.224949 +vt 0.113637 0.213593 +vt 0.113637 0.223069 +vt 0.108725 0.220233 +vt 0.121844 0.227808 +vt 0.118550 0.220233 +vt 0.105430 0.227808 +vt 0.113637 0.228742 +vt 0.120128 0.208068 +vt 0.125001 0.216509 +vt 0.123383 0.236191 +vt 0.129874 0.224949 +vt 0.136364 0.236191 +vt 0.113637 0.236191 +vt 0.103891 0.236191 +vt 0.105430 0.244574 +vt 0.113637 0.249313 +vt 0.108725 0.252149 +vt 0.121844 0.244574 +vt 0.113637 0.243640 +vt 0.113637 0.258789 +vt 0.118550 0.252149 +vt 0.129874 0.247433 +vt 0.125001 0.255874 +vt 0.120128 0.264314 +vt 0.136364 0.252958 +vt 0.136364 0.262434 +vt 0.131452 0.259598 +vt 0.144572 0.267173 +vt 0.141277 0.259598 +vt 0.128157 0.267173 +vt 0.136364 0.268107 +vt 0.142855 0.247433 +vt 0.147728 0.255874 +vt 0.146110 0.275556 +vt 0.152601 0.264314 +vt 0.159092 0.275556 +vt 0.136364 0.275556 +vt 0.126618 0.275556 +vt 0.128157 0.283939 +vt 0.136364 0.288678 +vt 0.131452 0.291514 +vt 0.144571 0.283939 +vt 0.136364 0.283005 +vt 0.136364 0.298154 +vt 0.141277 0.291514 +vt 0.152601 0.286798 +vt 0.147728 0.295239 +vt 0.142855 0.303679 +vt 0.159092 0.292323 +vt 0.159092 0.301799 +vt 0.154179 0.298963 +vt 0.167299 0.306538 +vt 0.164004 0.298963 +vt 0.150885 0.306538 +vt 0.159092 0.307472 +vt 0.165582 0.286798 +vt 0.170455 0.295239 +vt 0.175328 0.303679 +vt 0.204546 0.292323 +vt 0.204546 0.301799 +vt 0.199634 0.298963 +vt 0.212753 0.306538 +vt 0.209459 0.298963 +vt 0.196339 0.306538 +vt 0.204546 0.307472 +vt 0.211037 0.286798 +vt 0.198056 0.286798 +vt 0.204546 0.275556 +vt 0.215910 0.295239 +vt 0.193183 0.295239 +vt 0.220783 0.303679 +vt 0.188310 0.303679 +vt 0.227274 0.252958 +vt 0.227273 0.262434 +vt 0.222361 0.259598 +vt 0.235481 0.267173 +vt 0.232186 0.259598 +vt 0.219066 0.267173 +vt 0.227274 0.268107 +vt 0.233764 0.247433 +vt 0.220783 0.247433 +vt 0.227274 0.236191 +vt 0.238637 0.255874 +vt 0.215910 0.255874 +vt 0.237019 0.275556 +vt 0.243510 0.264314 +vt 0.250001 0.275556 +vt 0.227274 0.275556 +vt 0.211037 0.264314 +vt 0.217528 0.275556 +vt 0.250001 0.213593 +vt 0.250001 0.223069 +vt 0.245088 0.220233 +vt 0.258208 0.227808 +vt 0.254913 0.220233 +vt 0.241794 0.227808 +vt 0.250001 0.228742 +vt 0.256491 0.208068 +vt 0.243510 0.208068 +vt 0.261364 0.216509 +vt 0.238637 0.216509 +vt 0.259747 0.236191 +vt 0.266237 0.224949 +vt 0.272728 0.236191 +vt 0.233764 0.224949 +vt 0.240255 0.236191 +vt 0.250001 0.236191 +vt 0.219066 0.283939 +vt 0.227273 0.288678 +vt 0.222361 0.291514 +vt 0.235481 0.283939 +vt 0.227274 0.283005 +vt 0.227274 0.298154 +vt 0.232186 0.291514 +vt 0.243510 0.286798 +vt 0.233764 0.303679 +vt 0.238637 0.295239 +vt 0.250001 0.292323 +vt 0.250001 0.301799 +vt 0.245088 0.298963 +vt 0.258208 0.306538 +vt 0.254913 0.298963 +vt 0.241794 0.306538 +vt 0.250001 0.307472 +vt 0.256491 0.286798 +vt 0.261364 0.295239 +vt 0.266237 0.303679 +vt 0.241794 0.244574 +vt 0.250001 0.249313 +vt 0.245088 0.252149 +vt 0.258208 0.244574 +vt 0.250001 0.243640 +vt 0.250001 0.258789 +vt 0.254913 0.252149 +vt 0.266237 0.247433 +vt 0.261364 0.255874 +vt 0.256491 0.264314 +vt 0.272728 0.252958 +vt 0.272728 0.262434 +vt 0.267816 0.259598 +vt 0.280935 0.267173 +vt 0.277640 0.259598 +vt 0.264521 0.267173 +vt 0.272728 0.268107 +vt 0.279219 0.247433 +vt 0.284092 0.255874 +vt 0.282474 0.275556 +vt 0.288965 0.264314 +vt 0.295455 0.275556 +vt 0.272728 0.275556 +vt 0.262982 0.275556 +vt 0.264521 0.283939 +vt 0.272728 0.288678 +vt 0.267816 0.291514 +vt 0.280935 0.283939 +vt 0.272728 0.283005 +vt 0.272728 0.298154 +vt 0.277640 0.291514 +vt 0.288965 0.286798 +vt 0.284092 0.295239 +vt 0.279219 0.303679 +vt 0.295455 0.292323 +vt 0.295455 0.301799 +vt 0.290543 0.298963 +vt 0.303662 0.306538 +vt 0.300368 0.298963 +vt 0.287248 0.306538 +vt 0.295455 0.307472 +vt 0.301946 0.286798 +vt 0.306819 0.295239 +vt 0.311692 0.303679 +vt 0.264521 0.205209 +vt 0.272728 0.209948 +vt 0.267816 0.212784 +vt 0.280935 0.205209 +vt 0.272728 0.204275 +vt 0.272728 0.219424 +vt 0.277640 0.212784 +vt 0.288965 0.208068 +vt 0.284092 0.216509 +vt 0.279219 0.224949 +vt 0.295455 0.213593 +vt 0.295455 0.223069 +vt 0.290543 0.220233 +vt 0.303662 0.227808 +vt 0.300368 0.220233 +vt 0.287248 0.227808 +vt 0.295455 0.228742 +vt 0.301946 0.208068 +vt 0.306819 0.216509 +vt 0.305201 0.236191 +vt 0.311692 0.224949 +vt 0.318183 0.236191 +vt 0.295455 0.236191 +vt 0.285709 0.236191 +vt 0.287248 0.244574 +vt 0.295455 0.249313 +vt 0.290543 0.252149 +vt 0.303662 0.244574 +vt 0.295455 0.243640 +vt 0.295455 0.258789 +vt 0.300368 0.252149 +vt 0.311692 0.247433 +vt 0.306819 0.255874 +vt 0.301946 0.264314 +vt 0.318183 0.252958 +vt 0.318182 0.262434 +vt 0.313270 0.259598 +vt 0.326390 0.267173 +vt 0.323095 0.259598 +vt 0.309975 0.267173 +vt 0.318182 0.268107 +vt 0.324673 0.247433 +vt 0.329546 0.255874 +vt 0.327928 0.275556 +vt 0.334419 0.264314 +vt 0.340910 0.275556 +vt 0.318182 0.275556 +vt 0.308437 0.275556 +vt 0.309975 0.283939 +vt 0.318182 0.288678 +vt 0.313270 0.291514 +vt 0.326390 0.283939 +vt 0.318183 0.283005 +vt 0.318183 0.298154 +vt 0.323095 0.291514 +vt 0.334419 0.286798 +vt 0.324673 0.303679 +vt 0.329546 0.295239 +vt 0.340910 0.292323 +vt 0.340910 0.301799 +vt 0.335997 0.298963 +vt 0.349117 0.306538 +vt 0.345822 0.298963 +vt 0.332703 0.306538 +vt 0.340910 0.307472 +vt 0.347400 0.286798 +vt 0.352273 0.295239 +vt 0.357146 0.303679 +vt 0.537248 0.283939 +vt 0.545455 0.288678 +vt 0.540543 0.291514 +vt 0.553662 0.283939 +vt 0.545455 0.283005 +vt 0.545455 0.298154 +vt 0.550367 0.291514 +vt 0.535709 0.275556 +vt 0.545455 0.275556 +vt 0.555201 0.275556 +vt 0.514521 0.244574 +vt 0.522728 0.249313 +vt 0.517815 0.252149 +vt 0.530935 0.244574 +vt 0.522728 0.243640 +vt 0.522728 0.258789 +vt 0.527640 0.252149 +vt 0.512982 0.236191 +vt 0.522728 0.236191 +vt 0.538964 0.247433 +vt 0.532474 0.236191 +vt 0.545455 0.236191 +vt 0.534091 0.255874 +vt 0.529218 0.264314 +vt 0.491793 0.205209 +vt 0.500000 0.209948 +vt 0.495088 0.212784 +vt 0.508208 0.205209 +vt 0.500001 0.204275 +vt 0.500001 0.219424 +vt 0.504913 0.212784 +vt 0.490255 0.196826 +vt 0.516237 0.208068 +vt 0.509746 0.196826 +vt 0.522728 0.196826 +vt 0.511364 0.216509 +vt 0.500001 0.196826 +vt 0.506491 0.224949 +vt 0.537248 0.267173 +vt 0.545455 0.262434 +vt 0.545455 0.268107 +vt 0.545455 0.252958 +vt 0.540543 0.259598 +vt 0.553662 0.267173 +vt 0.550367 0.259598 +vt 0.551946 0.247433 +vt 0.561692 0.264314 +vt 0.556819 0.255874 +vt 0.559975 0.244574 +vt 0.568182 0.249313 +vt 0.563270 0.252149 +vt 0.576389 0.244574 +vt 0.568182 0.243640 +vt 0.568182 0.258789 +vt 0.573095 0.252149 +vt 0.558436 0.236191 +vt 0.568182 0.236191 +vt 0.577928 0.236191 +vt 0.514521 0.227808 +vt 0.522728 0.223069 +vt 0.522728 0.228742 +vt 0.522728 0.213593 +vt 0.517815 0.220233 +vt 0.530935 0.227808 +vt 0.527640 0.220233 +vt 0.529218 0.208068 +vt 0.534091 0.216509 +vt 0.538964 0.224949 +vt 0.537248 0.205209 +vt 0.545455 0.209948 +vt 0.540543 0.212784 +vt 0.553662 0.205209 +vt 0.545455 0.204275 +vt 0.545455 0.219424 +vt 0.550367 0.212784 +vt 0.535709 0.196826 +vt 0.545455 0.196826 +vt 0.561692 0.208068 +vt 0.555201 0.196826 +vt 0.568182 0.196826 +vt 0.556819 0.216509 +vt 0.551946 0.224949 +vt 0.559975 0.227808 +vt 0.568182 0.223069 +vt 0.568182 0.228742 +vt 0.568182 0.213593 +vt 0.563270 0.220233 +vt 0.576389 0.227808 +vt 0.573095 0.220233 +vt 0.574673 0.208068 +vt 0.579546 0.216509 +vt 0.584419 0.224949 +vt 0.582703 0.205209 +vt 0.590909 0.209948 +vt 0.585997 0.212784 +vt 0.599117 0.205209 +vt 0.590910 0.204275 +vt 0.590910 0.219424 +vt 0.595822 0.212784 +vt 0.581164 0.196826 +vt 0.590910 0.196826 +vt 0.600655 0.196826 +vt 0.491793 0.188443 +vt 0.500000 0.183704 +vt 0.500000 0.189377 +vt 0.500001 0.174228 +vt 0.495088 0.180868 +vt 0.508208 0.188443 +vt 0.504913 0.180868 +vt 0.506491 0.168703 +vt 0.511364 0.177143 +vt 0.516237 0.185584 +vt 0.514521 0.165844 +vt 0.522728 0.170583 +vt 0.517815 0.173419 +vt 0.530935 0.165844 +vt 0.522728 0.164910 +vt 0.522728 0.180059 +vt 0.527640 0.173419 +vt 0.512982 0.157461 +vt 0.522728 0.157461 +vt 0.538964 0.168703 +vt 0.532474 0.157461 +vt 0.545455 0.157461 +vt 0.534091 0.177143 +vt 0.529219 0.185584 +vt 0.537248 0.188443 +vt 0.545455 0.183704 +vt 0.545455 0.189377 +vt 0.545455 0.174228 +vt 0.540543 0.180868 +vt 0.553662 0.188443 +vt 0.550367 0.180868 +vt 0.551946 0.168703 +vt 0.556819 0.177143 +vt 0.561692 0.185584 +vt 0.559975 0.165844 +vt 0.568182 0.170583 +vt 0.563270 0.173419 +vt 0.576389 0.165844 +vt 0.568182 0.164910 +vt 0.568182 0.180059 +vt 0.573095 0.173419 +vt 0.558436 0.157461 +vt 0.568182 0.157461 +vt 0.584419 0.168703 +vt 0.577928 0.157461 +vt 0.590910 0.157461 +vt 0.574673 0.185584 +vt 0.579546 0.177143 +vt 0.582703 0.188443 +vt 0.590909 0.183704 +vt 0.590910 0.189377 +vt 0.590910 0.174228 +vt 0.585997 0.180868 +vt 0.599117 0.188443 +vt 0.595822 0.180868 +vt 0.597400 0.168703 +vt 0.602273 0.177144 +vt 0.607146 0.185584 +vt 0.605430 0.165844 +vt 0.613637 0.170583 +vt 0.608724 0.173419 +vt 0.621844 0.165844 +vt 0.613637 0.164910 +vt 0.613637 0.180059 +vt 0.618549 0.173419 +vt 0.603891 0.157461 +vt 0.613637 0.157461 +vt 0.623402 0.157495 +vt 0.719066 0.283939 +vt 0.727273 0.288678 +vt 0.722361 0.291514 +vt 0.735480 0.283939 +vt 0.727273 0.283005 +vt 0.727273 0.298154 +vt 0.732185 0.291514 +vt 0.717527 0.275556 +vt 0.727273 0.275556 +vt 0.737019 0.275556 +vt 0.696339 0.244574 +vt 0.704546 0.249313 +vt 0.699633 0.252149 +vt 0.712753 0.244574 +vt 0.704546 0.243640 +vt 0.704546 0.258789 +vt 0.709458 0.252149 +vt 0.694800 0.236191 +vt 0.704546 0.236191 +vt 0.720782 0.247433 +vt 0.714292 0.236191 +vt 0.727273 0.236191 +vt 0.715909 0.255874 +vt 0.711037 0.264314 +vt 0.673612 0.205209 +vt 0.681818 0.209948 +vt 0.676906 0.212784 +vt 0.690026 0.205209 +vt 0.681819 0.204275 +vt 0.681819 0.219424 +vt 0.686731 0.212784 +vt 0.672073 0.196826 +vt 0.698055 0.208068 +vt 0.691564 0.196826 +vt 0.704546 0.196826 +vt 0.693182 0.216509 +vt 0.681819 0.196826 +vt 0.688309 0.224949 +vt 0.719066 0.267173 +vt 0.727273 0.262434 +vt 0.727273 0.268107 +vt 0.727273 0.252958 +vt 0.722361 0.259598 +vt 0.735480 0.267173 +vt 0.732185 0.259598 +vt 0.733764 0.247433 +vt 0.738637 0.255874 +vt 0.743510 0.264314 +vt 0.741793 0.244574 +vt 0.750000 0.249313 +vt 0.745088 0.252149 +vt 0.758207 0.244574 +vt 0.750000 0.243640 +vt 0.750000 0.258789 +vt 0.754913 0.252149 +vt 0.740254 0.236191 +vt 0.750000 0.236191 +vt 0.759746 0.236191 +vt 0.696339 0.227808 +vt 0.704546 0.223069 +vt 0.704546 0.228742 +vt 0.704546 0.213593 +vt 0.699633 0.220233 +vt 0.712753 0.227808 +vt 0.709458 0.220233 +vt 0.711037 0.208068 +vt 0.715909 0.216509 +vt 0.720782 0.224949 +vt 0.719066 0.205209 +vt 0.727273 0.209948 +vt 0.722361 0.212784 +vt 0.735480 0.205209 +vt 0.727273 0.204275 +vt 0.727273 0.219424 +vt 0.732185 0.212784 +vt 0.717527 0.196826 +vt 0.727273 0.196826 +vt 0.743510 0.208068 +vt 0.737019 0.196826 +vt 0.750000 0.196826 +vt 0.738637 0.216509 +vt 0.733764 0.224949 +vt 0.741793 0.227808 +vt 0.750000 0.223069 +vt 0.750000 0.228742 +vt 0.750000 0.213593 +vt 0.745088 0.220233 +vt 0.758207 0.227808 +vt 0.754913 0.220233 +vt 0.756491 0.208068 +vt 0.761364 0.216509 +vt 0.766237 0.224949 +vt 0.764521 0.205209 +vt 0.772728 0.209948 +vt 0.767815 0.212784 +vt 0.780935 0.205209 +vt 0.772728 0.204275 +vt 0.772728 0.219424 +vt 0.777640 0.212784 +vt 0.762982 0.196826 +vt 0.772728 0.196826 +vt 0.782474 0.196826 +vt 0.673612 0.188443 +vt 0.681818 0.183704 +vt 0.681819 0.189377 +vt 0.681819 0.174228 +vt 0.676906 0.180868 +vt 0.690026 0.188443 +vt 0.686731 0.180868 +vt 0.688309 0.168703 +vt 0.693182 0.177143 +vt 0.698055 0.185584 +vt 0.696339 0.165844 +vt 0.704546 0.170583 +vt 0.699633 0.173419 +vt 0.712753 0.165844 +vt 0.704546 0.164910 +vt 0.704546 0.180059 +vt 0.709458 0.173419 +vt 0.694800 0.157461 +vt 0.720782 0.168703 +vt 0.714292 0.157461 +vt 0.727273 0.157461 +vt 0.715909 0.177143 +vt 0.704546 0.157461 +vt 0.711037 0.185584 +vt 0.719066 0.188443 +vt 0.727273 0.183704 +vt 0.727273 0.189377 +vt 0.727273 0.174228 +vt 0.722361 0.180868 +vt 0.735480 0.188443 +vt 0.732185 0.180868 +vt 0.733764 0.168703 +vt 0.738637 0.177143 +vt 0.743510 0.185584 +vt 0.741793 0.165844 +vt 0.750000 0.170583 +vt 0.745088 0.173419 +vt 0.758207 0.165844 +vt 0.750000 0.164910 +vt 0.750000 0.180059 +vt 0.754913 0.173419 +vt 0.740254 0.157461 +vt 0.750000 0.157461 +vt 0.766237 0.168703 +vt 0.759746 0.157461 +vt 0.772728 0.157461 +vt 0.756491 0.185584 +vt 0.761364 0.177143 +vt 0.764521 0.188443 +vt 0.772728 0.183704 +vt 0.772728 0.189377 +vt 0.772728 0.174228 +vt 0.767815 0.180868 +vt 0.780935 0.188443 +vt 0.777640 0.180868 +vt 0.779218 0.168703 +vt 0.784091 0.177144 +vt 0.788964 0.185584 +vt 0.787248 0.165844 +vt 0.795455 0.170583 +vt 0.790542 0.173419 +vt 0.803662 0.165844 +vt 0.795455 0.164910 +vt 0.795455 0.180059 +vt 0.800367 0.173419 +vt 0.785709 0.157461 +vt 0.795455 0.157461 +vt 0.805220 0.157495 +vt 0.900884 0.283939 +vt 0.909091 0.288678 +vt 0.904179 0.291514 +vt 0.917377 0.283803 +vt 0.909091 0.283005 +vt 0.909012 0.298291 +vt 0.914003 0.291514 +vt 0.899345 0.275556 +vt 0.909091 0.275556 +vt 0.926137 0.285397 +vt 0.918857 0.275522 +vt 0.931818 0.275556 +vt 0.920455 0.295239 +vt 0.914773 0.305080 +vt 0.878157 0.244574 +vt 0.886364 0.249313 +vt 0.881451 0.252149 +vt 0.894571 0.244574 +vt 0.886364 0.243640 +vt 0.886364 0.258789 +vt 0.891276 0.252149 +vt 0.876618 0.236191 +vt 0.886364 0.236191 +vt 0.902600 0.247433 +vt 0.896110 0.236191 +vt 0.909091 0.236191 +vt 0.897727 0.255874 +vt 0.892855 0.264314 +vt 0.855430 0.205209 +vt 0.863636 0.209948 +vt 0.858724 0.212784 +vt 0.871844 0.205209 +vt 0.863637 0.204275 +vt 0.863637 0.219424 +vt 0.868549 0.212784 +vt 0.853891 0.196826 +vt 0.863637 0.196826 +vt 0.879873 0.208068 +vt 0.873383 0.196826 +vt 0.886364 0.196826 +vt 0.875000 0.216509 +vt 0.870127 0.224949 +vt 0.900884 0.267173 +vt 0.909091 0.262434 +vt 0.909091 0.268107 +vt 0.909091 0.252958 +vt 0.904179 0.259598 +vt 0.917298 0.267173 +vt 0.914003 0.259598 +vt 0.915582 0.247433 +vt 0.920455 0.255874 +vt 0.925308 0.264348 +vt 0.923611 0.244574 +vt 0.931818 0.249313 +vt 0.926906 0.252149 +vt 0.940104 0.244438 +vt 0.931818 0.243640 +vt 0.931739 0.258926 +vt 0.936731 0.252149 +vt 0.922073 0.236191 +vt 0.931818 0.236191 +vt 0.948864 0.246032 +vt 0.941584 0.236157 +vt 0.954545 0.236191 +vt 0.943182 0.255874 +vt 0.937500 0.265715 +vt 0.878157 0.227808 +vt 0.886364 0.223069 +vt 0.886364 0.228742 +vt 0.886364 0.213593 +vt 0.881451 0.220233 +vt 0.894571 0.227808 +vt 0.891276 0.220233 +vt 0.892855 0.208068 +vt 0.897727 0.216509 +vt 0.902600 0.224949 +vt 0.900884 0.205209 +vt 0.909091 0.209948 +vt 0.904179 0.212784 +vt 0.917298 0.205209 +vt 0.909091 0.204275 +vt 0.909091 0.219424 +vt 0.914003 0.212784 +vt 0.899345 0.196826 +vt 0.909091 0.196826 +vt 0.925328 0.208068 +vt 0.918837 0.196826 +vt 0.931818 0.196826 +vt 0.920455 0.216509 +vt 0.915582 0.224949 +vt 0.923611 0.227808 +vt 0.931818 0.223069 +vt 0.931818 0.228742 +vt 0.931818 0.213593 +vt 0.926906 0.220233 +vt 0.940025 0.227808 +vt 0.936731 0.220233 +vt 0.938309 0.208068 +vt 0.943182 0.216509 +vt 0.948035 0.224983 +vt 0.946338 0.205209 +vt 0.954546 0.209948 +vt 0.949633 0.212784 +vt 0.962832 0.205073 +vt 0.954546 0.204275 +vt 0.954467 0.219561 +vt 0.959458 0.212784 +vt 0.944800 0.196826 +vt 0.954546 0.196826 +vt 0.971591 0.206667 +vt 0.964311 0.196792 +vt 0.977273 0.196826 +vt 0.965909 0.216509 +vt 0.960227 0.226350 +vt 0.855430 0.188443 +vt 0.863637 0.183704 +vt 0.863637 0.189377 +vt 0.863637 0.174228 +vt 0.858724 0.180868 +vt 0.871844 0.188443 +vt 0.868549 0.180868 +vt 0.870127 0.168703 +vt 0.875000 0.177143 +vt 0.879873 0.185584 +vt 0.878157 0.165844 +vt 0.886364 0.170583 +vt 0.881451 0.173419 +vt 0.894571 0.165844 +vt 0.886364 0.164910 +vt 0.886364 0.180059 +vt 0.891276 0.173419 +vt 0.876618 0.157461 +vt 0.886364 0.157461 +vt 0.902600 0.168703 +vt 0.896110 0.157461 +vt 0.909091 0.157461 +vt 0.897727 0.177143 +vt 0.892855 0.185584 +vt 0.900884 0.188443 +vt 0.909091 0.183704 +vt 0.909091 0.189377 +vt 0.909091 0.174228 +vt 0.904179 0.180868 +vt 0.917298 0.188443 +vt 0.914003 0.180868 +vt 0.915582 0.168703 +vt 0.920455 0.177143 +vt 0.925328 0.185584 +vt 0.923611 0.165844 +vt 0.931818 0.170583 +vt 0.926906 0.173419 +vt 0.940025 0.165844 +vt 0.931818 0.164910 +vt 0.931818 0.180059 +vt 0.936731 0.173419 +vt 0.922073 0.157461 +vt 0.931818 0.157461 +vt 0.948055 0.168703 +vt 0.941564 0.157461 +vt 0.954546 0.157461 +vt 0.943182 0.177144 +vt 0.938309 0.185584 +vt 0.946339 0.188443 +vt 0.954546 0.183704 +vt 0.954546 0.189377 +vt 0.954546 0.174228 +vt 0.949633 0.180868 +vt 0.962753 0.188443 +vt 0.959458 0.180868 +vt 0.961036 0.168703 +vt 0.970762 0.185618 +vt 0.965909 0.177143 +vt 0.969066 0.165844 +vt 0.977273 0.170583 +vt 0.972360 0.173419 +vt 0.985559 0.165708 +vt 0.977273 0.164910 +vt 0.977194 0.180196 +vt 0.982185 0.173419 +vt 0.967527 0.157461 +vt 0.977273 0.157461 +vt 0.994318 0.167302 +vt 0.987058 0.157461 +vt 1.000000 0.157461 +vt 0.982955 0.186985 +vt 0.988636 0.177144 +vt 0.173612 0.283939 +vt 0.181819 0.288678 +vt 0.176907 0.291514 +vt 0.190026 0.283939 +vt 0.181819 0.283005 +vt 0.181819 0.298154 +vt 0.186731 0.291514 +vt 0.172073 0.275556 +vt 0.181819 0.275556 +vt 0.191565 0.275556 +vt 0.150885 0.244574 +vt 0.159092 0.249313 +vt 0.154179 0.252149 +vt 0.167299 0.244574 +vt 0.159092 0.243640 +vt 0.159092 0.258789 +vt 0.164004 0.252149 +vt 0.149346 0.236191 +vt 0.159092 0.236191 +vt 0.175328 0.247433 +vt 0.168838 0.236191 +vt 0.181819 0.236191 +vt 0.170455 0.255874 +vt 0.165582 0.264314 +vt 0.128157 0.205209 +vt 0.136364 0.209948 +vt 0.131452 0.212784 +vt 0.144572 0.205209 +vt 0.136365 0.204275 +vt 0.136365 0.219424 +vt 0.141277 0.212784 +vt 0.126619 0.196826 +vt 0.136364 0.196826 +vt 0.152601 0.208068 +vt 0.146110 0.196826 +vt 0.159092 0.196826 +vt 0.147728 0.216509 +vt 0.142855 0.224949 +vt 0.173612 0.267173 +vt 0.181819 0.262434 +vt 0.181819 0.268107 +vt 0.181819 0.252958 +vt 0.176907 0.259598 +vt 0.190026 0.267173 +vt 0.186731 0.259598 +vt 0.188310 0.247433 +vt 0.193183 0.255874 +vt 0.198056 0.264314 +vt 0.196339 0.244574 +vt 0.204546 0.249313 +vt 0.199634 0.252149 +vt 0.212753 0.244574 +vt 0.204546 0.243640 +vt 0.204546 0.258789 +vt 0.209459 0.252149 +vt 0.194800 0.236191 +vt 0.204546 0.236191 +vt 0.214292 0.236191 +vt 0.150885 0.227808 +vt 0.159092 0.223069 +vt 0.159092 0.228742 +vt 0.159092 0.213593 +vt 0.154179 0.220233 +vt 0.167299 0.227808 +vt 0.164004 0.220233 +vt 0.165582 0.208068 +vt 0.170455 0.216509 +vt 0.175328 0.224949 +vt 0.173612 0.205209 +vt 0.181819 0.209948 +vt 0.176907 0.212784 +vt 0.190026 0.205209 +vt 0.181819 0.204275 +vt 0.181819 0.219424 +vt 0.186731 0.212784 +vt 0.172073 0.196826 +vt 0.181819 0.196826 +vt 0.198056 0.208068 +vt 0.191565 0.196826 +vt 0.204546 0.196826 +vt 0.193183 0.216509 +vt 0.188310 0.224949 +vt 0.196339 0.227808 +vt 0.204546 0.223069 +vt 0.204546 0.228742 +vt 0.204546 0.213593 +vt 0.199634 0.220233 +vt 0.212753 0.227808 +vt 0.209459 0.220233 +vt 0.211037 0.208068 +vt 0.215910 0.216509 +vt 0.220783 0.224949 +vt 0.219066 0.205209 +vt 0.227274 0.209948 +vt 0.222361 0.212784 +vt 0.235481 0.205209 +vt 0.227274 0.204275 +vt 0.227274 0.219424 +vt 0.232186 0.212784 +vt 0.217528 0.196826 +vt 0.227274 0.196826 +vt 0.237019 0.196826 +vt 0.128157 0.188443 +vt 0.136364 0.183704 +vt 0.136365 0.189377 +vt 0.136365 0.174228 +vt 0.131452 0.180868 +vt 0.144572 0.188443 +vt 0.141277 0.180868 +vt 0.142855 0.168703 +vt 0.147728 0.177143 +vt 0.152601 0.185584 +vt 0.150885 0.165844 +vt 0.159092 0.170583 +vt 0.154179 0.173419 +vt 0.167299 0.165844 +vt 0.159092 0.164910 +vt 0.159092 0.180059 +vt 0.164004 0.173419 +vt 0.149346 0.157461 +vt 0.159092 0.157461 +vt 0.175328 0.168703 +vt 0.168838 0.157461 +vt 0.181819 0.157461 +vt 0.170455 0.177143 +vt 0.165582 0.185584 +vt 0.173612 0.188443 +vt 0.181819 0.183704 +vt 0.181819 0.189377 +vt 0.181819 0.174228 +vt 0.176907 0.180868 +vt 0.190026 0.188443 +vt 0.186731 0.180868 +vt 0.188310 0.168703 +vt 0.193183 0.177143 +vt 0.198056 0.185584 +vt 0.196339 0.165844 +vt 0.204546 0.170583 +vt 0.199634 0.173419 +vt 0.212753 0.165844 +vt 0.204546 0.164910 +vt 0.204546 0.180059 +vt 0.209459 0.173419 +vt 0.194800 0.157461 +vt 0.204546 0.157461 +vt 0.220783 0.168703 +vt 0.214292 0.157461 +vt 0.227274 0.157461 +vt 0.215910 0.177144 +vt 0.211037 0.185584 +vt 0.219066 0.188443 +vt 0.227273 0.183704 +vt 0.227274 0.189377 +vt 0.227274 0.174228 +vt 0.222361 0.180868 +vt 0.235481 0.188443 +vt 0.232186 0.180868 +vt 0.233764 0.168703 +vt 0.238637 0.177144 +vt 0.243510 0.185584 +vt 0.241794 0.165844 +vt 0.250001 0.170583 +vt 0.245088 0.173419 +vt 0.258208 0.165844 +vt 0.250001 0.164910 +vt 0.250001 0.180059 +vt 0.254913 0.173419 +vt 0.240255 0.157461 +vt 0.250001 0.157461 +vt 0.259766 0.157495 +vt 0.355430 0.283939 +vt 0.363637 0.288678 +vt 0.358725 0.291514 +vt 0.371844 0.283939 +vt 0.363637 0.283005 +vt 0.363637 0.298154 +vt 0.368549 0.291514 +vt 0.353891 0.275556 +vt 0.363637 0.275556 +vt 0.373383 0.275556 +vt 0.332703 0.244574 +vt 0.340910 0.249313 +vt 0.335997 0.252149 +vt 0.349117 0.244574 +vt 0.340910 0.243640 +vt 0.340910 0.258789 +vt 0.345822 0.252149 +vt 0.331164 0.236191 +vt 0.340910 0.236191 +vt 0.357146 0.247433 +vt 0.350656 0.236191 +vt 0.363637 0.236191 +vt 0.352273 0.255874 +vt 0.347400 0.264314 +vt 0.309975 0.205209 +vt 0.318182 0.209948 +vt 0.313270 0.212784 +vt 0.326390 0.205209 +vt 0.318182 0.204275 +vt 0.318183 0.219424 +vt 0.323095 0.212784 +vt 0.308437 0.196826 +vt 0.334419 0.208068 +vt 0.327928 0.196826 +vt 0.340910 0.196826 +vt 0.329546 0.216509 +vt 0.318183 0.196826 +vt 0.324673 0.224949 +vt 0.355430 0.267173 +vt 0.363637 0.262434 +vt 0.363637 0.268107 +vt 0.363637 0.252958 +vt 0.358725 0.259598 +vt 0.371844 0.267173 +vt 0.368549 0.259598 +vt 0.370128 0.247433 +vt 0.375001 0.255874 +vt 0.379874 0.264314 +vt 0.378157 0.244574 +vt 0.386364 0.249313 +vt 0.381452 0.252149 +vt 0.394571 0.244574 +vt 0.386364 0.243640 +vt 0.386364 0.258789 +vt 0.391277 0.252149 +vt 0.376618 0.236191 +vt 0.386364 0.236191 +vt 0.396110 0.236191 +vt 0.332703 0.227808 +vt 0.340910 0.223069 +vt 0.340910 0.228742 +vt 0.340910 0.213593 +vt 0.335997 0.220233 +vt 0.349117 0.227808 +vt 0.345822 0.220233 +vt 0.347400 0.208068 +vt 0.352273 0.216509 +vt 0.357146 0.224949 +vt 0.355430 0.205209 +vt 0.363637 0.209948 +vt 0.358725 0.212784 +vt 0.371844 0.205209 +vt 0.363637 0.204275 +vt 0.363637 0.219424 +vt 0.368549 0.212784 +vt 0.353891 0.196826 +vt 0.363637 0.196826 +vt 0.379874 0.208068 +vt 0.373383 0.196826 +vt 0.386364 0.196826 +vt 0.375001 0.216509 +vt 0.370128 0.224949 +vt 0.378157 0.227808 +vt 0.386364 0.223069 +vt 0.386364 0.228742 +vt 0.386364 0.213593 +vt 0.381452 0.220233 +vt 0.394571 0.227808 +vt 0.391277 0.220233 +vt 0.392855 0.208068 +vt 0.397728 0.216509 +vt 0.402601 0.224949 +vt 0.400884 0.205209 +vt 0.409091 0.209948 +vt 0.404179 0.212784 +vt 0.417299 0.205209 +vt 0.409092 0.204275 +vt 0.409092 0.219424 +vt 0.414004 0.212784 +vt 0.399346 0.196826 +vt 0.409092 0.196826 +vt 0.418837 0.196826 +vt 0.309975 0.188443 +vt 0.318182 0.183704 +vt 0.318182 0.189377 +vt 0.318183 0.174228 +vt 0.313270 0.180868 +vt 0.326390 0.188443 +vt 0.323095 0.180868 +vt 0.324673 0.168703 +vt 0.329546 0.177143 +vt 0.334419 0.185584 +vt 0.332703 0.165844 +vt 0.340910 0.170583 +vt 0.335997 0.173419 +vt 0.349117 0.165844 +vt 0.340910 0.164910 +vt 0.340910 0.180059 +vt 0.345822 0.173419 +vt 0.331164 0.157461 +vt 0.357146 0.168703 +vt 0.350656 0.157461 +vt 0.363637 0.157461 +vt 0.352273 0.177143 +vt 0.340910 0.157461 +vt 0.347400 0.185584 +vt 0.355430 0.188443 +vt 0.363637 0.183704 +vt 0.363637 0.189377 +vt 0.363637 0.174228 +vt 0.358725 0.180868 +vt 0.371844 0.188443 +vt 0.368549 0.180868 +vt 0.370128 0.168703 +vt 0.375001 0.177143 +vt 0.379874 0.185584 +vt 0.378157 0.165844 +vt 0.386364 0.170583 +vt 0.381452 0.173419 +vt 0.394571 0.165844 +vt 0.386364 0.164910 +vt 0.386364 0.180059 +vt 0.391277 0.173419 +vt 0.376618 0.157461 +vt 0.386364 0.157461 +vt 0.402601 0.168703 +vt 0.396110 0.157461 +vt 0.409092 0.157461 +vt 0.392855 0.185584 +vt 0.397728 0.177143 +vt 0.400884 0.188443 +vt 0.409091 0.183704 +vt 0.409092 0.189377 +vt 0.409092 0.174228 +vt 0.404179 0.180868 +vt 0.417299 0.188443 +vt 0.414004 0.180868 +vt 0.415582 0.168703 +vt 0.420455 0.177144 +vt 0.425328 0.185584 +vt 0.423612 0.165844 +vt 0.431819 0.170583 +vt 0.426906 0.173419 +vt 0.440026 0.165844 +vt 0.431819 0.164910 +vt 0.431819 0.180059 +vt 0.436731 0.173419 +vt 0.422073 0.157461 +vt 0.431819 0.157461 +vt 0.441584 0.157495 +vt 0.477352 0.134726 +vt 0.477273 0.144339 +vt 0.472361 0.141503 +vt 0.477273 0.150012 +vt 0.482186 0.141503 +vt 0.485480 0.149078 +vt 0.468987 0.149214 +vt 0.483784 0.129304 +vt 0.471592 0.127937 +vt 0.477273 0.118096 +vt 0.488637 0.137778 +vt 0.465910 0.137778 +vt 0.493510 0.146219 +vt 0.460228 0.147620 +vt 0.500079 0.095360 +vt 0.500001 0.104974 +vt 0.495088 0.102138 +vt 0.508208 0.109712 +vt 0.504913 0.102138 +vt 0.491715 0.109849 +vt 0.500000 0.110646 +vt 0.506511 0.089939 +vt 0.494319 0.088572 +vt 0.500000 0.078731 +vt 0.511364 0.098413 +vt 0.488637 0.098413 +vt 0.509746 0.118096 +vt 0.516237 0.106853 +vt 0.522728 0.118096 +vt 0.500001 0.118096 +vt 0.482955 0.108254 +vt 0.490235 0.118130 +vt 0.522807 0.055995 +vt 0.522728 0.065609 +vt 0.517815 0.062773 +vt 0.530935 0.070347 +vt 0.527640 0.062773 +vt 0.514442 0.070484 +vt 0.522728 0.071281 +vt 0.529238 0.050573 +vt 0.517046 0.049207 +vt 0.511364 0.059048 +vt 0.532474 0.078731 +vt 0.538964 0.067488 +vt 0.545455 0.078731 +vt 0.522728 0.078731 +vt 0.534091 0.059048 +vt 0.505682 0.068889 +vt 0.512962 0.078765 +vt 0.491793 0.126479 +vt 0.500001 0.131218 +vt 0.495088 0.134054 +vt 0.508208 0.126479 +vt 0.500001 0.125545 +vt 0.500001 0.140694 +vt 0.504913 0.134054 +vt 0.516237 0.129338 +vt 0.506491 0.146219 +vt 0.511364 0.137778 +vt 0.522728 0.134862 +vt 0.522728 0.144339 +vt 0.517815 0.141503 +vt 0.530935 0.149078 +vt 0.527640 0.141503 +vt 0.514521 0.149078 +vt 0.522728 0.150012 +vt 0.529218 0.129338 +vt 0.534091 0.137778 +vt 0.538964 0.146219 +vt 0.514521 0.087114 +vt 0.522728 0.091852 +vt 0.517815 0.094688 +vt 0.530935 0.087114 +vt 0.522728 0.086180 +vt 0.522728 0.101329 +vt 0.527640 0.094688 +vt 0.538964 0.089973 +vt 0.534091 0.098413 +vt 0.529218 0.106853 +vt 0.545455 0.095497 +vt 0.545455 0.104974 +vt 0.540543 0.102138 +vt 0.553662 0.109712 +vt 0.550367 0.102138 +vt 0.537248 0.109712 +vt 0.545455 0.110646 +vt 0.551946 0.089973 +vt 0.556819 0.098413 +vt 0.555201 0.118096 +vt 0.561692 0.106853 +vt 0.568182 0.118096 +vt 0.545455 0.118096 +vt 0.535709 0.118096 +vt 0.537248 0.126479 +vt 0.545455 0.131217 +vt 0.540543 0.134054 +vt 0.553662 0.126479 +vt 0.545455 0.125545 +vt 0.545455 0.140694 +vt 0.550367 0.134054 +vt 0.561692 0.129338 +vt 0.556819 0.137778 +vt 0.551946 0.146219 +vt 0.568182 0.134862 +vt 0.568182 0.144339 +vt 0.563270 0.141503 +vt 0.576389 0.149078 +vt 0.573095 0.141503 +vt 0.559975 0.149078 +vt 0.568182 0.150012 +vt 0.574673 0.129338 +vt 0.579546 0.137778 +vt 0.584419 0.146219 +vt 0.537248 0.047749 +vt 0.545455 0.052487 +vt 0.540543 0.055323 +vt 0.553662 0.047749 +vt 0.545455 0.046815 +vt 0.545455 0.061964 +vt 0.550367 0.055323 +vt 0.561672 0.050573 +vt 0.551946 0.067488 +vt 0.556819 0.059048 +vt 0.568103 0.055995 +vt 0.568182 0.065609 +vt 0.563270 0.062773 +vt 0.576468 0.070484 +vt 0.573095 0.062773 +vt 0.559975 0.070347 +vt 0.568182 0.071281 +vt 0.573864 0.049207 +vt 0.579546 0.059048 +vt 0.577948 0.078765 +vt 0.585228 0.068889 +vt 0.590909 0.078731 +vt 0.568182 0.078731 +vt 0.558436 0.078731 +vt 0.559975 0.087114 +vt 0.568182 0.091852 +vt 0.563270 0.094688 +vt 0.576389 0.087114 +vt 0.568182 0.086180 +vt 0.568182 0.101329 +vt 0.573095 0.094688 +vt 0.584399 0.089939 +vt 0.574673 0.106853 +vt 0.579546 0.098413 +vt 0.590831 0.095361 +vt 0.590909 0.104974 +vt 0.585997 0.102138 +vt 0.599196 0.109849 +vt 0.595822 0.102138 +vt 0.582703 0.109712 +vt 0.590910 0.110646 +vt 0.596591 0.088572 +vt 0.602273 0.098413 +vt 0.600675 0.118130 +vt 0.607955 0.108254 +vt 0.613637 0.118096 +vt 0.590910 0.118096 +vt 0.581164 0.118096 +vt 0.582703 0.126479 +vt 0.590909 0.131218 +vt 0.585997 0.134054 +vt 0.599117 0.126479 +vt 0.590910 0.125545 +vt 0.590910 0.140694 +vt 0.595822 0.134054 +vt 0.607126 0.129304 +vt 0.602273 0.137778 +vt 0.597400 0.146219 +vt 0.613558 0.134726 +vt 0.613637 0.144339 +vt 0.608724 0.141503 +vt 0.621923 0.149214 +vt 0.618549 0.141503 +vt 0.605430 0.149078 +vt 0.613637 0.150012 +vt 0.619319 0.127937 +vt 0.625000 0.137778 +vt 0.630682 0.147620 +vt 0.659170 0.134726 +vt 0.659091 0.144339 +vt 0.654179 0.141503 +vt 0.667298 0.149078 +vt 0.664004 0.141503 +vt 0.650805 0.149214 +vt 0.659091 0.150012 +vt 0.665602 0.129304 +vt 0.653409 0.127937 +vt 0.659091 0.118096 +vt 0.670455 0.137778 +vt 0.647728 0.137778 +vt 0.675328 0.146219 +vt 0.642046 0.147620 +vt 0.681897 0.095360 +vt 0.681819 0.104974 +vt 0.676906 0.102138 +vt 0.690026 0.109712 +vt 0.686731 0.102138 +vt 0.673533 0.109849 +vt 0.681819 0.110646 +vt 0.688329 0.089939 +vt 0.676137 0.088572 +vt 0.681818 0.078731 +vt 0.693182 0.098413 +vt 0.670455 0.098413 +vt 0.691564 0.118096 +vt 0.698055 0.106853 +vt 0.704546 0.118096 +vt 0.681819 0.118096 +vt 0.664773 0.108254 +vt 0.672053 0.118130 +vt 0.704625 0.055995 +vt 0.704546 0.065609 +vt 0.699633 0.062773 +vt 0.712753 0.070347 +vt 0.709458 0.062773 +vt 0.696260 0.070484 +vt 0.704546 0.071281 +vt 0.711056 0.050573 +vt 0.698864 0.049207 +vt 0.693182 0.059048 +vt 0.714292 0.078731 +vt 0.720782 0.067488 +vt 0.727273 0.078731 +vt 0.704546 0.078731 +vt 0.715909 0.059048 +vt 0.687500 0.068889 +vt 0.694780 0.078765 +vt 0.673611 0.126479 +vt 0.681819 0.131218 +vt 0.676906 0.134054 +vt 0.690026 0.126479 +vt 0.681819 0.125545 +vt 0.681819 0.140694 +vt 0.686731 0.134054 +vt 0.698055 0.129338 +vt 0.693182 0.137778 +vt 0.688309 0.146219 +vt 0.704546 0.134862 +vt 0.704546 0.144339 +vt 0.699633 0.141503 +vt 0.712753 0.149078 +vt 0.709458 0.141503 +vt 0.696339 0.149078 +vt 0.704546 0.150012 +vt 0.711037 0.129338 +vt 0.715909 0.137778 +vt 0.720782 0.146219 +vt 0.696339 0.087114 +vt 0.704546 0.091852 +vt 0.699633 0.094688 +vt 0.712753 0.087114 +vt 0.704546 0.086180 +vt 0.704546 0.101329 +vt 0.709458 0.094688 +vt 0.720782 0.089973 +vt 0.715909 0.098413 +vt 0.711037 0.106853 +vt 0.727273 0.095497 +vt 0.727273 0.104974 +vt 0.722361 0.102138 +vt 0.735480 0.109712 +vt 0.732185 0.102138 +vt 0.719066 0.109712 +vt 0.727273 0.110646 +vt 0.733764 0.089973 +vt 0.738637 0.098413 +vt 0.737019 0.118096 +vt 0.743510 0.106853 +vt 0.750000 0.118096 +vt 0.717527 0.118096 +vt 0.727273 0.118096 +vt 0.719066 0.126479 +vt 0.727273 0.131217 +vt 0.722361 0.134054 +vt 0.735480 0.126479 +vt 0.727273 0.125545 +vt 0.727273 0.140694 +vt 0.732185 0.134054 +vt 0.743510 0.129338 +vt 0.738637 0.137778 +vt 0.733764 0.146219 +vt 0.750000 0.134862 +vt 0.750000 0.144339 +vt 0.745088 0.141503 +vt 0.758207 0.149078 +vt 0.754913 0.141503 +vt 0.741793 0.149078 +vt 0.750000 0.150012 +vt 0.756491 0.129338 +vt 0.761364 0.137778 +vt 0.766237 0.146219 +vt 0.719066 0.047749 +vt 0.727273 0.052487 +vt 0.722361 0.055323 +vt 0.735480 0.047749 +vt 0.727273 0.046815 +vt 0.727273 0.061964 +vt 0.732185 0.055323 +vt 0.743490 0.050573 +vt 0.738637 0.059048 +vt 0.733764 0.067488 +vt 0.749921 0.055995 +vt 0.750000 0.065609 +vt 0.745088 0.062773 +vt 0.758286 0.070484 +vt 0.754913 0.062773 +vt 0.741793 0.070347 +vt 0.750000 0.071281 +vt 0.755682 0.049207 +vt 0.759766 0.078765 +vt 0.767046 0.068889 +vt 0.772727 0.078731 +vt 0.750000 0.078731 +vt 0.761364 0.059048 +vt 0.740254 0.078731 +vt 0.741793 0.087114 +vt 0.750000 0.091852 +vt 0.745088 0.094688 +vt 0.758207 0.087114 +vt 0.750000 0.086180 +vt 0.750000 0.101329 +vt 0.754913 0.094688 +vt 0.766217 0.089939 +vt 0.756491 0.106853 +vt 0.761364 0.098413 +vt 0.772649 0.095361 +vt 0.772727 0.104974 +vt 0.767815 0.102138 +vt 0.781013 0.109849 +vt 0.777640 0.102138 +vt 0.764521 0.109712 +vt 0.772728 0.110646 +vt 0.778409 0.088572 +vt 0.782493 0.118130 +vt 0.789773 0.108254 +vt 0.795455 0.118096 +vt 0.772728 0.118096 +vt 0.784091 0.098413 +vt 0.762982 0.118096 +vt 0.764521 0.126479 +vt 0.772728 0.131218 +vt 0.767815 0.134054 +vt 0.780935 0.126479 +vt 0.772728 0.125545 +vt 0.772728 0.140694 +vt 0.777640 0.134054 +vt 0.788944 0.129304 +vt 0.784091 0.137778 +vt 0.779218 0.146219 +vt 0.795376 0.134726 +vt 0.795455 0.144339 +vt 0.790542 0.141503 +vt 0.803741 0.149214 +vt 0.800367 0.141503 +vt 0.787248 0.149078 +vt 0.795455 0.150012 +vt 0.801137 0.127937 +vt 0.806818 0.137778 +vt 0.812500 0.147620 +vt 0.840988 0.134726 +vt 0.840909 0.144339 +vt 0.835997 0.141503 +vt 0.849116 0.149078 +vt 0.845822 0.141503 +vt 0.832623 0.149214 +vt 0.840909 0.150012 +vt 0.847420 0.129304 +vt 0.835228 0.127937 +vt 0.840909 0.118096 +vt 0.852273 0.137778 +vt 0.829546 0.137778 +vt 0.857146 0.146219 +vt 0.823864 0.147620 +vt 0.863716 0.095360 +vt 0.863637 0.104974 +vt 0.858724 0.102138 +vt 0.871844 0.109712 +vt 0.868549 0.102138 +vt 0.855351 0.109849 +vt 0.863637 0.110646 +vt 0.870147 0.089939 +vt 0.857955 0.088572 +vt 0.863636 0.078731 +vt 0.875000 0.098413 +vt 0.852273 0.098413 +vt 0.873383 0.118096 +vt 0.879873 0.106853 +vt 0.886364 0.118096 +vt 0.863637 0.118096 +vt 0.846591 0.108254 +vt 0.853871 0.118130 +vt 0.886443 0.055995 +vt 0.886364 0.065609 +vt 0.881451 0.062773 +vt 0.894571 0.070347 +vt 0.891276 0.062773 +vt 0.878078 0.070484 +vt 0.886364 0.071281 +vt 0.892874 0.050573 +vt 0.880682 0.049207 +vt 0.875000 0.059048 +vt 0.896110 0.078731 +vt 0.902600 0.067488 +vt 0.909091 0.078731 +vt 0.886364 0.078731 +vt 0.897727 0.059048 +vt 0.869318 0.068889 +vt 0.876598 0.078765 +vt 0.855430 0.126479 +vt 0.863636 0.131218 +vt 0.858724 0.134054 +vt 0.871844 0.126479 +vt 0.863637 0.125545 +vt 0.863637 0.140694 +vt 0.868549 0.134054 +vt 0.879873 0.129338 +vt 0.870127 0.146219 +vt 0.875000 0.137778 +vt 0.886364 0.134862 +vt 0.886364 0.144339 +vt 0.881451 0.141503 +vt 0.894571 0.149078 +vt 0.891276 0.141503 +vt 0.878157 0.149078 +vt 0.886364 0.150012 +vt 0.892855 0.129338 +vt 0.897727 0.137778 +vt 0.902600 0.146219 +vt 0.878157 0.087114 +vt 0.886364 0.091852 +vt 0.881451 0.094688 +vt 0.894571 0.087114 +vt 0.886364 0.086180 +vt 0.891276 0.094688 +vt 0.886364 0.101329 +vt 0.902600 0.089973 +vt 0.892855 0.106853 +vt 0.897727 0.098413 +vt 0.909091 0.095497 +vt 0.909091 0.104974 +vt 0.904179 0.102138 +vt 0.917298 0.109712 +vt 0.914004 0.102138 +vt 0.900884 0.109712 +vt 0.909091 0.110646 +vt 0.915582 0.089973 +vt 0.920455 0.098413 +vt 0.918837 0.118096 +vt 0.925328 0.106853 +vt 0.931819 0.118096 +vt 0.899345 0.118096 +vt 0.909091 0.118096 +vt 0.900884 0.126479 +vt 0.909091 0.131217 +vt 0.904179 0.134054 +vt 0.917298 0.126479 +vt 0.909091 0.125545 +vt 0.909091 0.140694 +vt 0.914003 0.134054 +vt 0.925328 0.129338 +vt 0.915582 0.146219 +vt 0.920455 0.137778 +vt 0.931818 0.134862 +vt 0.931818 0.144339 +vt 0.926906 0.141503 +vt 0.940025 0.149078 +vt 0.936731 0.141503 +vt 0.923611 0.149078 +vt 0.931818 0.150012 +vt 0.938309 0.129338 +vt 0.943182 0.137778 +vt 0.948055 0.146219 +vt 0.900884 0.047749 +vt 0.909091 0.052487 +vt 0.904179 0.055323 +vt 0.917298 0.047749 +vt 0.909091 0.046815 +vt 0.909091 0.061964 +vt 0.914003 0.055323 +vt 0.925308 0.050573 +vt 0.920455 0.059048 +vt 0.915582 0.067488 +vt 0.931739 0.055995 +vt 0.931818 0.065609 +vt 0.926906 0.062773 +vt 0.940104 0.070484 +vt 0.936731 0.062773 +vt 0.923611 0.070347 +vt 0.931818 0.071281 +vt 0.937500 0.049207 +vt 0.943182 0.059048 +vt 0.941584 0.078765 +vt 0.948864 0.068889 +vt 0.954545 0.078731 +vt 0.931818 0.078731 +vt 0.922072 0.078731 +vt 0.923611 0.087114 +vt 0.931818 0.091852 +vt 0.926906 0.094688 +vt 0.940025 0.087114 +vt 0.931818 0.086180 +vt 0.931818 0.101329 +vt 0.936731 0.094688 +vt 0.948035 0.089939 +vt 0.938309 0.106853 +vt 0.943182 0.098413 +vt 0.954467 0.095361 +vt 0.954546 0.104974 +vt 0.949633 0.102138 +vt 0.962832 0.109849 +vt 0.959458 0.102138 +vt 0.946339 0.109712 +vt 0.954546 0.110646 +vt 0.960227 0.088572 +vt 0.965909 0.098413 +vt 0.964311 0.118130 +vt 0.971591 0.108254 +vt 0.977273 0.118096 +vt 0.954546 0.118096 +vt 0.944800 0.118096 +vt 0.946339 0.126479 +vt 0.954546 0.131218 +vt 0.949633 0.134054 +vt 0.962753 0.126479 +vt 0.954546 0.125545 +vt 0.954546 0.140694 +vt 0.959458 0.134054 +vt 0.970762 0.129304 +vt 0.965909 0.137778 +vt 0.961036 0.146219 +vt 0.977194 0.134726 +vt 0.977273 0.144339 +vt 0.972360 0.141503 +vt 0.985559 0.149214 +vt 0.982185 0.141503 +vt 0.969066 0.149078 +vt 0.977273 0.150012 +vt 0.982955 0.127937 +vt 0.988636 0.137778 +vt 0.994318 0.147620 +vt 0.423612 0.149078 +vt 0.431819 0.144339 +vt 0.431819 0.150012 +vt 0.431740 0.134726 +vt 0.426906 0.141503 +vt 0.440105 0.149214 +vt 0.436731 0.141503 +vt 0.415582 0.146219 +vt 0.420455 0.137778 +vt 0.437501 0.127937 +vt 0.425308 0.129304 +vt 0.431819 0.118096 +vt 0.443182 0.137778 +vt 0.448864 0.147620 +vt 0.378157 0.149078 +vt 0.386364 0.144339 +vt 0.386364 0.150012 +vt 0.386364 0.134862 +vt 0.381452 0.141503 +vt 0.394571 0.149078 +vt 0.391277 0.141503 +vt 0.370128 0.146219 +vt 0.375001 0.137778 +vt 0.392855 0.129338 +vt 0.379874 0.129338 +vt 0.386364 0.118096 +vt 0.397728 0.137778 +vt 0.402601 0.146219 +vt 0.332703 0.149078 +vt 0.340910 0.144339 +vt 0.340910 0.150012 +vt 0.340910 0.134862 +vt 0.335997 0.141503 +vt 0.349117 0.149078 +vt 0.345822 0.141503 +vt 0.324673 0.146219 +vt 0.329546 0.137778 +vt 0.347400 0.129338 +vt 0.334419 0.129338 +vt 0.340910 0.118096 +vt 0.352273 0.137778 +vt 0.357146 0.146219 +vt 0.409092 0.140694 +vt 0.409091 0.131218 +vt 0.414004 0.134054 +vt 0.400884 0.126479 +vt 0.404179 0.134054 +vt 0.417299 0.126479 +vt 0.409092 0.125545 +vt 0.399346 0.118096 +vt 0.418857 0.118130 +vt 0.409092 0.118096 +vt 0.400884 0.109712 +vt 0.409091 0.104974 +vt 0.409092 0.110646 +vt 0.409013 0.095361 +vt 0.404179 0.102138 +vt 0.417378 0.109849 +vt 0.414004 0.102138 +vt 0.392855 0.106853 +vt 0.397728 0.098413 +vt 0.414773 0.088572 +vt 0.402581 0.089939 +vt 0.409091 0.078731 +vt 0.420455 0.098413 +vt 0.426137 0.108254 +vt 0.363637 0.140694 +vt 0.363637 0.131217 +vt 0.368549 0.134054 +vt 0.355430 0.126479 +vt 0.358725 0.134054 +vt 0.371844 0.126479 +vt 0.363637 0.125545 +vt 0.353891 0.118096 +vt 0.363637 0.118096 +vt 0.373383 0.118096 +vt 0.355430 0.109712 +vt 0.363637 0.104974 +vt 0.363637 0.110646 +vt 0.363637 0.095497 +vt 0.358725 0.102138 +vt 0.371844 0.109712 +vt 0.368549 0.102138 +vt 0.347400 0.106853 +vt 0.370128 0.089973 +vt 0.357146 0.089973 +vt 0.363637 0.078731 +vt 0.375001 0.098413 +vt 0.352273 0.098413 +vt 0.379874 0.106853 +vt 0.386364 0.101329 +vt 0.386364 0.091852 +vt 0.391277 0.094688 +vt 0.378157 0.087114 +vt 0.381452 0.094688 +vt 0.394571 0.087114 +vt 0.386364 0.086180 +vt 0.376618 0.078731 +vt 0.396130 0.078765 +vt 0.386364 0.078731 +vt 0.378157 0.070347 +vt 0.386364 0.065609 +vt 0.386364 0.071281 +vt 0.386285 0.055995 +vt 0.381452 0.062773 +vt 0.394650 0.070484 +vt 0.391277 0.062773 +vt 0.370128 0.067488 +vt 0.375001 0.059048 +vt 0.392046 0.049207 +vt 0.379854 0.050573 +vt 0.386364 0.039365 +vt 0.397728 0.059048 +vt 0.403410 0.068889 +vt 0.318182 0.140694 +vt 0.318182 0.131217 +vt 0.323095 0.134054 +vt 0.309975 0.126479 +vt 0.313270 0.134054 +vt 0.326390 0.126479 +vt 0.318182 0.125545 +vt 0.308417 0.118130 +vt 0.318182 0.118096 +vt 0.327928 0.118096 +vt 0.309896 0.109849 +vt 0.318182 0.104974 +vt 0.318182 0.110646 +vt 0.318261 0.095360 +vt 0.313270 0.102138 +vt 0.326390 0.109712 +vt 0.323095 0.102138 +vt 0.301137 0.108254 +vt 0.306819 0.098413 +vt 0.324693 0.089939 +vt 0.312501 0.088572 +vt 0.318182 0.078731 +vt 0.329546 0.098413 +vt 0.334419 0.106853 +vt 0.340910 0.101329 +vt 0.340910 0.091852 +vt 0.345822 0.094688 +vt 0.332703 0.087114 +vt 0.335997 0.094688 +vt 0.349117 0.087114 +vt 0.340910 0.086180 +vt 0.331144 0.078765 +vt 0.340910 0.078731 +vt 0.350656 0.078731 +vt 0.332624 0.070484 +vt 0.340910 0.065609 +vt 0.340910 0.071281 +vt 0.340989 0.055995 +vt 0.335997 0.062773 +vt 0.349117 0.070347 +vt 0.345822 0.062773 +vt 0.323864 0.068889 +vt 0.329546 0.059048 +vt 0.347420 0.050573 +vt 0.335228 0.049207 +vt 0.340910 0.039365 +vt 0.352273 0.059048 +vt 0.357146 0.067488 +vt 0.363637 0.061964 +vt 0.363637 0.052487 +vt 0.368549 0.055323 +vt 0.355430 0.047749 +vt 0.358725 0.055323 +vt 0.371844 0.047749 +vt 0.363637 0.046815 +vt 0.353871 0.039399 +vt 0.363637 0.039365 +vt 0.373403 0.039399 +vt 0.355351 0.031119 +vt 0.363637 0.026243 +vt 0.363637 0.031916 +vt 0.363637 0.016493 +vt 0.358725 0.023407 +vt 0.371923 0.031119 +vt 0.368549 0.023407 +vt 0.346592 0.029524 +vt 0.352273 0.019683 +vt 0.369319 0.009841 +vt 0.357955 0.009841 +vt 0.363637 0.000000 +vt 0.380682 0.029524 +vt 0.375001 0.019683 +vt 0.113716 0.134726 +vt 0.113637 0.144339 +vt 0.108725 0.141503 +vt 0.121844 0.149078 +vt 0.118550 0.141503 +vt 0.105351 0.149214 +vt 0.113637 0.150012 +vt 0.120148 0.129304 +vt 0.107955 0.127937 +vt 0.113637 0.118096 +vt 0.125001 0.137778 +vt 0.102274 0.137778 +vt 0.129874 0.146219 +vt 0.096592 0.147620 +vt 0.136443 0.095360 +vt 0.136365 0.104974 +vt 0.131452 0.102138 +vt 0.144572 0.109712 +vt 0.141277 0.102138 +vt 0.128079 0.109849 +vt 0.136365 0.110646 +vt 0.142875 0.089939 +vt 0.130683 0.088572 +vt 0.136365 0.078731 +vt 0.147728 0.098413 +vt 0.125001 0.098413 +vt 0.146110 0.118096 +vt 0.152601 0.106853 +vt 0.159092 0.118096 +vt 0.136365 0.118096 +vt 0.119319 0.108254 +vt 0.126599 0.118130 +vt 0.159171 0.055995 +vt 0.159092 0.065609 +vt 0.154179 0.062773 +vt 0.167299 0.070347 +vt 0.164004 0.062773 +vt 0.150806 0.070484 +vt 0.159092 0.071281 +vt 0.165602 0.050573 +vt 0.153410 0.049207 +vt 0.170455 0.059048 +vt 0.147728 0.059048 +vt 0.168838 0.078731 +vt 0.175328 0.067488 +vt 0.181819 0.078731 +vt 0.159092 0.078731 +vt 0.142046 0.068889 +vt 0.149326 0.078765 +vt 0.128157 0.126479 +vt 0.136365 0.131218 +vt 0.131452 0.134054 +vt 0.144572 0.126479 +vt 0.136365 0.125545 +vt 0.136365 0.140694 +vt 0.141277 0.134054 +vt 0.152601 0.129338 +vt 0.147728 0.137778 +vt 0.142855 0.146219 +vt 0.159092 0.134862 +vt 0.159092 0.144339 +vt 0.154179 0.141503 +vt 0.167299 0.149078 +vt 0.164004 0.141503 +vt 0.150885 0.149078 +vt 0.159092 0.150012 +vt 0.165582 0.129338 +vt 0.170455 0.137778 +vt 0.175328 0.146219 +vt 0.150885 0.087114 +vt 0.159092 0.091852 +vt 0.154179 0.094688 +vt 0.167299 0.087114 +vt 0.159092 0.086180 +vt 0.159092 0.101329 +vt 0.164004 0.094688 +vt 0.175328 0.089973 +vt 0.170455 0.098413 +vt 0.165582 0.106853 +vt 0.181819 0.095497 +vt 0.181819 0.104974 +vt 0.176907 0.102138 +vt 0.190026 0.109712 +vt 0.186731 0.102138 +vt 0.173612 0.109712 +vt 0.181819 0.110646 +vt 0.188310 0.089973 +vt 0.193183 0.098413 +vt 0.191565 0.118096 +vt 0.198056 0.106853 +vt 0.204546 0.118096 +vt 0.181819 0.118096 +vt 0.172073 0.118096 +vt 0.173612 0.126479 +vt 0.181819 0.131217 +vt 0.176907 0.134054 +vt 0.190026 0.126479 +vt 0.181819 0.125545 +vt 0.181819 0.140694 +vt 0.186731 0.134054 +vt 0.198056 0.129338 +vt 0.193183 0.137778 +vt 0.188310 0.146219 +vt 0.204546 0.134862 +vt 0.204546 0.144339 +vt 0.199634 0.141503 +vt 0.212753 0.149078 +vt 0.209459 0.141503 +vt 0.196339 0.149078 +vt 0.204546 0.150012 +vt 0.211037 0.129338 +vt 0.215910 0.137778 +vt 0.220783 0.146219 +vt 0.173612 0.047749 +vt 0.181819 0.052487 +vt 0.176907 0.055323 +vt 0.190026 0.047749 +vt 0.181819 0.046815 +vt 0.181819 0.061964 +vt 0.186731 0.055323 +vt 0.198036 0.050573 +vt 0.193183 0.059048 +vt 0.188310 0.067488 +vt 0.204467 0.055995 +vt 0.204546 0.065609 +vt 0.199634 0.062773 +vt 0.212832 0.070484 +vt 0.209459 0.062773 +vt 0.196339 0.070347 +vt 0.204546 0.071281 +vt 0.210228 0.049207 +vt 0.215910 0.059048 +vt 0.214312 0.078765 +vt 0.221592 0.068889 +vt 0.227273 0.078731 +vt 0.204546 0.078731 +vt 0.194800 0.078731 +vt 0.196339 0.087114 +vt 0.204546 0.091852 +vt 0.199634 0.094688 +vt 0.212753 0.087114 +vt 0.204546 0.086180 +vt 0.204546 0.101329 +vt 0.209459 0.094688 +vt 0.220763 0.089939 +vt 0.215910 0.098413 +vt 0.211037 0.106853 +vt 0.227195 0.095361 +vt 0.227274 0.104974 +vt 0.222361 0.102138 +vt 0.235559 0.109849 +vt 0.232186 0.102138 +vt 0.219066 0.109712 +vt 0.227274 0.110646 +vt 0.232955 0.088572 +vt 0.238637 0.098413 +vt 0.237039 0.118130 +vt 0.244319 0.108254 +vt 0.250001 0.118096 +vt 0.217528 0.118096 +vt 0.227274 0.118096 +vt 0.219066 0.126479 +vt 0.227274 0.131218 +vt 0.222361 0.134054 +vt 0.235481 0.126479 +vt 0.227274 0.125545 +vt 0.227274 0.140694 +vt 0.232186 0.134054 +vt 0.243490 0.129304 +vt 0.238637 0.137778 +vt 0.233764 0.146219 +vt 0.249922 0.134726 +vt 0.250001 0.144339 +vt 0.245088 0.141503 +vt 0.258287 0.149214 +vt 0.254913 0.141503 +vt 0.241794 0.149078 +vt 0.250001 0.150012 +vt 0.255683 0.127937 +vt 0.261364 0.137778 +vt 0.267046 0.147620 +vn -0.0649 -0.9926 -0.1024 +vn 0.0161 -0.9959 -0.0887 +vn -0.0760 -0.9907 -0.1127 +vn 0.0606 -0.9966 -0.0551 +vn 0.0258 -0.9969 -0.0733 +vn -0.0643 -0.9955 -0.0703 +vn 0.0354 -0.9975 -0.0616 +vn -0.0516 -0.9985 -0.0179 +vn -0.1955 -0.9745 -0.1100 +vn -0.1836 -0.9828 0.0207 +vn -0.2002 -0.9685 -0.1480 +vn 0.0883 -0.9957 -0.0263 +vn 0.0356 -0.9992 -0.0144 +vn 0.0569 -0.9981 0.0226 +vn 0.0560 -0.9978 -0.0339 +vn 0.0127 -0.9994 -0.0306 +vn -0.1910 -0.9746 -0.1165 +vn -0.0404 -0.9990 -0.0202 +vn -0.1662 -0.9859 -0.0163 +vn 0.6104 -0.4432 0.6565 +vn 0.6000 -0.4653 0.6507 +vn 0.6222 -0.4423 0.6459 +vn 0.5809 -0.4960 0.6453 +vn 0.5919 -0.4714 0.6538 +vn 0.6399 -0.4514 0.6218 +vn 0.5996 -0.4805 0.6399 +vn 0.6189 -0.4575 0.6384 +vn 0.6357 -0.4161 0.6502 +vn 0.6456 -0.4354 0.6274 +vn 0.6523 -0.4107 0.6370 +vn 0.5597 -0.5330 0.6345 +vn 0.5830 -0.5119 0.6309 +vn 0.5418 -0.5824 0.6060 +vn 0.6010 -0.4782 0.6403 +vn 0.6967 -0.4082 0.5899 +vn 0.6634 -0.4583 0.5914 +vn 0.7656 -0.3847 0.5155 +vn 0.5986 -0.4963 0.6288 +vn -0.3321 -0.9346 -0.1273 +vn -0.3653 -0.9095 -0.1986 +vn -0.3776 -0.9162 -0.1341 +vn -0.3450 -0.9106 -0.2276 +vn -0.3168 -0.9302 -0.1852 +vn -0.3014 -0.9326 -0.1986 +vn -0.3527 -0.9219 -0.1599 +vn -0.3415 -0.9399 0.0025 +vn -0.3893 -0.9210 -0.0105 +vn -0.2678 -0.9442 -0.1914 +vn -0.3096 -0.9145 -0.2604 +vn -0.3746 -0.9268 -0.0271 +vn -0.3236 -0.9214 -0.2149 +vn -0.3442 -0.9367 -0.0639 +vn -0.3538 -0.9266 0.1274 +vn -0.3937 -0.9012 0.1814 +vn -0.3515 -0.9178 0.1845 +vn -0.3918 -0.9115 0.1252 +vn -0.3948 -0.9107 0.1213 +vn -0.3953 -0.8981 0.1925 +vn -0.3613 -0.9132 0.1884 +vn -0.2270 -0.9647 0.1333 +vn -0.2512 -0.9530 0.1693 +vn -0.3945 -0.9095 0.1309 +vn -0.4031 -0.8924 0.2027 +vn -0.2607 -0.9541 0.1471 +vn -0.3670 -0.9107 0.1893 +vn -0.2554 -0.9605 0.1103 +vn -0.1102 -0.9822 0.1517 +vn -0.0496 -0.9901 0.1315 +vn -0.0252 -0.9904 0.1358 +vn -0.1350 -0.9843 0.1133 +vn -0.1407 -0.9787 0.1496 +vn 0.0201 -0.9937 0.1101 +vn -0.0321 -0.9935 0.1087 +vn -0.0746 -0.9935 0.0855 +vn -0.0178 -0.9937 0.1110 +vn -0.1133 -0.9893 0.0920 +vn -0.0043 -0.9958 0.0916 +vn 0.0309 -0.9958 0.0853 +vn 0.0752 -0.9943 0.0759 +vn 0.1174 -0.9930 0.0092 +vn 0.6665 -0.3774 0.6429 +vn 0.7098 -0.3296 0.6225 +vn 0.7101 -0.3225 0.6258 +vn 0.7340 -0.3637 0.5735 +vn 0.6784 -0.3799 0.6288 +vn 0.7691 -0.2579 0.5848 +vn 0.7616 -0.2987 0.5751 +vn 0.6784 -0.3912 0.6218 +vn 0.7223 -0.3338 0.6056 +vn 0.7986 -0.3229 0.5079 +vn 0.8190 -0.2511 0.5160 +vn 0.7869 -0.2391 0.5689 +vn 0.8374 -0.1732 0.5184 +vn 0.8629 -0.0839 0.4983 +vn -0.0554 -0.2607 0.9638 +vn 0.0123 -0.2183 0.9758 +vn -0.0305 -0.1849 0.9823 +vn 0.0788 -0.2817 0.9562 +vn 0.0063 -0.2866 0.9580 +vn 0.0145 -0.1423 0.9897 +vn 0.0608 -0.1966 0.9786 +vn -0.0582 -0.3354 0.9402 +vn -0.0834 -0.2259 0.9705 +vn -0.0888 -0.3058 0.9479 +vn 0.0003 -0.3587 0.9334 +vn -0.0623 -0.1614 0.9849 +vn 0.1267 -0.2665 0.9555 +vn 0.0775 -0.3757 0.9235 +vn 0.1531 -0.3861 0.9097 +vn 0.0927 -0.1838 0.9785 +vn -0.0307 -0.1162 0.9927 +vn 0.0525 -0.1301 0.9901 +vn -0.0025 -0.0980 0.9952 +vn -0.8841 -0.4398 -0.1575 +vn -0.9073 -0.4056 -0.1108 +vn -0.9169 -0.3759 -0.1344 +vn -0.8733 -0.4805 -0.0804 +vn -0.8738 -0.4704 -0.1227 +vn -0.9300 -0.3504 -0.1111 +vn -0.9124 -0.3990 -0.0910 +vn -0.8353 -0.5235 -0.1680 +vn -0.8980 -0.4130 -0.1517 +vn -0.8509 -0.5006 -0.1590 +vn -0.8233 -0.5506 -0.1381 +vn -0.9220 -0.3611 -0.1394 +vn -0.8687 -0.4919 -0.0582 +vn -0.8086 -0.5823 -0.0840 +vn -0.7822 -0.6227 -0.0187 +vn -0.9132 -0.3974 -0.0897 +vn -0.9353 -0.3330 -0.1193 +vn -0.9361 -0.3363 -0.1027 +vn -0.9464 -0.3097 -0.0911 +vn -0.4447 -0.5474 -0.7089 +vn -0.5018 -0.5327 -0.6814 +vn -0.4747 -0.5048 -0.7209 +vn -0.5260 -0.5700 -0.6311 +vn -0.4910 -0.5659 -0.6623 +vn -0.5090 -0.4713 -0.7203 +vn -0.5264 -0.5228 -0.6705 +vn -0.4294 -0.5746 -0.6967 +vn -0.4028 -0.5235 -0.7508 +vn -0.3661 -0.5571 -0.7453 +vn -0.4443 -0.4748 -0.7597 +vn -0.5380 -0.5803 -0.6113 +vn -0.5259 -0.6118 -0.5908 +vn -0.5441 -0.6484 -0.5324 +vn -0.5314 -0.5213 -0.6678 +vn -0.4842 -0.5911 -0.6450 +vn -0.4816 -0.4160 -0.7714 +vn -0.5250 -0.4476 -0.7238 +vn -0.5106 -0.3435 -0.7881 +vn 0.8276 -0.3842 -0.4092 +vn 0.8223 -0.3521 -0.4470 +vn 0.8352 -0.3281 -0.4414 +vn 0.7797 -0.4201 -0.4641 +vn 0.8067 -0.4084 -0.4271 +vn 0.8307 -0.2985 -0.4700 +vn 0.8115 -0.3418 -0.4739 +vn 0.8012 -0.4534 -0.3904 +vn 0.8221 -0.3652 -0.4367 +vn 0.7875 -0.4328 -0.4387 +vn 0.8351 -0.3194 -0.4477 +vn 0.7492 -0.4323 -0.5018 +vn 0.7367 -0.5156 -0.4375 +vn 0.6538 -0.5704 -0.4971 +vn 0.8020 -0.3340 -0.4951 +vn 0.7827 -0.4804 -0.3956 +vn 0.8326 -0.2844 -0.4753 +vn 0.8238 -0.2703 -0.4982 +vn 0.8224 -0.2326 -0.5192 +vn 0.6909 -0.3970 0.6042 +vn 0.7235 -0.3387 0.6015 +vn 0.6887 -0.3666 0.6255 +vn 0.7775 -0.2597 0.5728 +vn 0.7312 -0.3484 0.5865 +vn 0.6939 -0.2756 0.6652 +vn 0.7459 -0.2596 0.6133 +vn 0.6651 -0.4285 0.6116 +vn 0.6677 -0.3834 0.6381 +vn 0.8227 -0.1379 0.5514 +vn 0.7674 -0.1599 0.6209 +vn 0.6477 -0.2881 0.7053 +vn 0.6945 -0.1568 0.7022 +vn 0.5959 -0.1363 0.7914 +vn -0.1091 -0.1824 0.9771 +vn -0.1141 -0.1247 0.9856 +vn -0.1365 -0.1461 0.9798 +vn -0.0753 -0.0998 0.9921 +vn -0.0871 -0.1434 0.9858 +vn -0.1486 -0.1049 0.9833 +vn -0.1155 -0.0906 0.9891 +vn -0.1192 -0.2230 0.9675 +vn -0.1466 -0.1633 0.9756 +vn -0.0731 -0.0794 0.9941 +vn -0.1152 -0.0751 0.9905 +vn -0.1654 -0.1265 0.9781 +vn -0.1448 -0.0826 0.9860 +vn -0.1642 -0.1039 0.9809 +vn -0.9133 -0.3787 -0.1496 +vn -0.9259 -0.3519 -0.1374 +vn -0.9181 -0.3684 -0.1458 +vn -0.9316 -0.3398 -0.1287 +vn -0.9248 -0.3540 -0.1392 +vn -0.9232 -0.3607 -0.1321 +vn -0.9288 -0.3461 -0.1321 +vn -0.8930 -0.4235 -0.1520 +vn -0.9121 -0.3846 -0.1417 +vn -0.9345 -0.3377 -0.1119 +vn -0.9270 -0.3550 -0.1206 +vn -0.9162 -0.3839 -0.1145 +vn -0.9221 -0.3717 -0.1072 +vn -0.9174 -0.3941 -0.0549 +vn -0.3635 -0.4928 -0.7906 +vn -0.3680 -0.4207 -0.8292 +vn -0.3242 -0.4444 -0.8351 +vn -0.4383 -0.3836 -0.8128 +vn -0.4104 -0.4480 -0.7942 +vn -0.3091 -0.3821 -0.8709 +vn -0.3741 -0.3663 -0.8520 +vn -0.3273 -0.5145 -0.7925 +vn -0.2919 -0.4633 -0.8367 +vn -0.4479 -0.3277 -0.8318 +vn -0.3775 -0.3245 -0.8672 +vn -0.2614 -0.4054 -0.8759 +vn -0.3073 -0.3287 -0.8930 +vn -0.2369 -0.3423 -0.9092 +vn 0.8227 -0.3356 -0.4588 +vn 0.8304 -0.3139 -0.4602 +vn 0.8285 -0.3178 -0.4611 +vn 0.8308 -0.2951 -0.4718 +vn 0.8277 -0.3216 -0.4598 +vn 0.8421 -0.2900 -0.4546 +vn 0.8359 -0.2948 -0.4629 +vn 0.8037 -0.3625 -0.4718 +vn 0.8224 -0.3124 -0.4754 +vn 0.8287 -0.2649 -0.4931 +vn 0.8416 -0.2740 -0.4653 +vn 0.8509 -0.2710 -0.4501 +vn 0.8610 -0.2603 -0.4369 +vn 0.8898 -0.2211 -0.3992 +vn 0.3594 0.3034 0.8825 +vn 0.4380 0.3878 0.8110 +vn 0.3299 0.4072 0.8516 +vn 0.5362 0.3484 0.7688 +vn 0.4790 0.3146 0.8195 +vn 0.3352 0.4915 0.8037 +vn 0.4655 0.4314 0.7728 +vn 0.3946 0.2392 0.8871 +vn 0.2178 0.3072 0.9264 +vn 0.2416 0.2265 0.9435 +vn 0.1941 0.4154 0.8887 +vn 0.5503 0.3699 0.7485 +vn 0.5618 0.2811 0.7780 +vn 0.5873 0.3111 0.7472 +vn 0.4707 0.4456 0.7615 +vn 0.5029 0.2571 0.8252 +vn 0.1704 0.5211 0.8363 +vn 0.3372 0.5366 0.7735 +vn 0.1375 0.6230 0.7700 +vn -0.4399 0.7502 0.4935 +vn -0.3839 0.7818 0.4912 +vn -0.4092 0.7873 0.4611 +vn -0.3539 0.7518 0.5563 +vn -0.3908 0.7513 0.5317 +vn -0.3917 0.7974 0.4590 +vn -0.3662 0.7859 0.4982 +vn -0.4829 0.6929 0.5354 +vn -0.4748 0.7407 0.4752 +vn -0.5565 0.6555 0.5105 +vn -0.4006 0.7069 0.5830 +vn -0.4240 0.7865 0.4490 +vn -0.3460 0.7313 0.5878 +vn -0.3290 0.6851 0.6499 +vn -0.2636 0.6177 0.7409 +vn -0.4122 0.7948 0.4454 +vn -0.4092 0.7798 0.4737 +vn -0.4394 0.7636 0.4731 +vn -0.3850 0.7707 0.5077 +vn -0.5770 0.7084 -0.4064 +vn -0.5475 0.7476 -0.3760 +vn -0.5422 0.7462 -0.3862 +vn -0.5948 0.7207 -0.3559 +vn -0.5863 0.7149 -0.3810 +vn -0.5482 0.7452 -0.3797 +vn -0.5481 0.7499 -0.3703 +vn -0.6448 0.6232 -0.4425 +vn -0.5884 0.6974 -0.4092 +vn -0.6591 0.5817 -0.4766 +vn -0.5586 0.7401 -0.3744 +vn -0.6067 0.7087 -0.3600 +vn -0.6843 0.6462 -0.3378 +vn -0.7229 0.6226 -0.2995 +vn -0.5605 0.7307 -0.3897 +vn -0.6562 0.6471 -0.3881 +vn -0.5829 0.7219 -0.3728 +vn -0.5839 0.7074 -0.3982 +vn -0.6643 0.6368 -0.3914 +vn 0.4407 0.5249 -0.7282 +vn 0.3741 0.5648 -0.7355 +vn 0.4402 0.5638 -0.6988 +vn 0.2985 0.5602 -0.7726 +vn 0.3573 0.5441 -0.7591 +vn 0.4184 0.6072 -0.6754 +vn 0.3469 0.5864 -0.7319 +vn 0.4318 0.5158 -0.7399 +vn 0.5188 0.5101 -0.6860 +vn 0.5247 0.4893 -0.6966 +vn 0.5080 0.5559 -0.6579 +vn 0.2441 0.5611 -0.7909 +vn 0.2495 0.5478 -0.7985 +vn 0.1256 0.5398 -0.8323 +vn 0.3312 0.5929 -0.7340 +vn 0.3425 0.5366 -0.7712 +vn 0.4939 0.6122 -0.6175 +vn 0.4056 0.6384 -0.6541 +vn 0.4737 0.6870 -0.5509 +vn 0.9370 0.2255 -0.2668 +vn 0.8781 0.2945 -0.3771 +vn 0.9123 0.3067 -0.2713 +vn 0.8420 0.2890 -0.4555 +vn 0.8882 0.2417 -0.3906 +vn 0.8361 0.3436 -0.4275 +vn 0.8619 0.4038 -0.3067 +vn 0.9392 0.2182 -0.2649 +vn 0.9725 0.2156 -0.0882 +vn 0.9815 0.1812 -0.0610 +vn 0.9418 0.3214 -0.0986 +vn 0.8099 0.3459 -0.4736 +vn 0.8635 0.2929 -0.4104 +vn 0.8402 0.3850 -0.3818 +vn 0.8030 0.3778 -0.4609 +vn 0.8914 0.2463 -0.3805 +vn 0.8844 0.4587 -0.0859 +vn 0.8180 0.4604 -0.3448 +vn 0.8190 0.5716 -0.0501 +vn 0.0420 0.9870 -0.1549 +vn -0.0028 0.9695 -0.2452 +vn -0.0045 0.9927 -0.1207 +vn 0.0413 0.9556 -0.2916 +vn 0.0236 0.9597 -0.2798 +vn -0.0009 0.9926 -0.1212 +vn 0.0224 0.9687 -0.2469 +vn 0.0587 0.9789 -0.1958 +vn 0.0450 0.9963 0.0734 +vn 0.0992 0.9936 0.0544 +vn 0.0314 0.9498 -0.3113 +vn -0.0077 0.9965 0.0833 +vn 0.1398 0.9608 -0.2392 +vn 0.0660 0.9431 -0.3260 +vn 0.2076 0.9473 -0.2440 +vn 0.1086 0.9698 -0.2181 +vn -0.0133 0.9954 0.0944 +vn 0.0936 0.9890 -0.1147 +vn 0.0861 0.9902 0.1100 +vn 0.4796 0.8629 -0.1593 +vn 0.3491 0.9026 -0.2516 +vn 0.3587 0.9261 -0.1172 +vn 0.3307 0.8591 -0.3906 +vn 0.4318 0.8469 -0.3103 +vn 0.2238 0.9642 -0.1418 +vn 0.2534 0.9198 -0.2995 +vn 0.5298 0.8183 -0.2228 +vn 0.4857 0.8737 0.0252 +vn 0.5467 0.8372 0.0150 +vn 0.4819 0.8022 -0.3524 +vn 0.3579 0.9332 0.0316 +vn 0.2338 0.8816 -0.4100 +vn 0.4123 0.8067 -0.4233 +vn 0.3259 0.8383 -0.4370 +vn 0.1741 0.9263 -0.3341 +vn 0.2118 0.9765 0.0388 +vn 0.1364 0.9720 -0.1913 +vn 0.7284 0.6353 -0.2563 +vn 0.6196 0.6900 -0.3742 +vn 0.6452 0.7318 -0.2193 +vn 0.6115 0.6283 -0.4810 +vn 0.6645 0.6140 -0.4258 +vn 0.5678 0.7868 -0.2420 +vn 0.5714 0.7132 -0.4059 +vn 0.7655 0.5543 -0.3268 +vn 0.7485 0.6628 -0.0185 +vn 0.6540 0.7564 -0.0038 +vn 0.6011 0.6467 -0.4695 +vn 0.6632 0.5548 -0.5024 +vn 0.6595 0.5915 -0.4638 +vn 0.5729 0.7106 -0.4084 +vn 0.6991 0.5427 -0.4655 +vn 0.5716 0.8205 0.0048 +vn 0.5611 0.7844 -0.2640 +vn 0.0752 0.9536 -0.2914 +vn 0.0644 0.9236 -0.3777 +vn 0.0378 0.9374 -0.3461 +vn 0.1262 0.9030 -0.4107 +vn 0.1049 0.9259 -0.3628 +vn 0.0503 0.9267 -0.3725 +vn 0.0717 0.9109 -0.4063 +vn 0.1556 0.8980 -0.4115 +vn 0.1223 0.9302 -0.3461 +vn 0.0930 0.9166 -0.3888 +vn 0.1518 0.9101 -0.3855 +vn 0.1379 0.9304 -0.3395 +vn 0.1160 0.9257 -0.3600 +vn 0.2200 0.9189 -0.3273 +vn 0.1659 0.9163 -0.3646 +vn 0.1776 0.9264 -0.3319 +vn 0.1958 0.9322 -0.3045 +vn 0.2558 0.8695 -0.4224 +vn 0.2340 0.8796 -0.4141 +vn 0.3242 0.9047 -0.2765 +vn 0.2727 0.8794 -0.3902 +vn 0.3706 0.8639 -0.3410 +vn 0.3026 0.9194 -0.2512 +vn 0.2769 0.9259 -0.2569 +vn 0.5545 0.7593 -0.3405 +vn 0.5570 0.7132 -0.4255 +vn 0.5251 0.7536 -0.3953 +vn 0.5838 0.6726 -0.4547 +vn 0.5737 0.7070 -0.4135 +vn 0.4972 0.7464 -0.4424 +vn 0.5518 0.6986 -0.4553 +vn 0.6025 0.6564 -0.4540 +vn 0.5571 0.6978 -0.4502 +vn 0.4819 0.7532 -0.4477 +vn 0.6028 0.6660 -0.4394 +vn 0.5628 0.6971 -0.4442 +vn 0.5637 0.6998 -0.4388 +vn 0.5457 0.6882 -0.4781 +vn 0.5880 0.6701 -0.4530 +vn 0.5042 0.7399 -0.4453 +vn 0.5181 0.7189 -0.4633 +vn 0.6403 0.6312 -0.4377 +vn 0.6099 0.6513 -0.4515 +vn 0.4955 0.7189 -0.4875 +vn 0.5754 0.6645 -0.4768 +vn 0.5474 0.6836 -0.4826 +vn 0.4590 0.7499 -0.4764 +vn 0.4114 0.7911 -0.4527 +vn 0.3456 0.8235 -0.4499 +vn 0.3557 0.7949 -0.4915 +vn 0.3001 0.8365 -0.4583 +vn 0.4221 0.7625 -0.4903 +vn 0.3994 0.7783 -0.4845 +vn 0.3138 0.8337 -0.4544 +vn 0.3670 0.7950 -0.4830 +vn 0.4556 0.7618 -0.4604 +vn 0.3953 0.8060 -0.4406 +vn 0.3643 0.8373 -0.4077 +vn 0.4707 0.7765 -0.4189 +vn 0.4274 0.8154 -0.3904 +vn 0.4193 0.8152 -0.3995 +vn 0.4517 0.7802 -0.4327 +vn 0.4700 0.7763 -0.4200 +vn 0.3982 0.8317 -0.3868 +vn 0.4145 0.8236 -0.3871 +vn 0.5451 0.7057 -0.4526 +vn 0.5289 0.7126 -0.4610 +vn 0.4418 0.7776 -0.4473 +vn 0.5077 0.7071 -0.4921 +vn 0.4182 0.8248 -0.3804 +vn 0.4010 0.8419 -0.3610 +vn 0.7689 0.4656 -0.4382 +vn 0.7444 0.4262 -0.5140 +vn 0.7262 0.4751 -0.4968 +vn 0.7732 0.3904 -0.4997 +vn 0.7717 0.4041 -0.4910 +vn 0.7124 0.4773 -0.5145 +vn 0.7443 0.4250 -0.5152 +vn 0.7910 0.4239 -0.4411 +vn 0.7659 0.4476 -0.4615 +vn 0.7301 0.4996 -0.4663 +vn 0.7942 0.4739 -0.3803 +vn 0.7917 0.4937 -0.3598 +vn 0.7862 0.4757 -0.3944 +vn 0.7742 0.5131 -0.3706 +vn 0.7977 0.4931 -0.3472 +vn 0.7613 0.5067 -0.4044 +vn 0.7710 0.5144 -0.3754 +vn 0.8151 0.4699 -0.3388 +vn 0.7324 0.5356 -0.4204 +vn 0.7689 0.5189 -0.3734 +vn 0.7157 0.5231 -0.4626 +vn 0.7313 0.5499 -0.4034 +vn 0.7976 0.5061 -0.3280 +vn 0.7110 0.5664 -0.4168 +vn 0.6704 0.6111 -0.4207 +vn 0.6505 0.6071 -0.4563 +vn 0.6300 0.6335 -0.4491 +vn 0.6870 0.5617 -0.4610 +vn 0.6912 0.5816 -0.4290 +vn 0.6070 0.6319 -0.4820 +vn 0.6403 0.5974 -0.4828 +vn 0.6713 0.5524 -0.4941 +vn 0.6318 0.5868 -0.5063 +vn 0.5986 0.6236 -0.5027 +vn 0.6478 0.5435 -0.5338 +vn 0.6204 0.5576 -0.5514 +vn 0.6250 0.5717 -0.5314 +vn 0.6262 0.5344 -0.5677 +vn 0.6321 0.5346 -0.5609 +vn 0.6107 0.5907 -0.5273 +vn 0.6179 0.5611 -0.5507 +vn 0.6654 0.5210 -0.5346 +vn 0.6397 0.5166 -0.5692 +vn 0.6412 0.5290 -0.5558 +vn 0.6340 0.5101 -0.5812 +vn 0.6500 0.4985 -0.5736 +vn 0.6290 0.5639 -0.5351 +vn 0.6028 0.6158 -0.5073 +vn 0.6096 0.6280 -0.4837 +vn 0.6269 0.5793 -0.5209 +vn 0.5873 0.6382 -0.4978 +vn 0.6459 0.5366 -0.5429 +vn 0.6395 0.5679 -0.5181 +vn 0.5735 0.6269 -0.5273 +vn 0.6259 0.5616 -0.5411 +vn 0.6529 0.5166 -0.5539 +vn 0.5655 0.6126 -0.5522 +vn 0.6276 0.5517 -0.5492 +vn 0.6556 0.5034 -0.5628 +vn 0.6185 0.5214 -0.5878 +vn 0.6273 0.5410 -0.5602 +vn 0.5864 0.4964 -0.6401 +vn 0.6362 0.4917 -0.5945 +vn 0.5693 0.5805 -0.5821 +vn 0.5714 0.5392 -0.6187 +vn 0.6600 0.4859 -0.5730 +vn 0.6424 0.4799 -0.5974 +vn 0.5982 0.4816 -0.6404 +vn 0.2141 0.9618 -0.1704 +vn 0.2353 0.9581 -0.1632 +vn 0.1962 0.9634 -0.1824 +vn 0.2093 0.9706 -0.1189 +vn 0.2553 0.9565 -0.1408 +vn 0.2092 0.9720 -0.1074 +vn 0.1792 0.9757 -0.1259 +vn 0.2739 0.9523 -0.1343 +vn 0.0912 0.9950 -0.0413 +vn 0.1936 0.9793 -0.0584 +vn -0.0129 0.9999 0.0003 +vn 0.1505 0.9878 -0.0391 +vn 0.2800 0.9560 -0.0872 +vn 0.1558 0.9876 0.0162 +vn 0.4027 0.8873 -0.2246 +vn 0.4190 0.8886 -0.1863 +vn 0.3929 0.8966 -0.2040 +vn 0.4019 0.8999 -0.1693 +vn 0.4190 0.8830 -0.2116 +vn 0.3789 0.9030 -0.2024 +vn 0.3776 0.9068 -0.1874 +vn 0.4206 0.8625 -0.2815 +vn 0.3036 0.9320 -0.1976 +vn 0.3119 0.9095 -0.2746 +vn 0.1144 0.9415 -0.3169 +vn 0.3720 0.9174 -0.1413 +vn 0.4101 0.8736 -0.2617 +vn 0.3481 0.9256 -0.1489 +vn 0.4211 0.7856 -0.4532 +vn 0.3872 0.8287 -0.4041 +vn 0.4151 0.8249 -0.3838 +vn 0.3246 0.8176 -0.4755 +vn 0.3692 0.8031 -0.4676 +vn 0.4054 0.8397 -0.3612 +vn 0.3765 0.8367 -0.3977 +vn 0.4129 0.7262 -0.5496 +vn 0.2916 0.8119 -0.5057 +vn 0.2401 0.7719 -0.5886 +vn 0.0992 0.7528 -0.6507 +vn 0.3862 0.8275 -0.4075 +vn 0.3380 0.7568 -0.5594 +vn 0.4139 0.8397 -0.3513 +vn 0.3405 0.9361 -0.0886 +vn 0.3016 0.9513 -0.0642 +vn 0.3001 0.9528 -0.0461 +vn 0.2626 0.9529 -0.1515 +vn 0.3419 0.9336 -0.1068 +vn 0.2126 0.9766 -0.0330 +vn 0.2241 0.9715 -0.0769 +vn 0.1165 0.9708 -0.2096 +vn 0.0982 0.9903 -0.0977 +vn 0.0593 0.9979 -0.0241 +vn -0.0562 0.9683 -0.2435 +vn -0.1817 0.9735 -0.1384 +vn -0.0399 0.9922 -0.1181 +vn -0.3441 0.9236 -0.1690 +vn -0.2269 0.9460 -0.2311 +vn -0.0941 0.9952 -0.0244 +vn -0.2431 0.9672 -0.0737 +vn -0.1028 0.9377 -0.3319 +vn -0.2763 0.9116 -0.3045 +vn -0.4114 0.9029 -0.1245 +vn -0.4292 0.8632 -0.2656 +vn -0.5655 0.7873 -0.2455 +vn -0.2830 0.9583 -0.0397 +vn -0.1579 0.9874 0.0058 +vn 0.4320 0.8372 -0.3353 +vn 0.3738 0.8399 -0.3934 +vn 0.3958 0.8601 -0.3217 +vn 0.2968 0.8152 -0.4973 +vn 0.3967 0.8199 -0.4126 +vn 0.2783 0.8942 -0.3507 +vn 0.2743 0.8535 -0.4430 +vn 0.1322 0.7972 -0.5890 +vn 0.1313 0.8527 -0.5055 +vn 0.1173 0.9052 -0.4085 +vn -0.0354 0.7645 -0.6436 +vn -0.1618 0.7947 -0.5850 +vn -0.0213 0.8306 -0.5564 +vn -0.2993 0.7386 -0.6040 +vn -0.1947 0.7385 -0.6455 +vn -0.0695 0.8756 -0.4780 +vn -0.2183 0.8120 -0.5413 +vn -0.0797 0.7215 -0.6877 +vn -0.2224 0.7027 -0.6758 +vn -0.3817 0.7309 -0.5657 +vn -0.3433 0.6889 -0.6384 +vn -0.4946 0.6612 -0.5640 +vn -0.2600 0.8131 -0.5207 +vn -0.1078 0.8905 -0.4420 +vn -0.2058 0.8833 -0.4211 +vn -0.3643 0.8167 -0.4476 +vn -0.3253 0.8692 -0.3724 +vn -0.4356 0.7266 -0.5313 +vn -0.3045 0.8107 -0.5000 +vn -0.4749 0.8086 -0.3473 +vn -0.4881 0.7484 -0.4490 +vn -0.5601 0.6529 -0.5099 +vn -0.5938 0.6730 -0.4409 +vn -0.5983 0.7189 -0.3537 +vn -0.6762 0.5776 -0.4573 +vn -0.7345 0.5387 -0.4126 +vn -0.6857 0.5906 -0.4254 +vn -0.7490 0.5286 -0.3995 +vn -0.7350 0.5333 -0.4187 +vn -0.6989 0.6064 -0.3791 +vn -0.7464 0.5375 -0.3924 +vn -0.6575 0.6000 -0.4556 +vn -0.7239 0.5648 -0.3961 +vn -0.7322 0.5480 -0.4043 +vn -0.7245 0.5741 -0.3814 +vn -0.7414 0.5423 -0.3952 +vn -0.6956 0.6259 -0.3526 +vn 0.3772 0.6620 -0.6476 +vn 0.2778 0.6361 -0.7199 +vn 0.3059 0.7020 -0.6430 +vn 0.2192 0.5666 -0.7943 +vn 0.3169 0.5999 -0.7346 +vn 0.1905 0.7105 -0.6774 +vn 0.1820 0.6238 -0.7600 +vn 0.1084 0.5489 -0.8288 +vn 0.0883 0.6030 -0.7928 +vn 0.0771 0.6824 -0.7269 +vn -0.0037 0.5298 -0.8481 +vn -0.0912 0.5514 -0.8292 +vn -0.0066 0.5766 -0.8170 +vn -0.1818 0.5286 -0.8292 +vn -0.1043 0.5199 -0.8478 +vn -0.0453 0.6297 -0.7754 +vn -0.1364 0.5755 -0.8063 +vn -0.0122 0.5277 -0.8493 +vn -0.1174 0.5204 -0.8458 +vn -0.2425 0.5321 -0.8112 +vn -0.2165 0.5078 -0.8338 +vn -0.3194 0.4750 -0.8199 +vn -0.1729 0.5883 -0.7899 +vn -0.0756 0.6607 -0.7468 +vn -0.1545 0.6610 -0.7342 +vn -0.2586 0.6205 -0.7403 +vn -0.2448 0.6653 -0.7053 +vn -0.2775 0.5516 -0.7866 +vn -0.2108 0.5992 -0.7724 +vn -0.3337 0.6502 -0.6825 +vn -0.3190 0.5944 -0.7381 +vn -0.3297 0.5195 -0.7883 +vn -0.3616 0.5790 -0.7307 +vn -0.4142 0.6352 -0.6518 +vn -0.3816 0.4941 -0.7811 +vn -0.4544 0.5359 -0.7115 +vn -0.3998 0.5647 -0.7220 +vn -0.5474 0.4964 -0.6737 +vn -0.4570 0.4747 -0.7522 +vn -0.4688 0.6183 -0.6308 +vn -0.5297 0.5674 -0.6304 +vn -0.3897 0.4391 -0.8095 +vn -0.4555 0.4276 -0.7808 +vn -0.6144 0.5516 -0.5641 +vn -0.5220 0.4468 -0.7265 +vn -0.5732 0.5143 -0.6379 +vn -0.6051 0.5924 -0.5318 +vn -0.5645 0.6314 -0.5316 +vn -0.6657 0.6129 -0.4257 +vn -0.7062 0.6060 -0.3659 +vn -0.7122 0.5964 -0.3702 +vn -0.6727 0.6018 -0.4305 +vn -0.6728 0.6050 -0.4257 +vn -0.7067 0.6089 -0.3601 +vn -0.6961 0.6192 -0.3633 +vn -0.6289 0.6321 -0.4527 +vn -0.6496 0.6648 -0.3688 +vn -0.6580 0.6602 -0.3622 +vn -0.5895 0.6801 -0.4357 +vn -0.5716 0.7291 -0.3763 +vn -0.5948 0.7121 -0.3729 +vn -0.5953 0.6951 -0.4029 +vn -0.5840 0.6938 -0.4213 +vn -0.5935 0.7183 -0.3629 +vn -0.5704 0.7349 -0.3668 +vn -0.5809 0.5885 -0.5623 +vn -0.6075 0.6113 -0.5071 +vn -0.6422 0.6027 -0.4736 +vn -0.0024 0.9992 0.0401 +vn 0.0350 0.9873 0.1548 +vn 0.0858 0.9946 0.0588 +vn -0.0195 0.9636 0.2665 +vn -0.0484 0.9859 0.1599 +vn 0.1403 0.9797 0.1433 +vn 0.0751 0.9698 0.2319 +vn -0.0884 0.9939 0.0652 +vn -0.1148 0.9794 0.1659 +vn 0.0428 0.9411 0.3354 +vn -0.1005 0.9594 0.2633 +vn -0.0454 0.9396 0.3393 +vn 0.1082 0.9481 0.2991 +vn 0.1218 0.9655 0.2303 +vn -0.4215 0.9052 -0.0532 +vn -0.3493 0.9361 0.0407 +vn -0.3145 0.9492 -0.0075 +vn -0.4067 0.9072 0.1077 +vn -0.4327 0.9009 0.0336 +vn -0.2405 0.9696 0.0444 +vn -0.3114 0.9459 0.0911 +vn -0.5267 0.8438 -0.1023 +vn -0.5047 0.8631 0.0176 +vn -0.3752 0.9163 0.1401 +vn -0.4852 0.8687 0.0992 +vn -0.4561 0.8775 0.1481 +vn -0.2910 0.9504 0.1096 +vn -0.1907 0.9795 0.0649 +vn -0.7239 0.5543 -0.4107 +vn -0.7372 0.5508 -0.3914 +vn -0.7346 0.5462 -0.4025 +vn -0.7280 0.6014 -0.3291 +vn -0.7240 0.5632 -0.3982 +vn -0.7111 0.6094 -0.3507 +vn -0.7299 0.5978 -0.3314 +vn -0.6677 0.6196 -0.4125 +vn -0.7181 0.6680 -0.1951 +vn -0.6787 0.6543 -0.3336 +vn -0.6795 0.7149 -0.1648 +vn -0.6696 0.6216 -0.4064 +vn -0.6536 0.7161 -0.2446 +vn -0.7054 0.6728 -0.2231 +vn -0.1910 0.9763 0.1018 +vn -0.2466 0.9538 0.1717 +vn -0.1821 0.9684 0.1704 +vn -0.3279 0.9290 0.1714 +vn -0.2739 0.9528 0.1309 +vn -0.1895 0.9523 0.2391 +vn -0.2705 0.9387 0.2136 +vn -0.3617 0.9114 0.1962 +vn -0.1889 0.9407 0.2816 +vn -0.2822 0.9298 0.2363 +vn -0.3640 0.9016 0.2335 +vn -0.3093 0.9037 0.2962 +vn -0.2924 0.9207 0.2582 +vn -0.3319 0.8702 0.3641 +vn -0.3630 0.8838 0.2950 +vn -0.2210 0.9259 0.3062 +vn -0.2667 0.8999 0.3450 +vn -0.4232 0.8806 0.2130 +vn -0.4004 0.8691 0.2902 +vn -0.2918 0.8603 0.4180 +vn -0.3806 0.8472 0.3706 +vn -0.3592 0.8185 0.4483 +vn -0.2239 0.8958 0.3838 +vn -0.1446 0.9243 0.3532 +vn -0.6004 0.7905 -0.1207 +vn -0.6263 0.7795 -0.0095 +vn -0.5676 0.8233 0.0010 +vn -0.6921 0.7190 -0.0633 +vn -0.6686 0.7355 -0.1095 +vn -0.5651 0.8220 0.0714 +vn -0.6353 0.7717 0.0294 +vn -0.6687 0.7422 -0.0437 +vn -0.6233 0.7813 0.0332 +vn -0.5568 0.8257 0.0899 +vn -0.6460 0.7633 0.0005 +vn -0.6145 0.7872 0.0516 +vn -0.6127 0.7895 0.0362 +vn -0.6163 0.7796 0.1109 +vn -0.6372 0.7694 0.0436 +vn -0.5664 0.8197 0.0852 +vn -0.5857 0.8039 0.1033 +vn -0.6608 0.7494 -0.0397 +vn -0.6461 0.7627 0.0302 +vn -0.5819 0.7895 0.1950 +vn -0.6271 0.7715 0.1072 +vn -0.5836 0.7774 0.2345 +vn -0.5514 0.8184 0.1614 +vn -0.5101 0.8479 0.1443 +vn -0.4662 0.8604 0.2059 +vn -0.4772 0.8320 0.2830 +vn -0.4337 0.8547 0.2851 +vn -0.5453 0.7923 0.2738 +vn -0.5167 0.8274 0.2198 +vn -0.4299 0.8276 0.3607 +vn -0.4899 0.8040 0.3370 +vn -0.5413 0.7732 0.3304 +vn -0.4938 0.7795 0.3854 +vn -0.4370 0.7954 0.4199 +vn -0.5195 0.7496 0.4100 +vn -0.4985 0.7325 0.4636 +vn -0.4960 0.7525 0.4331 +vn -0.4841 0.7259 0.4886 +vn -0.5029 0.7332 0.4576 +vn -0.4610 0.7584 0.4607 +vn -0.4783 0.7302 0.4878 +vn -0.5249 0.7645 0.3742 +vn -0.4894 0.7491 0.4464 +vn -0.4684 0.7284 0.5000 +vn -0.4669 0.7467 0.4737 +vn -0.4642 0.7306 0.5008 +vn -0.4284 0.7644 0.4819 +vn -0.6016 0.6852 -0.4105 +vn -0.5773 0.7062 -0.4098 +vn -0.6100 0.6772 -0.4114 +vn -0.5976 0.7066 -0.3789 +vn -0.5710 0.7127 -0.4073 +vn -0.6233 0.6912 -0.3656 +vn -0.5976 0.7103 -0.3719 +vn -0.6679 0.6745 -0.3146 +vn -0.6387 0.7081 -0.3011 +vn -0.6467 0.7175 -0.2587 +vn -0.7263 0.6459 -0.2348 +vn -0.7222 0.6760 -0.1468 +vn -0.6831 0.6960 -0.2210 +vn -0.7590 0.6476 -0.0670 +vn -0.7582 0.6364 -0.1419 +vn -0.6667 0.7262 -0.1674 +vn -0.7118 0.6959 -0.0948 +vn -0.7647 0.6047 -0.2225 +vn -0.7888 0.6000 -0.1335 +vn -0.7501 0.6608 -0.0249 +vn -0.8013 0.5959 -0.0535 +vn -0.8089 0.5880 0.0031 +vn -0.7059 0.7059 -0.0587 +vn -0.6733 0.7315 -0.1071 +vn -0.6659 0.7451 -0.0379 +vn -0.6778 0.7350 0.0147 +vn -0.6551 0.7552 0.0187 +vn -0.7210 0.6929 0.0043 +vn -0.6949 0.7186 -0.0234 +vn -0.6514 0.7554 0.0709 +vn -0.6864 0.7260 0.0414 +vn -0.7464 0.6651 0.0230 +vn -0.6900 0.7211 0.0625 +vn -0.6364 0.7607 0.1275 +vn -0.7570 0.6514 0.0510 +vn -0.7052 0.6971 0.1289 +vn -0.6926 0.7166 0.0827 +vn -0.7198 0.6574 0.2229 +vn -0.7592 0.6391 0.1228 +vn -0.6303 0.7593 0.1615 +vn -0.6579 0.7229 0.2110 +vn -0.8133 0.5802 0.0448 +vn -0.8061 0.5807 0.1135 +vn -0.6488 0.6965 0.3064 +vn -0.7797 0.5932 0.2003 +vn -0.7225 0.6310 0.2826 +vn -0.6003 0.7437 0.2941 +vn -0.5740 0.7748 0.2647 +vn -0.5145 0.7740 0.3689 +vn -0.4882 0.7600 0.4290 +vn -0.4765 0.7634 0.4360 +vn -0.5507 0.7386 0.3887 +vn -0.5342 0.7569 0.3764 +vn -0.4614 0.7618 0.4546 +vn -0.4859 0.7576 0.4357 +vn -0.5663 0.7361 0.3707 +vn -0.4784 0.7724 0.4176 +vn -0.4430 0.7780 0.4454 +vn -0.5456 0.7501 0.3736 +vn -0.4702 0.7816 0.4098 +vn -0.4693 0.7880 0.3985 +vn -0.4957 0.7378 0.4582 +vn -0.5273 0.7438 0.4107 +vn -0.4292 0.7968 0.4254 +vn -0.4406 0.7847 0.4360 +vn -0.6587 0.6702 0.3419 +vn -0.6116 0.6761 0.4109 +vn -0.5759 0.6659 0.4742 +vn 0.1214 0.9159 0.3825 +vn 0.1543 0.9061 0.3938 +vn 0.1382 0.9236 0.3577 +vn 0.1314 0.9006 0.4143 +vn 0.1542 0.9012 0.4050 +vn 0.1239 0.9297 0.3469 +vn 0.1289 0.9090 0.3963 +vn 0.1036 0.9182 0.3823 +vn 0.1613 0.9023 0.3997 +vn 0.0580 0.8975 0.4372 +vn 0.1451 0.8986 0.4139 +vn 0.0603 0.8976 0.4366 +vn 0.0529 0.9107 0.4096 +vn 0.0595 0.9474 0.3146 +vn -0.2250 0.8580 0.4617 +vn -0.1274 0.8766 0.4641 +vn -0.1771 0.8893 0.4215 +vn -0.0456 0.8619 0.5050 +vn -0.1442 0.8545 0.4990 +vn -0.0884 0.9160 0.3914 +vn -0.0439 0.8896 0.4547 +vn -0.2532 0.8377 0.4838 +vn -0.1559 0.8448 0.5119 +vn 0.0475 0.8738 0.4839 +vn -0.0606 0.8466 0.5287 +vn 0.0327 0.8504 0.5251 +vn 0.0443 0.8973 0.4391 +vn 0.0146 0.9225 0.3858 +vn -0.4547 0.7247 0.5177 +vn -0.4263 0.7277 0.5372 +vn -0.4504 0.7301 0.5138 +vn -0.3659 0.7390 0.5656 +vn -0.4238 0.7269 0.5403 +vn -0.4076 0.7594 0.5071 +vn -0.3825 0.7479 0.5424 +vn -0.4367 0.7487 0.4986 +vn -0.4086 0.7462 0.5255 +vn -0.2754 0.7540 0.5963 +vn -0.3351 0.7489 0.5717 +vn -0.2002 0.7383 0.6440 +vn -0.3163 0.7726 0.5505 +vn -0.3405 0.7952 0.5016 +vn 0.1171 0.9130 0.3909 +vn 0.1678 0.8978 0.4071 +vn 0.1708 0.9034 0.3932 +vn 0.1312 0.8862 0.4443 +vn 0.1228 0.8992 0.4200 +vn 0.1758 0.8981 0.4031 +vn 0.1744 0.8923 0.4162 +vn 0.1219 0.8850 0.4493 +vn 0.1402 0.9016 0.4091 +vn 0.1599 0.8979 0.4101 +vn 0.1228 0.8917 0.4357 +vn 0.1325 0.9075 0.3986 +vn 0.1431 0.9051 0.4004 +vn 0.1050 0.8957 0.4321 +vn 0.1220 0.8930 0.4332 +vn 0.1187 0.9068 0.4044 +vn 0.1085 0.9094 0.4015 +vn 0.0783 0.8585 0.5069 +vn 0.0981 0.8610 0.4990 +vn 0.0570 0.8958 0.4408 +vn 0.0911 0.8623 0.4982 +vn 0.0604 0.8629 0.5016 +vn 0.0551 0.9087 0.4138 +vn 0.0586 0.9045 0.4223 +vn -0.2541 0.8224 0.5090 +vn -0.1771 0.8145 0.5524 +vn -0.1660 0.8350 0.5246 +vn -0.2025 0.7696 0.6055 +vn -0.2476 0.7938 0.5555 +vn -0.0921 0.8275 0.5538 +vn -0.1301 0.7988 0.5873 +vn -0.1458 0.7549 0.6394 +vn -0.0896 0.7850 0.6130 +vn -0.0372 0.8150 0.5782 +vn -0.0836 0.7354 0.6724 +vn -0.0221 0.7479 0.6634 +vn -0.0531 0.7678 0.6384 +vn 0.0085 0.7197 0.6942 +vn -0.0329 0.7190 0.6942 +vn -0.0110 0.7893 0.6139 +vn 0.0107 0.7557 0.6548 +vn -0.0943 0.7128 0.6949 +vn -0.0354 0.6950 0.7182 +vn 0.0115 0.7301 0.6832 +vn -0.0012 0.6807 0.7326 +vn -0.0227 0.6696 0.7424 +vn 0.0247 0.7660 0.6423 +vn 0.0256 0.8071 0.5898 +vn 0.0482 0.8173 0.5742 +vn 0.0531 0.7880 0.6133 +vn 0.0732 0.8230 0.5632 +vn 0.0221 0.7623 0.6468 +vn 0.0366 0.7784 0.6266 +vn 0.0709 0.8212 0.5662 +vn 0.0415 0.7877 0.6146 +vn -0.0208 0.7485 0.6628 +vn 0.0039 0.7957 0.6056 +vn 0.0361 0.8309 0.5552 +vn -0.0673 0.7491 0.6590 +vn -0.0270 0.7933 0.6082 +vn -0.0320 0.8025 0.5958 +vn 0.0150 0.7407 0.6716 +vn -0.0487 0.7375 0.6735 +vn 0.0114 0.8290 0.5591 +vn 0.0157 0.8053 0.5926 +vn -0.0857 0.6652 0.7417 +vn -0.0733 0.6596 0.7480 +vn 0.0912 0.7416 0.6646 +vn -0.0048 0.6510 0.7591 +vn 0.0615 0.8133 0.5785 +vn 0.0529 0.8459 0.5306 +vn -0.4150 0.7656 0.4916 +vn -0.3893 0.7608 0.5193 +vn -0.3935 0.7643 0.5108 +vn -0.3591 0.7295 0.5822 +vn -0.3989 0.7593 0.5141 +vn -0.3299 0.7604 0.5593 +vn -0.3399 0.7453 0.5736 +vn -0.2851 0.6682 0.6871 +vn -0.2658 0.7117 0.6502 +vn -0.2324 0.7381 0.6334 +vn -0.2112 0.6048 0.7678 +vn -0.1198 0.6243 0.7719 +vn -0.1905 0.6690 0.7184 +vn -0.0614 0.5639 0.8235 +vn -0.1242 0.5650 0.8157 +vn -0.1404 0.6977 0.7025 +vn -0.0786 0.6352 0.7683 +vn -0.1921 0.5451 0.8161 +vn -0.1205 0.5098 0.8517 +vn -0.0365 0.5674 0.8226 +vn -0.0625 0.4949 0.8667 +vn -0.0211 0.4892 0.8719 +vn -0.0642 0.6339 0.7707 +vn -0.1139 0.6930 0.7119 +vn -0.0710 0.6775 0.7321 +vn -0.0325 0.6358 0.7711 +vn -0.0318 0.6687 0.7429 +vn -0.0211 0.5849 0.8108 +vn -0.0509 0.6324 0.7729 +vn 0.0066 0.6430 0.7658 +vn -0.0001 0.6042 0.7968 +vn 0.0066 0.5413 0.8408 +vn 0.0095 0.6070 0.7946 +vn 0.0211 0.5743 0.8183 +vn 0.0345 0.5147 0.8567 +vn 0.0505 0.5197 0.8528 +vn 0.0374 0.5453 0.8374 +vn 0.0316 0.4855 0.8737 +vn 0.0528 0.4956 0.8669 +vn 0.0114 0.5514 0.8341 +vn 0.0203 0.5141 0.8575 +vn 0.0284 0.4814 0.8760 +vn 0.0598 0.4678 0.8818 +vn -0.0374 0.4593 0.8874 +vn 0.0533 0.4418 0.8955 +vn -0.0119 0.3872 0.9219 +vn -0.0429 0.5700 0.8205 +vn -0.0448 0.5058 0.8615 +vn -0.1075 0.5677 0.8161 +vn -0.1175 0.5038 0.8558 +vn -0.1003 0.5707 0.8150 +vn -0.1020 0.4590 0.8825 +vn -0.1079 0.4988 0.8600 +vn -0.0629 0.5548 0.8296 +vn -0.1041 0.4833 0.8693 +vn -0.0977 0.4100 0.9068 +vn -0.0938 0.4607 0.8825 +vn -0.0131 0.5385 0.8425 +vn -0.1046 0.3671 0.9243 +vn -0.0330 0.3882 0.9210 +vn -0.0811 0.4349 0.8968 +vn 0.0710 0.3139 0.9467 +vn -0.0447 0.3254 0.9445 +vn 0.0221 0.4900 0.8714 +vn 0.0641 0.4056 0.9118 +vn -0.0701 0.3267 0.9425 +vn -0.0392 0.2909 0.9559 +vn 0.0681 0.2626 0.9625 +vn -0.0071 0.8942 0.4476 +vn -0.0232 0.9155 0.4016 +vn -0.0081 0.9100 0.4144 +vn 0.0194 0.9529 0.3025 +vn -0.0116 0.9066 0.4217 +vn -0.0221 0.9543 0.2978 +vn -0.0162 0.9579 0.2864 +vn -0.0168 0.8876 0.4603 +vn -0.0243 0.9022 0.4305 +vn 0.0229 0.9485 0.3160 +vn 0.0160 0.8957 0.4442 +vn -0.0119 0.9002 0.4353 +vn 0.0033 0.9040 0.4275 +vn 0.0236 0.8905 0.4544 +vn 0.0083 0.8938 0.4483 +vn 0.0004 0.8975 0.4410 +vn -0.0148 0.8942 0.4474 +vn 0.0449 0.8734 0.4848 +vn 0.0597 0.8780 0.4749 +vn 0.0588 0.8784 0.4743 +vn 0.1230 0.8758 0.4668 +vn 0.2444 0.8473 0.4716 +vn -0.0169 0.8830 0.4691 +vn -0.0135 0.8885 0.4587 +vn 0.1695 0.7485 0.6410 +vn 0.1819 0.8135 0.5523 +vn 0.1120 0.8162 0.5669 +vn 0.2974 0.7756 0.5567 +vn 0.2540 0.7580 0.6008 +vn 0.1046 0.8464 0.5221 +vn 0.1904 0.8294 0.5252 +vn 0.2559 0.6592 0.7071 +vn 0.3443 0.6773 0.6501 +vn 0.3117 0.7703 0.5562 +vn 0.4215 0.6791 0.6010 +vn 0.4904 0.6540 0.5760 +vn 0.1845 0.8236 0.5362 +vn 0.0990 0.8497 0.5178 +vn -0.0417 0.8818 0.4696 +vn -0.0183 0.8875 0.4604 +vn -0.0354 0.8963 0.4420 +vn 0.0502 0.8747 0.4820 +vn -0.0211 0.8748 0.4839 +vn 0.0178 0.9232 0.3837 +vn 0.0372 0.8974 0.4395 +vn 0.1755 0.8661 0.4680 +vn 0.1028 0.9557 0.2759 +vn 0.1270 0.9060 0.4038 +vn 0.2950 0.8475 0.4412 +vn 0.3309 0.8915 0.3092 +vn 0.2250 0.9047 0.3617 +vn 0.4651 0.8595 0.2118 +vn 0.4075 0.8394 0.3597 +vn 0.2052 0.9559 0.2099 +vn 0.3472 0.9206 0.1787 +vn 0.3690 0.8097 0.4563 +vn 0.4510 0.8022 0.3911 +vn 0.5100 0.8195 0.2613 +vn 0.0934 0.8475 0.5224 +vn 0.1755 0.8264 0.5350 +vn 0.1139 0.8584 0.5001 +vn 0.2817 0.7846 0.5523 +vn 0.1745 0.8176 0.5486 +vn 0.1998 0.8567 0.4755 +vn 0.2608 0.8150 0.5175 +vn 0.4136 0.7329 0.5401 +vn 0.3626 0.7874 0.4984 +vn 0.3118 0.8285 0.4651 +vn 0.5063 0.6931 0.5130 +vn 0.5286 0.7234 0.4441 +vn 0.4579 0.7525 0.4733 +vn 0.5925 0.6734 0.4421 +vn 0.5760 0.6699 0.4685 +vn 0.4425 0.7804 0.4417 +vn 0.5304 0.7310 0.4293 +vn 0.5680 0.6265 0.5337 +vn 0.6200 0.6138 0.4887 +vn 0.5761 0.6745 0.4617 +vn 0.6388 0.6080 0.4713 +vn 0.6178 0.6073 0.4995 +vn 0.5208 0.7253 0.4502 +vn 0.4279 0.7806 0.4555 +vn 0.4575 0.7625 0.4574 +vn 0.5193 0.7299 0.4445 +vn 0.4879 0.7644 0.4215 +vn 0.5511 0.6933 0.4644 +vn 0.5145 0.7205 0.4648 +vn 0.5249 0.7685 0.3657 +vn 0.5414 0.7220 0.4306 +vn 0.5687 0.6687 0.4790 +vn 0.5473 0.7243 0.4191 +vn 0.5434 0.7908 0.2817 +vn 0.5817 0.6592 0.4765 +vn 0.6049 0.7055 0.3693 +vn 0.5523 0.7271 0.4077 +vn 0.7109 0.6625 0.2360 +vn 0.6400 0.6499 0.4099 +vn 0.5562 0.7937 0.2463 +vn 0.6349 0.7425 0.2136 +vn 0.6108 0.6090 0.5060 +vn 0.6584 0.6119 0.4382 +vn 0.7418 0.6128 0.2726 +vn 0.3750 0.5539 0.7433 +vn 0.4936 0.4902 0.7183 +vn 0.4301 0.5830 0.6893 +vn 0.5530 0.4025 0.7295 +vn 0.4759 0.4580 0.7508 +vn 0.5110 0.5718 0.6418 +vn 0.5569 0.4643 0.6887 +vn 0.5955 0.3731 0.7114 +vn 0.5909 0.4418 0.6750 +vn 0.5635 0.5372 0.6276 +vn 0.6276 0.3692 0.6854 +vn 0.6525 0.4042 0.6410 +vn 0.6226 0.4202 0.6601 +vn 0.6925 0.3863 0.6093 +vn 0.6644 0.3682 0.6503 +vn 0.6232 0.4774 0.6195 +vn 0.6674 0.4312 0.6071 +vn 0.6261 0.3399 0.7017 +vn 0.6667 0.3537 0.6560 +vn 0.7037 0.4078 0.5818 +vn 0.7020 0.3593 0.6148 +vn 0.7215 0.3585 0.5923 +vn 0.6742 0.4571 0.5800 +vn 0.6158 0.5315 0.5815 +vn 0.6351 0.5440 0.5484 +vn 0.6885 0.4990 0.5262 +vn 0.6603 0.5533 0.5077 +vn 0.7042 0.4463 0.5521 +vn 0.6803 0.4795 0.5543 +vn 0.6794 0.5431 0.4933 +vn 0.7014 0.4869 0.5205 +vn 0.7039 0.4289 0.5661 +vn 0.6892 0.4842 0.5390 +vn 0.6657 0.5373 0.5178 +vn 0.6929 0.4270 0.5810 +vn 0.6831 0.4702 0.5587 +vn 0.6762 0.4806 0.5583 +vn 0.7217 0.4181 0.5516 +vn 0.7070 0.4166 0.5715 +vn 0.6653 0.5114 0.5439 +vn 0.6830 0.4801 0.5504 +vn 0.7179 0.3558 0.5983 +vn 0.7339 0.3503 0.5819 +vn 0.7356 0.4117 0.5379 +vn 0.7671 0.3323 0.5487 +vn 0.8183 0.2883 0.4972 +vn 0.6428 0.5451 0.5382 +vn 0.6785 0.4871 0.5498 +vn 0.6355 0.5607 0.5307 +vn 0.6939 0.5221 0.4958 +vn 0.6735 0.5722 0.4678 +vn 0.7369 0.4356 0.5169 +vn 0.6775 0.4982 0.5410 +vn 0.7396 0.5578 0.3764 +vn 0.7463 0.4872 0.4536 +vn 0.8044 0.3608 0.4719 +vn 0.8062 0.4425 0.3927 +vn 0.8181 0.5256 0.2332 +vn 0.8702 0.2907 0.3976 +vn 0.9191 0.3150 0.2366 +vn 0.8651 0.3863 0.3198 +vn 0.9731 0.2083 0.0977 +vn 0.9342 0.2283 0.2741 +vn 0.9419 0.3234 0.0906 +vn 0.8815 0.4484 0.1479 +vn 0.8829 0.2318 0.4084 +vn 0.9386 0.1907 0.2874 +vn 0.9758 0.1740 0.1326 +vn 0.9329 0.2268 -0.2796 +vn 0.9007 0.2607 -0.3475 +vn 0.9344 0.2183 -0.2816 +vn 0.8863 0.2917 -0.3596 +vn 0.9007 0.2789 -0.3330 +vn 0.9335 0.2275 -0.2771 +vn 0.8937 0.2638 -0.3628 +vn 0.9373 0.2694 -0.2208 +vn 0.9745 0.1402 -0.1752 +vn 0.9794 0.1640 -0.1175 +vn 0.9053 0.3247 -0.2737 +vn 0.9722 0.1544 -0.1757 +vn 0.8823 0.3492 -0.3156 +vn 0.9754 0.1755 -0.1333 +vn 0.9791 0.0882 -0.1831 +vn 0.9682 0.1675 -0.1856 +vn 0.9815 0.1304 -0.1397 +vn 0.9411 0.2285 -0.2490 +vn 0.9624 0.1483 -0.2273 +vn 0.9722 0.1975 -0.1254 +vn 0.9554 0.2312 -0.1835 +vn 0.9724 0.0596 -0.2254 +vn 0.9883 0.0560 -0.1417 +vn 0.9803 0.0042 -0.1975 +vn 0.9557 0.1333 -0.2622 +vn 0.9890 0.1026 -0.1059 +vn 0.9164 0.3069 -0.2569 +vn 0.9265 0.2198 -0.3054 +vn 0.8797 0.3190 -0.3526 +vn 0.9384 0.2889 -0.1896 +vn 0.9850 0.1474 -0.0893 +vn 0.9565 0.2503 -0.1494 +vn 0.9191 -0.1704 -0.3551 +vn 0.9322 -0.1117 -0.3443 +vn 0.9402 -0.1259 -0.3165 +vn 0.9112 -0.0763 -0.4048 +vn 0.9129 -0.1372 -0.3844 +vn 0.9535 -0.0687 -0.2935 +vn 0.9369 -0.0639 -0.3438 +vn 0.8947 -0.2058 -0.3964 +vn 0.9220 -0.1715 -0.3471 +vn 0.9438 -0.1234 -0.3067 +vn 0.9060 -0.0078 -0.4232 +vn 0.8864 -0.0917 -0.4537 +vn 0.8632 0.0157 -0.5045 +vn 0.9388 -0.0173 -0.3440 +vn 0.8941 -0.1612 -0.4178 +vn 0.9631 -0.0649 -0.2612 +vn 0.9618 -0.0139 -0.2732 +vn 0.9272 0.3235 -0.1884 +vn 0.9043 0.3789 -0.1966 +vn 0.9055 0.3665 -0.2138 +vn 0.8987 0.3677 -0.2389 +vn 0.9182 0.3448 -0.1948 +vn 0.8855 0.3976 -0.2402 +vn 0.8856 0.4055 -0.2264 +vn 0.8725 0.3941 -0.2888 +vn 0.8629 0.4352 -0.2568 +vn 0.8560 0.4358 -0.2780 +vn 0.8394 0.4357 -0.3248 +vn 0.8120 0.4927 -0.3128 +vn 0.8388 0.4653 -0.2824 +vn 0.7788 0.5123 -0.3619 +vn 0.8036 0.4798 -0.3520 +vn 0.8269 0.4845 -0.2853 +vn 0.8004 0.5112 -0.3131 +vn 0.8311 0.4005 -0.3858 +vn 0.7885 0.4603 -0.4077 +vn 0.7504 0.5016 -0.4305 +vn 0.9604 0.0406 -0.2756 +vn 0.9343 0.0920 -0.3443 +vn 0.9478 0.1167 -0.2968 +vn 0.9045 0.0569 -0.4225 +vn 0.9383 0.0292 -0.3447 +vn 0.9178 0.1870 -0.3502 +vn 0.9062 0.1333 -0.4012 +vn 0.8688 0.1011 -0.4847 +vn 0.8749 0.1742 -0.4519 +vn 0.8794 0.2444 -0.4086 +vn 0.8282 0.1669 -0.5350 +vn 0.8037 0.2481 -0.5408 +vn 0.8398 0.2138 -0.4990 +vn 0.7616 0.2910 -0.5790 +vn 0.7884 0.2294 -0.5707 +vn 0.8358 0.2781 -0.4733 +vn 0.7908 0.2985 -0.5343 +vn 0.8216 0.1368 -0.5533 +vn 0.7838 0.2199 -0.5807 +vn 0.7412 0.3415 -0.5778 +vn 0.7517 0.2845 -0.5949 +vn 0.7177 0.3537 -0.5998 +vn 0.7791 0.3353 -0.5296 +vn 0.8265 0.3295 -0.4564 +vn 0.8028 0.3815 -0.4582 +vn 0.7504 0.4146 -0.5147 +vn 0.7698 0.4392 -0.4632 +vn 0.7258 0.3850 -0.5701 +vn 0.7663 0.3706 -0.5248 +vn 0.7281 0.4785 -0.4907 +vn 0.7159 0.4369 -0.5446 +vn 0.6995 0.4062 -0.5879 +vn 0.6936 0.4505 -0.5621 +vn 0.6985 0.4917 -0.5199 +vn 0.6727 0.4394 -0.5953 +vn 0.6546 0.4749 -0.5881 +vn 0.6719 0.4640 -0.5772 +vn 0.6372 0.4907 -0.5942 +vn 0.6508 0.4650 -0.6001 +vn 0.6681 0.4958 -0.5548 +vn 0.6452 0.4988 -0.5786 +vn 0.6802 0.4205 -0.6004 +vn 0.6562 0.4595 -0.5985 +vn 0.6457 0.4826 -0.5917 +vn 0.8713 -0.2360 -0.4302 +vn 0.8544 -0.2114 -0.4746 +vn 0.8751 -0.1868 -0.4463 +vn 0.8275 -0.2374 -0.5087 +vn 0.8464 -0.2533 -0.4684 +vn 0.8647 -0.1372 -0.4832 +vn 0.8406 -0.1877 -0.5080 +vn 0.8170 -0.2061 -0.5385 +vn 0.8276 -0.1596 -0.5381 +vn 0.8480 -0.0840 -0.5232 +vn 0.8018 -0.1638 -0.5747 +vn 0.7942 -0.1013 -0.5991 +vn 0.8143 -0.1319 -0.5652 +vn 0.7721 -0.0363 -0.6344 +vn 0.7842 -0.1137 -0.6099 +vn 0.8263 -0.0526 -0.5608 +vn 0.7946 -0.0311 -0.6063 +vn 0.8068 -0.1681 -0.5663 +vn 0.7596 0.0586 -0.6477 +vn 0.7721 -0.0333 -0.6345 +vn 0.7437 0.0766 -0.6641 +vn 0.7891 0.0484 -0.6123 +vn 0.7920 -0.1091 -0.6006 +vn 0.8250 0.0375 -0.5638 +vn 0.8060 0.1335 -0.5766 +vn 0.7681 0.1935 -0.6103 +vn 0.7798 0.2105 -0.5895 +vn 0.7483 0.1447 -0.6474 +vn 0.7789 0.1261 -0.6142 +vn 0.7518 0.2583 -0.6066 +vn 0.7451 0.2174 -0.6305 +vn 0.7366 0.1675 -0.6553 +vn 0.7354 0.2362 -0.6352 +vn 0.7322 0.2938 -0.6144 +vn 0.7198 0.2113 -0.6612 +vn 0.7083 0.2724 -0.6512 +vn 0.7262 0.2544 -0.6386 +vn 0.6753 0.3095 -0.6694 +vn 0.6971 0.2538 -0.6705 +vn 0.7207 0.3106 -0.6198 +vn 0.6970 0.3220 -0.6407 +vn 0.7161 0.1714 -0.6766 +vn 0.6904 0.2364 -0.6836 +vn 0.6633 0.3635 -0.6541 +vn 0.6651 0.2920 -0.6872 +vn 0.6452 0.3442 -0.6821 +vn 0.7032 0.3659 -0.6095 +vn 0.6836 0.3698 -0.6292 +vn 0.6803 0.4193 -0.6011 +vn 0.6583 0.4471 -0.6055 +vn 0.6610 0.4550 -0.5967 +vn 0.6576 0.4155 -0.6284 +vn 0.6695 0.4143 -0.6165 +vn 0.6518 0.4698 -0.5953 +vn 0.6530 0.4519 -0.6077 +vn 0.6566 0.4092 -0.6335 +vn 0.6592 0.4492 -0.6030 +vn 0.6572 0.4740 -0.5860 +vn 0.6553 0.4168 -0.6299 +vn 0.6535 0.4534 -0.6062 +vn 0.6652 0.4463 -0.5985 +vn 0.6168 0.4665 -0.6340 +vn 0.6367 0.4381 -0.6345 +vn 0.6627 0.4700 -0.5830 +vn 0.6461 0.4720 -0.5997 +vn 0.6350 0.3808 -0.6720 +vn 0.6127 0.4198 -0.6695 +vn 0.5737 0.4602 -0.6776 +vn 0.3181 0.4214 -0.8492 +vn 0.3287 0.4992 -0.8017 +vn 0.3869 0.4628 -0.7975 +vn 0.2434 0.5342 -0.8095 +vn 0.2592 0.4815 -0.8372 +vn 0.4136 0.5035 -0.7585 +vn 0.3343 0.5326 -0.7775 +vn 0.2417 0.3917 -0.8878 +vn 0.3825 0.3801 -0.8421 +vn 0.3005 0.3175 -0.8994 +vn 0.1932 0.4651 -0.8639 +vn 0.4368 0.4355 -0.7871 +vn 0.1534 0.5205 -0.8400 +vn 0.4819 0.4749 -0.7363 +vn 0.0044 0.0955 -0.9954 +vn 0.0210 0.2043 -0.9787 +vn 0.0855 0.1682 -0.9820 +vn -0.0840 0.2526 -0.9639 +vn -0.0601 0.1646 -0.9845 +vn 0.1282 0.2543 -0.9586 +vn 0.0286 0.2727 -0.9617 +vn -0.0772 0.0446 -0.9960 +vn 0.0632 0.0563 -0.9964 +vn -0.0235 -0.0361 -0.9991 +vn -0.1305 0.1319 -0.9826 +vn 0.1366 0.1466 -0.9797 +vn -0.0881 0.3163 -0.9445 +vn -0.1837 0.2200 -0.9580 +vn -0.2360 0.2992 -0.9245 +vn 0.0368 0.3197 -0.9468 +vn 0.2106 0.2351 -0.9489 +vn 0.1565 0.3172 -0.9353 +vn -0.2533 -0.2349 -0.9384 +vn -0.2589 -0.1541 -0.9535 +vn -0.2096 -0.1839 -0.9603 +vn -0.3283 -0.1050 -0.9387 +vn -0.3019 -0.1777 -0.9366 +vn -0.1818 -0.1119 -0.9769 +vn -0.2595 -0.0965 -0.9609 +vn -0.2844 -0.2637 -0.9217 +vn -0.2095 -0.2764 -0.9379 +vn -0.1682 -0.2065 -0.9639 +vn -0.3488 -0.0359 -0.9365 +vn -0.3710 -0.1128 -0.9218 +vn -0.4243 -0.0086 -0.9055 +vn -0.2609 -0.0480 -0.9641 +vn -0.3276 -0.1920 -0.9251 +vn -0.1086 -0.1269 -0.9859 +vn -0.1579 -0.0482 -0.9863 +vn 0.1482 0.3759 -0.9147 +vn 0.0535 0.4221 -0.9049 +vn 0.1276 0.4479 -0.8849 +vn -0.0513 0.3833 -0.9222 +vn 0.0454 0.3667 -0.9292 +vn 0.0725 0.4989 -0.8636 +vn -0.0068 0.4515 -0.8922 +vn -0.1312 0.3928 -0.9102 +vn 0.0229 0.5133 -0.8579 +vn -0.0505 0.4656 -0.8835 +vn -0.1799 0.4171 -0.8908 +vn -0.1423 0.4946 -0.8574 +vn -0.0915 0.4766 -0.8743 +vn -0.2279 0.5000 -0.8354 +vn -0.2250 0.4581 -0.8600 +vn -0.0500 0.5150 -0.8557 +vn -0.1307 0.5218 -0.8430 +vn -0.2785 0.3612 -0.8899 +vn -0.3075 0.4157 -0.8559 +vn -0.3216 0.4549 -0.8304 +vn -0.1680 0.0150 -0.9857 +vn -0.2643 0.0657 -0.9622 +vn -0.1968 0.1007 -0.9752 +vn -0.3513 0.0256 -0.9359 +vn -0.2635 -0.0009 -0.9646 +vn -0.2620 0.1716 -0.9496 +vn -0.3292 0.1061 -0.9383 +vn -0.4123 0.0666 -0.9086 +vn -0.3804 0.1382 -0.9144 +vn -0.3256 0.2132 -0.9211 +vn -0.4608 0.1220 -0.8790 +vn -0.4671 0.1921 -0.8630 +vn -0.4283 0.1676 -0.8879 +vn -0.5021 0.2205 -0.8362 +vn -0.4954 0.1713 -0.8516 +vn -0.4016 0.2278 -0.8870 +vn -0.4624 0.2356 -0.8548 +vn -0.4756 0.0961 -0.8744 +vn -0.5026 0.1609 -0.8494 +vn -0.4934 0.2552 -0.8315 +vn -0.5102 0.2042 -0.8354 +vn -0.4968 0.2388 -0.8343 +vn -0.4545 0.2662 -0.8500 +vn -0.3746 0.2787 -0.8843 +vn -0.3759 0.3207 -0.8694 +vn -0.4399 0.3359 -0.8328 +vn -0.3833 0.3723 -0.8452 +vn -0.4807 0.2951 -0.8257 +vn -0.4472 0.2961 -0.8439 +vn -0.4033 0.3984 -0.8238 +vn -0.4576 0.3435 -0.8201 +vn -0.4787 0.2900 -0.8286 +vn -0.4521 0.3372 -0.8257 +vn -0.4040 0.3970 -0.8241 +vn -0.4694 0.2991 -0.8308 +vn -0.4591 0.3394 -0.8210 +vn -0.4467 0.3317 -0.8309 +vn -0.4937 0.3770 -0.7837 +vn -0.4809 0.3248 -0.8144 +vn -0.4219 0.3809 -0.8227 +vn -0.4562 0.3812 -0.8041 +vn -0.4821 0.2720 -0.8328 +vn -0.4881 0.3158 -0.8136 +vn -0.5141 0.3859 -0.7660 +vn -0.3249 -0.2730 -0.9055 +vn -0.3865 -0.2300 -0.8931 +vn -0.3513 -0.2071 -0.9131 +vn -0.4421 -0.2681 -0.8560 +vn -0.3813 -0.2828 -0.8801 +vn -0.3968 -0.1494 -0.9056 +vn -0.4291 -0.2009 -0.8806 +vn -0.4867 -0.2514 -0.8366 +vn -0.4615 -0.1760 -0.8695 +vn -0.4383 -0.0962 -0.8936 +vn -0.5215 -0.2105 -0.8269 +vn -0.5297 -0.1209 -0.8395 +vn -0.4915 -0.1510 -0.8576 +vn -0.5800 -0.0698 -0.8116 +vn -0.5622 -0.1521 -0.8129 +vn -0.4785 -0.0643 -0.8757 +vn -0.5325 -0.0457 -0.8451 +vn -0.5466 -0.2581 -0.7966 +vn -0.5797 -0.1815 -0.7944 +vn -0.5728 0.0081 -0.8196 +vn -0.6001 -0.1072 -0.7927 +vn -0.5959 -0.0288 -0.8025 +vn -0.5317 0.0218 -0.8466 +vn -0.4811 0.0168 -0.8765 +vn -0.4969 0.0949 -0.8626 +vn -0.5270 0.1364 -0.8388 +vn -0.5094 0.1516 -0.8470 +vn -0.5554 0.0888 -0.8268 +vn -0.5295 0.0865 -0.8439 +vn -0.5196 0.1791 -0.8354 +vn -0.5377 0.1462 -0.8303 +vn -0.5575 0.0819 -0.8261 +vn -0.5308 0.1463 -0.8347 +vn -0.5126 0.1907 -0.8372 +vn -0.5503 0.1011 -0.8288 +vn -0.5329 0.1543 -0.8319 +vn -0.5231 0.1463 -0.8396 +vn -0.5693 0.1741 -0.8035 +vn -0.5611 0.1310 -0.8173 +vn -0.5087 0.1869 -0.8404 +vn -0.5296 0.1880 -0.8271 +vn -0.5845 0.0413 -0.8103 +vn -0.5932 0.1007 -0.7987 +vn -0.5746 0.2089 -0.7913 +vn -0.6146 0.1548 -0.7735 +vn -0.6461 0.2089 -0.7341 +vn -0.5257 0.2134 -0.8234 +vn -0.4986 0.2222 -0.8379 +vn -0.4890 0.2545 -0.8343 +vn -0.5161 0.2832 -0.8083 +vn -0.4938 0.3031 -0.8150 +vn -0.5631 0.2490 -0.7880 +vn -0.5206 0.2398 -0.8194 +vn -0.5184 0.3540 -0.7784 +vn -0.5438 0.3050 -0.7818 +vn -0.6077 0.2661 -0.7483 +vn -0.5736 0.3390 -0.7457 +vn -0.5521 0.4298 -0.7145 +vn -0.6475 0.3094 -0.6965 +vn -0.6449 0.4152 -0.6416 +vn -0.6024 0.3760 -0.7040 +vn -0.6771 0.4920 -0.5472 +vn -0.6788 0.3817 -0.6273 +vn -0.5741 0.4890 -0.6567 +vn -0.6270 0.5155 -0.5840 +vn -0.6786 0.2769 -0.6803 +vn -0.6993 0.3598 -0.6176 +vn -0.6958 0.4620 -0.5499 +vn -0.8265 0.3706 -0.4236 +vn -0.7804 0.4738 -0.4079 +vn -0.7791 0.4303 -0.4559 +vn -0.7625 0.5523 -0.3369 +vn -0.8145 0.4487 -0.3677 +vn -0.7089 0.5285 -0.4670 +vn -0.7261 0.5613 -0.3970 +vn -0.8545 0.3331 -0.3984 +vn -0.8229 0.3098 -0.4762 +vn -0.8630 0.2287 -0.4504 +vn -0.8317 0.4294 -0.3520 +vn -0.7738 0.3889 -0.4999 +vn -0.7903 0.5267 -0.3130 +vn -0.7175 0.4807 -0.5040 +vn -0.9605 -0.0010 -0.2782 +vn -0.9506 0.1015 -0.2933 +vn -0.9377 0.0692 -0.3403 +vn -0.9648 0.1587 -0.2098 +vn -0.9706 0.0649 -0.2315 +vn -0.9154 0.1582 -0.3701 +vn -0.9385 0.1780 -0.2957 +vn -0.9757 -0.0643 -0.2094 +vn -0.9507 -0.0321 -0.3085 +vn -0.9673 -0.1419 -0.2102 +vn -0.9832 0.0275 -0.1803 +vn -0.9281 0.0520 -0.3686 +vn -0.9472 0.2471 -0.2044 +vn -0.9817 0.1252 -0.1436 +vn -0.9647 0.2399 -0.1086 +vn -0.9225 0.2467 -0.2967 +vn -0.8999 0.1362 -0.4141 +vn -0.8943 0.2399 -0.3778 +vn -0.9254 -0.3761 -0.0465 +vn -0.9344 -0.3515 -0.0568 +vn -0.9343 -0.3522 -0.0552 +vn -0.9514 -0.3053 -0.0399 +vn -0.9310 -0.3616 -0.0488 +vn -0.9519 -0.2942 -0.0851 +vn -0.9522 -0.2989 -0.0629 +vn -0.9219 -0.3814 -0.0677 +vn -0.9257 -0.3777 -0.0204 +vn -0.9302 -0.3606 -0.0685 +vn -0.9399 -0.3396 -0.0345 +vn -0.9775 -0.2091 -0.0260 +vn -0.9524 -0.3002 -0.0520 +vn -0.9850 -0.1723 -0.0119 +vn -0.9733 -0.2183 -0.0712 +vn -0.9590 -0.2673 -0.0945 +vn -0.9711 -0.1994 -0.1308 +vn -0.8740 0.3235 -0.3625 +vn -0.8737 0.3875 -0.2941 +vn -0.8484 0.4106 -0.3341 +vn -0.9158 0.3363 -0.2193 +vn -0.9018 0.3144 -0.2965 +vn -0.8306 0.4782 -0.2853 +vn -0.8731 0.4219 -0.2442 +vn -0.9185 0.3601 -0.1629 +vn -0.8689 0.4488 -0.2085 +vn -0.8116 0.5282 -0.2495 +vn -0.9030 0.4125 -0.1197 +vn -0.8557 0.5022 -0.1249 +vn -0.8632 0.4745 -0.1721 +vn -0.8390 0.5415 -0.0531 +vn -0.8785 0.4724 -0.0716 +vn -0.8141 0.5449 -0.2005 +vn -0.8198 0.5584 -0.1266 +vn -0.9319 0.3557 -0.0707 +vn -0.8958 0.4430 -0.0351 +vn -0.8574 0.5146 -0.0092 +vn -0.9824 -0.1110 -0.1500 +vn -0.9957 -0.0482 -0.0790 +vn -0.9911 -0.0111 -0.1327 +vn -0.9936 -0.1114 -0.0154 +vn -0.9876 -0.1368 -0.0767 +vn -0.9944 0.0597 -0.0876 +vn -0.9993 -0.0140 -0.0353 +vn -0.9973 -0.0732 0.0053 +vn -0.9998 0.0154 -0.0132 +vn -0.9922 0.1128 -0.0526 +vn -0.9994 -0.0099 0.0336 +vn -0.9965 0.0710 0.0434 +vn -0.9990 0.0438 0.0094 +vn -0.9873 0.1330 0.0866 +vn -0.9965 0.0498 0.0667 +vn -0.9913 0.1312 -0.0124 +vn -0.9882 0.1469 0.0439 +vn -0.9985 -0.0454 0.0304 +vn -0.9973 0.0390 0.0620 +vn -0.9694 0.2273 0.0923 +vn -0.9886 0.1220 0.0886 +vn -0.9668 0.2310 0.1092 +vn -0.9728 0.2275 0.0430 +vn -0.9725 0.2312 -0.0265 +vn -0.9446 0.3276 -0.0214 +vn -0.9227 0.3832 0.0414 +vn -0.9105 0.4134 -0.0011 +vn -0.9429 0.3205 0.0904 +vn -0.9507 0.3072 0.0424 +vn -0.8855 0.4637 0.0296 +vn -0.9120 0.4041 0.0700 +vn -0.9370 0.3355 0.0969 +vn -0.9059 0.4173 0.0717 +vn -0.8674 0.4960 0.0394 +vn -0.9197 0.3778 0.1063 +vn -0.8857 0.4523 0.1049 +vn -0.8992 0.4311 0.0747 +vn -0.8458 0.5069 0.1663 +vn -0.8925 0.4298 0.1369 +vn -0.8618 0.5043 0.0545 +vn -0.8498 0.5162 0.1063 +vn -0.9355 0.3304 0.1249 +vn -0.8984 0.4111 0.1540 +vn -0.8402 0.5034 0.2014 +vn -0.9238 -0.3695 -0.1000 +vn -0.9298 -0.3527 -0.1048 +vn -0.9295 -0.3570 -0.0928 +vn -0.9335 -0.3460 -0.0943 +vn -0.9256 -0.3622 -0.1100 +vn -0.9438 -0.3213 -0.0768 +vn -0.9384 -0.3347 -0.0858 +vn -0.9468 -0.3148 -0.0658 +vn -0.9524 -0.3003 -0.0526 +vn -0.9662 -0.2544 -0.0422 +vn -0.9609 -0.2759 -0.0226 +vn -0.9722 -0.2331 0.0201 +vn -0.9637 -0.2662 -0.0209 +vn -0.9843 -0.1679 0.0537 +vn -0.9732 -0.2291 0.0184 +vn -0.9781 -0.2076 -0.0146 +vn -0.9834 -0.1787 0.0320 +vn -0.9642 -0.2608 -0.0468 +vn -0.9919 -0.0881 0.0917 +vn -0.9888 -0.1390 0.0533 +vn -0.9897 -0.0420 0.1368 +vn -0.9923 -0.1127 0.0502 +vn -0.9782 -0.2077 -0.0037 +vn -0.9909 -0.1345 0.0084 +vn -0.9986 -0.0430 0.0317 +vn -0.9973 0.0173 0.0708 +vn -0.9979 0.0305 0.0566 +vn -0.9937 -0.0231 0.1095 +vn -0.9968 -0.0464 0.0652 +vn -0.9924 0.0862 0.0875 +vn -0.9936 0.0449 0.1032 +vn -0.9900 0.0104 0.1403 +vn -0.9894 0.0727 0.1257 +vn -0.9838 0.1397 0.1126 +vn -0.9817 0.0540 0.1823 +vn -0.9730 0.1257 0.1936 +vn -0.9836 0.0984 0.1509 +vn -0.9507 0.1763 0.2552 +vn -0.9682 0.1059 0.2264 +vn -0.9763 0.1652 0.1396 +vn -0.9626 0.1836 0.1989 +vn -0.9787 0.0334 0.2027 +vn -0.9634 0.0973 0.2498 +vn -0.9280 0.2461 0.2798 +vn -0.9376 0.1725 0.3020 +vn -0.8875 0.2716 0.3723 +vn -0.9617 0.2348 0.1411 +vn -0.9496 0.2373 0.2046 +vn -0.9389 0.3112 0.1470 +vn -0.9074 0.3651 0.2080 +vn -0.9041 0.3921 0.1695 +vn -0.9070 0.3148 0.2796 +vn -0.9327 0.2950 0.2073 +vn -0.8604 0.4601 0.2192 +vn -0.8803 0.3976 0.2588 +vn -0.8733 0.3474 0.3416 +vn -0.8470 0.4356 0.3045 +vn -0.7997 0.5332 0.2757 +vn -0.8205 0.4053 0.4031 +vn -0.7524 0.5117 0.4148 +vn -0.8073 0.4742 0.3511 +vn -0.6620 0.5770 0.4783 +vn -0.7487 0.4794 0.4577 +vn -0.7461 0.5796 0.3276 +vn -0.6868 0.5994 0.4111 +vn -0.8193 0.3708 0.4372 +vn -0.7452 0.4626 0.4802 +vn -0.6588 0.5575 0.5051 +vn -0.4634 0.4390 0.7697 +vn -0.4395 0.5708 0.6935 +vn -0.5190 0.5302 0.6705 +vn -0.3223 0.6152 0.7195 +vn -0.3673 0.5166 0.7734 +vn -0.5147 0.6269 0.5848 +vn -0.4162 0.6496 0.6363 +vn -0.3791 0.3717 0.8474 +vn -0.5539 0.3924 0.7342 +vn -0.4790 0.2857 0.8300 +vn -0.3001 0.4631 0.8339 +vn -0.5875 0.4942 0.6407 +vn -0.2557 0.5473 0.7969 +vn -0.5863 0.5835 0.5618 +vn -0.2186 0.0913 0.9715 +vn -0.1979 0.1675 0.9658 +vn -0.2592 0.1370 0.9560 +vn -0.1392 0.2058 0.9686 +vn -0.1611 0.1480 0.9758 +vn -0.2834 0.2059 0.9366 +vn -0.1948 0.2192 0.9560 +vn -0.1957 0.0874 0.9767 +vn -0.2930 0.0495 0.9548 +vn -0.2622 0.0341 0.9644 +vn -0.3313 0.1023 0.9379 +vn -0.1325 0.2574 0.9572 +vn -0.1272 0.1941 0.9727 +vn -0.1186 0.2549 0.9597 +vn -0.1925 0.2616 0.9458 +vn -0.1493 0.1436 0.9783 +vn -0.3912 0.1865 0.9012 +vn -0.3018 0.2687 0.9147 +vn -0.1467 -0.0565 0.9875 +vn -0.1443 -0.0171 0.9894 +vn -0.1647 -0.0325 0.9858 +vn -0.1199 0.0144 0.9927 +vn -0.1284 -0.0284 0.9913 +vn -0.1802 0.0106 0.9836 +vn -0.1458 0.0206 0.9891 +vn -0.1431 -0.0638 0.9876 +vn -0.1646 -0.0797 0.9831 +vn -0.1827 -0.0451 0.9821 +vn -0.1169 0.0630 0.9911 +vn -0.1172 0.0078 0.9931 +vn -0.1090 0.0672 0.9918 +vn -0.1442 0.0589 0.9878 +vn -0.1275 -0.0313 0.9913 +vn -0.2193 -0.0004 0.9756 +vn -0.1869 0.0510 0.9810 +vn -0.2730 0.3325 0.9027 +vn -0.1793 0.3668 0.9128 +vn -0.2349 0.4112 0.8807 +vn -0.1306 0.3132 0.9406 +vn -0.1867 0.3060 0.9335 +vn -0.1900 0.4596 0.8675 +vn -0.1425 0.3855 0.9116 +vn -0.1210 0.3221 0.9389 +vn -0.1396 0.3892 0.9105 +vn -0.1819 0.4793 0.8586 +vn -0.1166 0.3449 0.9314 +vn -0.1205 0.3989 0.9090 +vn -0.1387 0.3897 0.9104 +vn -0.0766 0.4318 0.8987 +vn -0.0961 0.3734 0.9227 +vn -0.1596 0.4584 0.8743 +vn -0.1173 0.4510 0.8847 +vn -0.1106 0.3134 0.9431 +vn -0.0605 0.4176 0.9066 +vn -0.0916 0.3615 0.9278 +vn -0.1661 0.0967 0.9813 +vn -0.1347 0.1333 0.9818 +vn -0.1451 0.1417 0.9792 +vn -0.1142 0.1085 0.9875 +vn -0.1391 0.0971 0.9855 +vn -0.1259 0.1718 0.9770 +vn -0.1173 0.1501 0.9817 +vn -0.1096 0.1214 0.9865 +vn -0.1150 0.1598 0.9804 +vn -0.1195 0.1978 0.9729 +vn -0.1034 0.1459 0.9839 +vn -0.0954 0.1835 0.9784 +vn -0.1123 0.1687 0.9792 +vn -0.0638 0.2155 0.9744 +vn -0.0839 0.1746 0.9810 +vn -0.1151 0.2087 0.9712 +vn -0.0906 0.2176 0.9718 +vn -0.0987 0.1238 0.9874 +vn -0.0778 0.1694 0.9825 +vn -0.0397 0.2621 0.9642 +vn -0.0409 0.2193 0.9748 +vn 0.0225 0.2839 0.9586 +vn -0.0830 0.2539 0.9637 +vn -0.1118 0.2529 0.9610 +vn -0.1060 0.3010 0.9477 +vn -0.0696 0.3347 0.9397 +vn -0.0877 0.3517 0.9320 +vn -0.0302 0.3040 0.9522 +vn -0.0759 0.2908 0.9537 +vn -0.0519 0.3909 0.9189 +vn -0.0339 0.3562 0.9338 +vn 0.0153 0.3274 0.9447 +vn 0.0011 0.3769 0.9262 +vn -0.0116 0.4268 0.9043 +vn 0.0603 0.3572 0.9321 +vn 0.0670 0.4071 0.9109 +vn 0.0377 0.3949 0.9179 +vn 0.0895 0.4170 0.9044 +vn 0.0906 0.3838 0.9189 +vn 0.0289 0.4402 0.8974 +vn 0.0678 0.4413 0.8948 +vn 0.0813 0.3357 0.9384 +vn 0.1017 0.3638 0.9259 +vn 0.0785 0.3783 0.9223 +vn -0.1355 -0.0593 0.9890 +vn -0.1171 -0.0419 0.9922 +vn -0.1280 -0.0334 0.9912 +vn -0.0902 -0.0591 0.9941 +vn -0.1159 -0.0608 0.9914 +vn -0.1162 -0.0120 0.9931 +vn -0.1039 -0.0322 0.9940 +vn -0.0586 -0.0638 0.9962 +vn -0.0923 -0.0263 0.9954 +vn -0.1075 0.0139 0.9941 +vn -0.0348 -0.0607 0.9975 +vn -0.0450 -0.0035 0.9990 +vn -0.0776 -0.0204 0.9968 +vn 0.0203 0.0226 0.9995 +vn 0.0005 -0.0291 0.9996 +vn -0.0916 0.0278 0.9954 +vn -0.0446 0.0370 0.9983 +vn 0.0203 -0.0891 0.9958 +vn 0.0509 -0.0540 0.9972 +vn 0.0333 0.0675 0.9971 +vn 0.0915 -0.0013 0.9958 +vn 0.1448 0.0618 0.9875 +vn -0.0434 0.0706 0.9966 +vn -0.0921 0.0709 0.9932 +vn -0.0867 0.1149 0.9896 +vn -0.0415 0.1459 0.9884 +vn -0.0699 0.1634 0.9841 +vn 0.0214 0.1142 0.9932 +vn -0.0430 0.1044 0.9936 +vn -0.0263 0.2059 0.9782 +vn 0.0037 0.1689 0.9856 +vn 0.0922 0.1317 0.9870 +vn 0.0547 0.1932 0.9796 +vn 0.0302 0.2451 0.9690 +vn 0.1499 0.1658 0.9747 +vn 0.1524 0.2391 0.9589 +vn 0.1054 0.2174 0.9703 +vn 0.2033 0.2534 0.9457 +vn 0.1960 0.2080 0.9583 +vn 0.0905 0.2718 0.9581 +vn 0.1520 0.2806 0.9477 +vn 0.2000 0.1272 0.9715 +vn 0.2343 0.1788 0.9556 +vn 0.1720 0.2676 0.9480 +vn 0.2427 0.2067 0.9478 +vn 0.2000 0.1797 0.9631 +vn 0.1444 0.3012 0.9426 +vn 0.0948 0.3043 0.9478 +vn 0.1142 0.3310 0.9367 +vn 0.1299 0.3312 0.9346 +vn 0.1169 0.3443 0.9315 +vn 0.1254 0.3004 0.9455 +vn 0.1359 0.3217 0.9370 +vn 0.0919 0.3364 0.9372 +vn 0.1020 0.3163 0.9431 +vn 0.0936 0.2426 0.9656 +vn 0.0432 0.2809 0.9588 +vn 0.0173 0.3157 0.9487 +vn 0.0374 0.1922 0.9806 +vn -0.0256 0.2309 0.9726 +vn -0.0172 0.2420 0.9701 +vn 0.0506 0.2264 0.9727 +vn 0.0383 0.1895 0.9811 +vn -0.0414 0.2768 0.9600 +vn -0.0316 0.2579 0.9656 +vn 0.1361 0.1241 0.9829 +vn 0.1328 0.1323 0.9822 +vn 0.1734 0.1752 0.9691 +vn 0.5102 0.0906 0.8552 +vn 0.5265 0.1539 0.8361 +vn 0.4766 0.1157 0.8714 +vn 0.5624 0.2116 0.7993 +vn 0.5516 0.1461 0.8212 +vn 0.4410 0.1770 0.8799 +vn 0.5170 0.2054 0.8310 +vn 0.5072 0.1041 0.8555 +vn 0.4518 0.0506 0.8907 +vn 0.4581 0.0631 0.8867 +vn 0.5402 0.1594 0.8263 +vn 0.4190 0.0830 0.9042 +vn 0.5655 0.2261 0.7931 +vn 0.3511 0.1467 0.9248 +vn 0.5259 0.0226 0.8502 +vn 0.5278 0.0503 0.8479 +vn 0.5062 0.0356 0.8617 +vn 0.5673 0.0808 0.8195 +vn 0.5490 0.0434 0.8347 +vn 0.4967 0.0620 0.8657 +vn 0.5298 0.0742 0.8448 +vn 0.5419 0.0331 0.8397 +vn 0.5066 0.0184 0.8620 +vn 0.5022 0.0370 0.8639 +vn 0.5703 0.0448 0.8202 +vn 0.4953 0.0313 0.8682 +vn 0.5899 0.1258 0.7976 +vn 0.6104 0.0932 0.7865 +vn 0.6721 0.1663 0.7215 +vn 0.5348 0.1039 0.8386 +vn 0.4767 0.0534 0.8774 +vn 0.4965 0.0867 0.8636 +vn 0.5898 0.0519 0.8058 +vn 0.5921 0.1287 0.7955 +vn 0.5462 0.0960 0.8321 +vn 0.6527 0.1388 0.7448 +vn 0.6338 0.1097 0.7656 +vn 0.5402 0.1138 0.8338 +vn 0.5973 0.1374 0.7902 +vn 0.6444 -0.0047 0.7646 +vn 0.5351 -0.0063 0.8448 +vn 0.6856 0.0871 0.7227 +vn 0.4975 0.0607 0.8654 +vn 0.6767 0.1084 0.7281 +vn 0.7276 0.1335 0.6729 +vn 0.7841 0.1268 0.6076 +vn 0.4859 0.0763 0.8706 +vn 0.5539 0.0763 0.8290 +vn 0.6067 0.0951 0.7892 +vn 0.5119 0.1242 0.8499 +vn 0.5379 0.1700 0.8257 +vn 0.5274 0.1722 0.8320 +vn 0.5885 0.1592 0.7926 +vn 0.5389 0.1324 0.8319 +vn 0.5561 0.2254 0.8000 +vn 0.5721 0.2062 0.7938 +vn 0.6432 0.2016 0.7386 +vn 0.5908 0.2813 0.7561 +vn 0.6112 0.2458 0.7523 +vn 0.6861 0.2461 0.6846 +vn 0.6760 0.3117 0.6677 +vn 0.6469 0.2817 0.7086 +vn 0.7091 0.3342 0.6208 +vn 0.7108 0.2927 0.6396 +vn 0.6270 0.3222 0.7092 +vn 0.6682 0.3420 0.6607 +vn 0.7206 0.2299 0.6540 +vn 0.7382 0.2763 0.6153 +vn 0.7378 0.3135 0.5978 +vn 0.5745 0.0460 0.8172 +vn 0.6178 0.0460 0.7849 +vn 0.5881 0.0506 0.8072 +vn 0.6729 0.0694 0.7364 +vn 0.6132 0.0513 0.7882 +vn 0.6342 0.0929 0.7675 +vn 0.6632 0.0756 0.7446 +vn 0.7496 0.0971 0.6547 +vn 0.7202 0.1107 0.6848 +vn 0.6939 0.1411 0.7061 +vn 0.8039 0.1146 0.5836 +vn 0.8036 0.1718 0.5698 +vn 0.7695 0.1428 0.6225 +vn 0.8347 0.1839 0.5190 +vn 0.8338 0.1501 0.5313 +vn 0.7533 0.1829 0.6316 +vn 0.7991 0.1995 0.5671 +vn 0.8349 0.1214 0.5368 +vn 0.8567 0.1375 0.4971 +vn 0.8243 0.1921 0.5325 +vn 0.8608 0.1512 0.4860 +vn 0.8487 0.1416 0.5095 +vn 0.7955 0.2093 0.5686 +vn 0.7505 0.2023 0.6292 +vn 0.7620 0.2285 0.6059 +vn 0.7860 0.2409 0.5693 +vn 0.7649 0.2581 0.5902 +vn 0.8044 0.2145 0.5540 +vn 0.7913 0.2222 0.5697 +vn 0.7658 0.2745 0.5816 +vn 0.7883 0.2408 0.5662 +vn 0.8080 0.1870 0.5586 +vn 0.7799 0.2289 0.5825 +vn 0.7528 0.2838 0.5939 +vn 0.7996 0.1720 0.5753 +vn 0.7730 0.2228 0.5940 +vn 0.7695 0.2172 0.6005 +vn 0.7937 0.2563 0.5516 +vn 0.8025 0.1924 0.5648 +vn 0.7433 0.2798 0.6076 +vn 0.7570 0.2816 0.5896 +vn 0.8343 0.1294 0.5359 +vn 0.8314 0.1565 0.5331 +vn 0.8303 0.2127 0.5150 +vn 0.7101 -0.0430 0.7027 +vn 0.7837 0.0244 0.6206 +vn 0.7342 0.0628 0.6760 +vn 0.8396 -0.0341 0.5421 +vn 0.7803 -0.0654 0.6220 +vn 0.7793 0.1245 0.6141 +vn 0.8266 0.0661 0.5589 +vn 0.8715 0.0169 0.4900 +vn 0.8542 0.0934 0.5115 +vn 0.8231 0.1371 0.5511 +vn 0.8936 0.0818 0.4412 +vn 0.8921 0.1392 0.4299 +vn 0.8774 0.1200 0.4645 +vn 0.9069 0.1452 0.3954 +vn 0.9055 0.1233 0.4061 +vn 0.8653 0.1486 0.4787 +vn 0.8896 0.1544 0.4297 +vn 0.9020 0.0489 0.4288 +vn 0.9141 0.1124 0.3895 +vn 0.9074 0.1287 0.4001 +vn 0.9205 0.1341 0.3670 +vn 0.9264 0.1040 0.3617 +vn 0.8903 0.1387 0.4336 +vn 0.8598 0.1385 0.4915 +vn 0.8727 0.1226 0.4726 +vn 0.8920 0.1135 0.4375 +vn 0.8785 0.1245 0.4612 +vn 0.9013 0.1126 0.4183 +vn 0.8917 0.1205 0.4362 +vn 0.8831 0.1258 0.4519 +vn 0.8960 0.1115 0.4299 +vn 0.9095 0.0920 0.4054 +vn 0.8965 0.0950 0.4328 +vn 0.8808 0.1083 0.4609 +vn 0.9109 0.0624 0.4079 +vn 0.9008 0.0710 0.4283 +vn 0.8968 0.0761 0.4359 +vn 0.9180 0.0583 0.3923 +vn 0.9158 0.0553 0.3978 +vn 0.8881 0.0819 0.4523 +vn 0.8990 0.0686 0.4324 +vn 0.9291 0.0551 0.3656 +vn 0.9337 0.0414 0.3555 +vn 0.9210 0.0488 0.3865 +vn 0.9435 0.0437 0.3284 +vn 0.9592 0.0348 0.2805 +vn 0.8946 0.0634 0.4423 +vn 0.8729 0.0894 0.4797 +vn 0.8617 0.0874 0.4998 +vn 0.8844 0.0862 0.4586 +vn 0.8590 0.1185 0.4980 +vn 0.9111 0.0591 0.4078 +vn 0.8888 0.0617 0.4541 +vn 0.8694 0.1496 0.4710 +vn 0.8979 0.0947 0.4298 +vn 0.9345 0.0511 0.3522 +vn 0.8788 0.1725 0.4449 +vn 0.9102 0.0993 0.4020 +vn 0.9522 0.0490 0.3013 +vn 0.9458 0.1214 0.3011 +vn 0.9244 0.1034 0.3670 +vn 0.9725 0.1380 0.1875 +vn 0.9695 0.0865 0.2293 +vn 0.9062 0.1658 0.3889 +vn 0.9421 0.1628 0.2930 +vn 0.9733 0.0280 0.2279 +vn 0.9839 0.0700 0.1643 +vn 0.9894 0.1243 0.0746 +vn 0.6011 0.3553 -0.7158 +vn 0.5413 0.3808 -0.7496 +vn 0.5819 0.4013 -0.7073 +vn 0.4695 0.3584 -0.8069 +vn 0.5431 0.3436 -0.7661 +vn 0.5345 0.4483 -0.7165 +vn 0.4936 0.4061 -0.7690 +vn 0.6026 0.3298 -0.7266 +vn 0.5385 0.3264 -0.7768 +vn 0.4451 0.3233 -0.8350 +vn 0.7001 0.1580 -0.6963 +vn 0.6564 0.1970 -0.7282 +vn 0.6811 0.2206 -0.6981 +vn 0.6097 0.1492 -0.7784 +vn 0.6596 0.1446 -0.7375 +vn 0.6510 0.2626 -0.7122 +vn 0.6273 0.2158 -0.7483 +vn 0.7128 0.0934 -0.6951 +vn 0.6595 0.0946 -0.7457 +vn 0.5603 0.1454 -0.8154 +vn 0.5858 0.0782 -0.8066 +vn 0.4784 0.0375 -0.8773 +vn 0.6045 0.2265 -0.7637 +vn 0.6278 0.2868 -0.7236 +vn 0.8065 -0.1595 -0.5693 +vn 0.7845 -0.1218 -0.6080 +vn 0.7972 -0.1072 -0.5941 +vn 0.7401 -0.1636 -0.6523 +vn 0.7828 -0.1668 -0.5995 +vn 0.7743 -0.0581 -0.6301 +vn 0.7592 -0.0986 -0.6433 +vn 0.8126 -0.2055 -0.5453 +vn 0.6878 -0.1640 -0.7071 +vn 0.7124 -0.2294 -0.6631 +vn 0.6022 -0.2815 -0.7470 +vn 0.7322 -0.0772 -0.6766 +vn 0.7787 -0.2055 -0.5927 +vn 0.7488 -0.0046 -0.6627 +vn 0.5946 0.2957 -0.7477 +vn 0.5381 0.2623 -0.8010 +vn 0.5355 0.3078 -0.7864 +vn 0.5262 0.1698 -0.8332 +vn 0.5791 0.2388 -0.7794 +vn 0.4543 0.2902 -0.8422 +vn 0.4790 0.2262 -0.8481 +vn 0.4489 0.1050 -0.8874 +vn 0.3580 0.2578 -0.8974 +vn 0.4083 0.1834 -0.8942 +vn 0.3544 0.0560 -0.9334 +vn 0.2513 0.0945 -0.9633 +vn 0.3319 0.1390 -0.9330 +vn 0.1469 0.0404 -0.9883 +vn 0.2463 0.0275 -0.9688 +vn 0.2669 0.2049 -0.9417 +vn 0.1877 0.1272 -0.9739 +vn 0.3522 -0.0000 -0.9359 +vn 0.2371 -0.0152 -0.9713 +vn 0.1181 -0.0237 -0.9927 +vn 0.7180 0.0280 -0.6954 +vn 0.6616 -0.0239 -0.7494 +vn 0.6601 0.0452 -0.7497 +vn 0.6507 -0.1322 -0.7477 +vn 0.7035 -0.0548 -0.7085 +vn 0.5871 0.0156 -0.8094 +vn 0.6068 -0.0692 -0.7918 +vn 0.5794 -0.2022 -0.7895 +vn 0.5468 -0.1165 -0.8291 +vn 0.5101 -0.0336 -0.8595 +vn 0.4964 -0.2554 -0.8296 +vn 0.4101 -0.2128 -0.8868 +vn 0.4828 -0.1639 -0.8603 +vn 0.3137 -0.2785 -0.9077 +vn 0.3998 -0.2894 -0.8697 +vn 0.4317 -0.1006 -0.8963 +vn 0.3571 -0.1828 -0.9160 +vn 0.4863 -0.3292 -0.8094 +vn 0.3854 -0.3514 -0.8532 +vn 0.2488 -0.2628 -0.9322 +vn 0.2838 -0.3618 -0.8880 +vn 0.1651 -0.3699 -0.9143 +vn 0.3182 -0.1660 -0.9333 +vn 0.3885 -0.0712 -0.9187 +vn 0.3179 -0.0668 -0.9457 +vn 0.2220 -0.1199 -0.9676 +vn 0.2279 -0.0577 -0.9720 +vn 0.2023 -0.2231 -0.9536 +vn 0.2774 -0.1491 -0.9491 +vn 0.1245 -0.0799 -0.9890 +vn 0.1466 -0.1604 -0.9761 +vn 0.1216 -0.2804 -0.9521 +vn 0.0758 -0.1960 -0.9777 +vn 0.0276 -0.1134 -0.9932 +vn 0.0275 -0.3120 -0.9497 +vn -0.0698 -0.2651 -0.9617 +vn 0.0044 -0.2300 -0.9732 +vn -0.1571 -0.3048 -0.9394 +vn -0.0738 -0.3273 -0.9420 +vn -0.0548 -0.1645 -0.9848 +vn -0.1276 -0.2300 -0.9648 +vn 0.0331 -0.3754 -0.9262 +vn -0.0761 -0.3717 -0.9252 +vn -0.1636 -0.3604 -0.9183 +vn 0.8124 -0.2500 -0.5267 +vn 0.7663 -0.3064 -0.5647 +vn 0.7744 -0.2445 -0.5835 +vn 0.7340 -0.4092 -0.5420 +vn 0.7909 -0.3240 -0.5191 +vn 0.7064 -0.2861 -0.6474 +vn 0.7108 -0.3615 -0.6033 +vn 0.6530 -0.4976 -0.5709 +vn 0.6409 -0.4249 -0.6393 +vn 0.6209 -0.3507 -0.7010 +vn 0.5622 -0.5623 -0.6064 +vn 0.4839 -0.5398 -0.6888 +vn 0.5641 -0.4859 -0.6676 +vn 0.3899 -0.6013 -0.6973 +vn 0.4629 -0.6036 -0.6492 +vn 0.5278 -0.4344 -0.7299 +vn 0.4418 -0.5195 -0.7313 +vn 0.5426 -0.6231 -0.5633 +vn 0.4439 -0.6507 -0.6160 +vn 0.3492 -0.5926 -0.7258 +vn 0.3579 -0.6637 -0.6568 +vn 0.2825 -0.6705 -0.6859 +vn 0.4181 -0.5097 -0.7519 +vn 0.4985 -0.4104 -0.7636 +vn 0.4432 -0.4152 -0.7944 +vn 0.3549 -0.4801 -0.8021 +vn 0.3696 -0.4133 -0.8322 +vn 0.3256 -0.5644 -0.7585 +vn 0.3938 -0.5002 -0.7711 +vn 0.2821 -0.4372 -0.8539 +vn 0.2911 -0.5157 -0.8057 +vn 0.2652 -0.6082 -0.7482 +vn 0.2405 -0.5429 -0.8046 +vn 0.2074 -0.4641 -0.8611 +vn 0.2013 -0.6299 -0.7501 +vn 0.1272 -0.5939 -0.7944 +vn 0.1897 -0.5680 -0.8008 +vn 0.0381 -0.6214 -0.7825 +vn 0.1181 -0.6414 -0.7580 +vn 0.1403 -0.5097 -0.8488 +vn 0.0732 -0.5621 -0.8238 +vn 0.1985 -0.6748 -0.7108 +vn 0.1129 -0.6719 -0.7319 +vn -0.0258 -0.5886 -0.8079 +vn 0.0272 -0.6600 -0.7508 +vn -0.0630 -0.6359 -0.7692 +vn 0.0854 -0.4622 -0.8826 +vn 0.0231 -0.5319 -0.8465 +vn 0.0068 -0.4373 -0.8993 +vn -0.0837 -0.4681 -0.8797 +vn -0.0795 -0.4157 -0.9060 +vn -0.0802 -0.5422 -0.8364 +vn -0.0278 -0.5023 -0.8643 +vn -0.1521 -0.4184 -0.8954 +vn -0.1316 -0.4847 -0.8647 +vn -0.1146 -0.5597 -0.8207 +vn -0.1570 -0.4921 -0.8562 +vn -0.1940 -0.4232 -0.8850 +vn -0.1612 -0.5572 -0.8146 +vn -0.2214 -0.5123 -0.8298 +vn -0.1819 -0.4995 -0.8470 +vn -0.2842 -0.5318 -0.7977 +vn -0.2235 -0.5532 -0.8025 +vn -0.2224 -0.4483 -0.8657 +vn -0.2613 -0.4845 -0.8348 +vn -0.1473 -0.6085 -0.7797 +vn -0.2259 -0.5861 -0.7780 +vn -0.3003 -0.5685 -0.7659 +vn -0.7150 0.2675 -0.6459 +vn -0.7465 0.3192 -0.5837 +vn -0.7153 0.3446 -0.6079 +vn -0.7992 0.2795 -0.5321 +vn -0.7601 0.2576 -0.5965 +vn -0.7244 0.4119 -0.5527 +vn -0.7654 0.3569 -0.5355 +vn -0.7127 0.2137 -0.6681 +vn -0.7664 0.2180 -0.6041 +vn -0.8170 0.2216 -0.5323 +vn -0.6164 -0.0016 -0.7874 +vn -0.6656 0.0353 -0.7455 +vn -0.6249 0.0701 -0.7775 +vn -0.7174 -0.0170 -0.6964 +vn -0.6678 -0.0284 -0.7437 +vn -0.6556 0.1192 -0.7456 +vn -0.6975 0.0591 -0.7141 +vn -0.6243 -0.0662 -0.7783 +vn -0.6695 -0.0823 -0.7382 +vn -0.7564 0.0031 -0.6541 +vn -0.7218 -0.0849 -0.6868 +vn -0.7836 -0.0757 -0.6166 +vn -0.7241 0.0793 -0.6850 +vn -0.6868 0.1491 -0.7114 +vn -0.5694 -0.2848 -0.7711 +vn -0.6201 -0.2418 -0.7463 +vn -0.5961 -0.2118 -0.7745 +vn -0.6423 -0.3035 -0.7038 +vn -0.6095 -0.3072 -0.7308 +vn -0.6211 -0.1665 -0.7658 +vn -0.6404 -0.2257 -0.7341 +vn -0.5516 -0.3648 -0.7501 +vn -0.6475 -0.3008 -0.7001 +vn -0.6301 -0.3945 -0.6688 +vn -0.6369 -0.4241 -0.6438 +vn -0.6408 -0.2178 -0.7361 +vn -0.5957 -0.3792 -0.7080 +vn -0.6253 -0.1387 -0.7679 +vn -0.7262 0.1665 -0.6670 +vn -0.7787 0.1285 -0.6140 +vn -0.7718 0.1812 -0.6095 +vn -0.7868 0.0421 -0.6157 +vn -0.7492 0.1003 -0.6547 +vn -0.8196 0.1660 -0.5482 +vn -0.8141 0.0979 -0.5723 +vn -0.8199 0.0019 -0.5725 +vn -0.8424 0.0725 -0.5340 +vn -0.8570 0.1442 -0.4947 +vn -0.8591 -0.0175 -0.5115 +vn -0.8974 0.0150 -0.4410 +vn -0.8693 0.0464 -0.4920 +vn -0.9302 -0.0287 -0.3660 +vn -0.8986 -0.0333 -0.4373 +vn -0.8879 0.0990 -0.4491 +vn -0.9162 0.0378 -0.3989 +vn -0.8493 -0.0649 -0.5238 +vn -0.9007 -0.0654 -0.4294 +vn -0.9415 -0.0859 -0.3257 +vn -0.6342 -0.1412 -0.7601 +vn -0.6612 -0.1932 -0.7248 +vn -0.6677 -0.1369 -0.7317 +vn -0.6554 -0.2636 -0.7077 +vn -0.6421 -0.2092 -0.7375 +vn -0.7046 -0.1512 -0.6933 +vn -0.6807 -0.2176 -0.6994 +vn -0.6594 -0.3228 -0.6789 +vn -0.6926 -0.2409 -0.6799 +vn -0.7347 -0.1625 -0.6587 +vn -0.6659 -0.3583 -0.6543 +vn -0.7315 -0.3005 -0.6120 +vn -0.7038 -0.2645 -0.6593 +vn -0.7722 -0.3677 -0.5181 +vn -0.7088 -0.3849 -0.5911 +vn -0.7560 -0.1972 -0.6241 +vn -0.7785 -0.2652 -0.5688 +vn -0.6403 -0.4527 -0.6205 +vn -0.6819 -0.4656 -0.5640 +vn -0.8307 -0.3395 -0.4411 +vn -0.7464 -0.4671 -0.4739 +vn -0.8288 -0.4563 -0.3237 +vn -0.8196 -0.2336 -0.5231 +vn -0.8028 -0.1471 -0.5777 +vn -0.8516 -0.1161 -0.5112 +vn -0.8969 -0.1635 -0.4108 +vn -0.9023 -0.0969 -0.4201 +vn -0.8799 -0.2875 -0.3782 +vn -0.8577 -0.2018 -0.4728 +vn -0.9430 -0.1288 -0.3067 +vn -0.9241 -0.2134 -0.3169 +vn -0.8993 -0.3516 -0.2600 +vn -0.9401 -0.2644 -0.2151 +vn -0.9615 -0.1930 -0.1955 +vn -0.9166 -0.3797 -0.1248 +vn -0.9385 -0.3435 -0.0345 +vn -0.9438 -0.3113 -0.1106 +vn -0.9261 -0.3771 0.0077 +vn -0.9210 -0.3886 -0.0262 +vn -0.9591 -0.2698 -0.0857 +vn -0.9442 -0.3292 -0.0145 +vn -0.8896 -0.4364 -0.1348 +vn -0.9076 -0.4191 -0.0236 +vn -0.9128 -0.4083 0.0023 +vn -0.5417 -0.4477 -0.7114 +vn -0.5594 -0.5075 -0.6553 +vn -0.5801 -0.4454 -0.6819 +vn -0.5458 -0.5708 -0.6133 +vn -0.5353 -0.5196 -0.6659 +vn -0.6139 -0.4718 -0.6329 +vn -0.5799 -0.5382 -0.6116 +vn -0.5556 -0.6147 -0.5598 +vn -0.5877 -0.5676 -0.5766 +vn -0.6166 -0.5116 -0.5984 +vn -0.5624 -0.6462 -0.5159 +vn -0.5994 -0.6278 -0.4966 +vn -0.5940 -0.6014 -0.5343 +vn -0.5905 -0.6716 -0.4474 +vn -0.5821 -0.6644 -0.4686 +vn -0.6100 -0.5751 -0.5451 +vn -0.6036 -0.6244 -0.4957 +vn -0.5489 -0.6824 -0.4827 +vn -0.5773 -0.6876 -0.4404 +vn -0.5730 -0.7210 -0.3895 +vn -0.5562 -0.7587 -0.3390 +vn -0.5912 -0.6268 -0.5076 +vn -0.5650 -0.7018 -0.4339 +vn -0.6108 -0.5495 -0.5699 +vn -0.6080 -0.5501 -0.5725 +vn -0.6093 -0.6124 -0.5036 +vn -0.6470 -0.5442 -0.5340 +vn -0.5778 -0.6785 -0.4536 +vn -0.5821 -0.6271 -0.5175 +vn -0.6876 -0.5614 -0.4604 +vn -0.6229 -0.6404 -0.4493 +vn -0.5724 -0.7234 -0.3860 +vn -0.6316 -0.6659 -0.3970 +vn -0.7227 -0.5780 -0.3789 +vn -0.5686 -0.7538 -0.3293 +vn -0.6446 -0.7128 -0.2764 +vn -0.6367 -0.6899 -0.3443 +vn -0.6576 -0.7325 -0.1759 +vn -0.5931 -0.7651 -0.2507 +vn -0.7276 -0.6168 -0.3001 +vn -0.7125 -0.6657 -0.2217 +vn -0.5381 -0.7924 -0.2872 +vn -0.5563 -0.7968 -0.2357 +vn -0.7444 -0.6571 -0.1188 +vn -0.6059 -0.7723 -0.1908 +vn -0.6916 -0.7013 -0.1726 +vn -0.8121 -0.5409 -0.2190 +vn -0.7847 -0.6019 -0.1479 +vn -0.8678 -0.4859 -0.1037 +vn -0.8716 -0.4899 -0.0148 +vn -0.8933 -0.4490 -0.0195 +vn -0.8267 -0.5602 -0.0522 +vn -0.8396 -0.5385 -0.0714 +vn -0.8966 -0.4427 0.0015 +vn -0.8712 -0.4908 -0.0089 +vn -0.8249 -0.5558 -0.1030 +vn -0.8781 -0.4743 -0.0623 +vn -0.9016 -0.4295 -0.0502 +vn -0.8475 -0.5094 -0.1490 +vn -0.8852 -0.4371 -0.1591 +vn -0.8839 -0.4505 -0.1252 +vn -0.8777 -0.4568 -0.1447 +vn -0.8600 -0.4830 -0.1645 +vn -0.9019 -0.4158 -0.1169 +vn -0.8990 -0.4112 -0.1504 +vn -0.7661 -0.6172 -0.1792 +vn -0.8056 -0.5699 -0.1615 +vn -0.8325 -0.5346 -0.1451 +vn -0.7890 0.3677 0.4922 +vn -0.7148 0.4226 0.5571 +vn -0.7364 0.4502 0.5050 +vn -0.6551 0.3739 0.6565 +vn -0.7379 0.3576 0.5723 +vn -0.6615 0.5225 0.5379 +vn -0.6520 0.4607 0.6022 +vn -0.8254 0.3036 0.4760 +vn -0.7512 0.3157 0.5796 +vn -0.6478 0.3087 0.6964 +vn -0.9677 0.0350 0.2497 +vn -0.9437 0.0672 0.3238 +vn -0.9568 0.0894 0.2767 +vn -0.9081 0.0420 0.4165 +vn -0.9457 0.0296 0.3236 +vn -0.9306 0.1503 0.3338 +vn -0.9174 0.0989 0.3854 +vn -0.9752 0.0012 0.2214 +vn -0.9472 0.0162 0.3201 +vn -0.8474 0.0575 0.5278 +vn -0.8957 0.0152 0.4444 +vn -0.7795 0.0067 0.6263 +vn -0.8804 0.1314 0.4555 +vn -0.8914 0.2071 0.4032 +vn -0.9688 -0.2417 -0.0541 +vn -0.9799 -0.1991 -0.0046 +vn -0.9816 -0.1896 -0.0221 +vn -0.9688 -0.2354 0.0769 +vn -0.9693 -0.2452 -0.0139 +vn -0.9902 -0.1338 0.0398 +vn -0.9839 -0.1679 0.0616 +vn -0.9553 -0.2851 -0.0780 +vn -0.9586 -0.2840 -0.0222 +vn -0.9568 -0.2167 0.1935 +vn -0.9494 -0.3003 0.0921 +vn -0.9033 -0.3301 0.2738 +vn -0.9811 -0.1310 0.1424 +vn -0.9898 -0.0728 0.1224 +vn -0.8384 0.2507 0.4838 +vn -0.7772 0.2091 0.5935 +vn -0.7627 0.2773 0.5843 +vn -0.7881 0.0832 0.6099 +vn -0.8381 0.1629 0.5206 +vn -0.6742 0.2505 0.6948 +vn -0.7175 0.1578 0.6785 +vn -0.7087 0.0414 0.7043 +vn -0.6450 0.1137 0.7556 +vn -0.5694 0.2057 0.7959 +vn -0.5918 0.0100 0.8060 +vn -0.4818 0.0300 0.8757 +vn -0.5579 0.0679 0.8271 +vn -0.3838 0.0160 0.9233 +vn -0.4839 -0.0050 0.8751 +vn -0.4788 0.1447 0.8659 +vn -0.4064 0.0664 0.9113 +vn -0.6140 0.0036 0.7893 +vn -0.4871 0.0078 0.8733 +vn -0.3778 0.0167 0.9257 +vn -0.9778 -0.0228 0.2081 +vn -0.9507 -0.0495 0.3061 +vn -0.9499 0.0029 0.3127 +vn -0.9421 -0.1661 0.2911 +vn -0.9708 -0.0924 0.2215 +vn -0.9074 -0.0140 0.4200 +vn -0.9211 -0.0897 0.3787 +vn -0.8999 -0.2268 0.3725 +vn -0.8813 -0.1255 0.4555 +vn -0.8433 -0.0403 0.5359 +vn -0.8372 -0.2680 0.4765 +vn -0.7706 -0.2063 0.6030 +vn -0.8335 -0.1598 0.5288 +vn -0.6675 -0.2537 0.7000 +vn -0.7550 -0.2908 0.5877 +vn -0.7803 -0.0731 0.6211 +vn -0.7088 -0.1495 0.6894 +vn -0.8240 -0.3526 0.4435 +vn -0.7421 -0.3532 0.5697 +vn -0.5784 -0.1886 0.7936 +vn -0.6510 -0.3286 0.6843 +vn -0.5236 -0.2627 0.8104 +vn -0.6395 -0.1028 0.7618 +vn -0.7033 -0.0319 0.7101 +vn -0.5912 -0.0009 0.8065 +vn -0.4877 -0.0111 0.8730 +vn -0.4882 0.0200 0.8725 +vn -0.4924 -0.1146 0.8628 +vn -0.5611 -0.0564 0.8258 +vn -0.3960 0.0128 0.9181 +vn -0.4213 -0.0399 0.9060 +vn -0.4264 -0.1381 0.8939 +vn -0.3641 -0.0556 0.9297 +vn -0.3151 0.0024 0.9490 +vn -0.3293 -0.1293 0.9353 +vn -0.2480 -0.0868 0.9648 +vn -0.3006 -0.0710 0.9511 +vn -0.1887 -0.1003 0.9769 +vn -0.2491 -0.1224 0.9607 +vn -0.2562 -0.0194 0.9664 +vn -0.2066 -0.0603 0.9766 +vn -0.3659 -0.1879 0.9115 +vn -0.2562 -0.1496 0.9550 +vn -0.1899 -0.1270 0.9735 +vn -0.9412 -0.3254 -0.0913 +vn -0.9237 -0.3806 -0.0437 +vn -0.9458 -0.3231 -0.0325 +vn -0.8802 -0.4731 -0.0379 +vn -0.9155 -0.3933 -0.0850 +vn -0.9303 -0.3617 0.0615 +vn -0.9013 -0.4329 0.0165 +vn -0.8291 -0.5584 0.0267 +vn -0.8652 -0.4935 0.0883 +vn -0.8922 -0.4173 0.1726 +vn -0.7755 -0.6223 0.1062 +vn -0.7606 -0.6071 0.2302 +vn -0.8188 -0.5516 0.1586 +vn -0.6783 -0.6632 0.3161 +vn -0.7167 -0.6654 0.2088 +vn -0.8303 -0.4947 0.2565 +vn -0.7496 -0.5821 0.3149 +vn -0.7366 -0.6707 0.0870 +vn -0.6842 -0.7022 0.1969 +vn -0.6534 -0.6457 0.3952 +vn -0.6213 -0.7220 0.3044 +vn -0.5510 -0.7368 0.3917 +vn -0.7365 -0.5592 0.3807 +vn -0.8207 -0.4555 0.3449 +vn -0.7809 -0.4382 0.4451 +vn -0.6961 -0.4931 0.5218 +vn -0.7248 -0.4179 0.5477 +vn -0.6519 -0.5945 0.4706 +vn -0.7202 -0.5319 0.4454 +vn -0.6559 -0.4216 0.6261 +vn -0.6471 -0.5190 0.5583 +vn -0.6009 -0.6372 0.4826 +vn -0.6177 -0.5312 0.5798 +vn -0.5996 -0.4103 0.6871 +vn -0.5567 -0.6560 0.5096 +vn -0.5265 -0.5694 0.6313 +vn -0.5895 -0.5431 0.5979 +vn -0.3987 -0.6032 0.6908 +vn -0.4768 -0.6632 0.5769 +vn -0.5547 -0.4304 0.7120 +vn -0.4701 -0.4942 0.7313 +vn -0.4928 -0.7472 0.4458 +vn -0.4281 -0.7395 0.5194 +vn -0.3400 -0.4959 0.7990 +vn -0.3678 -0.6980 0.6143 +vn -0.3139 -0.5939 0.7408 +vn -0.4028 -0.4038 0.8213 +vn -0.4715 -0.3217 0.8211 +vn -0.3616 -0.2320 0.9030 +vn -0.2526 -0.2349 0.9386 +vn -0.2606 -0.1757 0.9493 +vn -0.2676 -0.3553 0.8956 +vn -0.3238 -0.3085 0.8944 +vn -0.1987 -0.1677 0.9656 +vn -0.2132 -0.2437 0.9461 +vn -0.2583 -0.3695 0.8926 +vn -0.1859 -0.1593 0.9696 +vn -0.2122 -0.2377 0.9479 +vn -0.2330 -0.3234 0.9171 +vn -0.1936 -0.2296 0.9538 +vn -0.2145 -0.2279 0.9497 +vn -0.1317 -0.2548 0.9579 +vn -0.1854 -0.2940 0.9376 +vn -0.1867 -0.1643 0.9686 +vn -0.1639 -0.1897 0.9680 +vn -0.2499 -0.4660 0.8487 +vn -0.1698 -0.3858 0.9068 +vn -0.1090 -0.3360 0.9355 +vn 0.2260 0.0463 0.9730 +vn 0.3037 0.0283 0.9523 +vn 0.2261 0.0741 0.9713 +vn 0.3814 0.0192 0.9242 +vn 0.3095 0.0105 0.9508 +vn 0.2814 0.1171 0.9524 +vn 0.3581 0.0530 0.9322 +vn 0.2633 0.0850 0.9609 +vn 0.3214 0.0461 0.9458 +vn 0.3838 0.0419 0.9225 +vn 0.2622 0.1054 0.9592 +vn 0.3157 0.1269 0.9403 +vn 0.2763 0.1515 0.9490 +vn 0.3553 0.0876 0.9306 +vn 0.3186 0.0891 0.9437 +vn 0.2961 0.1699 0.9399 +vn 0.3343 0.1336 0.9329 +vn 0.2506 0.0563 0.9664 +vn 0.3227 0.0498 0.9452 +vn 0.3679 0.0783 0.9265 +vn 0.3728 0.0376 0.9271 +vn 0.4087 0.0138 0.9126 +vn 0.3338 0.1198 0.9350 +vn 0.2898 0.1441 0.9462 +vn 0.0862 -0.1158 0.9895 +vn 0.1525 -0.1078 0.9824 +vn 0.1022 -0.0801 0.9915 +vn 0.2180 -0.1260 0.9678 +vn 0.1530 -0.1319 0.9794 +vn 0.1498 -0.0404 0.9879 +vn 0.1992 -0.0877 0.9760 +vn 0.0850 -0.1190 0.9892 +vn 0.1569 -0.1298 0.9790 +vn 0.2799 -0.1133 0.9533 +vn 0.2294 -0.1350 0.9639 +vn 0.3161 -0.1367 0.9388 +vn 0.2443 -0.0710 0.9671 +vn 0.2011 -0.0111 0.9795 +vn 0.3110 0.1016 0.9449 +vn 0.3386 0.0961 0.9360 +vn 0.3329 0.0811 0.9395 +vn 0.3638 0.0769 0.9283 +vn 0.3336 0.1034 0.9370 +vn 0.3723 0.0724 0.9253 +vn 0.3706 0.0788 0.9254 +vn 0.4044 0.0397 0.9137 +vn 0.4101 0.0576 0.9102 +vn 0.4247 0.0635 0.9031 +vn 0.4413 0.0119 0.8972 +vn 0.4725 0.0204 0.8811 +vn 0.4451 0.0378 0.8947 +vn 0.4934 0.0068 0.8698 +vn 0.4740 0.0002 0.8805 +vn 0.4611 0.0514 0.8858 +vn 0.4865 0.0283 0.8732 +vn 0.4469 -0.0085 0.8945 +vn 0.4728 -0.0121 0.8811 +vn 0.4852 0.0009 0.8744 +vn 0.2654 0.0031 0.9641 +vn 0.3287 -0.0332 0.9438 +vn 0.3272 0.0110 0.9449 +vn 0.3255 -0.0931 0.9409 +vn 0.2874 -0.0544 0.9562 +vn 0.3773 -0.0053 0.9261 +vn 0.3651 -0.0559 0.9293 +vn 0.3574 -0.1071 0.9278 +vn 0.3869 -0.0688 0.9196 +vn 0.4049 -0.0269 0.9139 +vn 0.3920 -0.1118 0.9131 +vn 0.4228 -0.0897 0.9018 +vn 0.4062 -0.0798 0.9102 +vn 0.4420 -0.1032 0.8910 +vn 0.4197 -0.1147 0.9004 +vn 0.4257 -0.0521 0.9033 +vn 0.4414 -0.0748 0.8942 +vn 0.3812 -0.1362 0.9144 +vn 0.4165 -0.1344 0.8991 +vn 0.4421 -0.0846 0.8929 +vn 0.4336 -0.1315 0.8914 +vn 0.4158 -0.1261 0.9007 +vn 0.4498 -0.0615 0.8910 +vn 0.4397 -0.0345 0.8975 +vn 0.4568 -0.0319 0.8890 +vn 0.4658 -0.0378 0.8841 +vn 0.4693 -0.0261 0.8826 +vn 0.4465 -0.0506 0.8933 +vn 0.4584 -0.0476 0.8874 +vn 0.4651 -0.0167 0.8851 +vn 0.4537 -0.0292 0.8907 +vn 0.4135 -0.0566 0.9087 +vn 0.4242 -0.0122 0.9055 +vn 0.4509 0.0155 0.8924 +vn 0.3842 -0.0517 0.9218 +vn 0.4075 -0.0023 0.9132 +vn 0.3982 0.0022 0.9173 +vn 0.4657 -0.0353 0.8842 +vn 0.4063 -0.0539 0.9121 +vn 0.4340 0.0427 0.8999 +vn 0.4483 0.0274 0.8935 +vn 0.3813 -0.1212 0.9164 +vn 0.4062 -0.1191 0.9059 +vn 0.4823 -0.1218 0.8675 +vn 0.1049 -0.1306 0.9858 +vn 0.1611 -0.1546 0.9747 +vn 0.1607 -0.1292 0.9785 +vn 0.1634 -0.2230 0.9610 +vn 0.1247 -0.1706 0.9774 +vn 0.2200 -0.1433 0.9649 +vn 0.2023 -0.1808 0.9625 +vn 0.2019 -0.2796 0.9386 +vn 0.2413 -0.2072 0.9481 +vn 0.2776 -0.1605 0.9472 +vn 0.2505 -0.3080 0.9178 +vn 0.3222 -0.2597 0.9103 +vn 0.2784 -0.2315 0.9321 +vn 0.3739 -0.3081 0.8748 +vn 0.3160 -0.3251 0.8913 +vn 0.3226 -0.1859 0.9281 +vn 0.3632 -0.2343 0.9018 +vn 0.2314 -0.3908 0.8909 +vn 0.3072 -0.3913 0.8675 +vn 0.3960 -0.2835 0.8733 +vn 0.3640 -0.3879 0.8468 +vn 0.3901 -0.3775 0.8398 +vn 0.3830 -0.2178 0.8976 +vn 0.3558 -0.1691 0.9191 +vn 0.3891 -0.1624 0.9067 +vn 0.4168 -0.1873 0.8895 +vn 0.4164 -0.1558 0.8957 +vn 0.4135 -0.2370 0.8791 +vn 0.4007 -0.2010 0.8939 +vn 0.4349 -0.1644 0.8853 +vn 0.4295 -0.2010 0.8804 +vn 0.4161 -0.2759 0.8665 +vn 0.4291 -0.2160 0.8770 +vn 0.4289 -0.1762 0.8860 +vn 0.4207 -0.2883 0.8601 +vn 0.4438 -0.2498 0.8606 +vn 0.4292 -0.2319 0.8729 +vn 0.4594 -0.3055 0.8340 +vn 0.4455 -0.3011 0.8431 +vn 0.4282 -0.2103 0.8788 +vn 0.4403 -0.2485 0.8628 +vn 0.4110 -0.3668 0.8346 +vn 0.4479 -0.3659 0.8157 +vn 0.4495 -0.3312 0.8296 +vn 0.4827 -0.3816 0.7882 +vn 0.5141 -0.4258 0.7445 +vn 0.4151 -0.2583 0.8723 +vn 0.4033 -0.1957 0.8939 +vn 0.3761 -0.1949 0.9058 +vn 0.4029 -0.2550 0.8790 +vn 0.4044 -0.1870 0.8953 +vn 0.4312 -0.3309 0.8394 +vn 0.3894 -0.2665 0.8816 +vn 0.4731 -0.2111 0.8553 +vn 0.4519 -0.2932 0.8425 +vn 0.4948 -0.4000 0.7714 +vn 0.5114 -0.3434 0.7877 +vn 0.5490 -0.2566 0.7954 +vn 0.5537 -0.4489 0.7013 +vn 0.6156 -0.4276 0.6619 +vn 0.5690 -0.3932 0.7222 +vn 0.6473 -0.4516 0.6141 +vn 0.6099 -0.4664 0.6406 +vn 0.6111 -0.3366 0.7164 +vn 0.6452 -0.4040 0.6484 +vn 0.5689 -0.4653 0.6781 +vn 0.6125 -0.4738 0.6326 +vn 0.6360 -0.4624 0.6177 +vn 0.9911 0.0111 0.1328 +vn 0.9989 0.0324 0.0333 +vn 0.9940 0.0532 0.0957 +vn 0.9964 0.0512 -0.0670 +vn 0.9991 0.0089 0.0421 +vn 0.9924 0.1227 -0.0009 +vn 0.9940 0.0878 -0.0644 +vn 0.9881 0.0253 0.1516 +vn 0.9977 0.0344 0.0577 +vn 0.9969 0.0729 -0.0309 +vn 0.9481 0.0360 0.3160 +vn 0.9616 0.0133 0.2740 +vn 0.9496 0.0284 0.3123 +vn 0.9750 0.0255 0.2205 +vn 0.9620 0.0273 0.2715 +vn 0.9604 0.0396 0.2758 +vn 0.9714 0.0238 0.2361 +vn 0.9474 0.0793 0.3099 +vn 0.9621 0.0667 0.2644 +vn 0.9885 0.0311 0.1478 +vn 0.9778 0.0565 0.2018 +vn 0.9939 0.0442 0.1005 +vn 0.9827 0.0334 0.1821 +vn 0.9746 0.0403 0.2203 +vn 0.9159 0.0461 0.3988 +vn 0.9354 0.0884 0.3424 +vn 0.9221 0.1053 0.3724 +vn 0.9540 0.0483 0.2958 +vn 0.9362 0.0387 0.3492 +vn 0.9317 0.1310 0.3387 +vn 0.9454 0.1043 0.3088 +vn 0.9013 -0.0380 0.4315 +vn 0.9644 0.0571 0.2582 +vn 0.9554 -0.0164 0.2950 +vn 0.9753 -0.0091 0.2204 +vn 0.9509 0.1071 0.2904 +vn 0.9324 -0.0221 0.3606 +vn 0.9400 0.1205 0.3192 +vn 0.9893 0.0507 0.1368 +vn 0.9949 0.0666 0.0753 +vn 0.9957 0.0601 0.0706 +vn 0.9951 0.0378 0.0916 +vn 0.9911 0.0460 0.1249 +vn 0.9971 0.0735 0.0180 +vn 0.9970 0.0631 0.0447 +vn 0.9972 0.0454 0.0585 +vn 0.9973 0.0700 0.0191 +vn 0.9945 0.1009 -0.0283 +vn 0.9990 0.0426 0.0129 +vn 0.9976 0.0602 -0.0329 +vn 0.9973 0.0726 -0.0035 +vn 0.9951 0.0460 -0.0869 +vn 0.9987 0.0383 -0.0333 +vn 0.9936 0.1056 -0.0405 +vn 0.9944 0.0796 -0.0692 +vn 0.9991 0.0349 0.0209 +vn 0.9988 0.0299 -0.0374 +vn 0.9940 0.0222 -0.1068 +vn 0.9507 0.1068 0.2910 +vn 0.9615 0.1076 0.2529 +vn 0.9610 0.1024 0.2568 +vn 0.9695 0.0707 0.2344 +vn 0.9553 0.1050 0.2764 +vn 0.9749 0.0896 0.2038 +vn 0.9740 0.0852 0.2098 +vn 0.9835 0.0342 0.1778 +vn 0.9867 0.0586 0.1513 +vn 0.9896 0.0658 0.1281 +vn 0.9947 0.0108 0.1019 +vn 0.9992 0.0079 0.0374 +vn 0.9952 0.0335 0.0913 +vn 0.9997 -0.0118 -0.0189 +vn 0.9995 -0.0029 0.0321 +vn 0.9971 0.0450 0.0614 +vn 0.9998 0.0120 0.0100 +vn 0.9935 -0.0007 0.1134 +vn 0.9997 -0.0038 0.0233 +vn 0.9974 -0.0345 -0.0629 +vn 0.9979 -0.0259 -0.0592 +vn 0.9840 -0.0817 -0.1580 +vn 1.0000 0.0012 -0.0076 +vn 0.9987 0.0316 0.0404 +vn 0.9997 0.0235 0.0015 +vn 0.9988 0.0003 -0.0488 +vn 0.9988 0.0223 -0.0436 +vn 0.9961 -0.0461 -0.0754 +vn 0.9997 -0.0075 -0.0234 +vn 0.9940 0.0058 -0.1090 +vn 0.9944 -0.0268 -0.1019 +vn 0.9848 -0.0861 -0.1508 +vn 0.9847 -0.0595 -0.1636 +vn 0.9831 -0.0264 -0.1812 +vn 0.9658 -0.1303 -0.2241 +vn 0.9520 -0.1261 -0.2787 +vn 0.9697 -0.0946 -0.2250 +vn 0.9324 -0.1610 -0.3236 +vn 0.9445 -0.1563 -0.2888 +vn 0.9661 -0.0710 -0.2481 +vn 0.9469 -0.1194 -0.2984 +vn 0.9589 -0.1401 -0.2467 +vn 0.9386 -0.1670 -0.3018 +vn 0.9183 -0.1853 -0.3497 +vn 0.8828 -0.1163 0.4550 +vn 0.9069 -0.1606 0.3895 +vn 0.9229 -0.0858 0.3752 +vn 0.8665 -0.2530 0.4302 +vn 0.8676 -0.2018 0.4543 +vn 0.9419 -0.0934 0.3226 +vn 0.9141 -0.1784 0.3640 +vn 0.8613 -0.2746 0.4275 +vn 0.9152 -0.1800 0.3606 +vn 0.9514 -0.0924 0.2937 +vn 0.8761 -0.2721 0.3979 +vn 0.9271 -0.2069 0.3124 +vn 0.9175 -0.1816 0.3537 +vn 0.9404 -0.2678 0.2097 +vn 0.9015 -0.2870 0.3238 +vn 0.9551 -0.1087 0.2755 +vn 0.9586 -0.1656 0.2317 +vn 0.8253 -0.3597 0.4353 +vn 0.9676 -0.2329 0.0976 +vn 0.9079 -0.3695 0.1979 +vn 0.9281 -0.3719 0.0158 +vn 0.9797 -0.1267 0.1553 +vn 0.8708 -0.3591 0.3358 +vn 0.9795 -0.0556 0.1936 +vn 0.9940 -0.0236 0.1068 +vn 0.9985 -0.0533 0.0139 +vn 0.9998 -0.0082 0.0161 +vn 0.9864 -0.1642 0.0101 +vn 0.9926 -0.0884 0.0825 +vn 0.9966 -0.0331 -0.0746 +vn 0.9939 -0.0933 -0.0590 +vn 0.9696 -0.2320 -0.0774 +vn 0.9817 -0.1344 -0.1346 +vn 0.9833 -0.0799 -0.1633 +vn 0.9461 -0.2613 -0.1910 +vn 0.9334 -0.2099 -0.2909 +vn 0.9615 -0.1728 -0.2137 +vn 0.8918 -0.2658 -0.3661 +vn 0.9128 -0.2769 -0.3002 +vn 0.9587 -0.1290 -0.2535 +vn 0.9253 -0.1900 -0.3282 +vn 0.9188 -0.3555 -0.1713 +vn 0.8876 -0.3407 -0.3099 +vn 0.8837 -0.2737 -0.3797 +vn 0.8483 -0.3457 -0.4012 +vn 0.8043 -0.3878 -0.4501 +vn 0.9543 -0.1401 -0.2641 +vn 0.9239 -0.1966 -0.3281 +vn 0.9417 -0.1682 -0.2912 +vn 0.9210 -0.2071 -0.3300 +vn 0.9320 -0.1765 -0.3166 +vn 0.8948 -0.2580 -0.3644 +vn 0.9240 -0.2071 -0.3213 +vn 0.9091 -0.1995 -0.3657 +vn 0.8996 -0.2334 -0.3690 +vn 0.8513 -0.3239 -0.4128 +vn 0.8733 -0.2680 -0.4069 +vn 0.8829 -0.2314 -0.4086 +vn 0.8169 -0.3695 -0.4429 +vn 0.8155 -0.3264 -0.4779 +vn 0.8448 -0.3012 -0.4421 +vn 0.7820 -0.3772 -0.4962 +vn 0.7860 -0.3877 -0.4816 +vn 0.8488 -0.2701 -0.4545 +vn 0.8172 -0.3135 -0.4836 +vn 0.7656 -0.4379 -0.4713 +vn 0.7450 -0.4551 -0.4877 +vn 0.7509 -0.4501 -0.4831 +vn 0.6926 -0.6391 -0.3344 +vn 0.7354 -0.5867 -0.3391 +vn 0.7347 -0.5865 -0.3407 +vn 0.7578 -0.5425 -0.3625 +vn 0.7006 -0.6269 -0.3405 +vn 0.7143 -0.5843 -0.3851 +vn 0.7666 -0.5302 -0.3621 +vn 0.6250 -0.7098 -0.3248 +vn 0.6595 -0.6328 -0.4057 +vn 0.5469 -0.7277 -0.4140 +vn 0.6507 -0.6796 -0.3388 +vn 0.7067 -0.5829 -0.4008 +vn 0.6552 -0.6370 -0.4060 +vn 0.7437 -0.5263 -0.4121 +vn 0.4205 -0.8675 -0.2655 +vn 0.4549 -0.8606 -0.2289 +vn 0.4158 -0.8638 -0.2844 +vn 0.4657 -0.8540 -0.2319 +vn 0.4592 -0.8605 -0.2204 +vn 0.4411 -0.8494 -0.2897 +vn 0.4727 -0.8490 -0.2362 +vn 0.4170 -0.8835 -0.2133 +vn 0.3278 -0.8818 -0.3390 +vn 0.3031 -0.9184 -0.2544 +vn 0.4590 -0.8640 -0.2069 +vn 0.3493 -0.8593 -0.3735 +vn 0.4609 -0.8407 -0.2842 +vn 0.4533 -0.8546 -0.2534 +vn 0.4047 -0.8402 -0.3610 +vn 0.4963 -0.8296 -0.2559 +vn 0.4078 -0.8236 -0.3940 +vn 0.5147 -0.8044 -0.2966 +vn 0.2864 -0.9570 -0.0458 +vn 0.3476 -0.9357 -0.0596 +vn 0.3324 -0.9398 -0.0783 +vn 0.3152 -0.9444 -0.0930 +vn 0.3035 -0.9518 -0.0442 +vn 0.3561 -0.9284 -0.1061 +vn 0.3650 -0.9266 -0.0901 +vn 0.2032 -0.9791 0.0094 +vn 0.2316 -0.9688 -0.0878 +vn 0.2787 -0.9504 -0.1375 +vn 0.3215 -0.9354 -0.1469 +vn 0.2234 -0.9698 -0.0975 +vn 0.1900 -0.9605 -0.2031 +vn 0.3857 -0.9145 -0.1220 +vn 0.2323 -0.9724 -0.0232 +vn 0.2889 -0.9409 -0.1766 +vn 0.3875 -0.9100 -0.1476 +vn 0.5764 -0.7655 -0.2861 +vn 0.5487 -0.7674 -0.3317 +vn 0.6026 -0.7254 -0.3324 +vn 0.4752 -0.8159 -0.3293 +vn 0.5215 -0.8041 -0.2852 +vn 0.5877 -0.7039 -0.3988 +vn 0.5235 -0.7642 -0.3768 +vn 0.4326 -0.8119 -0.3919 +vn 0.5606 -0.6844 -0.4661 +vn 0.4902 -0.7584 -0.4295 +vn 0.3891 -0.7967 -0.4624 +vn 0.4075 -0.7408 -0.5340 +vn 0.4522 -0.7517 -0.4801 +vn 0.3490 -0.7161 -0.6045 +vn 0.3518 -0.7674 -0.5360 +vn 0.5015 -0.6880 -0.5245 +vn 0.4259 -0.6941 -0.5802 +vn 0.3518 -0.8138 -0.4625 +vn 0.3207 -0.7793 -0.5383 +vn 0.2995 -0.7328 -0.6109 +vn 0.4379 -0.8850 -0.1580 +vn 0.4288 -0.8837 -0.1875 +vn 0.4596 -0.8668 -0.1931 +vn 0.3549 -0.9153 -0.1900 +vn 0.4082 -0.9006 -0.1492 +vn 0.4388 -0.8622 -0.2529 +vn 0.3968 -0.8877 -0.2333 +vn 0.2805 -0.9246 -0.2576 +vn 0.3456 -0.8891 -0.3000 +vn 0.3890 -0.8579 -0.3355 +vn 0.2186 -0.9145 -0.3404 +vn 0.2338 -0.8721 -0.4298 +vn 0.2900 -0.8836 -0.3676 +vn 0.1625 -0.8566 -0.4897 +vn 0.1714 -0.8887 -0.4252 +vn 0.3235 -0.8504 -0.4148 +vn 0.2442 -0.8470 -0.4720 +vn 0.1480 -0.9339 -0.3253 +vn 0.1156 -0.8999 -0.4204 +vn 0.1613 -0.8371 -0.5227 +vn 0.0889 -0.8663 -0.4916 +vn 0.0628 -0.8361 -0.5449 +vn 0.2435 -0.8362 -0.4913 +vn 0.3224 -0.8366 -0.4428 +vn 0.3032 -0.8181 -0.4886 +vn 0.2502 -0.8030 -0.5408 +vn 0.2907 -0.7893 -0.5408 +vn 0.1814 -0.8188 -0.5447 +vn 0.2431 -0.8247 -0.5107 +vn 0.2595 -0.7589 -0.5972 +vn 0.2116 -0.7882 -0.5778 +vn 0.1256 -0.8077 -0.5760 +vn 0.1773 -0.7738 -0.6081 +vn 0.2268 -0.7306 -0.6439 +vn 0.0848 -0.7856 -0.6129 +vn 0.0976 -0.7359 -0.6700 +vn 0.1420 -0.7581 -0.6364 +vn 0.0341 -0.7013 -0.7120 +vn 0.0457 -0.7475 -0.6626 +vn 0.1765 -0.7152 -0.6762 +vn 0.1071 -0.7009 -0.7052 +vn 0.0335 -0.7991 -0.6002 +vn 0.0060 -0.7543 -0.6565 +vn -0.0228 -0.7026 -0.7112 +vn 0.1243 -0.9904 0.0602 +vn 0.0565 -0.9981 0.0235 +vn 0.1487 -0.9889 0.0009 +vn -0.0530 -0.9975 0.0465 +vn 0.0271 -0.9970 0.0717 +vn 0.1186 -0.9908 -0.0656 +vn 0.0126 -0.9998 -0.0114 +vn -0.1260 -0.9915 0.0320 +vn 0.0780 -0.9895 -0.1218 +vn -0.0257 -0.9989 -0.0378 +vn -0.1688 -0.9856 -0.0052 +vn -0.1227 -0.9855 -0.1173 +vn -0.0680 -0.9952 -0.0698 +vn -0.2144 -0.9581 -0.1898 +vn -0.2158 -0.9727 -0.0848 +vn 0.0031 -0.9865 -0.1635 +vn -0.0956 -0.9748 -0.2017 +vn -0.2655 -0.9631 0.0429 +vn -0.2918 -0.9551 -0.0508 +vn -0.1849 -0.9448 -0.2705 +vn -0.3105 -0.9392 -0.1466 +vn -0.3049 -0.9213 -0.2413 +vn -0.0675 -0.9610 -0.2680 +vn 0.0521 -0.9678 -0.2462 +vn 0.0599 -0.9430 -0.3272 +vn -0.0191 -0.9187 -0.3944 +vn 0.0561 -0.9095 -0.4120 +vn -0.1252 -0.9262 -0.3556 +vn -0.0411 -0.9427 -0.3309 +vn 0.0185 -0.8814 -0.4720 +vn -0.0648 -0.9015 -0.4279 +vn -0.1798 -0.9142 -0.3631 +vn -0.0125 -0.8654 -0.5010 +vn -0.0899 -0.8929 -0.4412 +vn -0.2019 -0.8958 -0.3958 +vn -0.1549 -0.8615 -0.4834 +vn -0.1153 -0.8823 -0.4563 +vn -0.2339 -0.8213 -0.5202 +vn -0.2347 -0.8604 -0.4523 +vn -0.0635 -0.8535 -0.5171 +vn -0.1361 -0.8339 -0.5347 +vn -0.3005 -0.8947 -0.3303 +vn -0.3135 -0.8552 -0.4128 +vn -0.2166 -0.7982 -0.5621 +vn -0.3270 -0.8123 -0.4828 +vn -0.3311 -0.7745 -0.5389 +vn -0.1191 -0.8162 -0.5652 +vn -0.0311 -0.8290 -0.5583 +vn -0.0282 -0.8023 -0.5962 +vn -0.0911 -0.7688 -0.6329 +vn -0.0356 -0.7611 -0.6477 +vn -0.1753 -0.7745 -0.6077 +vn -0.1038 -0.7974 -0.5944 +vn -0.0717 -0.7191 -0.6912 +vn -0.1323 -0.7427 -0.6564 +vn -0.2348 -0.7517 -0.6163 +vn -0.1667 -0.7204 -0.6732 +vn -0.1095 -0.6815 -0.7235 +vn -0.2681 -0.7167 -0.6438 +vn -0.2453 -0.6590 -0.7110 +vn -0.2007 -0.6956 -0.6898 +vn -0.3082 -0.6049 -0.7342 +vn -0.3023 -0.6617 -0.6861 +vn -0.1625 -0.6507 -0.7417 +vn -0.2329 -0.6185 -0.7504 +vn -0.3388 -0.7239 -0.6010 +vn -0.3540 -0.6618 -0.6608 +vn -0.3644 -0.6030 -0.7097 +vn -0.4064 -0.7137 -0.5704 +vn -0.4533 -0.6503 -0.6096 +vn -0.4016 -0.6584 -0.6366 +vn -0.5174 -0.6419 -0.5658 +vn -0.4745 -0.6864 -0.5511 +vn -0.4190 -0.6059 -0.6762 +vn -0.4770 -0.6122 -0.6306 +vn -0.4260 -0.7474 -0.5098 +vn -0.4906 -0.7140 -0.4995 +vn -0.5319 -0.6790 -0.5059 +vn -0.3872 -0.8778 -0.2819 +vn -0.4552 -0.8263 -0.3316 +vn -0.3878 -0.8440 -0.3706 +vn -0.5178 -0.8107 -0.2732 +vn -0.4696 -0.8451 -0.2557 +vn -0.4159 -0.8040 -0.4250 +vn -0.4857 -0.7979 -0.3570 +vn -0.4097 -0.8896 -0.2019 +vn -0.4812 -0.8562 -0.1881 +vn -0.5214 -0.7992 -0.2988 +vn -0.5209 -0.8315 -0.1931 +vn -0.5157 -0.8286 -0.2176 +vn -0.4933 -0.7871 -0.3702 +vn -0.4330 -0.7830 -0.4465 +vn -0.3483 -0.9340 0.0792 +vn -0.4193 -0.9076 0.0209 +vn -0.3646 -0.9311 -0.0117 +vn -0.4680 -0.8813 0.0655 +vn -0.4230 -0.9015 0.0914 +vn -0.3959 -0.9150 -0.0769 +vn -0.4540 -0.8909 -0.0118 +vn -0.3616 -0.9209 0.1457 +vn -0.4747 -0.8797 0.0279 +vn -0.4422 -0.8874 0.1299 +vn -0.4286 -0.9008 0.0692 +vn -0.4653 -0.8846 -0.0321 +vn -0.4219 -0.8936 0.1529 +vn -0.4142 -0.9029 -0.1149 +vn -0.4682 -0.7648 -0.4425 +vn -0.5176 -0.7570 -0.3986 +vn -0.5058 -0.7378 -0.4470 +vn -0.5237 -0.7792 -0.3444 +vn -0.5016 -0.7756 -0.3831 +vn -0.5362 -0.7197 -0.4410 +vn -0.5340 -0.7526 -0.3853 +vn -0.5202 -0.7931 -0.3167 +vn -0.5275 -0.7585 -0.3825 +vn -0.5377 -0.7152 -0.4465 +vn -0.5116 -0.7976 -0.3194 +vn -0.5272 -0.7628 -0.3742 +vn -0.5182 -0.7653 -0.3819 +vn -0.5626 -0.7511 -0.3453 +vn -0.5328 -0.7839 -0.3188 +vn -0.5344 -0.7266 -0.4318 +vn -0.5503 -0.7315 -0.4026 +vn -0.5100 -0.8249 -0.2439 +vn -0.5300 -0.8065 -0.2621 +vn -0.5517 -0.7828 -0.2877 +vn -0.4512 -0.8851 -0.1136 +vn -0.4971 -0.8652 -0.0654 +vn -0.4919 -0.8624 -0.1192 +vn -0.4912 -0.8709 -0.0161 +vn -0.4777 -0.8771 -0.0486 +vn -0.5184 -0.8475 -0.1137 +vn -0.5079 -0.8598 -0.0531 +vn -0.4723 -0.8813 -0.0100 +vn -0.4922 -0.8687 -0.0552 +vn -0.5058 -0.8548 -0.1158 +vn -0.4539 -0.8903 -0.0359 +vn -0.4583 -0.8860 -0.0700 +vn -0.4699 -0.8804 -0.0635 +vn -0.4611 -0.8847 -0.0684 +vn -0.4515 -0.8909 -0.0490 +vn -0.4823 -0.8704 -0.0994 +vn -0.4689 -0.8785 -0.0910 +vn -0.4254 -0.9050 0.0041 +vn -0.4324 -0.9011 -0.0327 +vn -0.4736 -0.8743 -0.1060 +vn -0.4333 -0.8986 -0.0686 +vn -0.4296 -0.8936 -0.1301 +vn -0.4956 -0.8552 -0.1518 +vn -0.4860 -0.8655 -0.1210 +vn -0.5005 -0.8456 -0.1856 +vn -0.5214 -0.8369 -0.1662 +vn -0.5241 -0.8261 -0.2068 +vn -0.4992 -0.8555 -0.1374 +vn -0.4997 -0.8540 -0.1444 +vn -0.5361 -0.8161 -0.2156 +vn -0.5199 -0.8373 -0.1689 +vn -0.4768 -0.8645 -0.1587 +vn -0.5022 -0.8444 -0.1862 +vn -0.5259 -0.8166 -0.2376 +vn -0.4722 -0.8611 -0.1883 +vn -0.4916 -0.8470 -0.2021 +vn -0.4868 -0.8499 -0.2015 +vn -0.5320 -0.8228 -0.1997 +vn -0.4902 -0.8490 -0.1970 +vn -0.5088 -0.8285 -0.2339 +vn -0.5179 -0.8273 -0.2175 +vn -0.4453 -0.8751 -0.1891 +vn -0.4821 -0.8500 -0.2122 +vn -0.5512 -0.8069 -0.2120 +vn -0.3977 -0.8949 0.2025 +vn -0.4156 -0.8834 0.2163 +vn -0.4187 -0.8851 0.2031 +vn -0.4002 -0.8986 0.1799 +vn -0.4095 -0.8866 0.2149 +vn -0.4134 -0.8897 0.1934 +vn -0.4052 -0.8918 0.2013 +vn -0.3616 -0.9281 0.0888 +vn -0.3601 -0.9185 0.1635 +vn -0.3740 -0.9140 0.1574 +vn -0.3128 -0.9494 0.0284 +vn -0.2550 -0.9637 0.0788 +vn -0.3042 -0.9449 0.1204 +vn -0.2287 -0.9734 -0.0121 +vn -0.2415 -0.9704 -0.0019 +vn -0.3092 -0.9426 0.1261 +vn -0.2596 -0.9628 0.0751 +vn -0.2936 -0.9505 -0.1016 +vn -0.2821 -0.9586 -0.0398 +vn -0.2051 -0.9690 -0.1379 +vn -0.2524 -0.9505 -0.1811 +vn -0.3122 -0.9492 0.0376 +vn -0.2286 -0.9661 -0.1201 +vn -0.3551 -0.9322 0.0690 +vn -0.3872 -0.9219 0.0080 +vn -0.3985 -0.9168 -0.0245 +vn -0.4111 -0.9113 -0.0218 +vn -0.3432 -0.9384 -0.0403 +vn -0.3637 -0.9315 0.0010 +vn -0.4011 -0.9146 -0.0502 +vn -0.3782 -0.9240 -0.0561 +vn -0.3159 -0.9415 -0.1173 +vn -0.3782 -0.9204 -0.0989 +vn -0.3510 -0.9314 -0.0967 +vn -0.3106 -0.9357 -0.1671 +vn -0.3084 -0.9386 -0.1545 +vn -0.3226 -0.9371 -0.1334 +vn -0.3324 -0.9241 -0.1884 +vn -0.3010 -0.9351 -0.1868 +vn -0.3410 -0.9296 -0.1397 +vn -0.3294 -0.9304 -0.1610 +vn -0.2816 -0.9336 -0.2215 +vn -0.4048 -0.8952 -0.1863 +vn -0.3559 -0.9063 -0.2278 +vn -0.4841 -0.8509 -0.2040 +vn -0.3755 -0.9092 -0.1799 +vn -0.2971 -0.9256 -0.2345 +vn -0.3812 -0.9089 -0.1690 +vn -0.4191 -0.8832 -0.2103 +vn -0.4639 -0.8571 -0.2238 +vn -0.4694 -0.8525 -0.2300 +vn -0.4607 -0.8687 -0.1815 +vn -0.4185 -0.8862 -0.1988 +vn -0.5298 -0.8169 -0.2276 +vn -0.5068 -0.8365 -0.2085 +vn -0.5257 -0.8323 -0.1760 +vn -0.5691 -0.7993 -0.1928 +vn -0.6226 -0.7540 -0.2094 +vn -0.6152 -0.7740 -0.1500 +vn -0.6928 -0.7076 -0.1391 +vn -0.6337 -0.7541 -0.1726 +vn -0.7650 -0.6287 -0.1399 +vn -0.6913 -0.7099 -0.1348 +vn -0.6941 -0.6916 -0.1997 +vn -0.7519 -0.6402 -0.1572 +vn -0.6079 -0.7742 -0.1759 +vn -0.6910 -0.7037 -0.1651 +vn -0.7697 -0.6177 -0.1612 +vn -0.6416 -0.7432 -0.1895 +vn -0.7052 -0.6852 -0.1820 +vn -0.6959 -0.6925 -0.1899 +vn -0.7401 -0.6619 -0.1184 +vn -0.6770 -0.7175 -0.1639 +vn -0.7660 -0.6163 -0.1829 +vn -0.7642 -0.6251 -0.1584 +vn -0.5810 -0.7885 -0.2016 +vn -0.6509 -0.7417 -0.1619 +vn -0.7153 -0.6924 -0.0938 +vn -0.2721 -0.9251 -0.2648 +vn -0.3022 -0.9164 -0.2623 +vn -0.2971 -0.9161 -0.2691 +vn -0.3341 -0.9207 -0.2016 +vn -0.2860 -0.9246 -0.2517 +vn -0.3570 -0.8971 -0.2604 +vn -0.3518 -0.9050 -0.2391 +vn -0.2528 -0.9304 -0.2653 +vn -0.2816 -0.9270 -0.2475 +vn -0.4075 -0.9048 -0.1229 +vn -0.3266 -0.9315 -0.1599 +vn -0.3876 -0.9218 0.0092 +vn -0.4273 -0.8808 -0.2038 +vn -0.4530 -0.8598 -0.2358 +vn -0.2655 -0.9364 -0.2292 +vn -0.2094 -0.9374 -0.2781 +vn -0.2168 -0.9497 -0.2260 +vn -0.2169 -0.9335 -0.2854 +vn -0.2425 -0.9259 -0.2897 +vn -0.1817 -0.9539 -0.2387 +vn -0.1883 -0.9391 -0.2875 +vn -0.2934 -0.9246 -0.2427 +vn -0.2046 -0.9558 -0.2109 +vn -0.2619 -0.9368 -0.2318 +vn -0.2375 -0.9707 -0.0353 +vn -0.1941 -0.9408 -0.2777 +vn -0.2710 -0.9169 -0.2930 +vn -0.2052 -0.9436 -0.2597 +vn -0.5459 -0.8101 -0.2136 +vn -0.5823 -0.8024 -0.1308 +vn -0.6243 -0.7646 -0.1599 +vn -0.4939 -0.8660 -0.0783 +vn -0.5061 -0.8459 -0.1683 +vn -0.6661 -0.7416 -0.0793 +vn -0.5951 -0.8012 -0.0628 +vn -0.4950 -0.8688 0.0142 +vn -0.6925 -0.7214 -0.0030 +vn -0.6030 -0.7976 0.0067 +vn -0.5074 -0.8546 0.1102 +vn -0.5995 -0.7850 0.1558 +vn -0.6042 -0.7933 0.0749 +vn -0.5764 -0.7701 0.2731 +vn -0.5256 -0.8245 0.2094 +vn -0.6836 -0.7254 0.0806 +vn -0.6508 -0.7367 0.1835 +vn -0.4257 -0.8916 0.1545 +vn -0.4573 -0.8531 0.2511 +vn -0.4968 -0.8042 0.3262 +vn -0.2304 -0.9313 -0.2820 +vn -0.2485 -0.9405 -0.2315 +vn -0.2720 -0.9307 -0.2445 +vn -0.1982 -0.9655 -0.1688 +vn -0.2118 -0.9420 -0.2602 +vn -0.2545 -0.9556 -0.1486 +vn -0.3016 -0.9409 -0.1540 +vn -0.2029 -0.9789 -0.0218 +vn -0.3193 -0.9476 -0.0077 +vn -0.2524 -0.9675 -0.0149 +vn -0.1893 -0.9728 0.1330 +vn -0.2263 -0.9497 0.2163 +vn -0.2399 -0.9637 0.1168 +vn -0.2160 -0.9314 0.2931 +vn -0.1896 -0.9519 0.2405 +vn -0.3004 -0.9433 0.1408 +vn -0.2587 -0.9337 0.2473 +vn -0.1986 -0.9662 0.1644 +vn -0.1849 -0.9499 0.2519 +vn -0.2423 -0.9170 0.3170 +vn -0.2012 -0.9328 0.2988 +vn -0.2335 -0.9170 0.3234 +vn -0.3316 -0.9282 0.1684 +vn -0.2770 -0.9227 0.2680 +vn -0.3575 -0.9056 0.2280 +vn -0.3317 -0.8884 0.3173 +vn -0.3900 -0.8747 0.2877 +vn -0.2719 -0.9017 0.3362 +vn -0.2971 -0.9096 0.2903 +vn -0.4037 -0.8466 0.3467 +vn -0.3261 -0.8764 0.3542 +vn -0.2721 -0.8973 0.3475 +vn -0.4206 -0.8252 0.3770 +vn -0.3301 -0.8713 0.3630 +vn -0.2855 -0.8853 0.3669 +vn -0.3275 -0.8506 0.4114 +vn -0.3339 -0.8666 0.3707 +vn -0.3327 -0.7964 0.5050 +vn -0.2966 -0.8560 0.4234 +vn -0.4091 -0.8195 0.4013 +vn -0.3766 -0.8036 0.4610 +vn -0.2678 -0.8954 0.3557 +vn -0.2954 -0.8570 0.4222 +vn -0.3184 -0.7793 0.5398 +vn -0.2951 -0.9111 -0.2876 +vn -0.2835 -0.9163 -0.2829 +vn -0.2908 -0.9102 -0.2947 +vn -0.2559 -0.9447 -0.2051 +vn -0.2819 -0.9163 -0.2845 +vn -0.2998 -0.9302 -0.2114 +vn -0.2790 -0.9389 -0.2014 +vn -0.2193 -0.9748 -0.0398 +vn -0.2655 -0.9630 -0.0465 +vn -0.2902 -0.9560 -0.0432 +vn -0.1958 -0.9715 0.1331 +vn -0.2303 -0.9442 0.2355 +vn -0.2471 -0.9619 0.1164 +vn -0.2108 -0.9278 0.3077 +vn -0.1992 -0.9452 0.2586 +vn -0.2804 -0.9492 0.1426 +vn -0.2457 -0.9334 0.2613 +vn -0.1740 -0.9719 0.1587 +vn -0.1891 -0.9424 0.2758 +vn -0.1996 -0.9294 0.3103 +vn -0.1907 -0.9243 0.3305 +vn -0.1675 -0.9283 0.3319 +vn -0.2223 -0.9376 0.2673 +vn -0.2413 -0.9560 0.1668 +vn -0.2085 -0.9487 0.2376 +vn -0.1897 -0.9421 0.2765 +vn -0.1917 -0.9456 0.2628 +vn -0.1886 -0.9366 0.2952 +vn -0.1993 -0.9408 0.2742 +vn -0.1915 -0.9371 0.2916 +vn -0.1848 -0.9380 0.2932 +vn -0.1737 -0.9374 0.3016 +vn -0.2027 -0.9322 0.3000 +vn -0.1838 -0.9384 0.2925 +vn -0.1581 -0.9401 0.3020 +vn -0.1749 -0.9322 0.3170 +vn -0.1821 -0.9387 0.2928 +vn -0.1581 -0.9134 0.3751 +vn -0.1527 -0.9312 0.3309 +vn -0.2054 -0.9300 0.3048 +vn -0.1884 -0.9233 0.3346 +vn -0.1407 -0.9363 0.3217 +vn -0.1325 -0.9261 0.3530 +vn -0.1577 -0.8830 0.4422 +vn -0.1253 -0.8918 0.4348 +vn -0.0964 -0.8020 0.5894 +vn -0.2022 -0.9102 0.3613 +vn -0.2287 -0.9178 0.3245 +vn -0.2591 -0.8984 0.3545 +vn -0.2579 -0.8657 0.4290 +vn -0.2911 -0.8601 0.4188 +vn -0.1737 -0.8607 0.4786 +vn -0.2195 -0.8949 0.3885 +vn -0.2974 -0.7982 0.5239 +vn -0.2348 -0.8240 0.5155 +vn -0.1275 -0.7877 0.6027 +vn -0.2028 -0.7507 0.6288 +vn -0.2806 -0.6853 0.6720 +vn -0.0798 -0.6753 0.7331 +vn -0.1088 -0.5540 0.8254 +vn -0.1607 -0.6564 0.7371 +vn -0.0826 -0.4338 0.8972 +vn -0.0587 -0.5484 0.8341 +vn -0.2346 -0.5677 0.7891 +vn -0.1502 -0.4652 0.8724 +vn -0.0617 -0.6645 0.7447 +vn -0.0567 -0.5398 0.8398 +vn -0.0683 -0.4243 0.9029 +vn 0.6969 -0.5122 -0.5019 +vn 0.6670 -0.5595 -0.4919 +vn 0.6988 -0.5187 -0.4924 +vn 0.6602 -0.5830 -0.4735 +vn 0.6537 -0.5585 -0.5106 +vn 0.7106 -0.5260 -0.4672 +vn 0.6813 -0.5708 -0.4583 +vn 0.7029 -0.4864 -0.5190 +vn 0.6365 -0.5432 -0.5475 +vn 0.6003 -0.6108 -0.5162 +vn 0.8699 -0.4532 -0.1945 +vn 0.8015 -0.4995 -0.3286 +vn 0.8547 -0.4081 -0.3209 +vn 0.7006 -0.6343 -0.3267 +vn 0.7905 -0.5627 -0.2416 +vn 0.8027 -0.4177 -0.4256 +vn 0.7462 -0.5259 -0.4082 +vn 0.8599 -0.5053 -0.0728 +vn 0.7687 -0.6207 -0.1543 +vn 0.6171 -0.6780 -0.3992 +vn 0.6479 -0.7261 -0.2301 +vn 0.4805 -0.8227 -0.3039 +vn 0.6973 -0.5494 -0.4603 +vn 0.7505 -0.4538 -0.4803 +vn 0.7777 -0.4374 0.4514 +vn 0.7771 -0.5195 0.3552 +vn 0.8317 -0.4325 0.3480 +vn 0.6840 -0.6366 0.3561 +vn 0.7218 -0.5416 0.4309 +vn 0.8504 -0.4732 0.2300 +vn 0.7689 -0.5759 0.2776 +vn 0.7221 -0.4616 0.5152 +vn 0.6773 -0.5553 0.4826 +vn 0.6446 -0.7148 0.2712 +vn 0.6206 -0.6626 0.4193 +vn 0.5271 -0.7894 0.3146 +vn 0.7539 -0.6236 0.2066 +vn 0.8495 -0.5133 0.1223 +vn 0.6819 -0.5013 -0.5325 +vn 0.6069 -0.5766 -0.5469 +vn 0.6188 -0.5422 -0.5684 +vn 0.5666 -0.6745 -0.4732 +vn 0.6488 -0.5673 -0.5071 +vn 0.5407 -0.6200 -0.5685 +vn 0.5257 -0.6575 -0.5396 +vn 0.4459 -0.7776 -0.4431 +vn 0.4547 -0.7208 -0.5231 +vn 0.4282 -0.7388 -0.5204 +vn 0.3203 -0.8382 -0.4414 +vn 0.2632 -0.8374 -0.4790 +vn 0.3288 -0.8025 -0.4978 +vn 0.2474 -0.8728 -0.4208 +vn 0.2425 -0.8650 -0.4393 +vn 0.3433 -0.8033 -0.4867 +vn 0.2815 -0.8447 -0.4553 +vn 0.3054 -0.8794 -0.3653 +vn 0.2135 -0.8965 -0.3880 +vn 0.2064 -0.9090 -0.3620 +vn 0.8130 -0.5813 0.0333 +vn 0.6960 -0.7170 0.0377 +vn 0.7386 -0.6709 -0.0652 +vn 0.6183 -0.7665 0.1734 +vn 0.7319 -0.6679 0.1348 +vn 0.6215 -0.7755 -0.1111 +vn 0.5984 -0.8003 0.0363 +vn 0.5155 -0.8394 0.1721 +vn 0.5094 -0.8600 0.0302 +vn 0.5015 -0.8555 -0.1290 +vn 0.4043 -0.9051 0.1311 +vn 0.3282 -0.9444 0.0164 +vn 0.4188 -0.9078 0.0222 +vn 0.2193 -0.9756 -0.0091 +vn 0.2985 -0.9510 0.0806 +vn 0.3873 -0.9154 -0.1099 +vn 0.2770 -0.9580 -0.0741 +vn 0.3957 -0.8972 0.1960 +vn 0.1724 -0.9799 -0.0996 +vn 0.2034 -0.9784 0.0361 +vn 0.1442 -0.9887 -0.0399 +vn 0.2300 -0.9607 -0.1552 +vn 0.2882 -0.9511 0.1105 +vn 0.3322 -0.9171 -0.2204 +vn 0.2448 -0.9244 -0.2925 +vn 0.1531 -0.9482 -0.2782 +vn 0.1802 -0.9243 -0.3364 +vn 0.1403 -0.9703 -0.1968 +vn 0.1852 -0.9561 -0.2272 +vn 0.1497 -0.9340 -0.3244 +vn 0.1249 -0.9558 -0.2660 +vn 0.1419 -0.9735 -0.1791 +vn 0.1887 -0.9444 -0.2692 +vn 0.1450 -0.9565 -0.2530 +vn 0.1581 -0.9698 -0.1859 +vn 0.1888 -0.9557 -0.2255 +vn 0.1763 -0.9546 -0.2402 +vn 0.1865 -0.9697 -0.1579 +vn 0.1643 -0.9697 -0.1806 +vn 0.2136 -0.9523 -0.2177 +vn 0.2207 -0.9553 -0.1965 +vn 0.1309 -0.9877 -0.0851 +vn 0.1171 -0.9881 -0.0992 +vn 0.1093 -0.9912 -0.0742 +vn 0.6565 -0.4918 0.5719 +vn 0.5919 -0.5629 0.5769 +vn 0.6336 -0.5617 0.5321 +vn 0.5396 -0.5670 0.6224 +vn 0.5951 -0.5180 0.6144 +vn 0.5807 -0.6424 0.5001 +vn 0.5442 -0.6153 0.5703 +vn 0.5050 -0.6161 0.6044 +vn 0.5062 -0.6572 0.5584 +vn 0.5227 -0.7160 0.4627 +vn 0.4585 -0.6734 0.5799 +vn 0.4138 -0.7380 0.5330 +vn 0.4660 -0.6960 0.5462 +vn 0.3507 -0.8067 0.4755 +vn 0.4040 -0.7335 0.5466 +vn 0.4613 -0.7624 0.4537 +vn 0.3883 -0.7996 0.4579 +vn 0.4823 -0.6670 0.5678 +vn 0.4316 -0.7333 0.5254 +vn 0.2845 -0.8866 0.3647 +vn 0.3705 -0.8101 0.4543 +vn 0.2680 -0.9110 0.3132 +vn 0.3468 -0.8645 0.3638 +vn 0.4303 -0.8358 0.3409 +vn 0.3578 -0.9057 0.2271 +vn 0.2528 -0.9508 0.1791 +vn 0.2768 -0.9512 0.1363 +vn 0.2177 -0.9391 0.2657 +vn 0.2971 -0.9162 0.2687 +vn 0.1969 -0.9762 0.0905 +vn 0.1855 -0.9688 0.1640 +vn 0.1769 -0.9593 0.2202 +vn 0.1426 -0.9794 0.1430 +vn 0.1380 -0.9881 0.0675 +vn 0.1137 -0.9816 0.1535 +vn 0.0684 -0.9909 0.1161 +vn 0.0992 -0.9872 0.1244 +vn 0.0492 -0.9948 0.0896 +vn 0.0742 -0.9904 0.1165 +vn 0.0916 -0.9926 0.0799 +vn 0.0536 -0.9946 0.0889 +vn 0.1607 -0.9726 0.1677 +vn 0.1038 -0.9899 0.0963 +vn 0.0293 -0.9971 0.0699 +vn 0.0766 -0.9953 0.0590 +vn 0.0454 -0.9964 0.0708 +vn 0.0917 -0.9952 0.0327 +vn 0.0880 -0.9961 0.0046 +vn 0.0304 -0.9988 0.0377 +vn 0.0672 -0.9975 -0.0204 +vn 0.0075 -0.9977 0.0674 +vn 0.0393 -0.9975 0.0583 +vn 0.0348 -0.9993 -0.0105 +vn 0.0015 -0.9990 0.0440 +vn 0.0042 -0.9989 0.0468 +vn -0.0056 -0.9986 0.0522 +vn 0.0273 -0.9990 0.0343 +vn -0.0050 -0.9996 0.0275 +vn -0.0194 -0.9981 0.0587 +vn -0.0161 -0.9982 0.0583 +vn -0.0200 -0.9985 0.0497 +vn -0.0134 -0.9995 0.0279 +vn -0.0035 -0.9973 0.0739 +vn -0.0198 -0.9967 0.0790 +vn -0.0362 -0.6050 0.7954 +vn -0.0241 -0.5094 0.8602 +vn -0.0510 -0.5246 0.8498 +vn 0.0514 -0.4669 0.8828 +vn 0.0086 -0.5504 0.8348 +vn -0.0572 -0.4269 0.9025 +vn -0.0089 -0.4320 0.9018 +vn -0.0363 -0.6824 0.7301 +vn 0.0225 -0.5860 0.8100 +vn 0.0872 -0.4961 0.8639 +vn -0.1050 -0.9320 0.3468 +vn -0.0641 -0.9158 0.3965 +vn -0.1096 -0.9208 0.3744 +vn 0.0031 -0.8849 0.4657 +vn -0.0555 -0.9200 0.3879 +vn -0.0988 -0.8826 0.4595 +vn -0.0368 -0.8807 0.4722 +vn -0.1249 -0.9244 0.3604 +vn -0.0767 -0.9116 0.4039 +vn 0.0768 -0.8117 0.5789 +vn 0.0011 -0.8751 0.4839 +vn 0.1316 -0.7770 0.6155 +vn 0.0039 -0.8199 0.5725 +vn -0.0658 -0.8117 0.5803 +vn -0.1381 -0.9685 0.2070 +vn -0.1372 -0.9422 0.3057 +vn -0.1758 -0.9403 0.2915 +vn -0.0495 -0.9488 0.3120 +vn -0.0854 -0.9637 0.2528 +vn -0.1760 -0.9211 0.3471 +vn -0.1258 -0.9277 0.3515 +vn -0.0823 -0.9908 0.1075 +vn -0.0213 -0.9833 0.1808 +vn -0.0316 -0.9362 0.3500 +vn 0.0314 -0.9697 0.2422 +vn 0.0838 -0.9475 0.3086 +vn -0.1172 -0.9227 0.3672 +vn -0.1595 -0.9185 0.3619 +vn -0.0246 -0.7133 0.7004 +vn 0.0753 -0.6550 0.7518 +vn 0.0356 -0.6174 0.7858 +vn 0.1317 -0.7249 0.6761 +vn 0.0438 -0.7426 0.6683 +vn 0.1115 -0.5527 0.8259 +vn 0.1426 -0.6256 0.7670 +vn 0.1816 -0.6847 0.7058 +vn 0.1860 -0.5932 0.7832 +vn 0.1721 -0.5000 0.8488 +vn 0.2476 -0.6166 0.7473 +vn 0.2803 -0.5307 0.7998 +vn 0.2293 -0.5600 0.7961 +vn 0.3435 -0.4723 0.8117 +vn 0.3058 -0.5529 0.7750 +vn 0.2242 -0.4774 0.8495 +vn 0.2954 -0.4603 0.8371 +vn 0.2427 -0.6554 0.7152 +vn 0.3092 -0.5658 0.7643 +vn 0.3533 -0.4849 0.8000 +vn -0.1339 -0.9140 0.3830 +vn -0.0917 -0.9056 0.4141 +vn -0.0988 -0.9026 0.4189 +vn -0.0312 -0.9210 0.3882 +vn -0.1069 -0.9178 0.3823 +vn -0.0297 -0.8821 0.4701 +vn -0.0275 -0.8992 0.4367 +vn 0.0639 -0.9142 0.4001 +vn 0.0563 -0.8816 0.4686 +vn 0.0717 -0.8397 0.5383 +vn 0.1610 -0.8843 0.4383 +vn 0.2224 -0.8268 0.5166 +vn 0.1384 -0.8563 0.4975 +vn 0.3103 -0.7738 0.5521 +vn 0.2506 -0.8367 0.4870 +vn 0.1563 -0.8010 0.5779 +vn 0.2523 -0.7738 0.5810 +vn 0.1742 -0.8994 0.4009 +vn 0.2575 -0.8419 0.4742 +vn 0.3501 -0.7035 0.6184 +vn 0.3301 -0.7759 0.5376 +vn 0.4000 -0.6883 0.6051 +vn 0.2840 -0.7181 0.6354 +vn 0.2045 -0.7387 0.6422 +vn 0.2625 -0.6535 0.7099 +vn 0.3312 -0.5931 0.7338 +vn 0.3094 -0.5753 0.7572 +vn 0.3698 -0.6341 0.6791 +vn 0.3125 -0.6558 0.6872 +vn 0.3525 -0.5207 0.7775 +vn 0.3711 -0.5651 0.7368 +vn 0.4000 -0.6114 0.6827 +vn 0.3905 -0.5419 0.7442 +vn 0.3834 -0.4704 0.7948 +vn 0.4324 -0.5676 0.7005 +vn 0.4401 -0.4942 0.7497 +vn 0.4079 -0.5195 0.7507 +vn 0.4916 -0.4440 0.7491 +vn 0.4705 -0.5155 0.7161 +vn 0.4018 -0.4478 0.7988 +vn 0.4472 -0.4289 0.7848 +vn 0.4526 -0.6041 0.6558 +vn 0.4911 -0.5357 0.6868 +vn 0.5171 -0.4732 0.7132 +vn -0.0004 -0.9991 0.0425 +vn 0.0919 -0.9946 0.0479 +vn 0.0428 -0.9934 0.1059 +vn 0.1162 -0.9932 -0.0017 +vn 0.0751 -0.9972 -0.0025 +vn 0.0914 -0.9856 0.1419 +vn 0.1243 -0.9906 0.0563 +vn 0.1064 -0.9941 0.0200 +vn 0.1203 -0.9906 0.0650 +vn 0.1106 -0.9802 0.1640 +vn 0.1086 -0.9930 0.0461 +vn 0.1332 -0.9875 0.0834 +vn 0.1162 -0.9905 0.0737 +vn 0.1816 -0.9727 0.1443 +vn 0.1322 -0.9883 0.0752 +vn 0.1264 -0.9792 0.1585 +vn 0.1617 -0.9745 0.1557 +vn 0.2531 -0.9322 0.2586 +vn 0.2045 -0.9451 0.2547 +vn 0.1494 -0.9499 0.2745 +vn 0.1985 -0.9036 0.3797 +vn 0.2839 -0.8566 0.4308 +vn 0.2627 -0.8478 0.4607 +vn 0.3200 -0.8784 0.3549 +vn 0.2481 -0.9040 0.3480 +vn 0.3323 -0.7971 0.5043 +vn 0.3448 -0.8259 0.4461 +vn 0.3560 -0.8445 0.4000 +vn 0.3867 -0.7935 0.4698 +vn 0.3937 -0.7478 0.5346 +vn 0.4167 -0.7819 0.4637 +vn 0.4681 -0.7280 0.5009 +vn 0.4288 -0.7580 0.4915 +vn 0.4989 -0.6786 0.5390 +vn 0.4617 -0.7309 0.5025 +vn 0.4401 -0.7161 0.5417 +vn 0.4890 -0.6860 0.5387 +vn 0.5357 -0.6219 0.5711 +vn 0.4576 -0.6682 0.5865 +vn 0.5087 -0.6471 0.5678 +vn 0.4836 -0.6099 0.6278 +vn 0.5380 -0.5600 0.6299 +vn 0.5129 -0.5509 0.6583 +vn 0.5653 -0.5758 0.5907 +vn 0.5262 -0.6049 0.5976 +vn 0.5476 -0.5036 0.6682 +vn 0.5700 -0.5304 0.6275 +vn 0.5805 -0.5429 0.6068 +vn 0.5861 -0.5111 0.6287 +vn 0.5662 -0.4820 0.6686 +vn 0.6023 -0.5034 0.6196 +vn 0.6155 -0.4829 0.6229 +vn 0.6030 -0.4938 0.6266 +vn 0.6233 -0.4718 0.6236 +vn 0.6160 -0.4821 0.6229 +vn 0.5938 -0.4823 0.6440 +vn 0.6163 -0.4765 0.6270 +g bubble_Icosphere_bubble +usemtl bubble +s 1 +f 5434/4089/3420 5433/4090/3421 5439/4091/3422 +f 5436/4092/3423 5433/4090/3421 5435/4093/3424 +f 5438/4094/3425 5433/4090/3421 5437/4095/3426 +f 4092/4096/3427 3995/4097/3428 3831/4098/3429 +f 4092/4096/3427 5435/4093/3424 5434/4089/3420 +f 5434/4089/3420 3994/4099/3430 3995/4097/3428 +f 5417/4100/3431 4094/4101/3432 3846/4102/3433 +f 5416/4103/3434 5436/4092/3423 5417/4100/3431 +f 5436/4092/3423 4093/4104/3435 4094/4101/3432 +f 3993/4105/3436 5415/4106/3437 3845/4107/3438 +f 3994/4099/3430 5438/4094/3425 3993/4105/3436 +f 5438/4094/3425 5416/4103/3434 5415/4106/3437 +f 5441/4108/3439 5440/4109/3440 5446/4110/3441 +f 5443/4111/3442 5440/4109/3440 5442/4112/3443 +f 5445/4113/3444 5440/4109/3440 5444/4114/3445 +f 3998/4115/3446 4004/4116/3447 3832/4117/3448 +f 3998/4115/3446 5442/4112/3443 5441/4108/3439 +f 4004/4116/3447 5446/4110/3441 4003/4118/3449 +f 5363/4119/3450 3996/4120/3451 3848/4121/3452 +f 5363/4119/3450 5444/4114/3445 5443/4111/3442 +f 5443/4111/3442 3997/4122/3453 3996/4120/3451 +f 4002/4123/3454 5361/4124/3455 3854/4125/3456 +f 4003/4118/3449 5445/4113/3444 4002/4123/3454 +f 5445/4113/3444 5362/4126/3457 5361/4124/3455 +f 5448/4127/3458 5447/4128/3459 5453/4129/3460 +f 5451/4130/3461 5449/4131/3462 5450/4132/3463 +f 5452/4133/3464 5447/4128/3459 5451/4130/3461 +f 3995/4134/3428 4010/4135/3465 3831/4136/3429 +f 3995/4134/3428 5449/4131/3462 5448/4127/3458 +f 4010/4135/3465 5453/4129/3460 4009/4137/3466 +f 5309/4138/3467 3993/4139/3436 3845/4140/3438 +f 5308/4141/3468 5450/4132/3463 5309/4138/3467 +f 5450/4132/3463 3994/4142/3430 3993/4139/3436 +f 4008/4143/3469 5307/4144/3470 3860/4145/3471 +f 4009/4137/3466 5452/4133/3464 4008/4143/3469 +f 5307/4144/3470 5451/4130/3461 5308/4141/3468 +f 5455/4146/3472 5454/4147/3473 5460/4148/3474 +f 5457/4149/3475 5454/4147/3473 5456/4150/3476 +f 5460/4148/3474 5458/4151/3477 5459/4152/3478 +f 4010/4153/3465 4016/4154/3479 3831/4155/3429 +f 4010/4153/3465 5456/4150/3476 5455/4146/3472 +f 4016/4154/3479 5460/4148/3474 4015/4156/3480 +f 5255/4157/3481 4008/4158/3469 3860/4159/3471 +f 5254/4160/3482 5457/4149/3475 5255/4157/3481 +f 5457/4149/3475 4009/4161/3466 4008/4158/3469 +f 4014/4162/3483 5253/4163/3484 3866/4164/3485 +f 4015/4156/3480 5459/4152/3478 4014/4162/3483 +f 5459/4152/3478 5254/4160/3482 5253/4163/3484 +f 5462/4165/3486 5461/4166/3487 5467/4167/3488 +f 5464/4168/3489 5461/4166/3487 5463/4169/3490 +f 5466/4170/3491 5461/4166/3487 5465/4171/3492 +f 4016/4172/3479 4119/4173/3493 3831/4174/3429 +f 4015/4175/3480 5462/4165/3486 4016/4172/3479 +f 5462/4165/3486 4120/4176/3494 4119/4173/3493 +f 5201/4177/3495 4014/4178/3483 3866/4179/3485 +f 5200/4180/3496 5464/4168/3489 5201/4177/3495 +f 5464/4168/3489 4015/4175/3480 4014/4178/3483 +f 4121/4181/3497 5199/4182/3498 3855/4183/3499 +f 4120/4176/3494 5466/4170/3491 4121/4181/3497 +f 5466/4170/3491 5200/4180/3496 5199/4182/3498 +f 5469/4184/3500 5468/4185/3501 5474/4186/3502 +f 5471/4187/3503 5468/4185/3501 5470/4188/3504 +f 5473/4189/3505 5468/4185/3501 5472/4190/3506 +f 4004/4116/3447 4025/4191/3507 3832/4117/3448 +f 4004/4116/3447 5470/4188/3504 5469/4184/3500 +f 4025/4191/3507 5474/4186/3502 4024/4192/3508 +f 5147/4193/3509 4002/4123/3454 3854/4125/3456 +f 5146/4194/3510 5471/4187/3503 5147/4193/3509 +f 5471/4187/3503 4003/4118/3449 4002/4123/3454 +f 4023/4195/3511 5145/4196/3512 3875/4197/3513 +f 4024/4192/3508 5473/4189/3505 4023/4195/3511 +f 5473/4189/3505 5146/4194/3510 5145/4196/3512 +f 5476/4198/3514 5475/4199/3515 5481/4200/3516 +f 5478/4201/3517 5475/4199/3515 5477/4202/3518 +f 5480/4203/3519 5475/4199/3515 5479/4204/3520 +f 4001/4205/3521 4031/4206/3522 3833/4207/3523 +f 4000/4208/3524 5476/4198/3514 4001/4205/3521 +f 4031/4206/3522 5481/4200/3516 4030/4209/3525 +f 5093/4210/3526 3999/4211/3527 3851/4212/3528 +f 5092/4213/3529 5478/4201/3517 5093/4210/3526 +f 5478/4201/3517 4000/4208/3524 3999/4211/3527 +f 4029/4214/3530 5091/4215/3531 3881/4216/3532 +f 4030/4209/3525 5480/4203/3519 4029/4214/3530 +f 5480/4203/3519 5092/4213/3529 5091/4215/3531 +f 5483/4217/3533 5482/4218/3534 5488/4219/3535 +f 5485/4220/3536 5482/4218/3534 5484/4221/3537 +f 5487/4222/3538 5482/4218/3534 5486/4223/3539 +f 4013/4224/3540 4037/4225/3541 3834/4226/3542 +f 4012/4227/3543 5483/4217/3533 4013/4224/3540 +f 5483/4217/3533 4036/4228/3544 4037/4225/3541 +f 5039/4229/3545 4011/4230/3546 3863/4231/3547 +f 5038/4232/3548 5485/4220/3536 5039/4229/3545 +f 5485/4220/3536 4012/4227/3543 4011/4230/3546 +f 4035/4233/3549 5037/4234/3550 3887/4235/3551 +f 4036/4228/3544 5487/4222/3538 4035/4233/3549 +f 5487/4222/3538 5038/4232/3548 5037/4234/3550 +f 5490/4236/3552 5489/4237/3553 5495/4238/3554 +f 5492/4239/3555 5489/4237/3553 5491/4240/3556 +f 5494/4241/3557 5489/4237/3553 5493/4242/3558 +f 4019/4243/3559 4043/4244/3560 3835/4245/3561 +f 4019/4243/3559 5491/4240/3556 5490/4236/3552 +f 4043/4244/3560 5495/4238/3554 4042/4246/3562 +f 4985/4247/3563 4017/4248/3564 3869/4249/3565 +f 4984/4250/3566 5492/4239/3555 4985/4247/3563 +f 5492/4239/3555 4018/4251/3567 4017/4248/3564 +f 4041/4252/3568 4983/4253/3569 3893/4254/3570 +f 4042/4246/3562 5494/4241/3557 4041/4252/3568 +f 5494/4241/3557 4984/4250/3566 4983/4253/3569 +f 5497/4255/3571 5496/4256/3572 5502/4257/3573 +f 5499/4258/3574 5496/4256/3572 5498/4259/3575 +f 5501/4260/3576 5496/4256/3572 5500/4261/3577 +f 4022/4262/3578 4049/4263/3579 3836/4264/3580 +f 4022/4262/3578 5498/4259/3575 5497/4255/3571 +f 4049/4263/3579 5502/4257/3573 4048/4265/3581 +f 4931/4266/3582 4020/4267/3583 3872/4268/3584 +f 4930/4269/3585 5499/4258/3574 4931/4266/3582 +f 5499/4258/3574 4021/4270/3586 4020/4267/3583 +f 4047/4271/3587 4929/4272/3588 3899/4273/3589 +f 4048/4265/3581 5501/4260/3576 4047/4271/3587 +f 4929/4272/3588 5500/4261/3577 4930/4269/3585 +f 5504/4274/3590 5503/4275/3591 5509/4276/3592 +f 5506/4277/3593 5503/4275/3591 5505/4278/3594 +f 5508/4279/3595 5503/4275/3591 5507/4280/3596 +f 4025/4191/3507 4200/4281/3597 3832/4117/3448 +f 4025/4191/3507 5505/4278/3594 5504/4274/3590 +f 4200/4281/3597 5509/4276/3592 4201/4282/3598 +f 4877/4283/3599 4023/4195/3511 3875/4197/3513 +f 4876/4284/3600 5506/4277/3593 4877/4283/3599 +f 5506/4277/3593 4024/4192/3508 4023/4195/3511 +f 4202/4285/3601 4875/4286/3602 3882/4287/3603 +f 4201/4282/3598 5508/4279/3595 4202/4285/3601 +f 5508/4279/3595 4876/4284/3600 4875/4286/3602 +f 5511/4288/3604 5510/4289/3605 5516/4290/3606 +f 5513/4291/3607 5510/4289/3605 5512/4292/3608 +f 5515/4293/3609 5510/4289/3605 5514/4294/3610 +f 4031/4206/3522 4218/4295/3611 3833/4207/3523 +f 4031/4206/3522 5512/4292/3608 5511/4288/3604 +f 4218/4295/3611 5516/4290/3606 4219/4296/3612 +f 4823/4297/3613 4029/4214/3530 3881/4216/3532 +f 4822/4298/3614 5513/4291/3607 4823/4297/3613 +f 5513/4291/3607 4030/4209/3525 4029/4214/3530 +f 4220/4299/3615 4821/4300/3616 3888/4301/3617 +f 4219/4296/3612 5515/4293/3609 4220/4299/3615 +f 5515/4293/3609 4822/4298/3614 4821/4300/3616 +f 5518/4302/3618 5517/4303/3619 5523/4304/3620 +f 5520/4305/3621 5517/4303/3619 5519/4306/3622 +f 5522/4307/3623 5517/4303/3619 5521/4308/3624 +f 4037/4225/3541 4236/4309/3625 3834/4226/3542 +f 4037/4225/3541 5519/4306/3622 5518/4302/3618 +f 4236/4309/3625 5523/4304/3620 4237/4310/3626 +f 4769/4311/3627 4035/4233/3549 3887/4235/3551 +f 4768/4312/3628 5520/4305/3621 4769/4311/3627 +f 5520/4305/3621 4036/4228/3544 4035/4233/3549 +f 4238/4313/3629 4767/4314/3630 3894/4315/3631 +f 4237/4310/3626 5522/4307/3623 4238/4313/3629 +f 5522/4307/3623 4768/4312/3628 4767/4314/3630 +f 5525/4316/3632 5524/4317/3633 5530/4318/3634 +f 5527/4319/3635 5524/4317/3633 5526/4320/3636 +f 5529/4321/3637 5524/4317/3633 5528/4322/3638 +f 4043/4244/3560 4254/4323/3639 3835/4245/3561 +f 4043/4244/3560 5526/4320/3636 5525/4316/3632 +f 4254/4323/3639 5530/4318/3634 4255/4324/3640 +f 4715/4325/3641 4041/4252/3568 3893/4254/3570 +f 4714/4326/3642 5527/4319/3635 4715/4325/3641 +f 5527/4319/3635 4042/4246/3562 4041/4252/3568 +f 4256/4327/3643 4713/4328/3644 3900/4329/3645 +f 4255/4324/3640 5529/4321/3637 4256/4327/3643 +f 5529/4321/3637 4714/4326/3642 4713/4328/3644 +f 5532/4330/3646 5531/4331/3647 5537/4332/3648 +f 5534/4333/3649 5531/4331/3647 5533/4334/3650 +f 5536/4335/3651 5531/4331/3647 5535/4336/3652 +f 4049/4263/3579 4182/4337/3653 3836/4264/3580 +f 4049/4263/3579 5533/4334/3650 5532/4330/3646 +f 4182/4337/3653 5537/4332/3648 4183/4338/3654 +f 4661/4339/3655 4047/4271/3587 3899/4273/3589 +f 4660/4340/3656 5534/4333/3649 4661/4339/3655 +f 5534/4333/3649 4048/4265/3581 4047/4271/3587 +f 4184/4341/3657 4659/4342/3658 3876/4343/3659 +f 4183/4338/3654 5536/4335/3651 4184/4341/3657 +f 5536/4335/3651 4660/4340/3656 4659/4342/3658 +f 5539/4344/3660 5538/4345/3661 5544/4346/3662 +f 5541/4347/3663 5538/4345/3661 5540/4348/3664 +f 5543/4349/3665 5538/4345/3661 5542/4350/3666 +f 4055/4351/3667 4070/4352/3668 3837/4353/3669 +f 4055/4351/3667 5540/4348/3664 5539/4344/3660 +f 4070/4352/3668 5544/4346/3662 4069/4354/3670 +f 4607/4355/3671 4053/4356/3672 3905/4357/3673 +f 4606/4358/3674 5541/4347/3663 4607/4355/3671 +f 5541/4347/3663 4054/4359/3675 4053/4356/3672 +f 4068/4360/3676 4605/4361/3677 3920/4362/3678 +f 4069/4354/3670 5543/4349/3665 4068/4360/3676 +f 5543/4349/3665 4606/4358/3674 4605/4361/3677 +f 5546/4363/3679 5545/4364/3680 5551/4365/3681 +f 5548/4366/3682 5545/4364/3680 5547/4367/3683 +f 5550/4368/3684 5545/4364/3680 5549/4369/3685 +f 4058/4370/3686 4076/4371/3687 3838/4372/3688 +f 4057/4373/3689 5546/4363/3679 4058/4370/3686 +f 5546/4363/3679 4075/4374/3690 4076/4371/3687 +f 4553/4375/3691 4056/4376/3692 3908/4377/3693 +f 4553/4375/3691 5549/4369/3685 5548/4366/3682 +f 4056/4376/3692 5547/4367/3683 4057/4373/3689 +f 4074/4378/3694 4551/4379/3695 3926/4380/3696 +f 4075/4374/3690 5550/4368/3684 4074/4378/3694 +f 5550/4368/3684 4552/4381/3697 4551/4379/3695 +f 5553/4382/3698 5552/4383/3699 5558/4384/3700 +f 5555/4385/3701 5552/4383/3699 5554/4386/3702 +f 5557/4387/3703 5552/4383/3699 5556/4388/3704 +f 4061/4389/3705 4079/4390/3706 3839/4391/3707 +f 4061/4389/3705 5554/4386/3702 5553/4382/3698 +f 4079/4390/3706 5558/4384/3700 4078/4392/3708 +f 4499/4393/3709 4059/4394/3710 3911/4395/3711 +f 4498/4396/3712 5555/4385/3701 4499/4393/3709 +f 5555/4385/3701 4060/4397/3713 4059/4394/3710 +f 4077/4398/3714 4497/4399/3715 3929/4400/3716 +f 4078/4392/3708 5557/4387/3703 4077/4398/3714 +f 5557/4387/3703 4498/4396/3712 4497/4399/3715 +f 5560/4401/3717 5559/4402/3718 5565/4403/3719 +f 5562/4404/3720 5559/4402/3718 5561/4405/3721 +f 5564/4406/3722 5559/4402/3718 5563/4407/3723 +f 4064/4408/3724 4082/4409/3725 3840/4410/3726 +f 4064/4408/3724 5561/4405/3721 5560/4401/3717 +f 4082/4409/3725 5565/4403/3719 4081/4411/3727 +f 4445/4412/3728 4062/4413/3729 3914/4414/3730 +f 4444/4415/3731 5562/4404/3720 4445/4412/3728 +f 5562/4404/3720 4063/4416/3732 4062/4413/3729 +f 4080/4417/3733 4443/4418/3734 3932/4419/3735 +f 4081/4411/3727 5564/4406/3722 4080/4417/3733 +f 5564/4406/3722 4444/4415/3731 4443/4418/3734 +f 5567/4420/3736 5566/4421/3737 5572/4422/3738 +f 5569/4423/3739 5566/4421/3737 5568/4424/3740 +f 5572/4422/3738 5570/4425/3741 5571/4426/3742 +f 4067/4427/3743 4317/4428/3744 3841/4429/3745 +f 4067/4427/3743 5568/4424/3740 5567/4420/3736 +f 4317/4428/3744 5572/4422/3738 4318/4430/3746 +f 4391/4431/3747 4065/4432/3748 3917/4433/3749 +f 4390/4434/3750 5569/4423/3739 4391/4431/3747 +f 5569/4423/3739 4066/4435/3751 4065/4432/3748 +f 4319/4436/3752 4389/4437/3753 3921/4438/3754 +f 4318/4430/3746 5571/4426/3742 4319/4436/3752 +f 5571/4426/3742 4390/4434/3750 4389/4437/3753 +f 5574/4439/3755 5573/4440/3756 5579/4441/3757 +f 5576/4442/3758 5573/4440/3756 5575/4443/3759 +f 5578/4444/3760 5573/4440/3756 5577/4445/3761 +f 4353/4446/3762 4071/4447/3763 3923/4448/3764 +f 4354/4449/3765 5574/4439/3755 4353/4446/3762 +f 5574/4439/3755 4072/4450/3766 4071/4447/3763 +f 4346/4451/3767 4355/4452/3768 3930/4453/3769 +f 4345/4454/3770 5576/4442/3758 4346/4451/3767 +f 5576/4442/3758 4354/4449/3765 4355/4452/3768 +f 4073/4455/3771 4344/4456/3772 3842/4457/3773 +f 4073/4455/3771 5579/4441/3757 5578/4444/3760 +f 4344/4456/3772 5577/4445/3761 4345/4454/3770 +f 5581/4458/3774 5580/4459/3775 5586/4460/3776 +f 5583/4461/3777 5580/4459/3775 5582/4462/3778 +f 5585/4463/3779 5580/4459/3775 5584/4464/3780 +f 4359/4465/3781 4323/4466/3782 3922/4467/3783 +f 4360/4468/3784 5581/4458/3774 4359/4465/3781 +f 5581/4458/3774 4324/4469/3785 4323/4466/3782 +f 4373/4470/3786 4361/4471/3787 3933/4472/3788 +f 4372/4473/3789 5583/4461/3777 4373/4470/3786 +f 5583/4461/3777 4360/4468/3784 4361/4471/3787 +f 4325/4474/3790 4371/4475/3791 3923/4448/3764 +f 4324/4469/3785 5585/4463/3779 4325/4474/3790 +f 4371/4475/3791 5584/4464/3780 4372/4473/3789 +f 5588/4476/3792 5587/4477/3793 5593/4478/3794 +f 5590/4479/3795 5587/4477/3793 5589/4480/3796 +f 5592/4481/3797 5587/4477/3793 5591/4482/3798 +f 4365/4483/3799 4320/4484/3800 3921/4438/3754 +f 4365/4483/3799 5589/4480/3796 5588/4476/3792 +f 5588/4476/3792 4321/4485/3801 4320/4484/3800 +f 4379/4486/3802 4367/4487/3803 3934/4488/3804 +f 4378/4489/3805 5590/4479/3795 4379/4486/3802 +f 5590/4479/3795 4366/4490/3806 4367/4487/3803 +f 4322/4491/3807 4377/4492/3808 3922/4467/3783 +f 4321/4485/3801 5592/4481/3797 4322/4491/3807 +f 5592/4481/3797 4378/4489/3805 4377/4492/3808 +f 5595/4493/3809 5594/4494/3810 5600/4495/3811 +f 5597/4496/3812 5594/4494/3810 5596/4497/3813 +f 5599/4498/3814 5594/4494/3810 5598/4499/3815 +f 4371/4475/3791 4353/4446/3762 3923/4448/3764 +f 4372/4473/3789 5595/4493/3809 4371/4475/3791 +f 5595/4493/3809 4354/4449/3765 4353/4446/3762 +f 4376/4500/3816 4373/4470/3786 3933/4472/3788 +f 4376/4500/3816 5598/4499/3815 5597/4496/3812 +f 4373/4470/3786 5596/4497/3813 4372/4473/3789 +f 4355/4452/3768 4374/4501/3817 3930/4453/3769 +f 4354/4449/3765 5599/4498/3814 4355/4452/3768 +f 5599/4498/3814 4375/4502/3818 4374/4501/3817 +f 5602/4503/3819 5601/4504/3820 5607/4505/3821 +f 5604/4506/3822 5601/4504/3820 5603/4507/3823 +f 5606/4508/3824 5601/4504/3820 5605/4509/3825 +f 4356/4510/3826 4376/4500/3816 3933/4472/3788 +f 4357/4511/3827 5602/4503/3819 4356/4510/3826 +f 5602/4503/3819 4375/4502/3818 4376/4500/3816 +f 4349/4512/3828 4358/4513/3829 3931/4514/3830 +f 4348/4515/3831 5604/4506/3822 4349/4512/3828 +f 5604/4506/3822 4357/4511/3827 4358/4513/3829 +f 4374/4501/3817 4347/4516/3832 3930/4453/3769 +f 4374/4501/3817 5607/4505/3821 5606/4508/3824 +f 4347/4516/3832 5605/4509/3825 4348/4515/3831 +f 5609/4517/3833 5608/4518/3834 5614/4519/3835 +f 5611/4520/3836 5608/4518/3834 5610/4521/3837 +f 5613/4522/3838 5608/4518/3834 5612/4523/3839 +f 4377/4492/3808 4359/4465/3781 3922/4467/3783 +f 4378/4489/3805 5609/4517/3833 4377/4492/3808 +f 5609/4517/3833 4360/4468/3784 4359/4465/3781 +f 4382/4524/3840 4379/4486/3802 3934/4488/3804 +f 4381/4525/3841 5611/4520/3836 4382/4524/3840 +f 5611/4520/3836 4378/4489/3805 4379/4486/3802 +f 4361/4471/3787 4380/4526/3842 3933/4472/3788 +f 4360/4468/3784 5613/4522/3838 4361/4471/3787 +f 5613/4522/3838 4381/4525/3841 4380/4526/3842 +f 5616/4527/3843 5615/4528/3844 5621/4529/3845 +f 5618/4530/3846 5615/4528/3844 5617/4531/3847 +f 5620/4532/3848 5615/4528/3844 5619/4533/3849 +f 4368/4534/3850 4382/4524/3840 3934/4488/3804 +f 4369/4535/3851 5616/4527/3843 4368/4534/3850 +f 5616/4527/3843 4381/4525/3841 4382/4524/3840 +f 4385/4536/3852 4370/4537/3853 3935/4538/3854 +f 4384/4539/3855 5618/4530/3846 4385/4536/3852 +f 5618/4530/3846 4369/4535/3851 4370/4537/3853 +f 4380/4526/3842 4383/4540/3856 3933/4472/3788 +f 4381/4525/3841 5620/4532/3848 4380/4526/3842 +f 5620/4532/3848 4384/4539/3855 4383/4540/3856 +f 5623/4541/3857 5622/4542/3858 5628/4543/3859 +f 5625/4544/3860 5622/4542/3858 5624/4545/3861 +f 5627/4546/3862 5622/4542/3858 5626/4547/3863 +f 4383/4540/3856 4356/4510/3826 3933/4472/3788 +f 4384/4539/3855 5623/4541/3857 4383/4540/3856 +f 5623/4541/3857 4357/4511/3827 4356/4510/3826 +f 4388/4548/3864 4385/4536/3852 3935/4538/3854 +f 4387/4549/3865 5625/4544/3860 4388/4548/3864 +f 5625/4544/3860 4384/4539/3855 4385/4536/3852 +f 4358/4513/3829 4386/4550/3866 3931/4514/3830 +f 4357/4511/3827 5627/4546/3862 4358/4513/3829 +f 5627/4546/3862 4387/4549/3865 4386/4550/3866 +f 5630/4551/3867 5629/4552/3868 5635/4553/3869 +f 5632/4554/3870 5629/4552/3868 5631/4555/3871 +f 5634/4556/3872 5629/4552/3868 5633/4557/3873 +f 4362/4558/3874 4388/4548/3864 3935/4538/3854 +f 4363/4559/3875 5630/4551/3867 4362/4558/3874 +f 5630/4551/3867 4387/4549/3865 4388/4548/3864 +f 4352/4560/3876 4364/4561/3877 3932/4562/3735 +f 4351/4563/3878 5632/4554/3870 4352/4560/3876 +f 5632/4554/3870 4363/4559/3875 4364/4561/3877 +f 4386/4550/3866 4350/4564/3879 3931/4514/3830 +f 4387/4549/3865 5634/4556/3872 4386/4550/3866 +f 4350/4564/3879 5633/4557/3873 4351/4563/3878 +f 5637/4565/3880 5636/4566/3881 5642/4567/3882 +f 5639/4568/3883 5636/4566/3881 5638/4569/3884 +f 5641/4570/3885 5636/4566/3881 5640/4571/3886 +f 4389/4437/3753 4365/4483/3799 3921/4438/3754 +f 4390/4434/3750 5637/4565/3880 4389/4437/3753 +f 5637/4565/3880 4366/4490/3806 4365/4483/3799 +f 4394/4572/3887 4391/4431/3747 3917/4433/3749 +f 4393/4573/3888 5639/4568/3883 4394/4572/3887 +f 5639/4568/3883 4390/4434/3750 4391/4431/3747 +f 4367/4487/3803 4392/4574/3889 3934/4488/3804 +f 4367/4487/3803 5642/4567/3882 5641/4570/3885 +f 4392/4574/3889 5640/4571/3886 4393/4573/3888 +f 5644/4575/3890 5643/4576/3891 5649/4577/3892 +f 5646/4578/3893 5643/4576/3891 5645/4579/3894 +f 5648/4580/3895 5643/4576/3891 5647/4581/3896 +f 4307/4582/3897 4394/4572/3887 3917/4433/3749 +f 4307/4582/3897 5645/4579/3894 5644/4575/3890 +f 4394/4572/3887 5649/4577/3892 4393/4573/3888 +f 4397/4583/3898 4305/4584/3899 3916/4585/3900 +f 4396/4586/3901 5646/4578/3893 4397/4583/3898 +f 5646/4578/3893 4306/4587/3902 4305/4584/3899 +f 4392/4574/3889 4395/4588/3903 3934/4488/3804 +f 4393/4573/3888 5648/4580/3895 4392/4574/3889 +f 5648/4580/3895 4396/4586/3901 4395/4588/3903 +f 5651/4589/3904 5650/4590/3905 5656/4591/3906 +f 5653/4592/3907 5650/4590/3905 5652/4593/3908 +f 5655/4594/3909 5650/4590/3905 5654/4595/3910 +f 4395/4588/3903 4368/4534/3850 3934/4488/3804 +f 4396/4586/3901 5651/4589/3904 4395/4588/3903 +f 5651/4589/3904 4369/4535/3851 4368/4534/3850 +f 4400/4596/3911 4397/4583/3898 3916/4585/3900 +f 4399/4597/3912 5653/4592/3907 4400/4596/3911 +f 5653/4592/3907 4396/4586/3901 4397/4583/3898 +f 4370/4537/3853 4398/4598/3913 3935/4538/3854 +f 4369/4535/3851 5655/4594/3909 4370/4537/3853 +f 5655/4594/3909 4399/4597/3912 4398/4598/3913 +f 5658/4599/3914 5657/4600/3915 5663/4601/3916 +f 5660/4602/3917 5657/4600/3915 5659/4603/3918 +f 5662/4604/3919 5657/4600/3915 5661/4605/3920 +f 4304/4606/3921 4400/4596/3911 3916/4585/3900 +f 4303/4607/3922 5658/4599/3914 4304/4606/3921 +f 5658/4599/3914 4399/4597/3912 4400/4596/3911 +f 4403/4608/3923 4302/4609/3924 3915/4610/3925 +f 4402/4611/3926 5660/4602/3917 4403/4608/3923 +f 5660/4602/3917 4303/4607/3922 4302/4609/3924 +f 4398/4598/3913 4401/4612/3927 3935/4538/3854 +f 4399/4597/3912 5662/4604/3919 4398/4598/3913 +f 5662/4604/3919 4402/4611/3926 4401/4612/3927 +f 5665/4613/3928 5664/4614/3929 5670/4615/3930 +f 5667/4616/3931 5664/4614/3929 5666/4617/3932 +f 5669/4618/3933 5664/4614/3929 5668/4619/3934 +f 4401/4612/3927 4362/4558/3874 3935/4538/3854 +f 4402/4611/3926 5665/4613/3928 4401/4612/3927 +f 4362/4558/3874 5670/4615/3930 4363/4559/3875 +f 4406/4620/3935 4403/4608/3923 3915/4610/3925 +f 4406/4620/3935 5668/4619/3934 5667/4616/3931 +f 5667/4616/3931 4402/4611/3926 4403/4608/3923 +f 4364/4561/3877 4404/4621/3936 3932/4562/3735 +f 4363/4559/3875 5669/4618/3933 4364/4561/3877 +f 5669/4618/3933 4405/4622/3937 4404/4621/3936 +f 5672/4623/3938 5671/4624/3939 5677/4625/3940 +f 5674/4626/3941 5671/4624/3939 5673/4627/3942 +f 5676/4628/3943 5671/4624/3939 5675/4629/3944 +f 4301/4630/3945 4406/4620/3935 3915/4610/3925 +f 4300/4631/3946 5672/4623/3938 4301/4630/3945 +f 5672/4623/3938 4405/4622/3937 4406/4620/3935 +f 4082/4632/3725 4299/4633/3947 3840/4410/3726 +f 4082/4632/3725 5675/4629/3944 5674/4626/3941 +f 4299/4633/3947 5673/4627/3942 4300/4631/3946 +f 4404/4621/3936 4080/4634/3733 3932/4562/3735 +f 4404/4621/3936 5677/4625/3940 5676/4628/3943 +f 5676/4628/3943 4081/4635/3727 4080/4634/3733 +f 5679/4636/3948 5678/4637/3949 5684/4638/3950 +f 5682/4639/3951 5680/4640/3952 5681/4641/3953 +f 5683/4642/3954 5678/4637/3949 5682/4639/3951 +f 4407/4643/3955 4346/4644/3767 3930/4645/3769 +f 4407/4643/3955 5680/4640/3952 5679/4636/3948 +f 5679/4636/3948 4345/4646/3770 4346/4644/3767 +f 4337/4647/3956 4409/4648/3957 3927/4649/3958 +f 4336/4650/3959 5681/4641/3953 4337/4647/3956 +f 5681/4641/3953 4408/4651/3960 4409/4648/3957 +f 4344/4652/3772 4335/4653/3961 3842/4654/3773 +f 4344/4652/3772 5684/4638/3950 5683/4642/3954 +f 4335/4653/3961 5682/4639/3951 4336/4650/3959 +f 5686/4655/3962 5685/4656/3963 5691/4657/3964 +f 5689/4658/3965 5687/4659/3966 5688/4660/3967 +f 5690/4661/3968 5685/4656/3963 5689/4658/3965 +f 4413/4662/3969 4349/4663/3828 3931/4664/3830 +f 4413/4662/3969 5687/4659/3966 5686/4655/3962 +f 4349/4663/3828 5691/4657/3964 4348/4665/3831 +f 4427/4666/3970 4415/4667/3971 3936/4668/3972 +f 4426/4669/3973 5688/4660/3967 4427/4666/3970 +f 5688/4660/3967 4414/4670/3974 4415/4667/3971 +f 4347/4671/3832 4425/4672/3975 3930/4645/3769 +f 4348/4665/3831 5690/4661/3968 4347/4671/3832 +f 4425/4672/3975 5689/4658/3965 4426/4669/3973 +f 5693/4673/3976 5692/4674/3977 5698/4675/3978 +f 5695/4676/3979 5692/4674/3977 5694/4677/3980 +f 5697/4678/3981 5692/4674/3977 5696/4679/3982 +f 4419/4680/3983 4352/4681/3876 3932/4419/3735 +f 4419/4680/3983 5694/4677/3980 5693/4673/3976 +f 4352/4681/3876 5698/4675/3978 4351/4682/3878 +f 4433/4683/3984 4421/4684/3985 3937/4685/3986 +f 4432/4686/3987 5695/4676/3979 4433/4683/3984 +f 5695/4676/3979 4420/4687/3988 4421/4684/3985 +f 4350/4688/3879 4431/4689/3989 3931/4664/3830 +f 4351/4682/3878 5697/4678/3981 4350/4688/3879 +f 4431/4689/3989 5696/4679/3982 4432/4686/3987 +f 5700/4690/3990 5699/4691/3991 5705/4692/3992 +f 5702/4693/3993 5699/4691/3991 5701/4694/3994 +f 5704/4695/3995 5699/4691/3991 5703/4696/3996 +f 4425/4672/3975 4407/4643/3955 3930/4645/3769 +f 4426/4669/3973 5700/4690/3990 4425/4672/3975 +f 5700/4690/3990 4408/4651/3960 4407/4643/3955 +f 4430/4697/3997 4427/4666/3970 3936/4668/3972 +f 4429/4698/3998 5702/4693/3993 4430/4697/3997 +f 4427/4666/3970 5701/4694/3994 4426/4669/3973 +f 4409/4648/3957 4428/4699/3999 3927/4649/3958 +f 4409/4648/3957 5705/4692/3992 5704/4695/3995 +f 4428/4699/3999 5703/4696/3996 4429/4698/3998 +f 5707/4700/4000 5706/4701/4001 5712/4702/4002 +f 5709/4703/4003 5706/4701/4001 5708/4704/4004 +f 5711/4705/4005 5706/4701/4001 5710/4706/4006 +f 4410/4707/4007 4430/4697/3997 3936/4668/3972 +f 4411/4708/4008 5707/4700/4000 4410/4707/4007 +f 5707/4700/4000 4429/4698/3998 4430/4697/3997 +f 4340/4709/4009 4412/4710/4010 3928/4711/4011 +f 4339/4712/4012 5709/4703/4003 4340/4709/4009 +f 5709/4703/4003 4411/4708/4008 4412/4710/4010 +f 4428/4699/3999 4338/4713/4013 3927/4649/3958 +f 4429/4698/3998 5711/4705/4005 4428/4699/3999 +f 5711/4705/4005 4339/4712/4012 4338/4713/4013 +f 5714/4714/4014 5713/4715/4015 5719/4716/4016 +f 5716/4717/4017 5713/4715/4015 5715/4718/4018 +f 5718/4719/4019 5713/4715/4015 5717/4720/4020 +f 4431/4689/3989 4413/4662/3969 3931/4664/3830 +f 4432/4686/3987 5714/4714/4014 4431/4689/3989 +f 5714/4714/4014 4414/4670/3974 4413/4662/3969 +f 4436/4721/4021 4433/4683/3984 3937/4685/3986 +f 4435/4722/4022 5716/4717/4017 4436/4721/4021 +f 5716/4717/4017 4432/4686/3987 4433/4683/3984 +f 4415/4667/3971 4434/4723/4023 3936/4668/3972 +f 4415/4667/3971 5719/4716/4016 5718/4719/4019 +f 5718/4719/4019 4435/4722/4022 4434/4723/4023 +f 5721/4724/4024 5720/4725/4025 5726/4726/4026 +f 5723/4727/4027 5720/4725/4025 5722/4728/4028 +f 5725/4729/4029 5720/4725/4025 5724/4730/4030 +f 4422/4731/4031 4436/4721/4021 3937/4685/3986 +f 4423/4732/4032 5721/4724/4024 4422/4731/4031 +f 5721/4724/4024 4435/4722/4022 4436/4721/4021 +f 4439/4733/4033 4424/4734/4034 3938/4735/4035 +f 4438/4736/4036 5723/4727/4027 4439/4733/4033 +f 5723/4727/4027 4423/4732/4032 4424/4734/4034 +f 4434/4723/4023 4437/4737/4037 3936/4668/3972 +f 4435/4722/4022 5725/4729/4029 4434/4723/4023 +f 5725/4729/4029 4438/4736/4036 4437/4737/4037 +f 5728/4738/4038 5727/4739/4039 5733/4740/4040 +f 5730/4741/4041 5727/4739/4039 5729/4742/4042 +f 5732/4743/4043 5727/4739/4039 5731/4744/4044 +f 4437/4737/4037 4410/4707/4007 3936/4668/3972 +f 4438/4736/4036 5728/4738/4038 4437/4737/4037 +f 5728/4738/4038 4411/4708/4008 4410/4707/4007 +f 4442/4745/4045 4439/4733/4033 3938/4735/4035 +f 4441/4746/4046 5730/4741/4041 4442/4745/4045 +f 5730/4741/4041 4438/4736/4036 4439/4733/4033 +f 4412/4710/4010 4440/4747/4047 3928/4711/4011 +f 4411/4708/4008 5732/4743/4043 4412/4710/4010 +f 5732/4743/4043 4441/4746/4046 4440/4747/4047 +f 5735/4748/4048 5734/4749/4049 5740/4750/4050 +f 5737/4751/4051 5734/4749/4049 5736/4752/4052 +f 5739/4753/4053 5734/4749/4049 5738/4754/4054 +f 4416/4755/4055 4442/4745/4045 3938/4735/4035 +f 4417/4756/4056 5735/4748/4048 4416/4755/4055 +f 5735/4748/4048 4441/4746/4046 4442/4745/4045 +f 4343/4757/4057 4418/4758/4058 3929/4759/3716 +f 4342/4760/4059 5737/4751/4051 4343/4757/4057 +f 5737/4751/4051 4417/4756/4056 4418/4758/4058 +f 4440/4747/4047 4341/4761/4060 3928/4711/4011 +f 4441/4746/4046 5739/4753/4053 4440/4747/4047 +f 5739/4753/4053 4342/4760/4059 4341/4761/4060 +f 5742/4762/4061 5741/4763/4062 5747/4764/4063 +f 5744/4765/4064 5741/4763/4062 5743/4766/4065 +f 5746/4767/4066 5741/4763/4062 5745/4768/4067 +f 4443/4418/3734 4419/4680/3983 3932/4419/3735 +f 4444/4415/3731 5742/4762/4061 4443/4418/3734 +f 5742/4762/4061 4420/4687/3988 4419/4680/3983 +f 4448/4769/4068 4445/4412/3728 3914/4414/3730 +f 4447/4770/4069 5744/4765/4064 4448/4769/4068 +f 5744/4765/4064 4444/4415/3731 4445/4412/3728 +f 4421/4684/3985 4446/4771/4070 3937/4685/3986 +f 4420/4687/3988 5746/4767/4066 4421/4684/3985 +f 5746/4767/4066 4447/4770/4069 4446/4771/4070 +f 5749/4772/4071 5748/4773/4072 5754/4774/4073 +f 5751/4775/4074 5748/4773/4072 5750/4776/4075 +f 5753/4777/4076 5748/4773/4072 5752/4778/4077 +f 4298/4779/4078 4448/4769/4068 3914/4414/3730 +f 4297/4780/4079 5749/4772/4071 4298/4779/4078 +f 5749/4772/4071 4447/4770/4069 4448/4769/4068 +f 4451/4781/4080 4296/4782/4081 3913/4783/4082 +f 4450/4784/4083 5751/4775/4074 4451/4781/4080 +f 5751/4775/4074 4297/4780/4079 4296/4782/4081 +f 4446/4771/4070 4449/4785/4084 3937/4685/3986 +f 4447/4770/4069 5753/4777/4076 4446/4771/4070 +f 5753/4777/4076 4450/4784/4083 4449/4785/4084 +f 5756/4786/4085 5755/4787/4086 5761/4788/4087 +f 5758/4789/4088 5755/4787/4086 5757/4790/4089 +f 5760/4791/4090 5755/4787/4086 5759/4792/4091 +f 4449/4785/4084 4422/4731/4031 3937/4685/3986 +f 4450/4784/4083 5756/4786/4085 4449/4785/4084 +f 5756/4786/4085 4423/4732/4032 4422/4731/4031 +f 4454/4793/4092 4451/4781/4080 3913/4783/4082 +f 4453/4794/4093 5758/4789/4088 4454/4793/4092 +f 5758/4789/4088 4450/4784/4083 4451/4781/4080 +f 4424/4734/4034 4452/4795/4094 3938/4735/4035 +f 4423/4732/4032 5760/4791/4090 4424/4734/4034 +f 5760/4791/4090 4453/4794/4093 4452/4795/4094 +f 5763/4796/4095 5762/4797/4096 5768/4798/4097 +f 5765/4799/4098 5762/4797/4096 5764/4800/4099 +f 5767/4801/4100 5762/4797/4096 5766/4802/4101 +f 4295/4803/4102 4454/4793/4092 3913/4783/4082 +f 4294/4804/4103 5763/4796/4095 4295/4803/4102 +f 5763/4796/4095 4453/4794/4093 4454/4793/4092 +f 4457/4805/4104 4293/4806/4105 3912/4807/4106 +f 4456/4808/4107 5765/4799/4098 4457/4805/4104 +f 5765/4799/4098 4294/4804/4103 4293/4806/4105 +f 4452/4795/4094 4455/4809/4108 3938/4735/4035 +f 4453/4794/4093 5767/4801/4100 4452/4795/4094 +f 5767/4801/4100 4456/4808/4107 4455/4809/4108 +f 5770/4810/4109 5769/4811/4110 5775/4812/4111 +f 5772/4813/4112 5769/4811/4110 5771/4814/4113 +f 5774/4815/4114 5769/4811/4110 5773/4816/4115 +f 4455/4809/4108 4416/4755/4055 3938/4735/4035 +f 4456/4808/4107 5770/4810/4109 4455/4809/4108 +f 5770/4810/4109 4417/4756/4056 4416/4755/4055 +f 4460/4817/4116 4457/4805/4104 3912/4807/4106 +f 4459/4818/4117 5772/4813/4112 4460/4817/4116 +f 5772/4813/4112 4456/4808/4107 4457/4805/4104 +f 4418/4758/4058 4458/4819/4118 3929/4759/3716 +f 4417/4756/4056 5774/4815/4114 4418/4758/4058 +f 5774/4815/4114 4459/4818/4117 4458/4819/4118 +f 5777/4820/4119 5776/4821/4120 5782/4822/4121 +f 5779/4823/4122 5776/4821/4120 5778/4824/4123 +f 5781/4825/4124 5776/4821/4120 5780/4826/4125 +f 4292/4827/4126 4460/4817/4116 3912/4807/4106 +f 4291/4828/4127 5777/4820/4119 4292/4827/4126 +f 5777/4820/4119 4459/4818/4117 4460/4817/4116 +f 4079/4829/3706 4290/4830/4128 3839/4391/3707 +f 4079/4829/3706 5780/4826/4125 5779/4823/4122 +f 4290/4830/4128 5778/4824/4123 4291/4828/4127 +f 4458/4819/4118 4077/4831/3714 3929/4759/3716 +f 4459/4818/4117 5781/4825/4124 4458/4819/4118 +f 5781/4825/4124 4078/4832/3708 4077/4831/3714 +f 5784/4833/4129 5783/4834/4130 5789/4835/4131 +f 5786/4836/4132 5783/4834/4130 5785/4837/4133 +f 5788/4838/4134 5783/4834/4130 5787/4839/4135 +f 4461/4840/4136 4337/4841/3956 3927/4842/3958 +f 4462/4843/4137 5784/4833/4129 4461/4840/4136 +f 5784/4833/4129 4336/4844/3959 4337/4841/3956 +f 4328/4845/4138 4463/4846/4139 3924/4847/4140 +f 4327/4848/4141 5786/4836/4132 4328/4845/4138 +f 5786/4836/4132 4462/4843/4137 4463/4846/4139 +f 4335/4849/3961 4326/4850/4142 3842/4851/3773 +f 4335/4849/3961 5789/4835/4131 5788/4838/4134 +f 5788/4838/4134 4327/4848/4141 4326/4850/4142 +f 5791/4852/4143 5790/4853/4144 5796/4854/4145 +f 5793/4855/4146 5790/4853/4144 5792/4856/4147 +f 5795/4857/4148 5790/4853/4144 5794/4858/4149 +f 4467/4859/4150 4340/4860/4009 3928/4861/4011 +f 4468/4862/4151 5791/4852/4143 4467/4859/4150 +f 5791/4852/4143 4339/4863/4012 4340/4860/4009 +f 4481/4864/4152 4469/4865/4153 3939/4866/4154 +f 4480/4867/4155 5793/4855/4146 4481/4864/4152 +f 5793/4855/4146 4468/4862/4151 4469/4865/4153 +f 4338/4868/4013 4479/4869/4156 3927/4842/3958 +f 4338/4868/4013 5796/4854/4145 5795/4857/4148 +f 4479/4869/4156 5794/4858/4149 4480/4867/4155 +f 5798/4870/4157 5797/4871/4158 5803/4872/4159 +f 5800/4873/4160 5797/4871/4158 5799/4874/4161 +f 5802/4875/4162 5797/4871/4158 5801/4876/4163 +f 4473/4877/4164 4343/4878/4057 3929/4400/3716 +f 4473/4877/4164 5799/4874/4161 5798/4870/4157 +f 4343/4878/4057 5803/4872/4159 4342/4879/4059 +f 4487/4880/4165 4475/4881/4166 3940/4882/4167 +f 4487/4880/4165 5801/4876/4163 5800/4873/4160 +f 5800/4873/4160 4474/4883/4168 4475/4881/4166 +f 4341/4884/4060 4485/4885/4169 3928/4861/4011 +f 4342/4879/4059 5802/4875/4162 4341/4884/4060 +f 5802/4875/4162 4486/4886/4170 4485/4885/4169 +f 5805/4887/4171 5804/4888/4172 5810/4889/4173 +f 5807/4890/4174 5804/4888/4172 5806/4891/4175 +f 5809/4892/4176 5804/4888/4172 5808/4893/4177 +f 4479/4869/4156 4461/4840/4136 3927/4842/3958 +f 4480/4867/4155 5805/4887/4171 4479/4869/4156 +f 5805/4887/4171 4462/4843/4137 4461/4840/4136 +f 4484/4894/4178 4481/4864/4152 3939/4866/4154 +f 4484/4894/4178 5808/4893/4177 5807/4890/4174 +f 4481/4864/4152 5806/4891/4175 4480/4867/4155 +f 4463/4846/4139 4482/4895/4179 3924/4847/4140 +f 4462/4843/4137 5809/4892/4176 4463/4846/4139 +f 5809/4892/4176 4483/4896/4180 4482/4895/4179 +f 5812/4897/4181 5811/4898/4182 5817/4899/4183 +f 5814/4900/4184 5811/4898/4182 5813/4901/4185 +f 5816/4902/4186 5811/4898/4182 5815/4903/4187 +f 4464/4904/4188 4484/4894/4178 3939/4866/4154 +f 4465/4905/4189 5812/4897/4181 4464/4904/4188 +f 5812/4897/4181 4483/4896/4180 4484/4894/4178 +f 4331/4906/4190 4466/4907/4191 3925/4908/4192 +f 4330/4909/4193 5814/4900/4184 4331/4906/4190 +f 5814/4900/4184 4465/4905/4189 4466/4907/4191 +f 4482/4895/4179 4329/4910/4194 3924/4847/4140 +f 4482/4895/4179 5817/4899/4183 5816/4902/4186 +f 4329/4910/4194 5815/4903/4187 4330/4909/4193 +f 5819/4911/4195 5818/4912/4196 5824/4913/4197 +f 5821/4914/4198 5818/4912/4196 5820/4915/4199 +f 5823/4916/4200 5818/4912/4196 5822/4917/4201 +f 4485/4885/4169 4467/4859/4150 3928/4861/4011 +f 4486/4886/4170 5819/4911/4195 4485/4885/4169 +f 5819/4911/4195 4468/4862/4151 4467/4859/4150 +f 4490/4918/4202 4487/4880/4165 3940/4882/4167 +f 4489/4919/4203 5821/4914/4198 4490/4918/4202 +f 5821/4914/4198 4486/4886/4170 4487/4880/4165 +f 4469/4865/4153 4488/4920/4204 3939/4866/4154 +f 4468/4862/4151 5823/4916/4200 4469/4865/4153 +f 5823/4916/4200 4489/4919/4203 4488/4920/4204 +f 5826/4921/4205 5825/4922/4206 5831/4923/4207 +f 5828/4924/4208 5825/4922/4206 5827/4925/4209 +f 5830/4926/4210 5825/4922/4206 5829/4927/4211 +f 4476/4928/4212 4490/4918/4202 3940/4882/4167 +f 4477/4929/4213 5826/4921/4205 4476/4928/4212 +f 5826/4921/4205 4489/4919/4203 4490/4918/4202 +f 4493/4930/4214 4478/4931/4215 3941/4932/4216 +f 4492/4933/4217 5828/4924/4208 4493/4930/4214 +f 5828/4924/4208 4477/4929/4213 4478/4931/4215 +f 4488/4920/4204 4491/4934/4218 3939/4866/4154 +f 4489/4919/4203 5830/4926/4210 4488/4920/4204 +f 5830/4926/4210 4492/4933/4217 4491/4934/4218 +f 5833/4935/4219 5832/4936/4220 5838/4937/4221 +f 5835/4938/4222 5832/4936/4220 5834/4939/4223 +f 5837/4940/4224 5832/4936/4220 5836/4941/4225 +f 4491/4934/4218 4464/4904/4188 3939/4866/4154 +f 4492/4933/4217 5833/4935/4219 4491/4934/4218 +f 5833/4935/4219 4465/4905/4189 4464/4904/4188 +f 4496/4942/4226 4493/4930/4214 3941/4932/4216 +f 4495/4943/4227 5835/4938/4222 4496/4942/4226 +f 5835/4938/4222 4492/4933/4217 4493/4930/4214 +f 4466/4907/4191 4494/4944/4228 3925/4908/4192 +f 4465/4905/4189 5837/4940/4224 4466/4907/4191 +f 5837/4940/4224 4495/4943/4227 4494/4944/4228 +f 5840/4945/4229 5839/4946/4230 5845/4947/4231 +f 5842/4948/4232 5839/4946/4230 5841/4949/4233 +f 5844/4950/4234 5839/4946/4230 5843/4951/4235 +f 4470/4952/4236 4496/4942/4226 3941/4932/4216 +f 4471/4953/4237 5840/4945/4229 4470/4952/4236 +f 5840/4945/4229 4495/4943/4227 4496/4942/4226 +f 4334/4954/4238 4472/4955/4239 3926/4956/3696 +f 4333/4957/4240 5842/4948/4232 4334/4954/4238 +f 4472/4955/4239 5841/4949/4233 4471/4953/4237 +f 4494/4944/4228 4332/4958/4241 3925/4908/4192 +f 4495/4943/4227 5844/4950/4234 4494/4944/4228 +f 5844/4950/4234 4333/4957/4240 4332/4958/4241 +f 5847/4959/4242 5846/4960/4243 5852/4961/4244 +f 5849/4962/4245 5846/4960/4243 5848/4963/4246 +f 5851/4964/4247 5846/4960/4243 5850/4965/4248 +f 4497/4399/3715 4473/4877/4164 3929/4400/3716 +f 4498/4396/3712 5847/4959/4242 4497/4399/3715 +f 5847/4959/4242 4474/4883/4168 4473/4877/4164 +f 4502/4966/4249 4499/4393/3709 3911/4395/3711 +f 4501/4967/4250 5849/4962/4245 4502/4966/4249 +f 5849/4962/4245 4498/4396/3712 4499/4393/3709 +f 4475/4881/4166 4500/4968/4251 3940/4882/4167 +f 4474/4883/4168 5851/4964/4247 4475/4881/4166 +f 4500/4968/4251 5850/4965/4248 4501/4967/4250 +f 5854/4969/4252 5853/4970/4253 5859/4971/4254 +f 5856/4972/4255 5853/4970/4253 5855/4973/4256 +f 5858/4974/4257 5853/4970/4253 5857/4975/4258 +f 4289/4976/4259 4502/4966/4249 3911/4395/3711 +f 4288/4977/4260 5854/4969/4252 4289/4976/4259 +f 4502/4966/4249 5859/4971/4254 4501/4967/4250 +f 4505/4978/4261 4287/4979/4262 3910/4980/4263 +f 4504/4981/4264 5856/4972/4255 4505/4978/4261 +f 5856/4972/4255 4288/4977/4260 4287/4979/4262 +f 4500/4968/4251 4503/4982/4265 3940/4882/4167 +f 4501/4967/4250 5858/4974/4257 4500/4968/4251 +f 5858/4974/4257 4504/4981/4264 4503/4982/4265 +f 5861/4983/4266 5860/4984/4267 5866/4985/4268 +f 5863/4986/4269 5860/4984/4267 5862/4987/4270 +f 5865/4988/4271 5860/4984/4267 5864/4989/4272 +f 4503/4982/4265 4476/4928/4212 3940/4882/4167 +f 4504/4981/4264 5861/4983/4266 4503/4982/4265 +f 5861/4983/4266 4477/4929/4213 4476/4928/4212 +f 4508/4990/4273 4505/4978/4261 3910/4980/4263 +f 4507/4991/4274 5863/4986/4269 4508/4990/4273 +f 5863/4986/4269 4504/4981/4264 4505/4978/4261 +f 4478/4931/4215 4506/4992/4275 3941/4932/4216 +f 4477/4929/4213 5865/4988/4271 4478/4931/4215 +f 5865/4988/4271 4507/4991/4274 4506/4992/4275 +f 5868/4993/4276 5867/4994/4277 5873/4995/4278 +f 5870/4996/4279 5867/4994/4277 5869/4997/4280 +f 5872/4998/4281 5867/4994/4277 5871/4999/4282 +f 4286/5000/4283 4508/4990/4273 3910/4980/4263 +f 4285/5001/4284 5868/4993/4276 4286/5000/4283 +f 5868/4993/4276 4507/4991/4274 4508/4990/4273 +f 4511/5002/4285 4284/5003/4286 3909/5004/4287 +f 4510/5005/4288 5870/4996/4279 4511/5002/4285 +f 5870/4996/4279 4285/5001/4284 4284/5003/4286 +f 4506/4992/4275 4509/5006/4289 3941/4932/4216 +f 4507/4991/4274 5872/4998/4281 4506/4992/4275 +f 5872/4998/4281 4510/5005/4288 4509/5006/4289 +f 5875/5007/4290 5874/5008/4291 5880/5009/4292 +f 5877/5010/4293 5874/5008/4291 5876/5011/4294 +f 5879/5012/4295 5874/5008/4291 5878/5013/4296 +f 4509/5006/4289 4470/4952/4236 3941/4932/4216 +f 4509/5006/4289 5876/5011/4294 5875/5007/4290 +f 4470/4952/4236 5880/5009/4292 4471/4953/4237 +f 4514/5014/4297 4511/5002/4285 3909/5004/4287 +f 4513/5015/4298 5877/5010/4293 4514/5014/4297 +f 5877/5010/4293 4510/5005/4288 4511/5002/4285 +f 4472/4955/4239 4512/5016/4299 3926/4956/3696 +f 4471/4953/4237 5879/5012/4295 4472/4955/4239 +f 5879/5012/4295 4513/5015/4298 4512/5016/4299 +f 5882/5017/4300 5881/5018/4301 5887/5019/4302 +f 5884/5020/4303 5881/5018/4301 5883/5021/4304 +f 5886/5022/4305 5881/5018/4301 5885/5023/4306 +f 4283/5024/4307 4514/5014/4297 3909/5004/4287 +f 4282/5025/4308 5882/5017/4300 4283/5024/4307 +f 5882/5017/4300 4513/5015/4298 4514/5014/4297 +f 4076/5026/3687 4281/5027/4309 3838/5028/3688 +f 4076/5026/3687 5885/5023/4306 5884/5020/4303 +f 4281/5027/4309 5883/5021/4304 4282/5025/4308 +f 4512/5016/4299 4074/5029/3694 3926/4956/3696 +f 4513/5015/4298 5886/5022/4305 4512/5016/4299 +f 5886/5022/4305 4075/5030/3690 4074/5029/3694 +f 5889/5031/4310 5888/5032/4311 5894/5033/4312 +f 5891/5034/4313 5888/5032/4311 5890/5035/4314 +f 5893/5036/4315 5888/5032/4311 5892/5037/4316 +f 4515/5038/4317 4328/5039/4138 3924/5040/4140 +f 4516/5041/4318 5889/5031/4310 4515/5038/4317 +f 5889/5031/4310 4327/5042/4141 4328/5039/4138 +f 4310/5043/4319 4517/5044/4320 3918/5045/4321 +f 4309/5046/4322 5891/5034/4313 4310/5043/4319 +f 5891/5034/4313 4516/5041/4318 4517/5044/4320 +f 4326/5047/4142 4308/5048/4323 3842/5049/3773 +f 4326/5047/4142 5894/5033/4312 5893/5036/4315 +f 4308/5048/4323 5892/5037/4316 4309/5046/4322 +f 5896/5050/4324 5895/5051/4325 5901/5052/4326 +f 5898/5053/4327 5895/5051/4325 5897/5054/4328 +f 5900/5055/4329 5895/5051/4325 5899/5056/4330 +f 4521/5057/4331 4331/5058/4190 3925/5059/4192 +f 4522/5060/4332 5896/5050/4324 4521/5057/4331 +f 5896/5050/4324 4330/5061/4193 4331/5058/4190 +f 4535/5062/4333 4523/5063/4334 3942/5064/4335 +f 4534/5065/4336 5898/5053/4327 4535/5062/4333 +f 5898/5053/4327 4522/5060/4332 4523/5063/4334 +f 4329/5066/4194 4533/5067/4337 3924/5040/4140 +f 4330/5061/4193 5900/5055/4329 4329/5066/4194 +f 4533/5067/4337 5899/5056/4330 4534/5065/4336 +f 5903/5068/4338 5902/5069/4339 5908/5070/4340 +f 5905/5071/4341 5902/5069/4339 5904/5072/4342 +f 5907/5073/4343 5902/5069/4339 5906/5074/4344 +f 4527/5075/4345 4334/5076/4238 3926/4380/3696 +f 4528/5077/4346 5903/5068/4338 4527/5075/4345 +f 5903/5068/4338 4333/5078/4240 4334/5076/4238 +f 4541/5079/4347 4529/5080/4348 3943/5081/4349 +f 4540/5082/4350 5905/5071/4341 4541/5079/4347 +f 5905/5071/4341 4528/5077/4346 4529/5080/4348 +f 4332/5083/4241 4539/5084/4351 3925/5059/4192 +f 4333/5078/4240 5907/5073/4343 4332/5083/4241 +f 5907/5073/4343 4540/5082/4350 4539/5084/4351 +f 5910/5085/4352 5909/5086/4353 5915/5087/4354 +f 5912/5088/4355 5909/5086/4353 5911/5089/4356 +f 5914/5090/4357 5909/5086/4353 5913/5091/4358 +f 4533/5067/4337 4515/5038/4317 3924/5040/4140 +f 4534/5065/4336 5910/5085/4352 4533/5067/4337 +f 5910/5085/4352 4516/5041/4318 4515/5038/4317 +f 4538/5092/4359 4535/5062/4333 3942/5064/4335 +f 4538/5092/4359 5913/5091/4358 5912/5088/4355 +f 4535/5062/4333 5911/5089/4356 4534/5065/4336 +f 4517/5044/4320 4536/5093/4360 3918/5045/4321 +f 4516/5041/4318 5914/5090/4357 4517/5044/4320 +f 5914/5090/4357 4537/5094/4361 4536/5093/4360 +f 5917/5095/4362 5916/5096/4363 5922/5097/4364 +f 5919/5098/4365 5916/5096/4363 5918/5099/4366 +f 5921/5100/4367 5916/5096/4363 5920/5101/4368 +f 4518/5102/4369 4538/5092/4359 3942/5064/4335 +f 4519/5103/4370 5917/5095/4362 4518/5102/4369 +f 5917/5095/4362 4537/5094/4361 4538/5092/4359 +f 4313/5104/4371 4520/5105/4372 3919/5106/4373 +f 4312/5107/4374 5919/5098/4365 4313/5104/4371 +f 5919/5098/4365 4519/5103/4370 4520/5105/4372 +f 4536/5093/4360 4311/5108/4375 3918/5045/4321 +f 4536/5093/4360 5922/5097/4364 5921/5100/4367 +f 5921/5100/4367 4312/5107/4374 4311/5108/4375 +f 5924/5109/4376 5923/5110/4377 5929/5111/4378 +f 5926/5112/4379 5923/5110/4377 5925/5113/4380 +f 5928/5114/4381 5923/5110/4377 5927/5115/4382 +f 4539/5084/4351 4521/5057/4331 3925/5059/4192 +f 4540/5082/4350 5924/5109/4376 4539/5084/4351 +f 5924/5109/4376 4522/5060/4332 4521/5057/4331 +f 4544/5116/4383 4541/5079/4347 3943/5081/4349 +f 4543/5117/4384 5926/5112/4379 4544/5116/4383 +f 5926/5112/4379 4540/5082/4350 4541/5079/4347 +f 4523/5063/4334 4542/5118/4385 3942/5064/4335 +f 4522/5060/4332 5928/5114/4381 4523/5063/4334 +f 5928/5114/4381 4543/5117/4384 4542/5118/4385 +f 5931/5119/4386 5930/5120/4387 5936/5121/4388 +f 5933/5122/4389 5930/5120/4387 5932/5123/4390 +f 5935/5124/4391 5930/5120/4387 5934/5125/4392 +f 4530/5126/4393 4544/5116/4383 3943/5081/4349 +f 4531/5127/4394 5931/5119/4386 4530/5126/4393 +f 5931/5119/4386 4543/5117/4384 4544/5116/4383 +f 4547/5128/4395 4532/5129/4396 3944/5130/4397 +f 4546/5131/4398 5933/5122/4389 4547/5128/4395 +f 5933/5122/4389 4531/5127/4394 4532/5129/4396 +f 4542/5118/4385 4545/5132/4399 3942/5064/4335 +f 4543/5117/4384 5935/5124/4391 4542/5118/4385 +f 5935/5124/4391 4546/5131/4398 4545/5132/4399 +f 5938/5133/4400 5937/5134/4401 5943/5135/4402 +f 5940/5136/4403 5937/5134/4401 5939/5137/4404 +f 5942/5138/4405 5937/5134/4401 5941/5139/4406 +f 4545/5132/4399 4518/5102/4369 3942/5064/4335 +f 4546/5131/4398 5938/5133/4400 4545/5132/4399 +f 5938/5133/4400 4519/5103/4370 4518/5102/4369 +f 4550/5140/4407 4547/5128/4395 3944/5130/4397 +f 4549/5141/4408 5940/5136/4403 4550/5140/4407 +f 5940/5136/4403 4546/5131/4398 4547/5128/4395 +f 4520/5105/4372 4548/5142/4409 3919/5106/4373 +f 4519/5103/4370 5942/5138/4405 4520/5105/4372 +f 5942/5138/4405 4549/5141/4408 4548/5142/4409 +f 5945/5143/4410 5944/5144/4411 5950/5145/4412 +f 5947/5146/4413 5944/5144/4411 5946/5147/4414 +f 5949/5148/4415 5944/5144/4411 5948/5149/4416 +f 4524/5150/4417 4550/5140/4407 3944/5130/4397 +f 4525/5151/4418 5945/5143/4410 4524/5150/4417 +f 5945/5143/4410 4549/5141/4408 4550/5140/4407 +f 4316/5152/4419 4526/5153/4420 3920/5154/3678 +f 4315/5155/4421 5947/5146/4413 4316/5152/4419 +f 5947/5146/4413 4525/5151/4418 4526/5153/4420 +f 4548/5142/4409 4314/5156/4422 3919/5106/4373 +f 4549/5141/4408 5949/5148/4415 4548/5142/4409 +f 5949/5148/4415 4315/5155/4421 4314/5156/4422 +f 5952/5157/4423 5951/5158/4424 5957/5159/4425 +f 5954/5160/4426 5951/5158/4424 5953/5161/4427 +f 5956/5162/4428 5951/5158/4424 5955/5163/4429 +f 4551/4379/3695 4527/5075/4345 3926/4380/3696 +f 4552/4381/3697 5952/5157/4423 4551/4379/3695 +f 5952/5157/4423 4528/5077/4346 4527/5075/4345 +f 4556/5164/4430 4553/4375/3691 3908/4377/3693 +f 4555/5165/4431 5954/5160/4426 4556/5164/4430 +f 5954/5160/4426 4552/4381/3697 4553/4375/3691 +f 4529/5080/4348 4554/5166/4432 3943/5081/4349 +f 4528/5077/4346 5956/5162/4428 4529/5080/4348 +f 5956/5162/4428 4555/5165/4431 4554/5166/4432 +f 5959/5167/4433 5958/5168/4434 5964/5169/4435 +f 5961/5170/4436 5958/5168/4434 5960/5171/4437 +f 5963/5172/4438 5958/5168/4434 5962/5173/4439 +f 4280/5174/4440 4556/5164/4430 3908/4377/3693 +f 4279/5175/4441 5959/5167/4433 4280/5174/4440 +f 5959/5167/4433 4555/5165/4431 4556/5164/4430 +f 4559/5176/4442 4278/5177/4443 3907/5178/4444 +f 4558/5179/4445 5961/5170/4436 4559/5176/4442 +f 5961/5170/4436 4279/5175/4441 4278/5177/4443 +f 4554/5166/4432 4557/5180/4446 3943/5081/4349 +f 4555/5165/4431 5963/5172/4438 4554/5166/4432 +f 5963/5172/4438 4558/5179/4445 4557/5180/4446 +f 5966/5181/4447 5965/5182/4448 5971/5183/4449 +f 5968/5184/4450 5965/5182/4448 5967/5185/4451 +f 5970/5186/4452 5965/5182/4448 5969/5187/4453 +f 4557/5180/4446 4530/5126/4393 3943/5081/4349 +f 4558/5179/4445 5966/5181/4447 4557/5180/4446 +f 5966/5181/4447 4531/5127/4394 4530/5126/4393 +f 4562/5188/4454 4559/5176/4442 3907/5178/4444 +f 4562/5188/4454 5969/5187/4453 5968/5184/4450 +f 4559/5176/4442 5967/5185/4451 4558/5179/4445 +f 4532/5129/4396 4560/5189/4455 3944/5130/4397 +f 4531/5127/4394 5970/5186/4452 4532/5129/4396 +f 5970/5186/4452 4561/5190/4456 4560/5189/4455 +f 5973/5191/4457 5972/5192/4458 5978/5193/4459 +f 5975/5194/4460 5972/5192/4458 5974/5195/4461 +f 5977/5196/4462 5972/5192/4458 5976/5197/4463 +f 4277/5198/4464 4562/5188/4454 3907/5178/4444 +f 4276/5199/4465 5973/5191/4457 4277/5198/4464 +f 5973/5191/4457 4561/5190/4456 4562/5188/4454 +f 4565/5200/4466 4275/5201/4467 3906/5202/4468 +f 4565/5200/4466 5976/5197/4463 5975/5194/4460 +f 5975/5194/4460 4276/5199/4465 4275/5201/4467 +f 4560/5189/4455 4563/5203/4469 3944/5130/4397 +f 4560/5189/4455 5978/5193/4459 5977/5196/4462 +f 5977/5196/4462 4564/5204/4470 4563/5203/4469 +f 5980/5205/4471 5979/5206/4472 5985/5207/4473 +f 5982/5208/4474 5979/5206/4472 5981/5209/4475 +f 5984/5210/4476 5979/5206/4472 5983/5211/4477 +f 4563/5203/4469 4524/5150/4417 3944/5130/4397 +f 4564/5204/4470 5980/5205/4471 4563/5203/4469 +f 4524/5150/4417 5985/5207/4473 4525/5151/4418 +f 4568/5212/4478 4565/5200/4466 3906/5202/4468 +f 4567/5213/4479 5982/5208/4474 4568/5212/4478 +f 5982/5208/4474 4564/5204/4470 4565/5200/4466 +f 4526/5153/4420 4566/5214/4480 3920/5154/3678 +f 4525/5151/4418 5984/5210/4476 4526/5153/4420 +f 5984/5210/4476 4567/5213/4479 4566/5214/4480 +f 5987/5215/4481 5986/5216/4482 5992/5217/4483 +f 5989/5218/4484 5986/5216/4482 5988/5219/4485 +f 5991/5220/4486 5986/5216/4482 5990/5221/4487 +f 4274/5222/4488 4568/5212/4478 3906/5202/4468 +f 4273/5223/4489 5987/5215/4481 4274/5222/4488 +f 5987/5215/4481 4567/5213/4479 4568/5212/4478 +f 4070/5224/3668 4272/5225/4490 3837/4353/3669 +f 4070/5224/3668 5990/5221/4487 5989/5218/4484 +f 4272/5225/4490 5988/5219/4485 4273/5223/4489 +f 4566/5214/4480 4068/5226/3676 3920/5154/3678 +f 4567/5213/4479 5991/5220/4486 4566/5214/4480 +f 5991/5220/4486 4069/5227/3670 4068/5226/3676 +f 5994/5228/4491 5993/5229/4492 5999/5230/4493 +f 5996/5231/4494 5993/5229/4492 5995/5232/4495 +f 5998/5233/4496 5993/5229/4492 5997/5234/4497 +f 4569/5235/4498 4310/5236/4319 3918/5237/4321 +f 4570/5238/4499 5994/5228/4491 4569/5235/4498 +f 5994/5228/4491 4309/5239/4322 4310/5236/4319 +f 4071/5240/3763 4571/5241/4500 3923/5242/3764 +f 4072/5243/3766 5996/5231/4494 4071/5240/3763 +f 5996/5231/4494 4570/5238/4499 4571/5241/4500 +f 4308/5244/4323 4073/5245/3771 3842/5246/3773 +f 4308/5244/4323 5999/5230/4493 5998/5233/4496 +f 4073/5245/3771 5997/5234/4497 4072/5243/3766 +f 6001/5247/4501 6000/5248/4502 6006/5249/4503 +f 6003/5250/4504 6000/5248/4502 6002/5251/4505 +f 6005/5252/4506 6000/5248/4502 6004/5253/4507 +f 4575/5254/4508 4313/5255/4371 3919/5256/4373 +f 4576/5257/4509 6001/5247/4501 4575/5254/4508 +f 6001/5247/4501 4312/5258/4374 4313/5255/4371 +f 4589/5259/4510 4577/5260/4511 3945/5261/4512 +f 4588/5262/4513 6003/5250/4504 4589/5259/4510 +f 6003/5250/4504 4576/5257/4509 4577/5260/4511 +f 4311/5263/4375 4587/5264/4514 3918/5237/4321 +f 4311/5263/4375 6006/5249/4503 6005/5252/4506 +f 4587/5264/4514 6004/5253/4507 4588/5262/4513 +f 6008/5265/4515 6007/5266/4516 6013/5267/4517 +f 6010/5268/4518 6007/5266/4516 6009/5269/4519 +f 6012/5270/4520 6007/5266/4516 6011/5271/4521 +f 4581/5272/4522 4316/5273/4419 3920/4362/3678 +f 4582/5274/4523 6008/5265/4515 4581/5272/4522 +f 6008/5265/4515 4315/5275/4421 4316/5273/4419 +f 4595/5276/4524 4583/5277/4525 3946/5278/4526 +f 4594/5279/4527 6010/5268/4518 4595/5276/4524 +f 6010/5268/4518 4582/5274/4523 4583/5277/4525 +f 4314/5280/4422 4593/5281/4528 3919/5256/4373 +f 4315/5275/4421 6012/5270/4520 4314/5280/4422 +f 6012/5270/4520 4594/5279/4527 4593/5281/4528 +f 6015/5282/4529 6014/5283/4530 6020/5284/4531 +f 6017/5285/4532 6014/5283/4530 6016/5286/4533 +f 6019/5287/4534 6014/5283/4530 6018/5288/4535 +f 4587/5264/4514 4569/5235/4498 3918/5237/4321 +f 4588/5262/4513 6015/5282/4529 4587/5264/4514 +f 6015/5282/4529 4570/5238/4499 4569/5235/4498 +f 4592/5289/4536 4589/5259/4510 3945/5261/4512 +f 4592/5289/4536 6018/5288/4535 6017/5285/4532 +f 4589/5259/4510 6016/5286/4533 4588/5262/4513 +f 4571/5241/4500 4590/5290/4537 3923/5242/3764 +f 4570/5238/4499 6019/5287/4534 4571/5241/4500 +f 6019/5287/4534 4591/5291/4538 4590/5290/4537 +f 6022/5292/4539 6021/5293/4540 6027/5294/4541 +f 6024/5295/4542 6021/5293/4540 6023/5296/4543 +f 6026/5297/4544 6021/5293/4540 6025/5298/4545 +f 4572/5299/4546 4592/5289/4536 3945/5261/4512 +f 4573/5300/4547 6022/5292/4539 4572/5299/4546 +f 6022/5292/4539 4591/5291/4538 4592/5289/4536 +f 4323/5301/3782 4574/5302/4548 3922/5303/3783 +f 4324/5304/3785 6024/5295/4542 4323/5301/3782 +f 6024/5295/4542 4573/5300/4547 4574/5302/4548 +f 4590/5290/4537 4325/5305/3790 3923/5242/3764 +f 4590/5290/4537 6027/5294/4541 6026/5297/4544 +f 6026/5297/4544 4324/5304/3785 4325/5305/3790 +f 6029/5306/4549 6028/5307/4550 6034/5308/4551 +f 6031/5309/4552 6028/5307/4550 6030/5310/4553 +f 6033/5311/4554 6028/5307/4550 6032/5312/4555 +f 4593/5281/4528 4575/5254/4508 3919/5256/4373 +f 4594/5279/4527 6029/5306/4549 4593/5281/4528 +f 6029/5306/4549 4576/5257/4509 4575/5254/4508 +f 4598/5313/4556 4595/5276/4524 3946/5278/4526 +f 4597/5314/4557 6031/5309/4552 4598/5313/4556 +f 6031/5309/4552 4594/5279/4527 4595/5276/4524 +f 4577/5260/4511 4596/5315/4558 3945/5261/4512 +f 4576/5257/4509 6033/5311/4554 4577/5260/4511 +f 6033/5311/4554 4597/5314/4557 4596/5315/4558 +f 6036/5316/4559 6035/5317/4560 6041/5318/4561 +f 6038/5319/4562 6035/5317/4560 6037/5320/4563 +f 6040/5321/4564 6035/5317/4560 6039/5322/4565 +f 4584/5323/4566 4598/5313/4556 3946/5278/4526 +f 4585/5324/4567 6036/5316/4559 4584/5323/4566 +f 6036/5316/4559 4597/5314/4557 4598/5313/4556 +f 4601/5325/4568 4586/5326/4569 3947/5327/4570 +f 4600/5328/4571 6038/5319/4562 4601/5325/4568 +f 6038/5319/4562 4585/5324/4567 4586/5326/4569 +f 4596/5315/4558 4599/5329/4572 3945/5261/4512 +f 4597/5314/4557 6040/5321/4564 4596/5315/4558 +f 6040/5321/4564 4600/5328/4571 4599/5329/4572 +f 6043/5330/4573 6042/5331/4574 6048/5332/4575 +f 6045/5333/4576 6042/5331/4574 6044/5334/4577 +f 6047/5335/4578 6042/5331/4574 6046/5336/4579 +f 4599/5329/4572 4572/5299/4546 3945/5261/4512 +f 4600/5328/4571 6043/5330/4573 4599/5329/4572 +f 4572/5299/4546 6048/5332/4575 4573/5300/4547 +f 4604/5337/4580 4601/5325/4568 3947/5327/4570 +f 4603/5338/4581 6045/5333/4576 4604/5337/4580 +f 6045/5333/4576 4600/5328/4571 4601/5325/4568 +f 4574/5302/4548 4602/5339/4582 3922/5303/3783 +f 4573/5300/4547 6047/5335/4578 4574/5302/4548 +f 6047/5335/4578 4603/5338/4581 4602/5339/4582 +f 6050/5340/4583 6049/5341/4584 6055/5342/4585 +f 6052/5343/4586 6049/5341/4584 6051/5344/4587 +f 6054/5345/4588 6049/5341/4584 6053/5346/4589 +f 4578/5347/4590 4604/5337/4580 3947/5327/4570 +f 4579/5348/4591 6050/5340/4583 4578/5347/4590 +f 6050/5340/4583 4603/5338/4581 4604/5337/4580 +f 4320/5349/3800 4580/5350/4592 3921/5351/3754 +f 4321/5352/3801 6052/5343/4586 4320/5349/3800 +f 4580/5350/4592 6051/5344/4587 4579/5348/4591 +f 4602/5339/4582 4322/5353/3807 3922/5303/3783 +f 4603/5338/4581 6054/5345/4588 4602/5339/4582 +f 6054/5345/4588 4321/5352/3801 4322/5353/3807 +f 6057/5354/4593 6056/5355/4594 6062/5356/4595 +f 6059/5357/4596 6056/5355/4594 6058/5358/4597 +f 6061/5359/4598 6056/5355/4594 6060/5360/4599 +f 4605/4361/3677 4581/5272/4522 3920/4362/3678 +f 4606/4358/3674 6057/5354/4593 4605/4361/3677 +f 6057/5354/4593 4582/5274/4523 4581/5272/4522 +f 4610/5361/4600 4607/4355/3671 3905/4357/3673 +f 4609/5362/4601 6059/5357/4596 4610/5361/4600 +f 6059/5357/4596 4606/4358/3674 4607/4355/3671 +f 4583/5277/4525 4608/5363/4602 3946/5278/4526 +f 4582/5274/4523 6061/5359/4598 4583/5277/4525 +f 6061/5359/4598 4609/5362/4601 4608/5363/4602 +f 6064/5364/4603 6063/5365/4604 6069/5366/4605 +f 6066/5367/4606 6063/5365/4604 6065/5368/4607 +f 6068/5369/4608 6063/5365/4604 6067/5370/4609 +f 4271/5371/4610 4610/5361/4600 3905/4357/3673 +f 4270/5372/4611 6064/5364/4603 4271/5371/4610 +f 4610/5361/4600 6069/5366/4605 4609/5362/4601 +f 4613/5373/4612 4269/5374/4613 3904/5375/4614 +f 4612/5376/4615 6066/5367/4606 4613/5373/4612 +f 6066/5367/4606 4270/5372/4611 4269/5374/4613 +f 4608/5363/4602 4611/5377/4616 3946/5278/4526 +f 4609/5362/4601 6068/5369/4608 4608/5363/4602 +f 6068/5369/4608 4612/5376/4615 4611/5377/4616 +f 6071/5378/4617 6070/5379/4618 6076/5380/4619 +f 6073/5381/4620 6070/5379/4618 6072/5382/4621 +f 6075/5383/4622 6070/5379/4618 6074/5384/4623 +f 4611/5377/4616 4584/5323/4566 3946/5278/4526 +f 4612/5376/4615 6071/5378/4617 4611/5377/4616 +f 6071/5378/4617 4585/5324/4567 4584/5323/4566 +f 4616/5385/4624 4613/5373/4612 3904/5375/4614 +f 4615/5386/4625 6073/5381/4620 4616/5385/4624 +f 6073/5381/4620 4612/5376/4615 4613/5373/4612 +f 4586/5326/4569 4614/5387/4626 3947/5327/4570 +f 4585/5324/4567 6075/5383/4622 4586/5326/4569 +f 6075/5383/4622 4615/5386/4625 4614/5387/4626 +f 6078/5388/4627 6077/5389/4628 6083/5390/4629 +f 6080/5391/4630 6077/5389/4628 6079/5392/4631 +f 6082/5393/4632 6077/5389/4628 6081/5394/4633 +f 4268/5395/4634 4616/5385/4624 3904/5375/4614 +f 4267/5396/4635 6078/5388/4627 4268/5395/4634 +f 6078/5388/4627 4615/5386/4625 4616/5385/4624 +f 4619/5397/4636 4266/5398/4637 3903/5399/4638 +f 4619/5397/4636 6081/5394/4633 6080/5391/4630 +f 4266/5398/4637 6079/5392/4631 4267/5396/4635 +f 4614/5387/4626 4617/5400/4639 3947/5327/4570 +f 4615/5386/4625 6082/5393/4632 4614/5387/4626 +f 6082/5393/4632 4618/5401/4640 4617/5400/4639 +f 6085/5402/4641 6084/5403/4642 6090/5404/4643 +f 6087/5405/4644 6084/5403/4642 6086/5406/4645 +f 6089/5407/4646 6084/5403/4642 6088/5408/4647 +f 4617/5400/4639 4578/5347/4590 3947/5327/4570 +f 4617/5400/4639 6086/5406/4645 6085/5402/4641 +f 4578/5347/4590 6090/5404/4643 4579/5348/4591 +f 4622/5409/4648 4619/5397/4636 3903/5399/4638 +f 4621/5410/4649 6087/5405/4644 4622/5409/4648 +f 6087/5405/4644 4618/5401/4640 4619/5397/4636 +f 4580/5350/4592 4620/5411/4650 3921/5351/3754 +f 4579/5348/4591 6089/5407/4646 4580/5350/4592 +f 6089/5407/4646 4621/5410/4649 4620/5411/4650 +f 6092/5412/4651 6091/5413/4652 6097/5414/4653 +f 6094/5415/4654 6091/5413/4652 6093/5416/4655 +f 6097/5414/4653 6095/5417/4656 6096/5418/4657 +f 4265/5419/4658 4622/5409/4648 3903/5399/4638 +f 4264/5420/4659 6092/5412/4651 4265/5419/4658 +f 6092/5412/4651 4621/5410/4649 4622/5409/4648 +f 4317/5421/3744 4263/5422/4660 3841/4429/3745 +f 4317/5421/3744 6095/5417/4656 6094/5415/4654 +f 4263/5422/4660 6093/5416/4655 4264/5420/4659 +f 4620/5411/4650 4319/5423/3752 3921/5351/3754 +f 4621/5410/4649 6096/5418/4657 4620/5411/4650 +f 6096/5418/4657 4318/5424/3746 4319/5423/3752 +f 6099/5425/4661 6098/5426/4662 6104/5427/4663 +f 6101/5428/4664 6098/5426/4662 6100/5429/4665 +f 6103/5430/4666 6098/5426/4662 6102/5431/4667 +f 4623/5432/4668 4026/5433/4669 3878/5434/4670 +f 4624/5435/4671 6099/5425/4661 4623/5432/4668 +f 6099/5425/4661 4027/5436/4672 4026/5433/4669 +f 4065/4432/3748 4625/5437/4673 3917/4433/3749 +f 4065/4432/3748 6102/5431/4667 6101/5428/4664 +f 6101/5428/4664 4624/5435/4671 4625/5437/4673 +f 4028/5438/4674 4067/4427/3743 3841/4429/3745 +f 4028/5438/4674 6104/5427/4663 6103/5430/4666 +f 6103/5430/4666 4066/4435/3751 4067/4427/3743 +f 6106/5439/4675 6105/5440/4676 6111/5441/4677 +f 6108/5442/4678 6105/5440/4676 6107/5443/4679 +f 6110/5444/4680 6105/5440/4676 6109/5445/4681 +f 4629/5446/4682 4188/5447/4683 3877/5448/4684 +f 4630/5449/4685 6106/5439/4675 4629/5446/4682 +f 6106/5439/4675 4189/5450/4686 4188/5447/4683 +f 4643/5451/4687 4631/5452/4688 3948/5453/4689 +f 4642/5454/4690 6108/5442/4678 4643/5451/4687 +f 6108/5442/4678 4630/5449/4685 4631/5452/4688 +f 4190/5455/4691 4641/5456/4692 3878/5434/4670 +f 4189/5450/4686 6110/5444/4680 4190/5455/4691 +f 6110/5444/4680 4642/5454/4690 4641/5456/4692 +f 6113/5457/4693 6112/5458/4694 6118/5459/4695 +f 6115/5460/4696 6112/5458/4694 6114/5461/4697 +f 6117/5462/4698 6112/5458/4694 6116/5463/4699 +f 4635/5464/4700 4185/5465/4701 3876/4343/3659 +f 4635/5464/4700 6114/5461/4697 6113/5457/4693 +f 6113/5457/4693 4186/5466/4702 4185/5465/4701 +f 4649/5467/4703 4637/5468/4704 3949/5469/4705 +f 4648/5470/4706 6115/5460/4696 4649/5467/4703 +f 6115/5460/4696 4636/5471/4707 4637/5468/4704 +f 4187/5472/4708 4647/5473/4709 3877/5448/4684 +f 4186/5466/4702 6117/5462/4698 4187/5472/4708 +f 6117/5462/4698 4648/5470/4706 4647/5473/4709 +f 6120/5474/4710 6119/5475/4711 6125/5476/4712 +f 6122/5477/4713 6119/5475/4711 6121/5478/4714 +f 6124/5479/4715 6119/5475/4711 6123/5480/4716 +f 4641/5456/4692 4623/5432/4668 3878/5434/4670 +f 4642/5454/4690 6120/5474/4710 4641/5456/4692 +f 6120/5474/4710 4624/5435/4671 4623/5432/4668 +f 4646/5481/4717 4643/5451/4687 3948/5453/4689 +f 4645/5482/4718 6122/5477/4713 4646/5481/4717 +f 6122/5477/4713 4642/5454/4690 4643/5451/4687 +f 4625/5437/4673 4644/5483/4719 3917/4433/3749 +f 4624/5435/4671 6124/5479/4715 4625/5437/4673 +f 6124/5479/4715 4645/5482/4718 4644/5483/4719 +f 6127/5484/4720 6126/5485/4721 6132/5486/4722 +f 6129/5487/4723 6126/5485/4721 6128/5488/4724 +f 6131/5489/4725 6126/5485/4721 6130/5490/4726 +f 4626/5491/4727 4646/5481/4717 3948/5453/4689 +f 4627/5492/4728 6127/5484/4720 4626/5491/4727 +f 6127/5484/4720 4645/5482/4718 4646/5481/4717 +f 4305/4584/3899 4628/5493/4729 3916/4585/3900 +f 4306/4587/3902 6129/5487/4723 4305/4584/3899 +f 6129/5487/4723 4627/5492/4728 4628/5493/4729 +f 4644/5483/4719 4307/4582/3897 3917/4433/3749 +f 4645/5482/4718 6131/5489/4725 4644/5483/4719 +f 6131/5489/4725 4306/4587/3902 4307/4582/3897 +f 6134/5494/4730 6133/5495/4731 6139/5496/4732 +f 6136/5497/4733 6133/5495/4731 6135/5498/4734 +f 6138/5499/4735 6133/5495/4731 6137/5500/4736 +f 4647/5473/4709 4629/5446/4682 3877/5448/4684 +f 4648/5470/4706 6134/5494/4730 4647/5473/4709 +f 6134/5494/4730 4630/5449/4685 4629/5446/4682 +f 4652/5501/4737 4649/5467/4703 3949/5469/4705 +f 4651/5502/4738 6136/5497/4733 4652/5501/4737 +f 6136/5497/4733 4648/5470/4706 4649/5467/4703 +f 4631/5452/4688 4650/5503/4739 3948/5453/4689 +f 4630/5449/4685 6138/5499/4735 4631/5452/4688 +f 6138/5499/4735 4651/5502/4738 4650/5503/4739 +f 6141/5504/4740 6140/5505/4741 6146/5506/4742 +f 6143/5507/4743 6140/5505/4741 6142/5508/4744 +f 6145/5509/4745 6140/5505/4741 6144/5510/4746 +f 4638/5511/4747 4652/5501/4737 3949/5469/4705 +f 4639/5512/4748 6141/5504/4740 4638/5511/4747 +f 6141/5504/4740 4651/5502/4738 4652/5501/4737 +f 4655/5513/4749 4640/5514/4750 3950/5515/4751 +f 4654/5516/4752 6143/5507/4743 4655/5513/4749 +f 6143/5507/4743 4639/5512/4748 4640/5514/4750 +f 4650/5503/4739 4653/5517/4753 3948/5453/4689 +f 4651/5502/4738 6145/5509/4745 4650/5503/4739 +f 6145/5509/4745 4654/5516/4752 4653/5517/4753 +f 6148/5518/4754 6147/5519/4755 6153/5520/4756 +f 6150/5521/4757 6147/5519/4755 6149/5522/4758 +f 6152/5523/4759 6147/5519/4755 6151/5524/4760 +f 4653/5517/4753 4626/5491/4727 3948/5453/4689 +f 4654/5516/4752 6148/5518/4754 4653/5517/4753 +f 6148/5518/4754 4627/5492/4728 4626/5491/4727 +f 4658/5525/4761 4655/5513/4749 3950/5515/4751 +f 4657/5526/4762 6150/5521/4757 4658/5525/4761 +f 6150/5521/4757 4654/5516/4752 4655/5513/4749 +f 4628/5493/4729 4656/5527/4763 3916/4585/3900 +f 4627/5492/4728 6152/5523/4759 4628/5493/4729 +f 6152/5523/4759 4657/5526/4762 4656/5527/4763 +f 6155/5528/4764 6154/5529/4765 6160/5530/4766 +f 6157/5531/4767 6154/5529/4765 6156/5532/4768 +f 6159/5533/4769 6154/5529/4765 6158/5534/4770 +f 4632/5535/4771 4658/5525/4761 3950/5515/4751 +f 4633/5536/4772 6155/5528/4764 4632/5535/4771 +f 6155/5528/4764 4657/5526/4762 4658/5525/4761 +f 4302/4609/3924 4634/5537/4773 3915/4610/3925 +f 4303/4607/3922 6157/5531/4767 4302/4609/3924 +f 6157/5531/4767 4633/5536/4772 4634/5537/4773 +f 4656/5527/4763 4304/4606/3921 3916/4585/3900 +f 4657/5526/4762 6159/5533/4769 4656/5527/4763 +f 6159/5533/4769 4303/4607/3922 4304/4606/3921 +f 6162/5538/4774 6161/5539/4775 6167/5540/4776 +f 6164/5541/4777 6161/5539/4775 6163/5542/4778 +f 6166/5543/4779 6161/5539/4775 6165/5544/4780 +f 4659/4342/3658 4635/5464/4700 3876/4343/3659 +f 4660/4340/3656 6162/5538/4774 4659/4342/3658 +f 6162/5538/4774 4636/5471/4707 4635/5464/4700 +f 4664/5545/4781 4661/4339/3655 3899/4273/3589 +f 4663/5546/4782 6164/5541/4777 4664/5545/4781 +f 6164/5541/4777 4660/4340/3656 4661/4339/3655 +f 4637/5468/4704 4662/5547/4783 3949/5469/4705 +f 4636/5471/4707 6166/5543/4779 4637/5468/4704 +f 6166/5543/4779 4663/5546/4782 4662/5547/4783 +f 6169/5548/4784 6168/5549/4785 6174/5550/4786 +f 6171/5551/4787 6168/5549/4785 6170/5552/4788 +f 6173/5553/4789 6168/5549/4785 6172/5554/4790 +f 4253/5555/4791 4664/5545/4781 3899/4273/3589 +f 4253/5555/4791 6170/5552/4788 6169/5548/4784 +f 4664/5545/4781 6174/5550/4786 4663/5546/4782 +f 4667/5556/4792 4251/5557/4793 3898/5558/4794 +f 4666/5559/4795 6171/5551/4787 4667/5556/4792 +f 6171/5551/4787 4252/5560/4796 4251/5557/4793 +f 4662/5547/4783 4665/5561/4797 3949/5469/4705 +f 4663/5546/4782 6173/5553/4789 4662/5547/4783 +f 6173/5553/4789 4666/5559/4795 4665/5561/4797 +f 6176/5562/4798 6175/5563/4799 6181/5564/4800 +f 6178/5565/4801 6175/5563/4799 6177/5566/4802 +f 6180/5567/4803 6175/5563/4799 6179/5568/4804 +f 4665/5561/4797 4638/5511/4747 3949/5469/4705 +f 4666/5559/4795 6176/5562/4798 4665/5561/4797 +f 6176/5562/4798 4639/5512/4748 4638/5511/4747 +f 4670/5569/4805 4667/5556/4792 3898/5558/4794 +f 4669/5570/4806 6178/5565/4801 4670/5569/4805 +f 6178/5565/4801 4666/5559/4795 4667/5556/4792 +f 4640/5514/4750 4668/5571/4807 3950/5515/4751 +f 4639/5512/4748 6180/5567/4803 4640/5514/4750 +f 6180/5567/4803 4669/5570/4806 4668/5571/4807 +f 6183/5572/4808 6182/5573/4809 6188/5574/4810 +f 6185/5575/4811 6182/5573/4809 6184/5576/4812 +f 6187/5577/4813 6182/5573/4809 6186/5578/4814 +f 4250/5579/4815 4670/5569/4805 3898/5558/4794 +f 4249/5580/4816 6183/5572/4808 4250/5579/4815 +f 6183/5572/4808 4669/5570/4806 4670/5569/4805 +f 4673/5581/4817 4248/5582/4818 3897/5583/4819 +f 4673/5581/4817 6186/5578/4814 6185/5575/4811 +f 6185/5575/4811 4249/5580/4816 4248/5582/4818 +f 4668/5571/4807 4671/5584/4820 3950/5515/4751 +f 4669/5570/4806 6187/5577/4813 4668/5571/4807 +f 6187/5577/4813 4672/5585/4821 4671/5584/4820 +f 6190/5586/4822 6189/5587/4823 6195/5588/4824 +f 6192/5589/4825 6189/5587/4823 6191/5590/4826 +f 6194/5591/4827 6189/5587/4823 6193/5592/4828 +f 4671/5584/4820 4632/5535/4771 3950/5515/4751 +f 4671/5584/4820 6191/5590/4826 6190/5586/4822 +f 6190/5586/4822 4633/5536/4772 4632/5535/4771 +f 4676/5593/4829 4673/5581/4817 3897/5583/4819 +f 4675/5594/4830 6192/5589/4825 4676/5593/4829 +f 6192/5589/4825 4672/5585/4821 4673/5581/4817 +f 4634/5537/4773 4674/5595/4831 3915/4610/3925 +f 4633/5536/4772 6194/5591/4827 4634/5537/4773 +f 6194/5591/4827 4675/5594/4830 4674/5595/4831 +f 6197/5596/4832 6196/5597/4833 6202/5598/4834 +f 6199/5599/4835 6196/5597/4833 6198/5600/4836 +f 6201/5601/4837 6196/5597/4833 6200/5602/4838 +f 4247/5603/4839 4676/5593/4829 3897/5583/4819 +f 4246/5604/4840 6197/5596/4832 4247/5603/4839 +f 4676/5593/4829 6202/5598/4834 4675/5594/4830 +f 4299/4633/3947 4245/5605/4841 3840/4410/3726 +f 4299/4633/3947 6200/5602/4838 6199/5599/4835 +f 6199/5599/4835 4246/5604/4840 4245/5605/4841 +f 4674/5595/4831 4301/4630/3945 3915/4610/3925 +f 4675/5594/4830 6201/5601/4837 4674/5595/4831 +f 6201/5601/4837 4300/4631/3946 4301/4630/3945 +f 6204/5606/4842 6203/5607/4843 6209/5608/4844 +f 6206/5609/4845 6203/5607/4843 6205/5610/4846 +f 6208/5611/4847 6203/5607/4843 6207/5612/4848 +f 4677/5613/4849 4050/5614/4850 3902/5615/4851 +f 4678/5616/4852 6204/5606/4842 4677/5613/4849 +f 6204/5606/4842 4051/5617/4853 4050/5614/4850 +f 4062/4413/3729 4679/5618/4854 3914/4414/3730 +f 4063/4416/3732 6206/5609/4845 4062/4413/3729 +f 6206/5609/4845 4678/5616/4852 4679/5618/4854 +f 4052/5619/4855 4064/4408/3724 3840/4410/3726 +f 4052/5619/4855 6209/5608/4844 6208/5611/4847 +f 4064/4408/3724 6207/5612/4848 4063/4416/3732 +f 6211/5620/4856 6210/5621/4857 6216/5622/4858 +f 6213/5623/4859 6210/5621/4857 6212/5624/4860 +f 6215/5625/4861 6210/5621/4857 6214/5626/4862 +f 4683/5627/4863 4260/5628/4864 3901/5629/4865 +f 4684/5630/4866 6211/5620/4856 4683/5627/4863 +f 6211/5620/4856 4261/5631/4867 4260/5628/4864 +f 4697/5632/4868 4685/5633/4869 3951/5634/4870 +f 4696/5635/4871 6213/5623/4859 4697/5632/4868 +f 6213/5623/4859 4684/5630/4866 4685/5633/4869 +f 4262/5636/4872 4695/5637/4873 3902/5615/4851 +f 4261/5631/4867 6215/5625/4861 4262/5636/4872 +f 4695/5637/4873 6214/5626/4862 4696/5635/4871 +f 6218/5638/4874 6217/5639/4875 6223/5640/4876 +f 6220/5641/4877 6217/5639/4875 6219/5642/4878 +f 6222/5643/4879 6217/5639/4875 6221/5644/4880 +f 4689/5645/4881 4257/5646/4882 3900/4329/3645 +f 4689/5645/4881 6219/5642/4878 6218/5638/4874 +f 6218/5638/4874 4258/5647/4883 4257/5646/4882 +f 4703/5648/4884 4691/5649/4885 3952/5650/4886 +f 4702/5651/4887 6220/5641/4877 4703/5648/4884 +f 6220/5641/4877 4690/5652/4888 4691/5649/4885 +f 4259/5653/4889 4701/5654/4890 3901/5629/4865 +f 4258/5647/4883 6222/5643/4879 4259/5653/4889 +f 6222/5643/4879 4702/5651/4887 4701/5654/4890 +f 6225/5655/4891 6224/5656/4892 6230/5657/4893 +f 6227/5658/4894 6224/5656/4892 6226/5659/4895 +f 6229/5660/4896 6224/5656/4892 6228/5661/4897 +f 4695/5637/4873 4677/5613/4849 3902/5615/4851 +f 4696/5635/4871 6225/5655/4891 4695/5637/4873 +f 6225/5655/4891 4678/5616/4852 4677/5613/4849 +f 4700/5662/4898 4697/5632/4868 3951/5634/4870 +f 4700/5662/4898 6228/5661/4897 6227/5658/4894 +f 6227/5658/4894 4696/5635/4871 4697/5632/4868 +f 4679/5618/4854 4698/5663/4899 3914/4414/3730 +f 4678/5616/4852 6229/5660/4896 4679/5618/4854 +f 6229/5660/4896 4699/5664/4900 4698/5663/4899 +f 6232/5665/4901 6231/5666/4902 6237/5667/4903 +f 6234/5668/4904 6231/5666/4902 6233/5669/4905 +f 6236/5670/4906 6231/5666/4902 6235/5671/4907 +f 4680/5672/4908 4700/5662/4898 3951/5634/4870 +f 4681/5673/4909 6232/5665/4901 4680/5672/4908 +f 6232/5665/4901 4699/5664/4900 4700/5662/4898 +f 4296/4782/4081 4682/5674/4910 3913/4783/4082 +f 4297/4780/4079 6234/5668/4904 4296/4782/4081 +f 6234/5668/4904 4681/5673/4909 4682/5674/4910 +f 4698/5663/4899 4298/4779/4078 3914/4414/3730 +f 4698/5663/4899 6237/5667/4903 6236/5670/4906 +f 6236/5670/4906 4297/4780/4079 4298/4779/4078 +f 6239/5675/4911 6238/5676/4912 6244/5677/4913 +f 6241/5678/4914 6238/5676/4912 6240/5679/4915 +f 6243/5680/4916 6238/5676/4912 6242/5681/4917 +f 4701/5654/4890 4683/5627/4863 3901/5629/4865 +f 4702/5651/4887 6239/5675/4911 4701/5654/4890 +f 6239/5675/4911 4684/5630/4866 4683/5627/4863 +f 4706/5682/4918 4703/5648/4884 3952/5650/4886 +f 4705/5683/4919 6241/5678/4914 4706/5682/4918 +f 6241/5678/4914 4702/5651/4887 4703/5648/4884 +f 4685/5633/4869 4704/5684/4920 3951/5634/4870 +f 4684/5630/4866 6243/5680/4916 4685/5633/4869 +f 6243/5680/4916 4705/5683/4919 4704/5684/4920 +f 6246/5685/4921 6245/5686/4922 6251/5687/4923 +f 6248/5688/4924 6245/5686/4922 6247/5689/4925 +f 6250/5690/4926 6245/5686/4922 6249/5691/4927 +f 4692/5692/4928 4706/5682/4918 3952/5650/4886 +f 4693/5693/4929 6246/5685/4921 4692/5692/4928 +f 6246/5685/4921 4705/5683/4919 4706/5682/4918 +f 4709/5694/4930 4694/5695/4931 3953/5696/4932 +f 4708/5697/4933 6248/5688/4924 4709/5694/4930 +f 6248/5688/4924 4693/5693/4929 4694/5695/4931 +f 4704/5684/4920 4707/5698/4934 3951/5634/4870 +f 4705/5683/4919 6250/5690/4926 4704/5684/4920 +f 6250/5690/4926 4708/5697/4933 4707/5698/4934 +f 6253/5699/4935 6252/5700/4936 6258/5701/4937 +f 6255/5702/4938 6252/5700/4936 6254/5703/4939 +f 6257/5704/4940 6252/5700/4936 6256/5705/4941 +f 4707/5698/4934 4680/5672/4908 3951/5634/4870 +f 4708/5697/4933 6253/5699/4935 4707/5698/4934 +f 6253/5699/4935 4681/5673/4909 4680/5672/4908 +f 4712/5706/4942 4709/5694/4930 3953/5696/4932 +f 4711/5707/4943 6255/5702/4938 4712/5706/4942 +f 6255/5702/4938 4708/5697/4933 4709/5694/4930 +f 4682/5674/4910 4710/5708/4944 3913/4783/4082 +f 4681/5673/4909 6257/5704/4940 4682/5674/4910 +f 6257/5704/4940 4711/5707/4943 4710/5708/4944 +f 6260/5709/4945 6259/5710/4946 6265/5711/4947 +f 6262/5712/4948 6259/5710/4946 6261/5713/4949 +f 6264/5714/4950 6259/5710/4946 6263/5715/4951 +f 4686/5716/4952 4712/5706/4942 3953/5696/4932 +f 4687/5717/4953 6260/5709/4945 4686/5716/4952 +f 6260/5709/4945 4711/5707/4943 4712/5706/4942 +f 4293/4806/4105 4688/5718/4954 3912/4807/4106 +f 4293/4806/4105 6263/5715/4951 6262/5712/4948 +f 4688/5718/4954 6261/5713/4949 4687/5717/4953 +f 4710/5708/4944 4295/4803/4102 3913/4783/4082 +f 4711/5707/4943 6264/5714/4950 4710/5708/4944 +f 6264/5714/4950 4294/4804/4103 4295/4803/4102 +f 6267/5719/4955 6266/5720/4956 6272/5721/4957 +f 6269/5722/4958 6266/5720/4956 6268/5723/4959 +f 6271/5724/4960 6266/5720/4956 6270/5725/4961 +f 4713/4328/3644 4689/5645/4881 3900/4329/3645 +f 4714/4326/3642 6267/5719/4955 4713/4328/3644 +f 6267/5719/4955 4690/5652/4888 4689/5645/4881 +f 4718/5726/4962 4715/4325/3641 3893/4254/3570 +f 4717/5727/4963 6269/5722/4958 4718/5726/4962 +f 6269/5722/4958 4714/4326/3642 4715/4325/3641 +f 4691/5649/4885 4716/5728/4964 3952/5650/4886 +f 4690/5652/4888 6271/5724/4960 4691/5649/4885 +f 4716/5728/4964 6270/5725/4961 4717/5727/4963 +f 6274/5729/4965 6273/5730/4966 6279/5731/4967 +f 6276/5732/4968 6273/5730/4966 6275/5733/4969 +f 6278/5734/4970 6273/5730/4966 6277/5735/4971 +f 4235/5736/4972 4718/5726/4962 3893/4254/3570 +f 4234/5737/4973 6274/5729/4965 4235/5736/4972 +f 4718/5726/4962 6279/5731/4967 4717/5727/4963 +f 4721/5738/4974 4233/5739/4975 3892/5740/4976 +f 4720/5741/4977 6276/5732/4968 4721/5738/4974 +f 6276/5732/4968 4234/5737/4973 4233/5739/4975 +f 4716/5728/4964 4719/5742/4978 3952/5650/4886 +f 4717/5727/4963 6278/5734/4970 4716/5728/4964 +f 6278/5734/4970 4720/5741/4977 4719/5742/4978 +f 6281/5743/4979 6280/5744/4980 6286/5745/4981 +f 6283/5746/4982 6280/5744/4980 6282/5747/4983 +f 6285/5748/4984 6280/5744/4980 6284/5749/4985 +f 4719/5742/4978 4692/5692/4928 3952/5650/4886 +f 4720/5741/4977 6281/5743/4979 4719/5742/4978 +f 6281/5743/4979 4693/5693/4929 4692/5692/4928 +f 4724/5750/4986 4721/5738/4974 3892/5740/4976 +f 4723/5751/4987 6283/5746/4982 4724/5750/4986 +f 6283/5746/4982 4720/5741/4977 4721/5738/4974 +f 4694/5695/4931 4722/5752/4988 3953/5696/4932 +f 4693/5693/4929 6285/5748/4984 4694/5695/4931 +f 6285/5748/4984 4723/5751/4987 4722/5752/4988 +f 6288/5753/4989 6287/5754/4990 6293/5755/4991 +f 6290/5756/4992 6287/5754/4990 6289/5757/4993 +f 6292/5758/4994 6287/5754/4990 6291/5759/4995 +f 4232/5760/4996 4724/5750/4986 3892/5740/4976 +f 4231/5761/4997 6288/5753/4989 4232/5760/4996 +f 6288/5753/4989 4723/5751/4987 4724/5750/4986 +f 4727/5762/4998 4230/5763/4999 3891/5764/5000 +f 4726/5765/5001 6290/5756/4992 4727/5762/4998 +f 6290/5756/4992 4231/5761/4997 4230/5763/4999 +f 4722/5752/4988 4725/5766/5002 3953/5696/4932 +f 4723/5751/4987 6292/5758/4994 4722/5752/4988 +f 6292/5758/4994 4726/5765/5001 4725/5766/5002 +f 6295/5767/5003 6294/5768/5004 6300/5769/5005 +f 6297/5770/5006 6294/5768/5004 6296/5771/5007 +f 6299/5772/5008 6294/5768/5004 6298/5773/5009 +f 4725/5766/5002 4686/5716/4952 3953/5696/4932 +f 4726/5765/5001 6295/5767/5003 4725/5766/5002 +f 6295/5767/5003 4687/5717/4953 4686/5716/4952 +f 4730/5774/5010 4727/5762/4998 3891/5764/5000 +f 4729/5775/5011 6297/5770/5006 4730/5774/5010 +f 6297/5770/5006 4726/5765/5001 4727/5762/4998 +f 4688/5718/4954 4728/5776/5012 3912/4807/4106 +f 4687/5717/4953 6299/5772/5008 4688/5718/4954 +f 6299/5772/5008 4729/5775/5011 4728/5776/5012 +f 6302/5777/5013 6301/5778/5014 6307/5779/5015 +f 6304/5780/5016 6301/5778/5014 6303/5781/5017 +f 6306/5782/5018 6301/5778/5014 6305/5783/5019 +f 4229/5784/5020 4730/5774/5010 3891/5764/5000 +f 4228/5785/5021 6302/5777/5013 4229/5784/5020 +f 6302/5777/5013 4729/5775/5011 4730/5774/5010 +f 4290/4830/4128 4227/5786/5022 3839/4391/3707 +f 4290/4830/4128 6305/5783/5019 6304/5780/5016 +f 4227/5786/5022 6303/5781/5017 4228/5785/5021 +f 4728/5776/5012 4292/4827/4126 3912/4807/4106 +f 4729/5775/5011 6306/5782/5018 4728/5776/5012 +f 6306/5782/5018 4291/4828/4127 4292/4827/4126 +f 6309/5787/5023 6308/5788/5024 6314/5789/5025 +f 6311/5790/5026 6308/5788/5024 6310/5791/5027 +f 6313/5792/5028 6308/5788/5024 6312/5793/5029 +f 4731/5794/5030 4044/5795/5031 3896/5796/5032 +f 4732/5797/5033 6309/5787/5023 4731/5794/5030 +f 6309/5787/5023 4045/5798/5034 4044/5795/5031 +f 4059/4394/3710 4733/5799/5035 3911/4395/3711 +f 4060/4397/3713 6311/5790/5026 4059/4394/3710 +f 6311/5790/5026 4732/5797/5033 4733/5799/5035 +f 4046/5800/5036 4061/4389/3705 3839/4391/3707 +f 4046/5800/5036 6314/5789/5025 6313/5792/5028 +f 4061/4389/3705 6312/5793/5029 4060/4397/3713 +f 6316/5801/5037 6315/5802/5038 6321/5803/5039 +f 6318/5804/5040 6315/5802/5038 6317/5805/5041 +f 6320/5806/5042 6315/5802/5038 6319/5807/5043 +f 4737/5808/5044 4242/5809/5045 3895/5810/5046 +f 4738/5811/5047 6316/5801/5037 4737/5808/5044 +f 6316/5801/5037 4243/5812/5048 4242/5809/5045 +f 4751/5813/5049 4739/5814/5050 3954/5815/5051 +f 4750/5816/5052 6318/5804/5040 4751/5813/5049 +f 6318/5804/5040 4738/5811/5047 4739/5814/5050 +f 4244/5817/5053 4749/5818/5054 3896/5796/5032 +f 4243/5812/5048 6320/5806/5042 4244/5817/5053 +f 4749/5818/5054 6319/5807/5043 4750/5816/5052 +f 6323/5819/5055 6322/5820/5056 6328/5821/5057 +f 6325/5822/5058 6322/5820/5056 6324/5823/5059 +f 6327/5824/5060 6322/5820/5056 6326/5825/5061 +f 4743/5826/5062 4239/5827/5063 3894/4315/3631 +f 4744/5828/5064 6323/5819/5055 4743/5826/5062 +f 6323/5819/5055 4240/5829/5065 4239/5827/5063 +f 4757/5830/5066 4745/5831/5067 3955/5832/5068 +f 4756/5833/5069 6325/5822/5058 4757/5830/5066 +f 6325/5822/5058 4744/5828/5064 4745/5831/5067 +f 4241/5834/5070 4755/5835/5071 3895/5810/5046 +f 4240/5829/5065 6327/5824/5060 4241/5834/5070 +f 6327/5824/5060 4756/5833/5069 4755/5835/5071 +f 6330/5836/5072 6329/5837/5073 6335/5838/5074 +f 6332/5839/5075 6329/5837/5073 6331/5840/5076 +f 6334/5841/5077 6329/5837/5073 6333/5842/5078 +f 4749/5818/5054 4731/5794/5030 3896/5796/5032 +f 4750/5816/5052 6330/5836/5072 4749/5818/5054 +f 6330/5836/5072 4732/5797/5033 4731/5794/5030 +f 4754/5843/5079 4751/5813/5049 3954/5815/5051 +f 4753/5844/5080 6332/5839/5075 4754/5843/5079 +f 6332/5839/5075 4750/5816/5052 4751/5813/5049 +f 4733/5799/5035 4752/5845/5081 3911/4395/3711 +f 4732/5797/5033 6334/5841/5077 4733/5799/5035 +f 6334/5841/5077 4753/5844/5080 4752/5845/5081 +f 6337/5846/5082 6336/5847/5083 6342/5848/5084 +f 6339/5849/5085 6336/5847/5083 6338/5850/5086 +f 6341/5851/5087 6336/5847/5083 6340/5852/5088 +f 4734/5853/5089 4754/5843/5079 3954/5815/5051 +f 4735/5854/5090 6337/5846/5082 4734/5853/5089 +f 6337/5846/5082 4753/5844/5080 4754/5843/5079 +f 4287/4979/4262 4736/5855/5091 3910/4980/4263 +f 4288/4977/4260 6339/5849/5085 4287/4979/4262 +f 6339/5849/5085 4735/5854/5090 4736/5855/5091 +f 4752/5845/5081 4289/4976/4259 3911/4395/3711 +f 4752/5845/5081 6342/5848/5084 6341/5851/5087 +f 6341/5851/5087 4288/4977/4260 4289/4976/4259 +f 6344/5856/5092 6343/5857/5093 6349/5858/5094 +f 6346/5859/5095 6343/5857/5093 6345/5860/5096 +f 6348/5861/5097 6343/5857/5093 6347/5862/5098 +f 4755/5835/5071 4737/5808/5044 3895/5810/5046 +f 4756/5833/5069 6344/5856/5092 4755/5835/5071 +f 6344/5856/5092 4738/5811/5047 4737/5808/5044 +f 4760/5863/5099 4757/5830/5066 3955/5832/5068 +f 4759/5864/5100 6346/5859/5095 4760/5863/5099 +f 6346/5859/5095 4756/5833/5069 4757/5830/5066 +f 4739/5814/5050 4758/5865/5101 3954/5815/5051 +f 4738/5811/5047 6348/5861/5097 4739/5814/5050 +f 6348/5861/5097 4759/5864/5100 4758/5865/5101 +f 6351/5866/5102 6350/5867/5103 6356/5868/5104 +f 6353/5869/5105 6350/5867/5103 6352/5870/5106 +f 6355/5871/5107 6350/5867/5103 6354/5872/5108 +f 4746/5873/5109 4760/5863/5099 3955/5832/5068 +f 4747/5874/5110 6351/5866/5102 4746/5873/5109 +f 6351/5866/5102 4759/5864/5100 4760/5863/5099 +f 4763/5875/5111 4748/5876/5112 3956/5877/5113 +f 4762/5878/5114 6353/5869/5105 4763/5875/5111 +f 6353/5869/5105 4747/5874/5110 4748/5876/5112 +f 4758/5865/5101 4761/5879/5115 3954/5815/5051 +f 4759/5864/5100 6355/5871/5107 4758/5865/5101 +f 6355/5871/5107 4762/5878/5114 4761/5879/5115 +f 6358/5880/5116 6357/5881/5117 6363/5882/5118 +f 6360/5883/5119 6357/5881/5117 6359/5884/5120 +f 6362/5885/5121 6357/5881/5117 6361/5886/5122 +f 4761/5879/5115 4734/5853/5089 3954/5815/5051 +f 4762/5878/5114 6358/5880/5116 4761/5879/5115 +f 6358/5880/5116 4735/5854/5090 4734/5853/5089 +f 4766/5887/5123 4763/5875/5111 3956/5877/5113 +f 4765/5888/5124 6360/5883/5119 4766/5887/5123 +f 6360/5883/5119 4762/5878/5114 4763/5875/5111 +f 4736/5855/5091 4764/5889/5125 3910/4980/4263 +f 4735/5854/5090 6362/5885/5121 4736/5855/5091 +f 6362/5885/5121 4765/5888/5124 4764/5889/5125 +f 6365/5890/5126 6364/5891/5127 6370/5892/5128 +f 6367/5893/5129 6364/5891/5127 6366/5894/5130 +f 6369/5895/5131 6364/5891/5127 6368/5896/5132 +f 4740/5897/5133 4766/5887/5123 3956/5877/5113 +f 4741/5898/5134 6365/5890/5126 4740/5897/5133 +f 6365/5890/5126 4765/5888/5124 4766/5887/5123 +f 4284/5003/4286 4742/5899/5135 3909/5004/4287 +f 4285/5001/4284 6367/5893/5129 4284/5003/4286 +f 4742/5899/5135 6366/5894/5130 4741/5898/5134 +f 4764/5889/5125 4286/5000/4283 3910/4980/4263 +f 4765/5888/5124 6369/5895/5131 4764/5889/5125 +f 6369/5895/5131 4285/5001/4284 4286/5000/4283 +f 6372/5900/5136 6371/5901/5137 6377/5902/5138 +f 6374/5903/5139 6371/5901/5137 6373/5904/5140 +f 6376/5905/5141 6371/5901/5137 6375/5906/5142 +f 4767/4314/3630 4743/5826/5062 3894/4315/3631 +f 4768/4312/3628 6372/5900/5136 4767/4314/3630 +f 6372/5900/5136 4744/5828/5064 4743/5826/5062 +f 4772/5907/5143 4769/4311/3627 3887/4235/3551 +f 4771/5908/5144 6374/5903/5139 4772/5907/5143 +f 6374/5903/5139 4768/4312/3628 4769/4311/3627 +f 4745/5831/5067 4770/5909/5145 3955/5832/5068 +f 4744/5828/5064 6376/5905/5141 4745/5831/5067 +f 6376/5905/5141 4771/5908/5144 4770/5909/5145 +f 6379/5910/5146 6378/5911/5147 6384/5912/5148 +f 6381/5913/5149 6378/5911/5147 6380/5914/5150 +f 6383/5915/5151 6378/5911/5147 6382/5916/5152 +f 4217/5917/5153 4772/5907/5143 3887/4235/3551 +f 4217/5917/5153 6380/5914/5150 6379/5910/5146 +f 4772/5907/5143 6384/5912/5148 4771/5908/5144 +f 4775/5918/5154 4215/5919/5155 3886/5920/5156 +f 4774/5921/5157 6381/5913/5149 4775/5918/5154 +f 6381/5913/5149 4216/5922/5158 4215/5919/5155 +f 4770/5909/5145 4773/5923/5159 3955/5832/5068 +f 4771/5908/5144 6383/5915/5151 4770/5909/5145 +f 6383/5915/5151 4774/5921/5157 4773/5923/5159 +f 6386/5924/5160 6385/5925/5161 6391/5926/5162 +f 6388/5927/5163 6385/5925/5161 6387/5928/5164 +f 6390/5929/5165 6385/5925/5161 6389/5930/5166 +f 4773/5923/5159 4746/5873/5109 3955/5832/5068 +f 4774/5921/5157 6386/5924/5160 4773/5923/5159 +f 6386/5924/5160 4747/5874/5110 4746/5873/5109 +f 4778/5931/5167 4775/5918/5154 3886/5920/5156 +f 4777/5932/5168 6388/5927/5163 4778/5931/5167 +f 6388/5927/5163 4774/5921/5157 4775/5918/5154 +f 4748/5876/5112 4776/5933/5169 3956/5877/5113 +f 4747/5874/5110 6390/5929/5165 4748/5876/5112 +f 6390/5929/5165 4777/5932/5168 4776/5933/5169 +f 6393/5934/5170 6392/5935/5171 6398/5936/5172 +f 6395/5937/5173 6392/5935/5171 6394/5938/5174 +f 6397/5939/5175 6392/5935/5171 6396/5940/5176 +f 4214/5941/5177 4778/5931/5167 3886/5920/5156 +f 4213/5942/5178 6393/5934/5170 4214/5941/5177 +f 6393/5934/5170 4777/5932/5168 4778/5931/5167 +f 4781/5943/5179 4212/5944/5180 3885/5945/5181 +f 4781/5943/5179 6396/5940/5176 6395/5937/5173 +f 6395/5937/5173 4213/5942/5178 4212/5944/5180 +f 4776/5933/5169 4779/5946/5182 3956/5877/5113 +f 4777/5932/5168 6397/5939/5175 4776/5933/5169 +f 6397/5939/5175 4780/5947/5183 4779/5946/5182 +f 6400/5948/5184 6399/5949/5185 6405/5950/5186 +f 6402/5951/5187 6399/5949/5185 6401/5952/5188 +f 6404/5953/5189 6399/5949/5185 6403/5954/5190 +f 4779/5946/5182 4740/5897/5133 3956/5877/5113 +f 4780/5947/5183 6400/5948/5184 4779/5946/5182 +f 6400/5948/5184 4741/5898/5134 4740/5897/5133 +f 4784/5955/5191 4781/5943/5179 3885/5945/5181 +f 4783/5956/5192 6402/5951/5187 4784/5955/5191 +f 6402/5951/5187 4780/5947/5183 4781/5943/5179 +f 4742/5899/5135 4782/5957/5193 3909/5004/4287 +f 4741/5898/5134 6404/5953/5189 4742/5899/5135 +f 6404/5953/5189 4783/5956/5192 4782/5957/5193 +f 6407/5958/5194 6406/5959/5195 6412/5960/5196 +f 6409/5961/5197 6406/5959/5195 6408/5962/5198 +f 6411/5963/5199 6406/5959/5195 6410/5964/5200 +f 4211/5965/5201 4784/5955/5191 3885/5945/5181 +f 4210/5966/5202 6407/5958/5194 4211/5965/5201 +f 6407/5958/5194 4783/5956/5192 4784/5955/5191 +f 4281/5027/4309 4209/5967/5203 3838/5028/3688 +f 4281/5027/4309 6410/5964/5200 6409/5961/5197 +f 4209/5967/5203 6408/5962/5198 4210/5966/5202 +f 4782/5957/5193 4283/5024/4307 3909/5004/4287 +f 4783/5956/5192 6411/5963/5199 4782/5957/5193 +f 6411/5963/5199 4282/5025/4308 4283/5024/4307 +f 6414/5968/5204 6413/5969/5205 6419/5970/5206 +f 6416/5971/5207 6413/5969/5205 6415/5972/5208 +f 6418/5973/5209 6413/5969/5205 6417/5974/5210 +f 4785/5975/5211 4038/5976/5212 3890/5977/5213 +f 4786/5978/5214 6414/5968/5204 4785/5975/5211 +f 6414/5968/5204 4039/5979/5215 4038/5976/5212 +f 4056/4376/3692 4787/5980/5216 3908/4377/3693 +f 4057/4373/3689 6416/5971/5207 4056/4376/3692 +f 6416/5971/5207 4786/5978/5214 4787/5980/5216 +f 4040/5981/5217 4058/4370/3686 3838/4372/3688 +f 4040/5981/5217 6419/5970/5206 6418/5973/5209 +f 4058/4370/3686 6417/5974/5210 4057/4373/3689 +f 6421/5982/5218 6420/5983/5219 6426/5984/5220 +f 6423/5985/5221 6420/5983/5219 6422/5986/5222 +f 6425/5987/5223 6420/5983/5219 6424/5988/5224 +f 4791/5989/5225 4224/5990/5226 3889/5991/5227 +f 4791/5989/5225 6422/5986/5222 6421/5982/5218 +f 4224/5990/5226 6426/5984/5220 4225/5992/5228 +f 4805/5993/5229 4793/5994/5230 3957/5995/5231 +f 4804/5996/5232 6423/5985/5221 4805/5993/5229 +f 6423/5985/5221 4792/5997/5233 4793/5994/5230 +f 4226/5998/5234 4803/5999/5235 3890/5977/5213 +f 4225/5992/5228 6425/5987/5223 4226/5998/5234 +f 6425/5987/5223 4804/5996/5232 4803/5999/5235 +f 6428/6000/5236 6427/6001/5237 6433/6002/5238 +f 6430/6003/5239 6427/6001/5237 6429/6004/5240 +f 6432/6005/5241 6427/6001/5237 6431/6006/5242 +f 4797/6007/5243 4221/6008/5244 3888/4301/3617 +f 4797/6007/5243 6429/6004/5240 6428/6000/5236 +f 4221/6008/5244 6433/6002/5238 4222/6009/5245 +f 4811/6010/5246 4799/6011/5247 3958/6012/5248 +f 4810/6013/5249 6430/6003/5239 4811/6010/5246 +f 6430/6003/5239 4798/6014/5250 4799/6011/5247 +f 4223/6015/5251 4809/6016/5252 3889/5991/5227 +f 4222/6009/5245 6432/6005/5241 4223/6015/5251 +f 6432/6005/5241 4810/6013/5249 4809/6016/5252 +f 6435/6017/5253 6434/6018/5254 6440/6019/5255 +f 6437/6020/5256 6434/6018/5254 6436/6021/5257 +f 6439/6022/5258 6434/6018/5254 6438/6023/5259 +f 4803/5999/5235 4785/5975/5211 3890/5977/5213 +f 4804/5996/5232 6435/6017/5253 4803/5999/5235 +f 6435/6017/5253 4786/5978/5214 4785/5975/5211 +f 4808/6024/5260 4805/5993/5229 3957/5995/5231 +f 4807/6025/5261 6437/6020/5256 4808/6024/5260 +f 6437/6020/5256 4804/5996/5232 4805/5993/5229 +f 4787/5980/5216 4806/6026/5262 3908/4377/3693 +f 4787/5980/5216 6440/6019/5255 6439/6022/5258 +f 4806/6026/5262 6438/6023/5259 4807/6025/5261 +f 6442/6027/5263 6441/6028/5264 6447/6029/5265 +f 6444/6030/5266 6441/6028/5264 6443/6031/5267 +f 6446/6032/5268 6441/6028/5264 6445/6033/5269 +f 4788/6034/5270 4808/6024/5260 3957/5995/5231 +f 4788/6034/5270 6443/6031/5267 6442/6027/5263 +f 4808/6024/5260 6447/6029/5265 4807/6025/5261 +f 4278/5177/4443 4790/6035/5271 3907/5178/4444 +f 4279/5175/4441 6444/6030/5266 4278/5177/4443 +f 6444/6030/5266 4789/6036/5272 4790/6035/5271 +f 4806/6026/5262 4280/5174/4440 3908/4377/3693 +f 4807/6025/5261 6446/6032/5268 4806/6026/5262 +f 6446/6032/5268 4279/5175/4441 4280/5174/4440 +f 6449/6037/5273 6448/6038/5274 6454/6039/5275 +f 6451/6040/5276 6448/6038/5274 6450/6041/5277 +f 6453/6042/5278 6448/6038/5274 6452/6043/5279 +f 4809/6016/5252 4791/5989/5225 3889/5991/5227 +f 4810/6013/5249 6449/6037/5273 4809/6016/5252 +f 6449/6037/5273 4792/5997/5233 4791/5989/5225 +f 4814/6044/5280 4811/6010/5246 3958/6012/5248 +f 4813/6045/5281 6451/6040/5276 4814/6044/5280 +f 6451/6040/5276 4810/6013/5249 4811/6010/5246 +f 4793/5994/5230 4812/6046/5282 3957/5995/5231 +f 4793/5994/5230 6454/6039/5275 6453/6042/5278 +f 4812/6046/5282 6452/6043/5279 4813/6045/5281 +f 6456/6047/5283 6455/6048/5284 6461/6049/5285 +f 6458/6050/5286 6455/6048/5284 6457/6051/5287 +f 6460/6052/5288 6455/6048/5284 6459/6053/5289 +f 4800/6054/5290 4814/6044/5280 3958/6012/5248 +f 4801/6055/5291 6456/6047/5283 4800/6054/5290 +f 4814/6044/5280 6461/6049/5285 4813/6045/5281 +f 4817/6056/5292 4802/6057/5293 3959/6058/5294 +f 4816/6059/5295 6458/6050/5286 4817/6056/5292 +f 6458/6050/5286 4801/6055/5291 4802/6057/5293 +f 4812/6046/5282 4815/6060/5296 3957/5995/5231 +f 4813/6045/5281 6460/6052/5288 4812/6046/5282 +f 6460/6052/5288 4816/6059/5295 4815/6060/5296 +f 6463/6061/5297 6462/6062/5298 6468/6063/5299 +f 6465/6064/5300 6462/6062/5298 6464/6065/5301 +f 6467/6066/5302 6462/6062/5298 6466/6067/5303 +f 4815/6060/5296 4788/6034/5270 3957/5995/5231 +f 4816/6059/5295 6463/6061/5297 4815/6060/5296 +f 6463/6061/5297 4789/6036/5272 4788/6034/5270 +f 4820/6068/5304 4817/6056/5292 3959/6058/5294 +f 4819/6069/5305 6465/6064/5300 4820/6068/5304 +f 6465/6064/5300 4816/6059/5295 4817/6056/5292 +f 4790/6035/5271 4818/6070/5306 3907/5178/4444 +f 4790/6035/5271 6468/6063/5299 6467/6066/5302 +f 4818/6070/5306 6466/6067/5303 4819/6069/5305 +f 6470/6071/5307 6469/6072/5308 6475/6073/5309 +f 6472/6074/5310 6469/6072/5308 6471/6075/5311 +f 6474/6076/5312 6469/6072/5308 6473/6077/5313 +f 4794/6078/5314 4820/6068/5304 3959/6058/5294 +f 4795/6079/5315 6470/6071/5307 4794/6078/5314 +f 4820/6068/5304 6475/6073/5309 4819/6069/5305 +f 4275/5201/4467 4796/6080/5316 3906/5202/4468 +f 4276/5199/4465 6472/6074/5310 4275/5201/4467 +f 6472/6074/5310 4795/6079/5315 4796/6080/5316 +f 4818/6070/5306 4277/5198/4464 3907/5178/4444 +f 4819/6069/5305 6474/6076/5312 4818/6070/5306 +f 6474/6076/5312 4276/5199/4465 4277/5198/4464 +f 6477/6081/5317 6476/6082/5318 6482/6083/5319 +f 6479/6084/5320 6476/6082/5318 6478/6085/5321 +f 6481/6086/5322 6476/6082/5318 6480/6087/5323 +f 4821/4300/3616 4797/6007/5243 3888/4301/3617 +f 4822/4298/3614 6477/6081/5317 4821/4300/3616 +f 6477/6081/5317 4798/6014/5250 4797/6007/5243 +f 4826/6088/5324 4823/4297/3613 3881/4216/3532 +f 4825/6089/5325 6479/6084/5320 4826/6088/5324 +f 6479/6084/5320 4822/4298/3614 4823/4297/3613 +f 4799/6011/5247 4824/6090/5326 3958/6012/5248 +f 4799/6011/5247 6482/6083/5319 6481/6086/5322 +f 4824/6090/5326 6480/6087/5323 4825/6089/5325 +f 6484/6091/5327 6483/6092/5328 6489/6093/5329 +f 6486/6094/5330 6483/6092/5328 6485/6095/5331 +f 6488/6096/5332 6483/6092/5328 6487/6097/5333 +f 4199/6098/5334 4826/6088/5324 3881/4216/3532 +f 4198/6099/5335 6484/6091/5327 4199/6098/5334 +f 6484/6091/5327 4825/6089/5325 4826/6088/5324 +f 4829/6100/5336 4197/6101/5337 3880/6102/5338 +f 4828/6103/5339 6486/6094/5330 4829/6100/5336 +f 6486/6094/5330 4198/6099/5335 4197/6101/5337 +f 4824/6090/5326 4827/6104/5340 3958/6012/5248 +f 4825/6089/5325 6488/6096/5332 4824/6090/5326 +f 6488/6096/5332 4828/6103/5339 4827/6104/5340 +f 6491/6105/5341 6490/6106/5342 6496/6107/5343 +f 6493/6108/5344 6490/6106/5342 6492/6109/5345 +f 6495/6110/5346 6490/6106/5342 6494/6111/5347 +f 4827/6104/5340 4800/6054/5290 3958/6012/5248 +f 4828/6103/5339 6491/6105/5341 4827/6104/5340 +f 6491/6105/5341 4801/6055/5291 4800/6054/5290 +f 4832/6112/5348 4829/6100/5336 3880/6102/5338 +f 4831/6113/5349 6493/6108/5344 4832/6112/5348 +f 6493/6108/5344 4828/6103/5339 4829/6100/5336 +f 4802/6057/5293 4830/6114/5350 3959/6058/5294 +f 4801/6055/5291 6495/6110/5346 4802/6057/5293 +f 6495/6110/5346 4831/6113/5349 4830/6114/5350 +f 6498/6115/5351 6497/6116/5352 6503/6117/5353 +f 6500/6118/5354 6497/6116/5352 6499/6119/5355 +f 6502/6120/5356 6497/6116/5352 6501/6121/5357 +f 4196/6122/5358 4832/6112/5348 3880/6102/5338 +f 4195/6123/5359 6498/6115/5351 4196/6122/5358 +f 6498/6115/5351 4831/6113/5349 4832/6112/5348 +f 4835/6124/5360 4194/6125/5361 3879/6126/5362 +f 4834/6127/5363 6500/6118/5354 4835/6124/5360 +f 6500/6118/5354 4195/6123/5359 4194/6125/5361 +f 4830/6114/5350 4833/6128/5364 3959/6058/5294 +f 4831/6113/5349 6502/6120/5356 4830/6114/5350 +f 6502/6120/5356 4834/6127/5363 4833/6128/5364 +f 6505/6129/5365 6504/6130/5366 6510/6131/5367 +f 6507/6132/5368 6504/6130/5366 6506/6133/5369 +f 6509/6134/5370 6504/6130/5366 6508/6135/5371 +f 4833/6128/5364 4794/6078/5314 3959/6058/5294 +f 4834/6127/5363 6505/6129/5365 4833/6128/5364 +f 6505/6129/5365 4795/6079/5315 4794/6078/5314 +f 4838/6136/5372 4835/6124/5360 3879/6126/5362 +f 4837/6137/5373 6507/6132/5368 4838/6136/5372 +f 6507/6132/5368 4834/6127/5363 4835/6124/5360 +f 4796/6080/5316 4836/6138/5374 3906/5202/4468 +f 4795/6079/5315 6509/6134/5370 4796/6080/5316 +f 6509/6134/5370 4837/6137/5373 4836/6138/5374 +f 6512/6139/5375 6511/6140/5376 6517/6141/5377 +f 6514/6142/5378 6511/6140/5376 6513/6143/5379 +f 6516/6144/5380 6511/6140/5376 6515/6145/5381 +f 4193/6146/5382 4838/6136/5372 3879/6126/5362 +f 4192/6147/5383 6512/6139/5375 4193/6146/5382 +f 6512/6139/5375 4837/6137/5373 4838/6136/5372 +f 4272/5225/4490 4191/6148/5384 3837/4353/3669 +f 4273/5223/4489 6514/6142/5378 4272/5225/4490 +f 4191/6148/5384 6513/6143/5379 4192/6147/5383 +f 4836/6138/5374 4274/5222/4488 3906/5202/4468 +f 4837/6137/5373 6516/6144/5380 4836/6138/5374 +f 6516/6144/5380 4273/5223/4489 4274/5222/4488 +f 6519/6149/5385 6518/6150/5386 6524/6151/5387 +f 6521/6152/5388 6518/6150/5386 6520/6153/5389 +f 6523/6154/5390 6518/6150/5386 6522/6155/5391 +f 4839/6156/5392 4032/6157/5393 3884/6158/5394 +f 4840/6159/5395 6519/6149/5385 4839/6156/5392 +f 6519/6149/5385 4033/6160/5396 4032/6157/5393 +f 4053/4356/3672 4841/6161/5397 3905/4357/3673 +f 4054/4359/3675 6521/6152/5388 4053/4356/3672 +f 6521/6152/5388 4840/6159/5395 4841/6161/5397 +f 4034/6162/5398 4055/4351/3667 3837/4353/3669 +f 4034/6162/5398 6524/6151/5387 6523/6154/5390 +f 4055/4351/3667 6522/6155/5391 4054/4359/3675 +f 6526/6163/5399 6525/6164/5400 6531/6165/5401 +f 6528/6166/5402 6525/6164/5400 6527/6167/5403 +f 6530/6168/5404 6525/6164/5400 6529/6169/5405 +f 4845/6170/5406 4206/6171/5407 3883/6172/5408 +f 4846/6173/5409 6526/6163/5399 4845/6170/5406 +f 6526/6163/5399 4207/6174/5410 4206/6171/5407 +f 4859/6175/5411 4847/6176/5412 3960/6177/5413 +f 4858/6178/5414 6528/6166/5402 4859/6175/5411 +f 6528/6166/5402 4846/6173/5409 4847/6176/5412 +f 4208/6179/5415 4857/6180/5416 3884/6158/5394 +f 4207/6174/5410 6530/6168/5404 4208/6179/5415 +f 4857/6180/5416 6529/6169/5405 4858/6178/5414 +f 6533/6181/5417 6532/6182/5418 6538/6183/5419 +f 6535/6184/5420 6532/6182/5418 6534/6185/5421 +f 6537/6186/5422 6532/6182/5418 6536/6187/5423 +f 4851/6188/5424 4203/6189/5425 3882/4287/3603 +f 4852/6190/5426 6533/6181/5417 4851/6188/5424 +f 6533/6181/5417 4204/6191/5427 4203/6189/5425 +f 4865/6192/5428 4853/6193/5429 3961/6194/5430 +f 4865/6192/5428 6536/6187/5423 6535/6184/5420 +f 6535/6184/5420 4852/6190/5426 4853/6193/5429 +f 4205/6195/5431 4863/6196/5432 3883/6172/5408 +f 4204/6191/5427 6537/6186/5422 4205/6195/5431 +f 6537/6186/5422 4864/6197/5433 4863/6196/5432 +f 6540/6198/5434 6539/6199/5435 6545/6200/5436 +f 6542/6201/5437 6539/6199/5435 6541/6202/5438 +f 6544/6203/5439 6539/6199/5435 6543/6204/5440 +f 4857/6180/5416 4839/6156/5392 3884/6158/5394 +f 4858/6178/5414 6540/6198/5434 4857/6180/5416 +f 6540/6198/5434 4840/6159/5395 4839/6156/5392 +f 4862/6205/5441 4859/6175/5411 3960/6177/5413 +f 4862/6205/5441 6543/6204/5440 6542/6201/5437 +f 6542/6201/5437 4858/6178/5414 4859/6175/5411 +f 4841/6161/5397 4860/6206/5442 3905/4357/3673 +f 4840/6159/5395 6544/6203/5439 4841/6161/5397 +f 6544/6203/5439 4861/6207/5443 4860/6206/5442 +f 6547/6208/5444 6546/6209/5445 6552/6210/5446 +f 6549/6211/5447 6546/6209/5445 6548/6212/5448 +f 6551/6213/5449 6546/6209/5445 6550/6214/5450 +f 4842/6215/5451 4862/6205/5441 3960/6177/5413 +f 4843/6216/5452 6547/6208/5444 4842/6215/5451 +f 6547/6208/5444 4861/6207/5443 4862/6205/5441 +f 4269/5374/4613 4844/6217/5453 3904/5375/4614 +f 4270/5372/4611 6549/6211/5447 4269/5374/4613 +f 6549/6211/5447 4843/6216/5452 4844/6217/5453 +f 4860/6206/5442 4271/5371/4610 3905/4357/3673 +f 4860/6206/5442 6552/6210/5446 6551/6213/5449 +f 6551/6213/5449 4270/5372/4611 4271/5371/4610 +f 6554/6218/5454 6553/6219/5455 6559/6220/5456 +f 6556/6221/5457 6553/6219/5455 6555/6222/5458 +f 6558/6223/5459 6553/6219/5455 6557/6224/5460 +f 4863/6196/5432 4845/6170/5406 3883/6172/5408 +f 4863/6196/5432 6555/6222/5458 6554/6218/5454 +f 4845/6170/5406 6559/6220/5456 4846/6173/5409 +f 4868/6225/5461 4865/6192/5428 3961/6194/5430 +f 4867/6226/5462 6556/6221/5457 4868/6225/5461 +f 6556/6221/5457 4864/6197/5433 4865/6192/5428 +f 4847/6176/5412 4866/6227/5463 3960/6177/5413 +f 4846/6173/5409 6558/6223/5459 4847/6176/5412 +f 6558/6223/5459 4867/6226/5462 4866/6227/5463 +f 6561/6228/5464 6560/6229/5465 6566/6230/5466 +f 6563/6231/5467 6560/6229/5465 6562/6232/5468 +f 6565/6233/5469 6560/6229/5465 6564/6234/5470 +f 4854/6235/5471 4868/6225/5461 3961/6194/5430 +f 4855/6236/5472 6561/6228/5464 4854/6235/5471 +f 6561/6228/5464 4867/6226/5462 4868/6225/5461 +f 4871/6237/5473 4856/6238/5474 3962/6239/5475 +f 4870/6240/5476 6563/6231/5467 4871/6237/5473 +f 6563/6231/5467 4855/6236/5472 4856/6238/5474 +f 4866/6227/5463 4869/6241/5477 3960/6177/5413 +f 4867/6226/5462 6565/6233/5469 4866/6227/5463 +f 6565/6233/5469 4870/6240/5476 4869/6241/5477 +f 6568/6242/5478 6567/6243/5479 6573/6244/5480 +f 6570/6245/5481 6567/6243/5479 6569/6246/5482 +f 6572/6247/5483 6567/6243/5479 6571/6248/5484 +f 4869/6241/5477 4842/6215/5451 3960/6177/5413 +f 4870/6240/5476 6568/6242/5478 4869/6241/5477 +f 6568/6242/5478 4843/6216/5452 4842/6215/5451 +f 4874/6249/5485 4871/6237/5473 3962/6239/5475 +f 4873/6250/5486 6570/6245/5481 4874/6249/5485 +f 6570/6245/5481 4870/6240/5476 4871/6237/5473 +f 4844/6217/5453 4872/6251/5487 3904/5375/4614 +f 4843/6216/5452 6572/6247/5483 4844/6217/5453 +f 6572/6247/5483 4873/6250/5486 4872/6251/5487 +f 6575/6252/5488 6574/6253/5489 6580/6254/5490 +f 6577/6255/5491 6574/6253/5489 6576/6256/5492 +f 6579/6257/5493 6574/6253/5489 6578/6258/5494 +f 4848/6259/5495 4874/6249/5485 3962/6239/5475 +f 4849/6260/5496 6575/6252/5488 4848/6259/5495 +f 6575/6252/5488 4873/6250/5486 4874/6249/5485 +f 4266/5398/4637 4850/6261/5497 3903/5399/4638 +f 4267/5396/4635 6577/6255/5491 4266/5398/4637 +f 6577/6255/5491 4849/6260/5496 4850/6261/5497 +f 4872/6251/5487 4268/5395/4634 3904/5375/4614 +f 4873/6250/5486 6579/6257/5493 4872/6251/5487 +f 4268/5395/4634 6578/6258/5494 4267/5396/4635 +f 6582/6262/5498 6581/6263/5499 6587/6264/5500 +f 6584/6265/5501 6581/6263/5499 6583/6266/5502 +f 6586/6267/5503 6581/6263/5499 6585/6268/5504 +f 4875/4286/3602 4851/6188/5424 3882/4287/3603 +f 4876/4284/3600 6582/6262/5498 4875/4286/3602 +f 6582/6262/5498 4852/6190/5426 4851/6188/5424 +f 4880/6269/5505 4877/4283/3599 3875/4197/3513 +f 4879/6270/5506 6584/6265/5501 4880/6269/5505 +f 6584/6265/5501 4876/4284/3600 4877/4283/3599 +f 4853/6193/5429 4878/6271/5507 3961/6194/5430 +f 4852/6190/5426 6586/6267/5503 4853/6193/5429 +f 6586/6267/5503 4879/6270/5506 4878/6271/5507 +f 6589/6272/5508 6588/6273/5509 6594/6274/5510 +f 6591/6275/5511 6588/6273/5509 6590/6276/5512 +f 6593/6277/5513 6588/6273/5509 6592/6278/5514 +f 4181/6279/5515 4880/6269/5505 3875/4197/3513 +f 4180/6280/5516 6589/6272/5508 4181/6279/5515 +f 6589/6272/5508 4879/6270/5506 4880/6269/5505 +f 4883/6281/5517 4179/6282/5518 3874/6283/5519 +f 4882/6284/5520 6591/6275/5511 4883/6281/5517 +f 6591/6275/5511 4180/6280/5516 4179/6282/5518 +f 4878/6271/5507 4881/6285/5521 3961/6194/5430 +f 4879/6270/5506 6593/6277/5513 4878/6271/5507 +f 6593/6277/5513 4882/6284/5520 4881/6285/5521 +f 6596/6286/5522 6595/6287/5523 6601/6288/5524 +f 6598/6289/5525 6595/6287/5523 6597/6290/5526 +f 6600/6291/5527 6595/6287/5523 6599/6292/5528 +f 4881/6285/5521 4854/6235/5471 3961/6194/5430 +f 4882/6284/5520 6596/6286/5522 4881/6285/5521 +f 6596/6286/5522 4855/6236/5472 4854/6235/5471 +f 4886/6293/5529 4883/6281/5517 3874/6283/5519 +f 4885/6294/5530 6598/6289/5525 4886/6293/5529 +f 6598/6289/5525 4882/6284/5520 4883/6281/5517 +f 4856/6238/5474 4884/6295/5531 3962/6239/5475 +f 4855/6236/5472 6600/6291/5527 4856/6238/5474 +f 6600/6291/5527 4885/6294/5530 4884/6295/5531 +f 6603/6296/5532 6602/6297/5533 6608/6298/5534 +f 6605/6299/5535 6602/6297/5533 6604/6300/5536 +f 6607/6301/5537 6602/6297/5533 6606/6302/5538 +f 4178/6303/5539 4886/6293/5529 3874/6283/5519 +f 4177/6304/5540 6603/6296/5532 4178/6303/5539 +f 6603/6296/5532 4885/6294/5530 4886/6293/5529 +f 4889/6305/5541 4176/6306/5542 3873/6307/5543 +f 4888/6308/5544 6605/6299/5535 4889/6305/5541 +f 6605/6299/5535 4177/6304/5540 4176/6306/5542 +f 4884/6295/5531 4887/6309/5545 3962/6239/5475 +f 4885/6294/5530 6607/6301/5537 4884/6295/5531 +f 6607/6301/5537 4888/6308/5544 4887/6309/5545 +f 6610/6310/5546 6609/6311/5547 6615/6312/5548 +f 6612/6313/5549 6609/6311/5547 6611/6314/5550 +f 6614/6315/5551 6609/6311/5547 6613/6316/5552 +f 4887/6309/5545 4848/6259/5495 3962/6239/5475 +f 4888/6308/5544 6610/6310/5546 4887/6309/5545 +f 6610/6310/5546 4849/6260/5496 4848/6259/5495 +f 4892/6317/5553 4889/6305/5541 3873/6307/5543 +f 4892/6317/5553 6613/6316/5552 6612/6313/5549 +f 6612/6313/5549 4888/6308/5544 4889/6305/5541 +f 4850/6261/5497 4890/6318/5554 3903/5399/4638 +f 4849/6260/5496 6614/6315/5551 4850/6261/5497 +f 6614/6315/5551 4891/6319/5555 4890/6318/5554 +f 6617/6320/5556 6616/6321/5557 6622/6322/5558 +f 6619/6323/5559 6616/6321/5557 6618/6324/5560 +f 6621/6325/5561 6616/6321/5557 6620/6326/5562 +f 4175/6327/5563 4892/6317/5553 3873/6307/5543 +f 4174/6328/5564 6617/6320/5556 4175/6327/5563 +f 6617/6320/5556 4891/6319/5555 4892/6317/5553 +f 4263/5422/4660 4173/6329/5565 3841/4429/3745 +f 4263/5422/4660 6620/6326/5562 6619/6323/5559 +f 4173/6329/5565 6618/6324/5560 4174/6328/5564 +f 4890/6318/5554 4265/5419/4658 3903/5399/4638 +f 4890/6318/5554 6622/6322/5558 6621/6325/5561 +f 6621/6325/5561 4264/5420/4659 4265/5419/4658 +f 6624/6330/5566 6623/6331/5567 6629/6332/5568 +f 6626/6333/5569 6623/6331/5567 6625/6334/5570 +f 6628/6335/5571 6623/6331/5567 6627/6336/5572 +f 4893/6337/5573 4247/5603/4839 3897/5583/4819 +f 4894/6338/5574 6624/6330/5566 4893/6337/5573 +f 6624/6330/5566 4246/5604/4840 4247/5603/4839 +f 4050/5614/4850 4895/6339/5575 3902/5615/4851 +f 4051/5617/4853 6626/6333/5569 4050/5614/4850 +f 6626/6333/5569 4894/6338/5574 4895/6339/5575 +f 4245/5605/4841 4052/5619/4855 3840/4410/3726 +f 4245/5605/4841 6629/6332/5568 6628/6335/5571 +f 4052/5619/4855 6627/6336/5572 4051/5617/4853 +f 6631/6340/5576 6630/6341/5577 6636/6342/5578 +f 6633/6343/5579 6630/6341/5577 6632/6344/5580 +f 6635/6345/5581 6630/6341/5577 6634/6346/5582 +f 4899/6347/5583 4250/5579/4815 3898/5558/4794 +f 4900/6348/5584 6631/6340/5576 4899/6347/5583 +f 6631/6340/5576 4249/5580/4816 4250/5579/4815 +f 4913/6349/5585 4901/6350/5586 3963/6351/5587 +f 4912/6352/5588 6633/6343/5579 4913/6349/5585 +f 6633/6343/5579 4900/6348/5584 4901/6350/5586 +f 4248/5582/4818 4911/6353/5589 3897/5583/4819 +f 4248/5582/4818 6636/6342/5578 6635/6345/5581 +f 4911/6353/5589 6634/6346/5582 4912/6352/5588 +f 6638/6354/5590 6637/6355/5591 6643/6356/5592 +f 6640/6357/5593 6637/6355/5591 6639/6358/5594 +f 6642/6359/5595 6637/6355/5591 6641/6360/5596 +f 4905/6361/5597 4253/5555/4791 3899/4273/3589 +f 4905/6361/5597 6639/6358/5594 6638/6354/5590 +f 6638/6354/5590 4252/5560/4796 4253/5555/4791 +f 4919/6362/5598 4907/6363/5599 3964/6364/5600 +f 4918/6365/5601 6640/6357/5593 4919/6362/5598 +f 6640/6357/5593 4906/6366/5602 4907/6363/5599 +f 4251/5557/4793 4917/6367/5603 3898/5558/4794 +f 4252/5560/4796 6642/6359/5595 4251/5557/4793 +f 4917/6367/5603 6641/6360/5596 4918/6365/5601 +f 6645/6368/5604 6644/6369/5605 6650/6370/5606 +f 6647/6371/5607 6644/6369/5605 6646/6372/5608 +f 6649/6373/5609 6644/6369/5605 6648/6374/5610 +f 4911/6353/5589 4893/6337/5573 3897/5583/4819 +f 4912/6352/5588 6645/6368/5604 4911/6353/5589 +f 6645/6368/5604 4894/6338/5574 4893/6337/5573 +f 4916/6375/5611 4913/6349/5585 3963/6351/5587 +f 4916/6375/5611 6648/6374/5610 6647/6371/5607 +f 4913/6349/5585 6646/6372/5608 4912/6352/5588 +f 4895/6339/5575 4914/6376/5612 3902/5615/4851 +f 4894/6338/5574 6649/6373/5609 4895/6339/5575 +f 6649/6373/5609 4915/6377/5613 4914/6376/5612 +f 6652/6378/5614 6651/6379/5615 6657/6380/5616 +f 6654/6381/5617 6651/6379/5615 6653/6382/5618 +f 6656/6383/5619 6651/6379/5615 6655/6384/5620 +f 4896/6385/5621 4916/6375/5611 3963/6351/5587 +f 4897/6386/5622 6652/6378/5614 4896/6385/5621 +f 6652/6378/5614 4915/6377/5613 4916/6375/5611 +f 4260/5628/4864 4898/6387/5623 3901/5629/4865 +f 4261/5631/4867 6654/6381/5617 4260/5628/4864 +f 6654/6381/5617 4897/6386/5622 4898/6387/5623 +f 4914/6376/5612 4262/5636/4872 3902/5615/4851 +f 4914/6376/5612 6657/6380/5616 6656/6383/5619 +f 6656/6383/5619 4261/5631/4867 4262/5636/4872 +f 6659/6388/5624 6658/6389/5625 6664/6390/5626 +f 6661/6391/5627 6658/6389/5625 6660/6392/5628 +f 6663/6393/5629 6658/6389/5625 6662/6394/5630 +f 4917/6367/5603 4899/6347/5583 3898/5558/4794 +f 4918/6365/5601 6659/6388/5624 4917/6367/5603 +f 6659/6388/5624 4900/6348/5584 4899/6347/5583 +f 4922/6395/5631 4919/6362/5598 3964/6364/5600 +f 4921/6396/5632 6661/6391/5627 4922/6395/5631 +f 6661/6391/5627 4918/6365/5601 4919/6362/5598 +f 4901/6350/5586 4920/6397/5633 3963/6351/5587 +f 4900/6348/5584 6663/6393/5629 4901/6350/5586 +f 6663/6393/5629 4921/6396/5632 4920/6397/5633 +f 6666/6398/5634 6665/6399/5635 6671/6400/5636 +f 6668/6401/5637 6665/6399/5635 6667/6402/5638 +f 6670/6403/5639 6665/6399/5635 6669/6404/5640 +f 4908/6405/5641 4922/6395/5631 3964/6364/5600 +f 4909/6406/5642 6666/6398/5634 4908/6405/5641 +f 6666/6398/5634 4921/6396/5632 4922/6395/5631 +f 4925/6407/5643 4910/6408/5644 3965/6409/5645 +f 4924/6410/5646 6668/6401/5637 4925/6407/5643 +f 6668/6401/5637 4909/6406/5642 4910/6408/5644 +f 4920/6397/5633 4923/6411/5647 3963/6351/5587 +f 4921/6396/5632 6670/6403/5639 4920/6397/5633 +f 6670/6403/5639 4924/6410/5646 4923/6411/5647 +f 6673/6412/5648 6672/6413/5649 6678/6414/5650 +f 6675/6415/5651 6672/6413/5649 6674/6416/5652 +f 6677/6417/5653 6672/6413/5649 6676/6418/5654 +f 4923/6411/5647 4896/6385/5621 3963/6351/5587 +f 4924/6410/5646 6673/6412/5648 4923/6411/5647 +f 6673/6412/5648 4897/6386/5622 4896/6385/5621 +f 4928/6419/5655 4925/6407/5643 3965/6409/5645 +f 4927/6420/5656 6675/6415/5651 4928/6419/5655 +f 6675/6415/5651 4924/6410/5646 4925/6407/5643 +f 4898/6387/5623 4926/6421/5657 3901/5629/4865 +f 4897/6386/5622 6677/6417/5653 4898/6387/5623 +f 6677/6417/5653 4927/6420/5656 4926/6421/5657 +f 6680/6422/5658 6679/6423/5659 6685/6424/5660 +f 6682/6425/5661 6679/6423/5659 6681/6426/5662 +f 6684/6427/5663 6679/6423/5659 6683/6428/5664 +f 4902/6429/5665 4928/6419/5655 3965/6409/5645 +f 4903/6430/5666 6680/6422/5658 4902/6429/5665 +f 6680/6422/5658 4927/6420/5656 4928/6419/5655 +f 4257/5646/4882 4904/6431/5667 3900/4329/3645 +f 4258/5647/4883 6682/6425/5661 4257/5646/4882 +f 6682/6425/5661 4903/6430/5666 4904/6431/5667 +f 4926/6421/5657 4259/5653/4889 3901/5629/4865 +f 4927/6420/5656 6684/6427/5663 4926/6421/5657 +f 6684/6427/5663 4258/5647/4883 4259/5653/4889 +f 6687/6432/5668 6686/6433/5669 6692/6434/5670 +f 6689/6435/5671 6686/6433/5669 6688/6436/5672 +f 6691/6437/5673 6686/6433/5669 6690/6438/5674 +f 4929/4272/3588 4905/6361/5597 3899/4273/3589 +f 4930/4269/3585 6687/6432/5668 4929/4272/3588 +f 6687/6432/5668 4906/6366/5602 4905/6361/5597 +f 4934/6439/5675 4931/4266/3582 3872/4268/3584 +f 4933/6440/5676 6689/6435/5671 4934/6439/5675 +f 6689/6435/5671 4930/4269/3585 4931/4266/3582 +f 4907/6363/5599 4932/6441/5677 3964/6364/5600 +f 4906/6366/5602 6691/6437/5673 4907/6363/5599 +f 6691/6437/5673 4933/6440/5676 4932/6441/5677 +f 6694/6442/5678 6693/6443/5679 6699/6444/5680 +f 6696/6445/5681 6693/6443/5679 6695/6446/5682 +f 6698/6447/5683 6693/6443/5679 6697/6448/5684 +f 4172/6449/5685 4934/6439/5675 3872/4268/3584 +f 4171/6450/5686 6694/6442/5678 4172/6449/5685 +f 6694/6442/5678 4933/6440/5676 4934/6439/5675 +f 4937/6451/5687 4170/6452/5688 3871/6453/5689 +f 4936/6454/5690 6696/6445/5681 4937/6451/5687 +f 6696/6445/5681 4171/6450/5686 4170/6452/5688 +f 4932/6441/5677 4935/6455/5691 3964/6364/5600 +f 4933/6440/5676 6698/6447/5683 4932/6441/5677 +f 6698/6447/5683 4936/6454/5690 4935/6455/5691 +f 6701/6456/5692 6700/6457/5693 6706/6458/5694 +f 6703/6459/5695 6700/6457/5693 6702/6460/5696 +f 6705/6461/5697 6700/6457/5693 6704/6462/5698 +f 4935/6455/5691 4908/6405/5641 3964/6364/5600 +f 4936/6454/5690 6701/6456/5692 4935/6455/5691 +f 6701/6456/5692 4909/6406/5642 4908/6405/5641 +f 4940/6463/5699 4937/6451/5687 3871/6453/5689 +f 4939/6464/5700 6703/6459/5695 4940/6463/5699 +f 6703/6459/5695 4936/6454/5690 4937/6451/5687 +f 4910/6408/5644 4938/6465/5701 3965/6409/5645 +f 4909/6406/5642 6705/6461/5697 4910/6408/5644 +f 6705/6461/5697 4939/6464/5700 4938/6465/5701 +f 6708/6466/5702 6707/6467/5703 6713/6468/5704 +f 6710/6469/5705 6707/6467/5703 6709/6470/5706 +f 6712/6471/5707 6707/6467/5703 6711/6472/5708 +f 4169/6473/5709 4940/6463/5699 3871/6453/5689 +f 4168/6474/5710 6708/6466/5702 4169/6473/5709 +f 6708/6466/5702 4939/6464/5700 4940/6463/5699 +f 4943/6475/5711 4167/6476/5712 3870/6477/5713 +f 4943/6475/5711 6711/6472/5708 6710/6469/5705 +f 6710/6469/5705 4168/6474/5710 4167/6476/5712 +f 4938/6465/5701 4941/6478/5714 3965/6409/5645 +f 4939/6464/5700 6712/6471/5707 4938/6465/5701 +f 6712/6471/5707 4942/6479/5715 4941/6478/5714 +f 6715/6480/5716 6714/6481/5717 6720/6482/5718 +f 6717/6483/5719 6714/6481/5717 6716/6484/5720 +f 6719/6485/5721 6714/6481/5717 6718/6486/5722 +f 4941/6478/5714 4902/6429/5665 3965/6409/5645 +f 4942/6479/5715 6715/6480/5716 4941/6478/5714 +f 6715/6480/5716 4903/6430/5666 4902/6429/5665 +f 4946/6487/5723 4943/6475/5711 3870/6477/5713 +f 4945/6488/5724 6717/6483/5719 4946/6487/5723 +f 6717/6483/5719 4942/6479/5715 4943/6475/5711 +f 4904/6431/5667 4944/6489/5725 3900/4329/3645 +f 4903/6430/5666 6719/6485/5721 4904/6431/5667 +f 6719/6485/5721 4945/6488/5724 4944/6489/5725 +f 6722/6490/5726 6721/6491/5727 6727/6492/5728 +f 6724/6493/5729 6721/6491/5727 6723/6494/5730 +f 6726/6495/5731 6721/6491/5727 6725/6496/5732 +f 4166/6497/5733 4946/6487/5723 3870/6477/5713 +f 4165/6498/5734 6722/6490/5726 4166/6497/5733 +f 6722/6490/5726 4945/6488/5724 4946/6487/5723 +f 4254/4323/3639 4164/6499/5735 3835/4245/3561 +f 4254/4323/3639 6725/6496/5732 6724/6493/5729 +f 4164/6499/5735 6723/6494/5730 4165/6498/5734 +f 4944/6489/5725 4256/4327/3643 3900/4329/3645 +f 4945/6488/5724 6726/6495/5731 4944/6489/5725 +f 6726/6495/5731 4255/4324/3640 4256/4327/3643 +f 6729/6500/5736 6728/6501/5737 6734/6502/5738 +f 6731/6503/5739 6728/6501/5737 6730/6504/5740 +f 6733/6505/5741 6728/6501/5737 6732/6506/5742 +f 4947/6507/5743 4229/5784/5020 3891/5764/5000 +f 4948/6508/5744 6729/6500/5736 4947/6507/5743 +f 6729/6500/5736 4228/5785/5021 4229/5784/5020 +f 4044/5795/5031 4949/6509/5745 3896/5796/5032 +f 4045/5798/5034 6731/6503/5739 4044/5795/5031 +f 6731/6503/5739 4948/6508/5744 4949/6509/5745 +f 4227/5786/5022 4046/5800/5036 3839/4391/3707 +f 4227/5786/5022 6734/6502/5738 6733/6505/5741 +f 4046/5800/5036 6732/6506/5742 4045/5798/5034 +f 6736/6510/5746 6735/6511/5747 6741/6512/5748 +f 6738/6513/5749 6735/6511/5747 6737/6514/5750 +f 6740/6515/5751 6735/6511/5747 6739/6516/5752 +f 4953/6517/5753 4232/5760/4996 3892/5740/4976 +f 4954/6518/5754 6736/6510/5746 4953/6517/5753 +f 6736/6510/5746 4231/5761/4997 4232/5760/4996 +f 4967/6519/5755 4955/6520/5756 3966/6521/5757 +f 4966/6522/5758 6738/6513/5749 4967/6519/5755 +f 6738/6513/5749 4954/6518/5754 4955/6520/5756 +f 4230/5763/4999 4965/6523/5759 3891/5764/5000 +f 4231/5761/4997 6740/6515/5751 4230/5763/4999 +f 4965/6523/5759 6739/6516/5752 4966/6522/5758 +f 6743/6524/5760 6742/6525/5761 6748/6526/5762 +f 6745/6527/5763 6742/6525/5761 6744/6528/5764 +f 6747/6529/5765 6742/6525/5761 6746/6530/5766 +f 4959/6531/5767 4235/5736/4972 3893/4254/3570 +f 4959/6531/5767 6744/6528/5764 6743/6524/5760 +f 6743/6524/5760 4234/5737/4973 4235/5736/4972 +f 4973/6532/5768 4961/6533/5769 3967/6534/5770 +f 4972/6535/5771 6745/6527/5763 4973/6532/5768 +f 6745/6527/5763 4960/6536/5772 4961/6533/5769 +f 4233/5739/4975 4971/6537/5773 3892/5740/4976 +f 4234/5737/4973 6747/6529/5765 4233/5739/4975 +f 6747/6529/5765 4972/6535/5771 4971/6537/5773 +f 6750/6538/5774 6749/6539/5775 6755/6540/5776 +f 6752/6541/5777 6749/6539/5775 6751/6542/5778 +f 6754/6543/5779 6749/6539/5775 6753/6544/5780 +f 4965/6523/5759 4947/6507/5743 3891/5764/5000 +f 4966/6522/5758 6750/6538/5774 4965/6523/5759 +f 6750/6538/5774 4948/6508/5744 4947/6507/5743 +f 4970/6545/5781 4967/6519/5755 3966/6521/5757 +f 4969/6546/5782 6752/6541/5777 4970/6545/5781 +f 6752/6541/5777 4966/6522/5758 4967/6519/5755 +f 4949/6509/5745 4968/6547/5783 3896/5796/5032 +f 4948/6508/5744 6754/6543/5779 4949/6509/5745 +f 6754/6543/5779 4969/6546/5782 4968/6547/5783 +f 6757/6548/5784 6756/6549/5785 6762/6550/5786 +f 6759/6551/5787 6756/6549/5785 6758/6552/5788 +f 6761/6553/5789 6756/6549/5785 6760/6554/5790 +f 4950/6555/5791 4970/6545/5781 3966/6521/5757 +f 4951/6556/5792 6757/6548/5784 4950/6555/5791 +f 6757/6548/5784 4969/6546/5782 4970/6545/5781 +f 4242/5809/5045 4952/6557/5793 3895/5810/5046 +f 4243/5812/5048 6759/6551/5787 4242/5809/5045 +f 6759/6551/5787 4951/6556/5792 4952/6557/5793 +f 4968/6547/5783 4244/5817/5053 3896/5796/5032 +f 4968/6547/5783 6762/6550/5786 6761/6553/5789 +f 6761/6553/5789 4243/5812/5048 4244/5817/5053 +f 6764/6558/5794 6763/6559/5795 6769/6560/5796 +f 6766/6561/5797 6763/6559/5795 6765/6562/5798 +f 6768/6563/5799 6763/6559/5795 6767/6564/5800 +f 4971/6537/5773 4953/6517/5753 3892/5740/4976 +f 4972/6535/5771 6764/6558/5794 4971/6537/5773 +f 6764/6558/5794 4954/6518/5754 4953/6517/5753 +f 4976/6565/5801 4973/6532/5768 3967/6534/5770 +f 4975/6566/5802 6766/6561/5797 4976/6565/5801 +f 6766/6561/5797 4972/6535/5771 4973/6532/5768 +f 4955/6520/5756 4974/6567/5803 3966/6521/5757 +f 4954/6518/5754 6768/6563/5799 4955/6520/5756 +f 6768/6563/5799 4975/6566/5802 4974/6567/5803 +f 6771/6568/5804 6770/6569/5805 6776/6570/5806 +f 6773/6571/5807 6770/6569/5805 6772/6572/5808 +f 6775/6573/5809 6770/6569/5805 6774/6574/5810 +f 4962/6575/5811 4976/6565/5801 3967/6534/5770 +f 4963/6576/5812 6771/6568/5804 4962/6575/5811 +f 6771/6568/5804 4975/6566/5802 4976/6565/5801 +f 4979/6577/5813 4964/6578/5814 3968/6579/5815 +f 4978/6580/5816 6773/6571/5807 4979/6577/5813 +f 6773/6571/5807 4963/6576/5812 4964/6578/5814 +f 4974/6567/5803 4977/6581/5817 3966/6521/5757 +f 4975/6566/5802 6775/6573/5809 4974/6567/5803 +f 6775/6573/5809 4978/6580/5816 4977/6581/5817 +f 6778/6582/5818 6777/6583/5819 6783/6584/5820 +f 6780/6585/5821 6777/6583/5819 6779/6586/5822 +f 6782/6587/5823 6777/6583/5819 6781/6588/5824 +f 4977/6581/5817 4950/6555/5791 3966/6521/5757 +f 4978/6580/5816 6778/6582/5818 4977/6581/5817 +f 6778/6582/5818 4951/6556/5792 4950/6555/5791 +f 4982/6589/5825 4979/6577/5813 3968/6579/5815 +f 4981/6590/5826 6780/6585/5821 4982/6589/5825 +f 6780/6585/5821 4978/6580/5816 4979/6577/5813 +f 4952/6557/5793 4980/6591/5827 3895/5810/5046 +f 4951/6556/5792 6782/6587/5823 4952/6557/5793 +f 6782/6587/5823 4981/6590/5826 4980/6591/5827 +f 6785/6592/5828 6784/6593/5829 6790/6594/5830 +f 6787/6595/5831 6784/6593/5829 6786/6596/5832 +f 6789/6597/5833 6784/6593/5829 6788/6598/5834 +f 4956/6599/5835 4982/6589/5825 3968/6579/5815 +f 4957/6600/5836 6785/6592/5828 4956/6599/5835 +f 6785/6592/5828 4981/6590/5826 4982/6589/5825 +f 4239/5827/5063 4958/6601/5837 3894/4315/3631 +f 4240/5829/5065 6787/6595/5831 4239/5827/5063 +f 6787/6595/5831 4957/6600/5836 4958/6601/5837 +f 4980/6591/5827 4241/5834/5070 3895/5810/5046 +f 4981/6590/5826 6789/6597/5833 4980/6591/5827 +f 6789/6597/5833 4240/5829/5065 4241/5834/5070 +f 6792/6602/5838 6791/6603/5839 6797/6604/5840 +f 6794/6605/5841 6791/6603/5839 6793/6606/5842 +f 6796/6607/5843 6791/6603/5839 6795/6608/5844 +f 4983/4253/3569 4959/6531/5767 3893/4254/3570 +f 4984/4250/3566 6792/6602/5838 4983/4253/3569 +f 6792/6602/5838 4960/6536/5772 4959/6531/5767 +f 4988/6609/5845 4985/4247/3563 3869/4249/3565 +f 4987/6610/5846 6794/6605/5841 4988/6609/5845 +f 6794/6605/5841 4984/4250/3566 4985/4247/3563 +f 4961/6533/5769 4986/6611/5847 3967/6534/5770 +f 4960/6536/5772 6796/6607/5843 4961/6533/5769 +f 6796/6607/5843 4987/6610/5846 4986/6611/5847 +f 6799/6612/5848 6798/6613/5849 6804/6614/5850 +f 6801/6615/5851 6798/6613/5849 6800/6616/5852 +f 6803/6617/5853 6798/6613/5849 6802/6618/5854 +f 4163/6619/5855 4988/6609/5845 3869/4249/3565 +f 4163/6619/5855 6800/6616/5852 6799/6612/5848 +f 4988/6609/5845 6804/6614/5850 4987/6610/5846 +f 4991/6620/5856 4161/6621/5857 3868/6622/5858 +f 4990/6623/5859 6801/6615/5851 4991/6620/5856 +f 6801/6615/5851 4162/6624/5860 4161/6621/5857 +f 4986/6611/5847 4989/6625/5861 3967/6534/5770 +f 4987/6610/5846 6803/6617/5853 4986/6611/5847 +f 6803/6617/5853 4990/6623/5859 4989/6625/5861 +f 6806/6626/5862 6805/6627/5863 6811/6628/5864 +f 6808/6629/5865 6805/6627/5863 6807/6630/5866 +f 6810/6631/5867 6805/6627/5863 6809/6632/5868 +f 4989/6625/5861 4962/6575/5811 3967/6534/5770 +f 4990/6623/5859 6806/6626/5862 4989/6625/5861 +f 6806/6626/5862 4963/6576/5812 4962/6575/5811 +f 4994/6633/5869 4991/6620/5856 3868/6622/5858 +f 4993/6634/5870 6808/6629/5865 4994/6633/5869 +f 6808/6629/5865 4990/6623/5859 4991/6620/5856 +f 4964/6578/5814 4992/6635/5871 3968/6579/5815 +f 4963/6576/5812 6810/6631/5867 4964/6578/5814 +f 6810/6631/5867 4993/6634/5870 4992/6635/5871 +f 6813/6636/5872 6812/6637/5873 6818/6638/5874 +f 6815/6639/5875 6812/6637/5873 6814/6640/5876 +f 6817/6641/5877 6812/6637/5873 6816/6642/5878 +f 4160/6643/5879 4994/6633/5869 3868/6622/5858 +f 4159/6644/5880 6813/6636/5872 4160/6643/5879 +f 6813/6636/5872 4993/6634/5870 4994/6633/5869 +f 4997/6645/5881 4158/6646/5882 3867/6647/5883 +f 4997/6645/5881 6816/6642/5878 6815/6639/5875 +f 6815/6639/5875 4159/6644/5880 4158/6646/5882 +f 4992/6635/5871 4995/6648/5884 3968/6579/5815 +f 4993/6634/5870 6817/6641/5877 4992/6635/5871 +f 6817/6641/5877 4996/6649/5885 4995/6648/5884 +f 6820/6650/5886 6819/6651/5887 6825/6652/5888 +f 6822/6653/5889 6819/6651/5887 6821/6654/5890 +f 6824/6655/5891 6819/6651/5887 6823/6656/5892 +f 4995/6648/5884 4956/6599/5835 3968/6579/5815 +f 4996/6649/5885 6820/6650/5886 4995/6648/5884 +f 6820/6650/5886 4957/6600/5836 4956/6599/5835 +f 5000/6657/5893 4997/6645/5881 3867/6647/5883 +f 4999/6658/5894 6822/6653/5889 5000/6657/5893 +f 6822/6653/5889 4996/6649/5885 4997/6645/5881 +f 4958/6601/5837 4998/6659/5895 3894/4315/3631 +f 4958/6601/5837 6825/6652/5888 6824/6655/5891 +f 6824/6655/5891 4999/6658/5894 4998/6659/5895 +f 6827/6660/5896 6826/6661/5897 6832/6662/5898 +f 6829/6663/5899 6826/6661/5897 6828/6664/5900 +f 6831/6665/5901 6826/6661/5897 6830/6666/5902 +f 4157/6667/5903 5000/6657/5893 3867/6647/5883 +f 4156/6668/5904 6827/6660/5896 4157/6667/5903 +f 6827/6660/5896 4999/6658/5894 5000/6657/5893 +f 4236/4309/3625 4155/6669/5905 3834/4226/3542 +f 4236/4309/3625 6830/6666/5902 6829/6663/5899 +f 4155/6669/5905 6828/6664/5900 4156/6668/5904 +f 4998/6659/5895 4238/4313/3629 3894/4315/3631 +f 4999/6658/5894 6831/6665/5901 4998/6659/5895 +f 6831/6665/5901 4237/4310/3626 4238/4313/3629 +f 6834/6670/5906 6833/6671/5907 6839/6672/5908 +f 6836/6673/5909 6833/6671/5907 6835/6674/5910 +f 6838/6675/5911 6833/6671/5907 6837/6676/5912 +f 5001/6677/5913 4211/5965/5201 3885/5945/5181 +f 5002/6678/5914 6834/6670/5906 5001/6677/5913 +f 6834/6670/5906 4210/5966/5202 4211/5965/5201 +f 4038/6679/5212 5003/6680/5915 3890/6681/5213 +f 4039/6682/5215 6836/6673/5909 4038/6679/5212 +f 6836/6673/5909 5002/6678/5914 5003/6680/5915 +f 4209/5967/5203 4040/6683/5217 3838/5028/3688 +f 4209/5967/5203 6839/6672/5908 6838/6675/5911 +f 4040/6683/5217 6837/6676/5912 4039/6682/5215 +f 6841/6684/5916 6840/6685/5917 6846/6686/5918 +f 6843/6687/5919 6840/6685/5917 6842/6688/5920 +f 6845/6689/5921 6840/6685/5917 6844/6690/5922 +f 5007/6691/5923 4214/5941/5177 3886/5920/5156 +f 5008/6692/5924 6841/6684/5916 5007/6691/5923 +f 6841/6684/5916 4213/5942/5178 4214/5941/5177 +f 5021/6693/5925 5009/6694/5926 3969/6695/5927 +f 5020/6696/5928 6843/6687/5919 5021/6693/5925 +f 6843/6687/5919 5008/6692/5924 5009/6694/5926 +f 4212/5944/5180 5019/6697/5929 3885/5945/5181 +f 4213/5942/5178 6845/6689/5921 4212/5944/5180 +f 5019/6697/5929 6844/6690/5922 5020/6696/5928 +f 6848/6698/5930 6847/6699/5931 6853/6700/5932 +f 6850/6701/5933 6847/6699/5931 6849/6702/5934 +f 6852/6703/5935 6847/6699/5931 6851/6704/5936 +f 5013/6705/5937 4217/5917/5153 3887/4235/3551 +f 5014/6706/5938 6848/6698/5930 5013/6705/5937 +f 6848/6698/5930 4216/5922/5158 4217/5917/5153 +f 5027/6707/5939 5015/6708/5940 3970/6709/5941 +f 5026/6710/5942 6850/6701/5933 5027/6707/5939 +f 6850/6701/5933 5014/6706/5938 5015/6708/5940 +f 4215/5919/5155 5025/6711/5943 3886/5920/5156 +f 4216/5922/5158 6852/6703/5935 4215/5919/5155 +f 6852/6703/5935 5026/6710/5942 5025/6711/5943 +f 6855/6712/5944 6854/6713/5945 6860/6714/5946 +f 6857/6715/5947 6854/6713/5945 6856/6716/5948 +f 6859/6717/5949 6854/6713/5945 6858/6718/5950 +f 5019/6697/5929 5001/6677/5913 3885/5945/5181 +f 5020/6696/5928 6855/6712/5944 5019/6697/5929 +f 6855/6712/5944 5002/6678/5914 5001/6677/5913 +f 5024/6719/5951 5021/6693/5925 3969/6695/5927 +f 5023/6720/5952 6857/6715/5947 5024/6719/5951 +f 6857/6715/5947 5020/6696/5928 5021/6693/5925 +f 5003/6680/5915 5022/6721/5953 3890/6681/5213 +f 5002/6678/5914 6859/6717/5949 5003/6680/5915 +f 6859/6717/5949 5023/6720/5952 5022/6721/5953 +f 6862/6722/5954 6861/6723/5955 6867/6724/5956 +f 6864/6725/5957 6861/6723/5955 6863/6726/5958 +f 6866/6727/5959 6861/6723/5955 6865/6728/5960 +f 5004/6729/5961 5024/6719/5951 3969/6695/5927 +f 5005/6730/5962 6862/6722/5954 5004/6729/5961 +f 6862/6722/5954 5023/6720/5952 5024/6719/5951 +f 4224/6731/5226 5006/6732/5963 3889/6733/5227 +f 4225/6734/5228 6864/6725/5957 4224/6731/5226 +f 6864/6725/5957 5005/6730/5962 5006/6732/5963 +f 5022/6721/5953 4226/6735/5234 3890/6681/5213 +f 5022/6721/5953 6867/6724/5956 6866/6727/5959 +f 4226/6735/5234 6865/6728/5960 4225/6734/5228 +f 6869/6736/5964 6868/6737/5965 6874/6738/5966 +f 6871/6739/5967 6868/6737/5965 6870/6740/5968 +f 6873/6741/5969 6868/6737/5965 6872/6742/5970 +f 5025/6711/5943 5007/6691/5923 3886/5920/5156 +f 5026/6710/5942 6869/6736/5964 5025/6711/5943 +f 6869/6736/5964 5008/6692/5924 5007/6691/5923 +f 5030/6743/5971 5027/6707/5939 3970/6709/5941 +f 5029/6744/5972 6871/6739/5967 5030/6743/5971 +f 6871/6739/5967 5026/6710/5942 5027/6707/5939 +f 5009/6694/5926 5028/6745/5973 3969/6695/5927 +f 5008/6692/5924 6873/6741/5969 5009/6694/5926 +f 6873/6741/5969 5029/6744/5972 5028/6745/5973 +f 6876/6746/5974 6875/6747/5975 6881/6748/5976 +f 6878/6749/5977 6875/6747/5975 6877/6750/5978 +f 6880/6751/5979 6875/6747/5975 6879/6752/5980 +f 5016/6753/5981 5030/6743/5971 3970/6709/5941 +f 5017/6754/5982 6876/6746/5974 5016/6753/5981 +f 6876/6746/5974 5029/6744/5972 5030/6743/5971 +f 5033/6755/5983 5018/6756/5984 3971/6757/5985 +f 5032/6758/5986 6878/6749/5977 5033/6755/5983 +f 6878/6749/5977 5017/6754/5982 5018/6756/5984 +f 5028/6745/5973 5031/6759/5987 3969/6695/5927 +f 5029/6744/5972 6880/6751/5979 5028/6745/5973 +f 6880/6751/5979 5032/6758/5986 5031/6759/5987 +f 6883/6760/5988 6882/6761/5989 6888/6762/5990 +f 6885/6763/5991 6882/6761/5989 6884/6764/5992 +f 6887/6765/5993 6882/6761/5989 6886/6766/5994 +f 5031/6759/5987 5004/6729/5961 3969/6695/5927 +f 5032/6758/5986 6883/6760/5988 5031/6759/5987 +f 6883/6760/5988 5005/6730/5962 5004/6729/5961 +f 5036/6767/5995 5033/6755/5983 3971/6757/5985 +f 5035/6768/5996 6885/6763/5991 5036/6767/5995 +f 6885/6763/5991 5032/6758/5986 5033/6755/5983 +f 5006/6732/5963 5034/6769/5997 3889/6733/5227 +f 5005/6730/5962 6887/6765/5993 5006/6732/5963 +f 6887/6765/5993 5035/6768/5996 5034/6769/5997 +f 6890/6770/5998 6889/6771/5999 6895/6772/6000 +f 6892/6773/6001 6889/6771/5999 6891/6774/6002 +f 6894/6775/6003 6889/6771/5999 6893/6776/6004 +f 5010/6777/6005 5036/6767/5995 3971/6757/5985 +f 5011/6778/6006 6890/6770/5998 5010/6777/6005 +f 6890/6770/5998 5035/6768/5996 5036/6767/5995 +f 4221/6779/5244 5012/6780/6007 3888/6781/3617 +f 4222/6782/5245 6892/6773/6001 4221/6779/5244 +f 5012/6780/6007 6891/6774/6002 5011/6778/6006 +f 5034/6769/5997 4223/6783/5251 3889/6733/5227 +f 5034/6769/5997 6895/6772/6000 6894/6775/6003 +f 4223/6783/5251 6893/6776/6004 4222/6782/5245 +f 6897/6784/6008 6896/6785/6009 6902/6786/6010 +f 6899/6787/6011 6896/6785/6009 6898/6788/6012 +f 6901/6789/6013 6896/6785/6009 6900/6790/6014 +f 5037/4234/3550 5013/6705/5937 3887/4235/3551 +f 5038/4232/3548 6897/6784/6008 5037/4234/3550 +f 6897/6784/6008 5014/6706/5938 5013/6705/5937 +f 5042/6791/6015 5039/4229/3545 3863/4231/3547 +f 5041/6792/6016 6899/6787/6011 5042/6791/6015 +f 6899/6787/6011 5038/4232/3548 5039/4229/3545 +f 5015/6708/5940 5040/6793/6017 3970/6709/5941 +f 5014/6706/5938 6901/6789/6013 5015/6708/5940 +f 6901/6789/6013 5041/6792/6016 5040/6793/6017 +f 6904/6794/6018 6903/6795/6019 6909/6796/6020 +f 6906/6797/6021 6903/6795/6019 6905/6798/6022 +f 6908/6799/6023 6903/6795/6019 6907/6800/6024 +f 4145/6801/6025 5042/6791/6015 3863/4231/3547 +f 4144/6802/6026 6904/6794/6018 4145/6801/6025 +f 6904/6794/6018 5041/6792/6016 5042/6791/6015 +f 5045/6803/6027 4143/6804/6028 3862/6805/6029 +f 5044/6806/6030 6906/6797/6021 5045/6803/6027 +f 6906/6797/6021 4144/6802/6026 4143/6804/6028 +f 5040/6793/6017 5043/6807/6031 3970/6709/5941 +f 5041/6792/6016 6908/6799/6023 5040/6793/6017 +f 6908/6799/6023 5044/6806/6030 5043/6807/6031 +f 6911/6808/6032 6910/6809/6033 6916/6810/6034 +f 6913/6811/6035 6910/6809/6033 6912/6812/6036 +f 6915/6813/6037 6910/6809/6033 6914/6814/6038 +f 5043/6807/6031 5016/6753/5981 3970/6709/5941 +f 5044/6806/6030 6911/6808/6032 5043/6807/6031 +f 6911/6808/6032 5017/6754/5982 5016/6753/5981 +f 5048/6815/6039 5045/6803/6027 3862/6805/6029 +f 5047/6816/6040 6913/6811/6035 5048/6815/6039 +f 6913/6811/6035 5044/6806/6030 5045/6803/6027 +f 5018/6756/5984 5046/6817/6041 3971/6757/5985 +f 5017/6754/5982 6915/6813/6037 5018/6756/5984 +f 6915/6813/6037 5047/6816/6040 5046/6817/6041 +f 6918/6818/6042 6917/6819/6043 6923/6820/6044 +f 6920/6821/6045 6917/6819/6043 6919/6822/6046 +f 6922/6823/6047 6917/6819/6043 6921/6824/6048 +f 4142/6825/6049 5048/6815/6039 3862/6805/6029 +f 4141/6826/6050 6918/6818/6042 4142/6825/6049 +f 6918/6818/6042 5047/6816/6040 5048/6815/6039 +f 5051/6827/6051 4140/6828/6052 3861/6829/6053 +f 5050/6830/6054 6920/6821/6045 5051/6827/6051 +f 6920/6821/6045 4141/6826/6050 4140/6828/6052 +f 5046/6817/6041 5049/6831/6055 3971/6757/5985 +f 5047/6816/6040 6922/6823/6047 5046/6817/6041 +f 6922/6823/6047 5050/6830/6054 5049/6831/6055 +f 6925/6832/6056 6924/6833/6057 6930/6834/6058 +f 6927/6835/6059 6924/6833/6057 6926/6836/6060 +f 6929/6837/6061 6924/6833/6057 6928/6838/6062 +f 5049/6831/6055 5010/6777/6005 3971/6757/5985 +f 5050/6830/6054 6925/6832/6056 5049/6831/6055 +f 6925/6832/6056 5011/6778/6006 5010/6777/6005 +f 5054/6839/6063 5051/6827/6051 3861/6829/6053 +f 5054/6839/6063 6928/6838/6062 6927/6835/6059 +f 6927/6835/6059 5050/6830/6054 5051/6827/6051 +f 5012/6780/6007 5052/6840/6064 3888/6781/3617 +f 5011/6778/6006 6929/6837/6061 5012/6780/6007 +f 6929/6837/6061 5053/6841/6065 5052/6840/6064 +f 6932/6842/6066 6931/6843/6067 6937/6844/6068 +f 6934/6845/6069 6931/6843/6067 6933/6846/6070 +f 6936/6847/6071 6931/6843/6067 6935/6848/6072 +f 4139/6849/6073 5054/6839/6063 3861/6829/6053 +f 4138/6850/6074 6932/6842/6066 4139/6849/6073 +f 6932/6842/6066 5053/6841/6065 5054/6839/6063 +f 4218/6851/3611 4137/6852/6075 3833/6853/3523 +f 4218/6851/3611 6935/6848/6072 6934/6845/6069 +f 4137/6852/6075 6933/6846/6070 4138/6850/6074 +f 5052/6840/6064 4220/6854/3615 3888/6781/3617 +f 5052/6840/6064 6937/6844/6068 6936/6847/6071 +f 6936/6847/6071 4219/6855/3612 4220/6854/3615 +f 6939/6856/6076 6938/6857/6077 6944/6858/6078 +f 6941/6859/6079 6938/6857/6077 6940/6860/6080 +f 6943/6861/6081 6938/6857/6077 6942/6862/6082 +f 5055/6863/6083 4193/6146/5382 3879/6126/5362 +f 5056/6864/6084 6939/6856/6076 5055/6863/6083 +f 6939/6856/6076 4192/6147/5383 4193/6146/5382 +f 4032/6157/5393 5057/6865/6085 3884/6158/5394 +f 4033/6160/5396 6941/6859/6079 4032/6157/5393 +f 6941/6859/6079 5056/6864/6084 5057/6865/6085 +f 4191/6148/5384 4034/6162/5398 3837/4353/3669 +f 4192/6147/5383 6943/6861/6081 4191/6148/5384 +f 6943/6861/6081 4033/6160/5396 4034/6162/5398 +f 6946/6866/6086 6945/6867/6087 6951/6868/6088 +f 6948/6869/6089 6945/6867/6087 6947/6870/6090 +f 6950/6871/6091 6945/6867/6087 6949/6872/6092 +f 5061/6873/6093 4196/6122/5358 3880/6102/5338 +f 5062/6874/6094 6946/6866/6086 5061/6873/6093 +f 6946/6866/6086 4195/6123/5359 4196/6122/5358 +f 5075/6875/6095 5063/6876/6096 3972/6877/6097 +f 5074/6878/6098 6948/6869/6089 5075/6875/6095 +f 6948/6869/6089 5062/6874/6094 5063/6876/6096 +f 4194/6125/5361 5073/6879/6099 3879/6126/5362 +f 4194/6125/5361 6951/6868/6088 6950/6871/6091 +f 6950/6871/6091 5074/6878/6098 5073/6879/6099 +f 6953/6880/6100 6952/6881/6101 6958/6882/6102 +f 6955/6883/6103 6952/6881/6101 6954/6884/6104 +f 6957/6885/6105 6952/6881/6101 6956/6886/6106 +f 5067/6887/6107 4199/6098/5334 3881/4216/3532 +f 5068/6888/6108 6953/6880/6100 5067/6887/6107 +f 6953/6880/6100 4198/6099/5335 4199/6098/5334 +f 5081/6889/6109 5069/6890/6110 3973/6891/6111 +f 5080/6892/6112 6955/6883/6103 5081/6889/6109 +f 6955/6883/6103 5068/6888/6108 5069/6890/6110 +f 4197/6101/5337 5079/6893/6113 3880/6102/5338 +f 4198/6099/5335 6957/6885/6105 4197/6101/5337 +f 6957/6885/6105 5080/6892/6112 5079/6893/6113 +f 6960/6894/6114 6959/6895/6115 6965/6896/6116 +f 6962/6897/6117 6959/6895/6115 6961/6898/6118 +f 6964/6899/6119 6959/6895/6115 6963/6900/6120 +f 5073/6879/6099 5055/6863/6083 3879/6126/5362 +f 5074/6878/6098 6960/6894/6114 5073/6879/6099 +f 6960/6894/6114 5056/6864/6084 5055/6863/6083 +f 5078/6901/6121 5075/6875/6095 3972/6877/6097 +f 5077/6902/6122 6962/6897/6117 5078/6901/6121 +f 6962/6897/6117 5074/6878/6098 5075/6875/6095 +f 5057/6865/6085 5076/6903/6123 3884/6158/5394 +f 5056/6864/6084 6964/6899/6119 5057/6865/6085 +f 6964/6899/6119 5077/6902/6122 5076/6903/6123 +f 6967/6904/6124 6966/6905/6125 6972/6906/6126 +f 6969/6907/6127 6966/6905/6125 6968/6908/6128 +f 6971/6909/6129 6966/6905/6125 6970/6910/6130 +f 5058/6911/6131 5078/6901/6121 3972/6877/6097 +f 5059/6912/6132 6967/6904/6124 5058/6911/6131 +f 6967/6904/6124 5077/6902/6122 5078/6901/6121 +f 4206/6171/5407 5060/6913/6133 3883/6172/5408 +f 4207/6174/5410 6969/6907/6127 4206/6171/5407 +f 6969/6907/6127 5059/6912/6132 5060/6913/6133 +f 5076/6903/6123 4208/6179/5415 3884/6158/5394 +f 5077/6902/6122 6971/6909/6129 5076/6903/6123 +f 6971/6909/6129 4207/6174/5410 4208/6179/5415 +f 6974/6914/6134 6973/6915/6135 6979/6916/6136 +f 6976/6917/6137 6973/6915/6135 6975/6918/6138 +f 6978/6919/6139 6973/6915/6135 6977/6920/6140 +f 5079/6893/6113 5061/6873/6093 3880/6102/5338 +f 5080/6892/6112 6974/6914/6134 5079/6893/6113 +f 6974/6914/6134 5062/6874/6094 5061/6873/6093 +f 5084/6921/6141 5081/6889/6109 3973/6891/6111 +f 5083/6922/6142 6976/6917/6137 5084/6921/6141 +f 6976/6917/6137 5080/6892/6112 5081/6889/6109 +f 5063/6876/6096 5082/6923/6143 3972/6877/6097 +f 5062/6874/6094 6978/6919/6139 5063/6876/6096 +f 6978/6919/6139 5083/6922/6142 5082/6923/6143 +f 6981/6924/6144 6980/6925/6145 6986/6926/6146 +f 6983/6927/6147 6980/6925/6145 6982/6928/6148 +f 6985/6929/6149 6980/6925/6145 6984/6930/6150 +f 5070/6931/6151 5084/6921/6141 3973/6891/6111 +f 5071/6932/6152 6981/6924/6144 5070/6931/6151 +f 6981/6924/6144 5083/6922/6142 5084/6921/6141 +f 5087/6933/6153 5072/6934/6154 3974/6935/6155 +f 5086/6936/6156 6983/6927/6147 5087/6933/6153 +f 6983/6927/6147 5071/6932/6152 5072/6934/6154 +f 5082/6923/6143 5085/6937/6157 3972/6877/6097 +f 5083/6922/6142 6985/6929/6149 5082/6923/6143 +f 6985/6929/6149 5086/6936/6156 5085/6937/6157 +f 6988/6938/6158 6987/6939/6159 6993/6940/6160 +f 6990/6941/6161 6987/6939/6159 6989/6942/6162 +f 6992/6943/6163 6987/6939/6159 6991/6944/6164 +f 5085/6937/6157 5058/6911/6131 3972/6877/6097 +f 5086/6936/6156 6988/6938/6158 5085/6937/6157 +f 6988/6938/6158 5059/6912/6132 5058/6911/6131 +f 5090/6945/6165 5087/6933/6153 3974/6935/6155 +f 5089/6946/6166 6990/6941/6161 5090/6945/6165 +f 6990/6941/6161 5086/6936/6156 5087/6933/6153 +f 5060/6913/6133 5088/6947/6167 3883/6172/5408 +f 5059/6912/6132 6992/6943/6163 5060/6913/6133 +f 5088/6947/6167 6991/6944/6164 5089/6946/6166 +f 6995/6948/6168 6994/6949/6169 7000/6950/6170 +f 6997/6951/6171 6994/6949/6169 6996/6952/6172 +f 6999/6953/6173 6994/6949/6169 6998/6954/6174 +f 5064/6955/6175 5090/6945/6165 3974/6935/6155 +f 5065/6956/6176 6995/6948/6168 5064/6955/6175 +f 6995/6948/6168 5089/6946/6166 5090/6945/6165 +f 4203/6189/5425 5066/6957/6177 3882/4287/3603 +f 4204/6191/5427 6997/6951/6171 4203/6189/5425 +f 6997/6951/6171 5065/6956/6176 5066/6957/6177 +f 5088/6947/6167 4205/6195/5431 3883/6172/5408 +f 5089/6946/6166 6999/6953/6173 5088/6947/6167 +f 6999/6953/6173 4204/6191/5427 4205/6195/5431 +f 7002/6958/6178 7001/6959/6179 7007/6960/6180 +f 7004/6961/6181 7001/6959/6179 7003/6962/6182 +f 7006/6963/6183 7001/6959/6179 7005/6964/6184 +f 5091/4215/3531 5067/6887/6107 3881/4216/3532 +f 5092/4213/3529 7002/6958/6178 5091/4215/3531 +f 7002/6958/6178 5068/6888/6108 5067/6887/6107 +f 5096/6965/6185 5093/4210/3526 3851/4212/3528 +f 5095/6966/6186 7004/6961/6181 5096/6965/6185 +f 7004/6961/6181 5092/4213/3529 5093/4210/3526 +f 5069/6890/6110 5094/6967/6187 3973/6891/6111 +f 5068/6888/6108 7006/6963/6183 5069/6890/6110 +f 7006/6963/6183 5095/6966/6186 5094/6967/6187 +f 7009/6968/6188 7008/6969/6189 7014/6970/6190 +f 7011/6971/6191 7008/6969/6189 7010/6972/6192 +f 7013/6973/6193 7008/6969/6189 7012/6974/6194 +f 4109/6975/6195 5096/6965/6185 3851/4212/3528 +f 4108/6976/6196 7009/6968/6188 4109/6975/6195 +f 7009/6968/6188 5095/6966/6186 5096/6965/6185 +f 5099/6977/6197 4107/6978/6198 3850/6979/6199 +f 5098/6980/6200 7011/6971/6191 5099/6977/6197 +f 7011/6971/6191 4108/6976/6196 4107/6978/6198 +f 5094/6967/6187 5097/6981/6201 3973/6891/6111 +f 5095/6966/6186 7013/6973/6193 5094/6967/6187 +f 7013/6973/6193 5098/6980/6200 5097/6981/6201 +f 7016/6982/6202 7015/6983/6203 7021/6984/6204 +f 7018/6985/6205 7015/6983/6203 7017/6986/6206 +f 7020/6987/6207 7015/6983/6203 7019/6988/6208 +f 5097/6981/6201 5070/6931/6151 3973/6891/6111 +f 5098/6980/6200 7016/6982/6202 5097/6981/6201 +f 7016/6982/6202 5071/6932/6152 5070/6931/6151 +f 5102/6989/6209 5099/6977/6197 3850/6979/6199 +f 5101/6990/6210 7018/6985/6205 5102/6989/6209 +f 7018/6985/6205 5098/6980/6200 5099/6977/6197 +f 5072/6934/6154 5100/6991/6211 3974/6935/6155 +f 5071/6932/6152 7020/6987/6207 5072/6934/6154 +f 7020/6987/6207 5101/6990/6210 5100/6991/6211 +f 7023/6992/6212 7022/6993/6213 7028/6994/6214 +f 7025/6995/6215 7022/6993/6213 7024/6996/6216 +f 7027/6997/6217 7022/6993/6213 7026/6998/6218 +f 4106/6999/6219 5102/6989/6209 3850/6979/6199 +f 4105/7000/6220 7023/6992/6212 4106/6999/6219 +f 7023/6992/6212 5101/6990/6210 5102/6989/6209 +f 5105/7001/6221 4104/7002/6222 3849/7003/6223 +f 5104/7004/6224 7025/6995/6215 5105/7001/6221 +f 7025/6995/6215 4105/7000/6220 4104/7002/6222 +f 5100/6991/6211 5103/7005/6225 3974/6935/6155 +f 5101/6990/6210 7027/6997/6217 5100/6991/6211 +f 7027/6997/6217 5104/7004/6224 5103/7005/6225 +f 7030/7006/6226 7029/7007/6227 7035/7008/6228 +f 7032/7009/6229 7029/7007/6227 7031/7010/6230 +f 7034/7011/6231 7029/7007/6227 7033/7012/6232 +f 5103/7005/6225 5064/6955/6175 3974/6935/6155 +f 5104/7004/6224 7030/7006/6226 5103/7005/6225 +f 7030/7006/6226 5065/6956/6176 5064/6955/6175 +f 5108/7013/6233 5105/7001/6221 3849/7003/6223 +f 5107/7014/6234 7032/7009/6229 5108/7013/6233 +f 7032/7009/6229 5104/7004/6224 5105/7001/6221 +f 5066/6957/6177 5106/7015/6235 3882/4287/3603 +f 5065/6956/6176 7034/7011/6231 5066/6957/6177 +f 7034/7011/6231 5107/7014/6234 5106/7015/6235 +f 7037/7016/6236 7036/7017/6237 7042/7018/6238 +f 7039/7019/6239 7036/7017/6237 7038/7020/6240 +f 7041/7021/6241 7036/7017/6237 7040/7022/6242 +f 4103/7023/6243 5108/7013/6233 3849/7003/6223 +f 4102/7024/6244 7037/7016/6236 4103/7023/6243 +f 7037/7016/6236 5107/7014/6234 5108/7013/6233 +f 4200/4281/3597 4101/7025/6245 3832/4117/3448 +f 4200/4281/3597 7040/7022/6242 7039/7019/6239 +f 4101/7025/6245 7038/7020/6240 4102/7024/6244 +f 5106/7015/6235 4202/4285/3601 3882/4287/3603 +f 5107/7014/6234 7041/7021/6241 5106/7015/6235 +f 7041/7021/6241 4201/4282/3598 4202/4285/3601 +f 7044/7026/6246 7043/7027/6247 7049/7028/6248 +f 7046/7029/6249 7043/7027/6247 7045/7030/6250 +f 7048/7031/6251 7043/7027/6247 7047/7032/6252 +f 5109/7033/6253 4175/6327/5563 3873/6307/5543 +f 5110/7034/6254 7044/7026/6246 5109/7033/6253 +f 7044/7026/6246 4174/6328/5564 4175/6327/5563 +f 4026/5433/4669 5111/7035/6255 3878/5434/4670 +f 4027/5436/4672 7046/7029/6249 4026/5433/4669 +f 7046/7029/6249 5110/7034/6254 5111/7035/6255 +f 4173/6329/5565 4028/5438/4674 3841/4429/3745 +f 4174/6328/5564 7048/7031/6251 4173/6329/5565 +f 7048/7031/6251 4027/5436/4672 4028/5438/4674 +f 7051/7036/6256 7050/7037/6257 7056/7038/6258 +f 7053/7039/6259 7050/7037/6257 7052/7040/6260 +f 7055/7041/6261 7050/7037/6257 7054/7042/6262 +f 5115/7043/6263 4178/6303/5539 3874/6283/5519 +f 5116/7044/6264 7051/7036/6256 5115/7043/6263 +f 7051/7036/6256 4177/6304/5540 4178/6303/5539 +f 5129/7045/6265 5117/7046/6266 3975/7047/6267 +f 5128/7048/6268 7053/7039/6259 5129/7045/6265 +f 7053/7039/6259 5116/7044/6264 5117/7046/6266 +f 4176/6306/5542 5127/7049/6269 3873/6307/5543 +f 4177/6304/5540 7055/7041/6261 4176/6306/5542 +f 7055/7041/6261 5128/7048/6268 5127/7049/6269 +f 7058/7050/6270 7057/7051/6271 7063/7052/6272 +f 7060/7053/6273 7057/7051/6271 7059/7054/6274 +f 7062/7055/6275 7057/7051/6271 7061/7056/6276 +f 5121/7057/6277 4181/6279/5515 3875/4197/3513 +f 5121/7057/6277 7059/7054/6274 7058/7050/6270 +f 4181/6279/5515 7063/7052/6272 4180/6280/5516 +f 5135/7058/6278 5123/7059/6279 3976/7060/6280 +f 5134/7061/6281 7060/7053/6273 5135/7058/6278 +f 7060/7053/6273 5122/7062/6282 5123/7059/6279 +f 4179/6282/5518 5133/7063/6283 3874/6283/5519 +f 4180/6280/5516 7062/7055/6275 4179/6282/5518 +f 7062/7055/6275 5134/7061/6281 5133/7063/6283 +f 7065/7064/6284 7064/7065/6285 7070/7066/6286 +f 7067/7067/6287 7064/7065/6285 7066/7068/6288 +f 7069/7069/6289 7064/7065/6285 7068/7070/6290 +f 5127/7049/6269 5109/7033/6253 3873/6307/5543 +f 5128/7048/6268 7065/7064/6284 5127/7049/6269 +f 7065/7064/6284 5110/7034/6254 5109/7033/6253 +f 5132/7071/6291 5129/7045/6265 3975/7047/6267 +f 5131/7072/6292 7067/7067/6287 5132/7071/6291 +f 7067/7067/6287 5128/7048/6268 5129/7045/6265 +f 5111/7035/6255 5130/7073/6293 3878/5434/4670 +f 5110/7034/6254 7069/7069/6289 5111/7035/6255 +f 7069/7069/6289 5131/7072/6292 5130/7073/6293 +f 7072/7074/6294 7071/7075/6295 7077/7076/6296 +f 7074/7077/6297 7071/7075/6295 7073/7078/6298 +f 7076/7079/6299 7071/7075/6295 7075/7080/6300 +f 5112/7081/6301 5132/7071/6291 3975/7047/6267 +f 5113/7082/6302 7072/7074/6294 5112/7081/6301 +f 7072/7074/6294 5131/7072/6292 5132/7071/6291 +f 4188/5447/4683 5114/7083/6303 3877/5448/4684 +f 4189/5450/4686 7074/7077/6297 4188/5447/4683 +f 7074/7077/6297 5113/7082/6302 5114/7083/6303 +f 5130/7073/6293 4190/5455/4691 3878/5434/4670 +f 5131/7072/6292 7076/7079/6299 5130/7073/6293 +f 7076/7079/6299 4189/5450/4686 4190/5455/4691 +f 7079/7084/6304 7078/7085/6305 7084/7086/6306 +f 7081/7087/6307 7078/7085/6305 7080/7088/6308 +f 7083/7089/6309 7078/7085/6305 7082/7090/6310 +f 5133/7063/6283 5115/7043/6263 3874/6283/5519 +f 5133/7063/6283 7080/7088/6308 7079/7084/6304 +f 7079/7084/6304 5116/7044/6264 5115/7043/6263 +f 5138/7091/6311 5135/7058/6278 3976/7060/6280 +f 5137/7092/6312 7081/7087/6307 5138/7091/6311 +f 7081/7087/6307 5134/7061/6281 5135/7058/6278 +f 5117/7046/6266 5136/7093/6313 3975/7047/6267 +f 5116/7044/6264 7083/7089/6309 5117/7046/6266 +f 7083/7089/6309 5137/7092/6312 5136/7093/6313 +f 7086/7094/6314 7085/7095/6315 7091/7096/6316 +f 7088/7097/6317 7085/7095/6315 7087/7098/6318 +f 7090/7099/6319 7085/7095/6315 7089/7100/6320 +f 5124/7101/6321 5138/7091/6311 3976/7060/6280 +f 5125/7102/6322 7086/7094/6314 5124/7101/6321 +f 7086/7094/6314 5137/7092/6312 5138/7091/6311 +f 5141/7103/6323 5126/7104/6324 3977/7105/6325 +f 5140/7106/6326 7088/7097/6317 5141/7103/6323 +f 7088/7097/6317 5125/7102/6322 5126/7104/6324 +f 5136/7093/6313 5139/7107/6327 3975/7047/6267 +f 5137/7092/6312 7090/7099/6319 5136/7093/6313 +f 7090/7099/6319 5140/7106/6326 5139/7107/6327 +f 7093/7108/6328 7092/7109/6329 7098/7110/6330 +f 7095/7111/6331 7092/7109/6329 7094/7112/6332 +f 7097/7113/6333 7092/7109/6329 7096/7114/6334 +f 5139/7107/6327 5112/7081/6301 3975/7047/6267 +f 5140/7106/6326 7093/7108/6328 5139/7107/6327 +f 7093/7108/6328 5113/7082/6302 5112/7081/6301 +f 5144/7115/6335 5141/7103/6323 3977/7105/6325 +f 5143/7116/6336 7095/7111/6331 5144/7115/6335 +f 7095/7111/6331 5140/7106/6326 5141/7103/6323 +f 5114/7083/6303 5142/7117/6337 3877/5448/4684 +f 5113/7082/6302 7097/7113/6333 5114/7083/6303 +f 7097/7113/6333 5143/7116/6336 5142/7117/6337 +f 7100/7118/6338 7099/7119/6339 7105/7120/6340 +f 7102/7121/6341 7099/7119/6339 7101/7122/6342 +f 7104/7123/6343 7099/7119/6339 7103/7124/6344 +f 5118/7125/6345 5144/7115/6335 3977/7105/6325 +f 5119/7126/6346 7100/7118/6338 5118/7125/6345 +f 7100/7118/6338 5143/7116/6336 5144/7115/6335 +f 4185/5465/4701 5120/7127/6347 3876/4343/3659 +f 4186/5466/4702 7102/7121/6341 4185/5465/4701 +f 5120/7127/6347 7101/7122/6342 5119/7126/6346 +f 5142/7117/6337 4187/5472/4708 3877/5448/4684 +f 5143/7116/6336 7104/7123/6343 5142/7117/6337 +f 7104/7123/6343 4186/5466/4702 4187/5472/4708 +f 7107/7128/6348 7106/7129/6349 7112/7130/6350 +f 7109/7131/6351 7106/7129/6349 7108/7132/6352 +f 7111/7133/6353 7106/7129/6349 7110/7134/6354 +f 5145/4196/3512 5121/7057/6277 3875/4197/3513 +f 5146/4194/3510 7107/7128/6348 5145/4196/3512 +f 7107/7128/6348 5122/7062/6282 5121/7057/6277 +f 5150/7135/6355 5147/4193/3509 3854/4125/3456 +f 5149/7136/6356 7109/7131/6351 5150/7135/6355 +f 7109/7131/6351 5146/4194/3510 5147/4193/3509 +f 5123/7059/6279 5148/7137/6357 3976/7060/6280 +f 5123/7059/6279 7112/7130/6350 7111/7133/6353 +f 5148/7137/6357 7110/7134/6354 5149/7136/6356 +f 7114/7138/6358 7113/7139/6359 7119/7140/6360 +f 7116/7141/6361 7113/7139/6359 7115/7142/6362 +f 7118/7143/6363 7113/7139/6359 7117/7144/6364 +f 4118/7145/6365 5150/7135/6355 3854/4125/3456 +f 4118/7145/6365 7115/7142/6362 7114/7138/6358 +f 5150/7135/6355 7119/7140/6360 5149/7136/6356 +f 5153/7146/6366 4116/7147/6367 3853/7148/6368 +f 5152/7149/6369 7116/7141/6361 5153/7146/6366 +f 7116/7141/6361 4117/7150/6370 4116/7147/6367 +f 5148/7137/6357 5151/7151/6371 3976/7060/6280 +f 5149/7136/6356 7118/7143/6363 5148/7137/6357 +f 7118/7143/6363 5152/7149/6369 5151/7151/6371 +f 7121/7152/6372 7120/7153/6373 7126/7154/6374 +f 7123/7155/6375 7120/7153/6373 7122/7156/6376 +f 7125/7157/6377 7120/7153/6373 7124/7158/6378 +f 5151/7151/6371 5124/7101/6321 3976/7060/6280 +f 5152/7149/6369 7121/7152/6372 5151/7151/6371 +f 7121/7152/6372 5125/7102/6322 5124/7101/6321 +f 5156/7159/6379 5153/7146/6366 3853/7148/6368 +f 5155/7160/6380 7123/7155/6375 5156/7159/6379 +f 7123/7155/6375 5152/7149/6369 5153/7146/6366 +f 5126/7104/6324 5154/7161/6381 3977/7105/6325 +f 5125/7102/6322 7125/7157/6377 5126/7104/6324 +f 7125/7157/6377 5155/7160/6380 5154/7161/6381 +f 7128/7162/6382 7127/7163/6383 7133/7164/6384 +f 7130/7165/6385 7127/7163/6383 7129/7166/6386 +f 7132/7167/6387 7127/7163/6383 7131/7168/6388 +f 4115/7169/6389 5156/7159/6379 3853/7148/6368 +f 4114/7170/6390 7128/7162/6382 4115/7169/6389 +f 7128/7162/6382 5155/7160/6380 5156/7159/6379 +f 5159/7171/6391 4113/7172/6392 3852/7173/6393 +f 5159/7171/6391 7131/7168/6388 7130/7165/6385 +f 4113/7172/6392 7129/7166/6386 4114/7170/6390 +f 5154/7161/6381 5157/7174/6394 3977/7105/6325 +f 5155/7160/6380 7132/7167/6387 5154/7161/6381 +f 7132/7167/6387 5158/7175/6395 5157/7174/6394 +f 7135/7176/6396 7134/7177/6397 7140/7178/6398 +f 7137/7179/6399 7134/7177/6397 7136/7180/6400 +f 7139/7181/6401 7134/7177/6397 7138/7182/6402 +f 5157/7174/6394 5118/7125/6345 3977/7105/6325 +f 5157/7174/6394 7136/7180/6400 7135/7176/6396 +f 5118/7125/6345 7140/7178/6398 5119/7126/6346 +f 5162/7183/6403 5159/7171/6391 3852/7173/6393 +f 5161/7184/6404 7137/7179/6399 5162/7183/6403 +f 7137/7179/6399 5158/7175/6395 5159/7171/6391 +f 5120/7127/6347 5160/7185/6405 3876/4343/3659 +f 5119/7126/6346 7139/7181/6401 5120/7127/6347 +f 7139/7181/6401 5161/7184/6404 5160/7185/6405 +f 7142/7186/6406 7141/7187/6407 7147/7188/6408 +f 7144/7189/6409 7141/7187/6407 7143/7190/6410 +f 7146/7191/6411 7141/7187/6407 7145/7192/6412 +f 4112/7193/6413 5162/7183/6403 3852/7173/6393 +f 4111/7194/6414 7142/7186/6406 4112/7193/6413 +f 7142/7186/6406 5161/7184/6404 5162/7183/6403 +f 4182/4337/3653 4110/7195/6415 3836/4264/3580 +f 4182/4337/3653 7145/7192/6412 7144/7189/6409 +f 4110/7195/6415 7143/7190/6410 4111/7194/6414 +f 5160/7185/6405 4184/4341/3657 3876/4343/3659 +f 5161/7184/6404 7146/7191/6411 5160/7185/6405 +f 7146/7191/6411 4183/4338/3654 4184/4341/3657 +f 7149/7196/6416 7148/7197/6417 7154/7198/6418 +f 7152/7199/6419 7150/7200/6420 7151/7201/6421 +f 7153/7202/6422 7148/7197/6417 7152/7199/6419 +f 5163/7203/6423 4005/7204/6424 3857/7205/6425 +f 5164/7206/6426 7149/7196/6416 5163/7203/6423 +f 7149/7196/6416 4006/7207/6427 4005/7204/6424 +f 4020/4267/3583 5165/7208/6428 3872/4268/3584 +f 4021/4270/3586 7151/7201/6421 4020/4267/3583 +f 7151/7201/6421 5164/7206/6426 5165/7208/6428 +f 4007/7209/6429 4022/4262/3578 3836/4264/3580 +f 4007/7209/6429 7154/7198/6418 7153/7202/6422 +f 4022/4262/3578 7152/7199/6419 4021/4270/3586 +f 7156/7210/6430 7155/7211/6431 7161/7212/6432 +f 7158/7213/6433 7155/7211/6431 7157/7214/6434 +f 7160/7215/6435 7155/7211/6431 7159/7216/6436 +f 5169/7217/6437 4125/7218/6438 3856/7219/6439 +f 5170/7220/6440 7156/7210/6430 5169/7217/6437 +f 7156/7210/6430 4126/7221/6441 4125/7218/6438 +f 5183/7222/6442 5171/7223/6443 3978/7224/6444 +f 5182/7225/6445 7158/7213/6433 5183/7222/6442 +f 7158/7213/6433 5170/7220/6440 5171/7223/6443 +f 4127/7226/6446 5181/7227/6447 3857/7205/6425 +f 4126/7221/6441 7160/7215/6435 4127/7226/6446 +f 5181/7227/6447 7159/7216/6436 5182/7225/6445 +f 7163/7228/6448 7162/7229/6449 7168/7230/6450 +f 7165/7231/6451 7162/7229/6449 7164/7232/6452 +f 7167/7233/6453 7162/7229/6449 7166/7234/6454 +f 5175/7235/6455 4122/7236/6456 3855/4183/3499 +f 5175/7235/6455 7164/7232/6452 7163/7228/6448 +f 7163/7228/6448 4123/7237/6457 4122/7236/6456 +f 5189/7238/6458 5177/7239/6459 3979/7240/6460 +f 5188/7241/6461 7165/7231/6451 5189/7238/6458 +f 7165/7231/6451 5176/7242/6462 5177/7239/6459 +f 4124/7243/6463 5187/7244/6464 3856/7219/6439 +f 4123/7237/6457 7167/7233/6453 4124/7243/6463 +f 7167/7233/6453 5188/7241/6461 5187/7244/6464 +f 7170/7245/6465 7169/7246/6466 7175/7247/6467 +f 7172/7248/6468 7169/7246/6466 7171/7249/6469 +f 7174/7250/6470 7169/7246/6466 7173/7251/6471 +f 5181/7227/6447 5163/7203/6423 3857/7205/6425 +f 5182/7225/6445 7170/7245/6465 5181/7227/6447 +f 7170/7245/6465 5164/7206/6426 5163/7203/6423 +f 5186/7252/6472 5183/7222/6442 3978/7224/6444 +f 5186/7252/6472 7173/7251/6471 7172/7248/6468 +f 5183/7222/6442 7171/7249/6469 5182/7225/6445 +f 5165/7208/6428 5184/7253/6473 3872/4268/3584 +f 5164/7206/6426 7174/7250/6470 5165/7208/6428 +f 7174/7250/6470 5185/7254/6474 5184/7253/6473 +f 7177/7255/6475 7176/7256/6476 7182/7257/6477 +f 7179/7258/6478 7176/7256/6476 7178/7259/6479 +f 7181/7260/6480 7176/7256/6476 7180/7261/6481 +f 5166/7262/6482 5186/7252/6472 3978/7224/6444 +f 5167/7263/6483 7177/7255/6475 5166/7262/6482 +f 7177/7255/6475 5185/7254/6474 5186/7252/6472 +f 4170/6452/5688 5168/7264/6484 3871/6453/5689 +f 4171/6450/5686 7179/7258/6478 4170/6452/5688 +f 7179/7258/6478 5167/7263/6483 5168/7264/6484 +f 5184/7253/6473 4172/6449/5685 3872/4268/3584 +f 5184/7253/6473 7182/7257/6477 7181/7260/6480 +f 4172/6449/5685 7180/7261/6481 4171/6450/5686 +f 7184/7265/6485 7183/7266/6486 7189/7267/6487 +f 7186/7268/6488 7183/7266/6486 7185/7269/6489 +f 7188/7270/6490 7183/7266/6486 7187/7271/6491 +f 5187/7244/6464 5169/7217/6437 3856/7219/6439 +f 5188/7241/6461 7184/7265/6485 5187/7244/6464 +f 7184/7265/6485 5170/7220/6440 5169/7217/6437 +f 5192/7272/6492 5189/7238/6458 3979/7240/6460 +f 5191/7273/6493 7186/7268/6488 5192/7272/6492 +f 7186/7268/6488 5188/7241/6461 5189/7238/6458 +f 5171/7223/6443 5190/7274/6494 3978/7224/6444 +f 5170/7220/6440 7188/7270/6490 5171/7223/6443 +f 7188/7270/6490 5191/7273/6493 5190/7274/6494 +f 7191/7275/6495 7190/7276/6496 7196/7277/6497 +f 7193/7278/6498 7190/7276/6496 7192/7279/6499 +f 7195/7280/6500 7190/7276/6496 7194/7281/6501 +f 5178/7282/6502 5192/7272/6492 3979/7240/6460 +f 5179/7283/6503 7191/7275/6495 5178/7282/6502 +f 7191/7275/6495 5191/7273/6493 5192/7272/6492 +f 5195/7284/6504 5180/7285/6505 3980/7286/6506 +f 5194/7287/6507 7193/7278/6498 5195/7284/6504 +f 7193/7278/6498 5179/7283/6503 5180/7285/6505 +f 5190/7274/6494 5193/7288/6508 3978/7224/6444 +f 5191/7273/6493 7195/7280/6500 5190/7274/6494 +f 7195/7280/6500 5194/7287/6507 5193/7288/6508 +f 7198/7289/6509 7197/7290/6510 7203/7291/6511 +f 7200/7292/6512 7197/7290/6510 7199/7293/6513 +f 7202/7294/6514 7197/7290/6510 7201/7295/6515 +f 5193/7288/6508 5166/7262/6482 3978/7224/6444 +f 5194/7287/6507 7198/7289/6509 5193/7288/6508 +f 7198/7289/6509 5167/7263/6483 5166/7262/6482 +f 5198/7296/6516 5195/7284/6504 3980/7286/6506 +f 5197/7297/6517 7200/7292/6512 5198/7296/6516 +f 7200/7292/6512 5194/7287/6507 5195/7284/6504 +f 5168/7264/6484 5196/7298/6518 3871/6453/5689 +f 5167/7263/6483 7202/7294/6514 5168/7264/6484 +f 7202/7294/6514 5197/7297/6517 5196/7298/6518 +f 7205/7299/6519 7204/7300/6520 7210/7301/6521 +f 7207/7302/6522 7204/7300/6520 7206/7303/6523 +f 7209/7304/6524 7204/7300/6520 7208/7305/6525 +f 5172/7306/6526 5198/7296/6516 3980/7286/6506 +f 5173/7307/6527 7205/7299/6519 5172/7306/6526 +f 7205/7299/6519 5197/7297/6517 5198/7296/6516 +f 4167/6476/5712 5174/7308/6528 3870/6477/5713 +f 4168/6474/5710 7207/7302/6522 4167/6476/5712 +f 5174/7308/6528 7206/7303/6523 5173/7307/6527 +f 5196/7298/6518 4169/6473/5709 3871/6453/5689 +f 5197/7297/6517 7209/7304/6524 5196/7298/6518 +f 7209/7304/6524 4168/6474/5710 4169/6473/5709 +f 7212/7309/6529 7211/7310/6530 7217/7311/6531 +f 7214/7312/6532 7211/7310/6530 7213/7313/6533 +f 7216/7314/6534 7211/7310/6530 7215/7315/6535 +f 5199/4182/3498 5175/7235/6455 3855/4183/3499 +f 5200/4180/3496 7212/7309/6529 5199/4182/3498 +f 7212/7309/6529 5176/7242/6462 5175/7235/6455 +f 5204/7316/6536 5201/4177/3495 3866/4179/3485 +f 5204/7316/6536 7215/7315/6535 7214/7312/6532 +f 7214/7312/6532 5200/4180/3496 5201/4177/3495 +f 5177/7239/6459 5202/7317/6537 3979/7240/6460 +f 5176/7242/6462 7216/7314/6534 5177/7239/6459 +f 7216/7314/6534 5203/7318/6538 5202/7317/6537 +f 7219/7319/6539 7218/7320/6540 7224/7321/6541 +f 7221/7322/6542 7218/7320/6540 7220/7323/6543 +f 7223/7324/6544 7218/7320/6540 7222/7325/6545 +f 4154/7326/6546 5204/7316/6536 3866/4179/3485 +f 4153/7327/6547 7219/7319/6539 4154/7326/6546 +f 7219/7319/6539 5203/7318/6538 5204/7316/6536 +f 5207/7328/6548 4152/7329/6549 3865/7330/6550 +f 5206/7331/6551 7221/7322/6542 5207/7328/6548 +f 7221/7322/6542 4153/7327/6547 4152/7329/6549 +f 5202/7317/6537 5205/7332/6552 3979/7240/6460 +f 5203/7318/6538 7223/7324/6544 5202/7317/6537 +f 7223/7324/6544 5206/7331/6551 5205/7332/6552 +f 7226/7333/6553 7225/7334/6554 7231/7335/6555 +f 7228/7336/6556 7225/7334/6554 7227/7337/6557 +f 7230/7338/6558 7225/7334/6554 7229/7339/6559 +f 5205/7332/6552 5178/7282/6502 3979/7240/6460 +f 5206/7331/6551 7226/7333/6553 5205/7332/6552 +f 7226/7333/6553 5179/7283/6503 5178/7282/6502 +f 5210/7340/6560 5207/7328/6548 3865/7330/6550 +f 5210/7340/6560 7229/7339/6559 7228/7336/6556 +f 7228/7336/6556 5206/7331/6551 5207/7328/6548 +f 5180/7285/6505 5208/7341/6561 3980/7286/6506 +f 5179/7283/6503 7230/7338/6558 5180/7285/6505 +f 7230/7338/6558 5209/7342/6562 5208/7341/6561 +f 7233/7343/6563 7232/7344/6564 7238/7345/6565 +f 7235/7346/6566 7232/7344/6564 7234/7347/6567 +f 7237/7348/6568 7232/7344/6564 7236/7349/6569 +f 4151/7350/6570 5210/7340/6560 3865/7330/6550 +f 4150/7351/6571 7233/7343/6563 4151/7350/6570 +f 7233/7343/6563 5209/7342/6562 5210/7340/6560 +f 5213/7352/6572 4149/7353/6573 3864/7354/6574 +f 5212/7355/6575 7235/7346/6566 5213/7352/6572 +f 7235/7346/6566 4150/7351/6571 4149/7353/6573 +f 5208/7341/6561 5211/7356/6576 3980/7286/6506 +f 5209/7342/6562 7237/7348/6568 5208/7341/6561 +f 7237/7348/6568 5212/7355/6575 5211/7356/6576 +f 7240/7357/6577 7239/7358/6578 7245/7359/6579 +f 7242/7360/6580 7239/7358/6578 7241/7361/6581 +f 7244/7362/6582 7239/7358/6578 7243/7363/6583 +f 5211/7356/6576 5172/7306/6526 3980/7286/6506 +f 5212/7355/6575 7240/7357/6577 5211/7356/6576 +f 5172/7306/6526 7245/7359/6579 5173/7307/6527 +f 5216/7364/6584 5213/7352/6572 3864/7354/6574 +f 5215/7365/6585 7242/7360/6580 5216/7364/6584 +f 7242/7360/6580 5212/7355/6575 5213/7352/6572 +f 5174/7308/6528 5214/7366/6586 3870/6477/5713 +f 5173/7307/6527 7244/7362/6582 5174/7308/6528 +f 7244/7362/6582 5215/7365/6585 5214/7366/6586 +f 7247/7367/6587 7246/7368/6588 7252/7369/6589 +f 7249/7370/6590 7246/7368/6588 7248/7371/6591 +f 7251/7372/6592 7246/7368/6588 7250/7373/6593 +f 4148/7374/6594 5216/7364/6584 3864/7354/6574 +f 4147/7375/6595 7247/7367/6587 4148/7374/6594 +f 7247/7367/6587 5215/7365/6585 5216/7364/6584 +f 4164/6499/5735 4146/7376/6596 3835/4245/3561 +f 4164/6499/5735 7250/7373/6593 7249/7370/6590 +f 4146/7376/6596 7248/7371/6591 4147/7375/6595 +f 5214/7366/6586 4166/6497/5733 3870/6477/5713 +f 5215/7365/6585 7251/7372/6592 5214/7366/6586 +f 7251/7372/6592 4165/6498/5734 4166/6497/5733 +f 7254/7377/6597 7253/7378/6598 7259/7379/6599 +f 7256/7380/6600 7253/7378/6598 7255/7381/6601 +f 7258/7382/6602 7253/7378/6598 7257/7383/6603 +f 5217/7384/6604 4148/7385/6594 3864/7386/6574 +f 5218/7387/6605 7254/7377/6597 5217/7384/6604 +f 7254/7377/6597 4147/7388/6595 4148/7385/6594 +f 4017/4248/3564 5219/7389/6606 3869/4249/3565 +f 4018/4251/3567 7256/7380/6600 4017/4248/3564 +f 7256/7380/6600 5218/7387/6605 5219/7389/6606 +f 4146/7390/6596 4019/4243/3559 3835/4245/3561 +f 4146/7390/6596 7259/7379/6599 7258/7382/6602 +f 4019/4243/3559 7257/7383/6603 4018/4251/3567 +f 7261/7391/6607 7260/7392/6608 7266/7393/6609 +f 7263/7394/6610 7260/7392/6608 7262/7395/6611 +f 7265/7396/6612 7260/7392/6608 7264/7397/6613 +f 5223/7398/6614 4151/7399/6570 3865/7400/6550 +f 5224/7401/6615 7261/7391/6607 5223/7398/6614 +f 7261/7391/6607 4150/7402/6571 4151/7399/6570 +f 5237/7403/6616 5225/7404/6617 3981/7405/6618 +f 5236/7406/6619 7263/7394/6610 5237/7403/6616 +f 7263/7394/6610 5224/7401/6615 5225/7404/6617 +f 4149/7407/6573 5235/7408/6620 3864/7386/6574 +f 4150/7402/6571 7265/7396/6612 4149/7407/6573 +f 7265/7396/6612 5236/7406/6619 5235/7408/6620 +f 7268/7409/6621 7267/7410/6622 7273/7411/6623 +f 7270/7412/6624 7267/7410/6622 7269/7413/6625 +f 7272/7414/6626 7267/7410/6622 7271/7415/6627 +f 5229/7416/6628 4154/7417/6546 3866/4164/3485 +f 5229/7416/6628 7269/7413/6625 7268/7409/6621 +f 4154/7417/6546 7273/7411/6623 4153/7418/6547 +f 5243/7419/6629 5231/7420/6630 3982/7421/6631 +f 5242/7422/6632 7270/7412/6624 5243/7419/6629 +f 7270/7412/6624 5230/7423/6633 5231/7420/6630 +f 4152/7424/6549 5241/7425/6634 3865/7400/6550 +f 4153/7418/6547 7272/7414/6626 4152/7424/6549 +f 7272/7414/6626 5242/7422/6632 5241/7425/6634 +f 7275/7426/6635 7274/7427/6636 7280/7428/6637 +f 7277/7429/6638 7274/7427/6636 7276/7430/6639 +f 7279/7431/6640 7274/7427/6636 7278/7432/6641 +f 5235/7408/6620 5217/7384/6604 3864/7386/6574 +f 5236/7406/6619 7275/7426/6635 5235/7408/6620 +f 7275/7426/6635 5218/7387/6605 5217/7384/6604 +f 5240/7433/6642 5237/7403/6616 3981/7405/6618 +f 5239/7434/6643 7277/7429/6638 5240/7433/6642 +f 7277/7429/6638 5236/7406/6619 5237/7403/6616 +f 5219/7389/6606 5238/7435/6644 3869/4249/3565 +f 5218/7387/6605 7279/7431/6640 5219/7389/6606 +f 7279/7431/6640 5239/7434/6643 5238/7435/6644 +f 7282/7436/6645 7281/7437/6646 7287/7438/6647 +f 7284/7439/6648 7281/7437/6646 7283/7440/6649 +f 7286/7441/6650 7281/7437/6646 7285/7442/6651 +f 5220/7443/6652 5240/7433/6642 3981/7405/6618 +f 5221/7444/6653 7282/7436/6645 5220/7443/6652 +f 7282/7436/6645 5239/7434/6643 5240/7433/6642 +f 4161/6621/5857 5222/7445/6654 3868/6622/5858 +f 4162/6624/5860 7284/7439/6648 4161/6621/5857 +f 7284/7439/6648 5221/7444/6653 5222/7445/6654 +f 5238/7435/6644 4163/6619/5855 3869/4249/3565 +f 5239/7434/6643 7286/7441/6650 5238/7435/6644 +f 7286/7441/6650 4162/6624/5860 4163/6619/5855 +f 7289/7446/6655 7288/7447/6656 7294/7448/6657 +f 7291/7449/6658 7288/7447/6656 7290/7450/6659 +f 7293/7451/6660 7288/7447/6656 7292/7452/6661 +f 5241/7425/6634 5223/7398/6614 3865/7400/6550 +f 5242/7422/6632 7289/7446/6655 5241/7425/6634 +f 7289/7446/6655 5224/7401/6615 5223/7398/6614 +f 5246/7453/6662 5243/7419/6629 3982/7421/6631 +f 5245/7454/6663 7291/7449/6658 5246/7453/6662 +f 7291/7449/6658 5242/7422/6632 5243/7419/6629 +f 5225/7404/6617 5244/7455/6664 3981/7405/6618 +f 5225/7404/6617 7294/7448/6657 7293/7451/6660 +f 5244/7455/6664 7292/7452/6661 5245/7454/6663 +f 7296/7456/6665 7295/7457/6666 7301/7458/6667 +f 7298/7459/6668 7295/7457/6666 7297/7460/6669 +f 7300/7461/6670 7295/7457/6666 7299/7462/6671 +f 5232/7463/6672 5246/7453/6662 3982/7421/6631 +f 5233/7464/6673 7296/7456/6665 5232/7463/6672 +f 5246/7453/6662 7301/7458/6667 5245/7454/6663 +f 5249/7465/6674 5234/7466/6675 3983/7467/6676 +f 5249/7465/6674 7299/7462/6671 7298/7459/6668 +f 7298/7459/6668 5233/7464/6673 5234/7466/6675 +f 5244/7455/6664 5247/7468/6677 3981/7405/6618 +f 5245/7454/6663 7300/7461/6670 5244/7455/6664 +f 7300/7461/6670 5248/7469/6678 5247/7468/6677 +f 7303/7470/6679 7302/7471/6680 7308/7472/6681 +f 7305/7473/6682 7302/7471/6680 7304/7474/6683 +f 7307/7475/6684 7302/7471/6680 7306/7476/6685 +f 5247/7468/6677 5220/7443/6652 3981/7405/6618 +f 5248/7469/6678 7303/7470/6679 5247/7468/6677 +f 7303/7470/6679 5221/7444/6653 5220/7443/6652 +f 5252/7477/6686 5249/7465/6674 3983/7467/6676 +f 5251/7478/6687 7305/7473/6682 5252/7477/6686 +f 7305/7473/6682 5248/7469/6678 5249/7465/6674 +f 5222/7445/6654 5250/7479/6688 3868/6622/5858 +f 5221/7444/6653 7307/7475/6684 5222/7445/6654 +f 7307/7475/6684 5251/7478/6687 5250/7479/6688 +f 7310/7480/6689 7309/7481/6690 7315/7482/6691 +f 7312/7483/6692 7309/7481/6690 7311/7484/6693 +f 7314/7485/6694 7309/7481/6690 7313/7486/6695 +f 5226/7487/6696 5252/7477/6686 3983/7467/6676 +f 5227/7488/6697 7310/7480/6689 5226/7487/6696 +f 7310/7480/6689 5251/7478/6687 5252/7477/6686 +f 4158/6646/5882 5228/7489/6698 3867/6647/5883 +f 4159/6644/5880 7312/7483/6692 4158/6646/5882 +f 5228/7489/6698 7311/7484/6693 5227/7488/6697 +f 5250/7479/6688 4160/6643/5879 3868/6622/5858 +f 5251/7478/6687 7314/7485/6694 5250/7479/6688 +f 7314/7485/6694 4159/6644/5880 4160/6643/5879 +f 7317/7490/6699 7316/7491/6700 7322/7492/6701 +f 7319/7493/6702 7316/7491/6700 7318/7494/6703 +f 7321/7495/6704 7316/7491/6700 7320/7496/6705 +f 5253/4163/3484 5229/7416/6628 3866/4164/3485 +f 5254/4160/3482 7317/7490/6699 5253/4163/3484 +f 7317/7490/6699 5230/7423/6633 5229/7416/6628 +f 5258/7497/6706 5255/4157/3481 3860/4159/3471 +f 5257/7498/6707 7319/7493/6702 5258/7497/6706 +f 7319/7493/6702 5254/4160/3482 5255/4157/3481 +f 5231/7420/6630 5256/7499/6708 3982/7421/6631 +f 5231/7420/6630 7322/7492/6701 7321/7495/6704 +f 5256/7499/6708 7320/7496/6705 5257/7498/6707 +f 7324/7500/6709 7323/7501/6710 7329/7502/6711 +f 7326/7503/6712 7323/7501/6710 7325/7504/6713 +f 7328/7505/6714 7323/7501/6710 7327/7506/6715 +f 4136/7507/6716 5258/7497/6706 3860/4159/3471 +f 4136/7507/6716 7325/7504/6713 7324/7500/6709 +f 5258/7497/6706 7329/7502/6711 5257/7498/6707 +f 5261/7508/6717 4134/7509/6718 3859/7510/6719 +f 5260/7511/6720 7326/7503/6712 5261/7508/6717 +f 7326/7503/6712 4135/7512/6721 4134/7509/6718 +f 5256/7499/6708 5259/7513/6722 3982/7421/6631 +f 5257/7498/6707 7328/7505/6714 5256/7499/6708 +f 7328/7505/6714 5260/7511/6720 5259/7513/6722 +f 7331/7514/6723 7330/7515/6724 7336/7516/6725 +f 7333/7517/6726 7330/7515/6724 7332/7518/6727 +f 7335/7519/6728 7330/7515/6724 7334/7520/6729 +f 5259/7513/6722 5232/7463/6672 3982/7421/6631 +f 5260/7511/6720 7331/7514/6723 5259/7513/6722 +f 7331/7514/6723 5233/7464/6673 5232/7463/6672 +f 5264/7521/6730 5261/7508/6717 3859/7510/6719 +f 5264/7521/6730 7334/7520/6729 7333/7517/6726 +f 7333/7517/6726 5260/7511/6720 5261/7508/6717 +f 5234/7466/6675 5262/7522/6731 3983/7467/6676 +f 5233/7464/6673 7335/7519/6728 5234/7466/6675 +f 7335/7519/6728 5263/7523/6732 5262/7522/6731 +f 7338/7524/6733 7337/7525/6734 7343/7526/6735 +f 7340/7527/6736 7337/7525/6734 7339/7528/6737 +f 7342/7529/6738 7337/7525/6734 7341/7530/6739 +f 4133/7531/6740 5264/7521/6730 3859/7510/6719 +f 4133/7531/6740 7339/7528/6737 7338/7524/6733 +f 7338/7524/6733 5263/7523/6732 5264/7521/6730 +f 5267/7532/6741 4131/7533/6742 3858/7534/6743 +f 5266/7535/6744 7340/7527/6736 5267/7532/6741 +f 7340/7527/6736 4132/7536/6745 4131/7533/6742 +f 5262/7522/6731 5265/7537/6746 3983/7467/6676 +f 5262/7522/6731 7343/7526/6735 7342/7529/6738 +f 5265/7537/6746 7341/7530/6739 5266/7535/6744 +f 7345/7538/6747 7344/7539/6748 7350/7540/6749 +f 7347/7541/6750 7344/7539/6748 7346/7542/6751 +f 7349/7543/6752 7344/7539/6748 7348/7544/6753 +f 5265/7537/6746 5226/7487/6696 3983/7467/6676 +f 5266/7535/6744 7345/7538/6747 5265/7537/6746 +f 7345/7538/6747 5227/7488/6697 5226/7487/6696 +f 5270/7545/6754 5267/7532/6741 3858/7534/6743 +f 5269/7546/6755 7347/7541/6750 5270/7545/6754 +f 7347/7541/6750 5266/7535/6744 5267/7532/6741 +f 5228/7489/6698 5268/7547/6756 3867/6647/5883 +f 5227/7488/6697 7349/7543/6752 5228/7489/6698 +f 7349/7543/6752 5269/7546/6755 5268/7547/6756 +f 7352/7548/6757 7351/7549/6758 7357/7550/6759 +f 7354/7551/6760 7351/7549/6758 7353/7552/6761 +f 7356/7553/6762 7351/7549/6758 7355/7554/6763 +f 4130/7555/6764 5270/7545/6754 3858/7534/6743 +f 4129/7556/6765 7352/7548/6757 4130/7555/6764 +f 7352/7548/6757 5269/7546/6755 5270/7545/6754 +f 4155/6669/5905 4128/7557/6766 3834/4226/3542 +f 4155/6669/5905 7355/7554/6763 7354/7551/6760 +f 7354/7551/6760 4129/7556/6765 4128/7557/6766 +f 5268/7547/6756 4157/6667/5903 3867/6647/5883 +f 5269/7546/6755 7356/7553/6762 5268/7547/6756 +f 7356/7553/6762 4156/6668/5904 4157/6667/5903 +f 7359/7558/6767 7358/7559/6768 7364/7560/6769 +f 7361/7561/6770 7358/7559/6768 7360/7562/6771 +f 7363/7563/6772 7358/7559/6768 7362/7564/6773 +f 5271/7565/6774 4130/7566/6764 3858/7567/6743 +f 5272/7568/6775 7359/7558/6767 5271/7565/6774 +f 7359/7558/6767 4129/7569/6765 4130/7566/6764 +f 4011/4230/3546 5273/7570/6776 3863/4231/3547 +f 4012/4227/3543 7361/7561/6770 4011/4230/3546 +f 7361/7561/6770 5272/7568/6775 5273/7570/6776 +f 4128/7571/6766 4013/4224/3540 3834/4226/3542 +f 4128/7571/6766 7364/7560/6769 7363/7563/6772 +f 4013/4224/3540 7362/7564/6773 4012/4227/3543 +f 7366/7572/6777 7365/7573/6778 7371/7574/6779 +f 7368/7575/6780 7365/7573/6778 7367/7576/6781 +f 7370/7577/6782 7365/7573/6778 7369/7578/6783 +f 5277/7579/6784 4133/7580/6740 3859/7581/6719 +f 5278/7582/6785 7366/7572/6777 5277/7579/6784 +f 7366/7572/6777 4132/7583/6745 4133/7580/6740 +f 5291/7584/6786 5279/7585/6787 3984/7586/6788 +f 5290/7587/6789 7368/7575/6780 5291/7584/6786 +f 7368/7575/6780 5278/7582/6785 5279/7585/6787 +f 4131/7588/6742 5289/7589/6790 3858/7567/6743 +f 4131/7588/6742 7371/7574/6779 7370/7577/6782 +f 5289/7589/6790 7369/7578/6783 5290/7587/6789 +f 7373/7590/6791 7372/7591/6792 7378/7592/6793 +f 7375/7593/6794 7372/7591/6792 7374/7594/6795 +f 7377/7595/6796 7372/7591/6792 7376/7596/6797 +f 5283/7597/6798 4136/7598/6716 3860/4145/3471 +f 5283/7597/6798 7374/7594/6795 7373/7590/6791 +f 7373/7590/6791 4135/7599/6721 4136/7598/6716 +f 5297/7600/6799 5285/7601/6800 3985/7602/6801 +f 5296/7603/6802 7375/7593/6794 5297/7600/6799 +f 7375/7593/6794 5284/7604/6803 5285/7601/6800 +f 4134/7605/6718 5295/7606/6804 3859/7581/6719 +f 4134/7605/6718 7378/7592/6793 7377/7595/6796 +f 5295/7606/6804 7376/7596/6797 5296/7603/6802 +f 7380/7607/6805 7379/7608/6806 7385/7609/6807 +f 7382/7610/6808 7379/7608/6806 7381/7611/6809 +f 7384/7612/6810 7379/7608/6806 7383/7613/6811 +f 5289/7589/6790 5271/7565/6774 3858/7567/6743 +f 5290/7587/6789 7380/7607/6805 5289/7589/6790 +f 7380/7607/6805 5272/7568/6775 5271/7565/6774 +f 5294/7614/6812 5291/7584/6786 3984/7586/6788 +f 5294/7614/6812 7383/7613/6811 7382/7610/6808 +f 5291/7584/6786 7381/7611/6809 5290/7587/6789 +f 5273/7570/6776 5292/7615/6813 3863/4231/3547 +f 5272/7568/6775 7384/7612/6810 5273/7570/6776 +f 7384/7612/6810 5293/7616/6814 5292/7615/6813 +f 7387/7617/6815 7386/7618/6816 7392/7619/6817 +f 7389/7620/6818 7386/7618/6816 7388/7621/6819 +f 7391/7622/6820 7386/7618/6816 7390/7623/6821 +f 5274/7624/6822 5294/7614/6812 3984/7586/6788 +f 5275/7625/6823 7387/7617/6815 5274/7624/6822 +f 7387/7617/6815 5293/7616/6814 5294/7614/6812 +f 4143/6804/6028 5276/7626/6824 3862/6805/6029 +f 4144/6802/6026 7389/7620/6818 4143/6804/6028 +f 7389/7620/6818 5275/7625/6823 5276/7626/6824 +f 5292/7615/6813 4145/6801/6025 3863/4231/3547 +f 5292/7615/6813 7392/7619/6817 7391/7622/6820 +f 4145/6801/6025 7390/7623/6821 4144/6802/6026 +f 7394/7627/6825 7393/7628/6826 7399/7629/6827 +f 7396/7630/6828 7393/7628/6826 7395/7631/6829 +f 7399/7629/6827 7397/7632/6830 7398/7633/6831 +f 5295/7606/6804 5277/7579/6784 3859/7581/6719 +f 5296/7603/6802 7394/7627/6825 5295/7606/6804 +f 5277/7579/6784 7399/7629/6827 5278/7582/6785 +f 5300/7634/6832 5297/7600/6799 3985/7602/6801 +f 5300/7634/6832 7397/7632/6830 7396/7630/6828 +f 5297/7600/6799 7395/7631/6829 5296/7603/6802 +f 5279/7585/6787 5298/7635/6833 3984/7586/6788 +f 5278/7582/6785 7398/7633/6831 5279/7585/6787 +f 7398/7633/6831 5299/7636/6834 5298/7635/6833 +f 7401/7637/6835 7400/7638/6836 7406/7639/6837 +f 7403/7640/6838 7400/7638/6836 7402/7641/6839 +f 7405/7642/6840 7400/7638/6836 7404/7643/6841 +f 5286/7644/6842 5300/7634/6832 3985/7602/6801 +f 5287/7645/6843 7401/7637/6835 5286/7644/6842 +f 7401/7637/6835 5299/7636/6834 5300/7634/6832 +f 5303/7646/6844 5288/7647/6845 3986/7648/6846 +f 5303/7646/6844 7404/7643/6841 7403/7640/6838 +f 5288/7647/6845 7402/7641/6839 5287/7645/6843 +f 5298/7635/6833 5301/7649/6847 3984/7586/6788 +f 5298/7635/6833 7406/7639/6837 7405/7642/6840 +f 7405/7642/6840 5302/7650/6848 5301/7649/6847 +f 7408/7651/6849 7407/7652/6850 7413/7653/6851 +f 7410/7654/6852 7407/7652/6850 7409/7655/6853 +f 7412/7656/6854 7407/7652/6850 7411/7657/6855 +f 5301/7649/6847 5274/7624/6822 3984/7586/6788 +f 5302/7650/6848 7408/7651/6849 5301/7649/6847 +f 5274/7624/6822 7413/7653/6851 5275/7625/6823 +f 5306/7658/6856 5303/7646/6844 3986/7648/6846 +f 5306/7658/6856 7411/7657/6855 7410/7654/6852 +f 7410/7654/6852 5302/7650/6848 5303/7646/6844 +f 5276/7626/6824 5304/7659/6857 3862/6805/6029 +f 5275/7625/6823 7412/7656/6854 5276/7626/6824 +f 7412/7656/6854 5305/7660/6858 5304/7659/6857 +f 7415/7661/6859 7414/7662/6860 7420/7663/6861 +f 7417/7664/6862 7414/7662/6860 7416/7665/6863 +f 7419/7666/6864 7414/7662/6860 7418/7667/6865 +f 5280/7668/6866 5306/7658/6856 3986/7648/6846 +f 5281/7669/6867 7415/7661/6859 5280/7668/6866 +f 7415/7661/6859 5305/7660/6858 5306/7658/6856 +f 4140/6828/6052 5282/7670/6868 3861/6829/6053 +f 4140/6828/6052 7418/7667/6865 7417/7664/6862 +f 5282/7670/6868 7416/7665/6863 5281/7669/6867 +f 5304/7659/6857 4142/6825/6049 3862/6805/6029 +f 5305/7660/6858 7419/7666/6864 5304/7659/6857 +f 7419/7666/6864 4141/6826/6050 4142/6825/6049 +f 7422/7671/6869 7421/7672/6870 7427/7673/6871 +f 7424/7674/6872 7421/7672/6870 7423/7675/6873 +f 7426/7676/6874 7421/7672/6870 7425/7677/6875 +f 5307/4144/3470 5283/7597/6798 3860/4145/3471 +f 5308/4141/3468 7422/7671/6869 5307/4144/3470 +f 7422/7671/6869 5284/7604/6803 5283/7597/6798 +f 5312/7678/6876 5309/4138/3467 3845/4140/3438 +f 5311/7679/6877 7424/7674/6872 5312/7678/6876 +f 7424/7674/6872 5308/4141/3468 5309/4138/3467 +f 5285/7601/6800 5310/7680/6878 3985/7602/6801 +f 5285/7601/6800 7427/7673/6871 7426/7676/6874 +f 7426/7676/6874 5311/7679/6877 5310/7680/6878 +f 7429/7681/6879 7428/7682/6880 7434/7683/6881 +f 7431/7684/6882 7428/7682/6880 7430/7685/6883 +f 7433/7686/6884 7428/7682/6880 7432/7687/6885 +f 4091/7688/6886 5312/7678/6876 3845/4140/3438 +f 4090/7689/6887 7429/7681/6879 4091/7688/6886 +f 7429/7681/6879 5311/7679/6877 5312/7678/6876 +f 5315/7690/6888 4089/7691/6889 3844/7692/6890 +f 5314/7693/6891 7431/7684/6882 5315/7690/6888 +f 7431/7684/6882 4090/7689/6887 4089/7691/6889 +f 5310/7680/6878 5313/7694/6892 3985/7602/6801 +f 5311/7679/6877 7433/7686/6884 5310/7680/6878 +f 7433/7686/6884 5314/7693/6891 5313/7694/6892 +f 7436/7695/6893 7435/7696/6894 7441/7697/6895 +f 7438/7698/6896 7435/7696/6894 7437/7699/6897 +f 7440/7700/6898 7435/7696/6894 7439/7701/6899 +f 5313/7694/6892 5286/7644/6842 3985/7602/6801 +f 5314/7693/6891 7436/7695/6893 5313/7694/6892 +f 5286/7644/6842 7441/7697/6895 5287/7645/6843 +f 5318/7702/6900 5315/7690/6888 3844/7692/6890 +f 5318/7702/6900 7439/7701/6899 7438/7698/6896 +f 7438/7698/6896 5314/7693/6891 5315/7690/6888 +f 5288/7647/6845 5316/7703/6901 3986/7648/6846 +f 5287/7645/6843 7440/7700/6898 5288/7647/6845 +f 7440/7700/6898 5317/7704/6902 5316/7703/6901 +f 7443/7705/6903 7442/7706/6904 7448/7707/6905 +f 7445/7708/6906 7442/7706/6904 7444/7709/6907 +f 7447/7710/6908 7442/7706/6904 7446/7711/6909 +f 4088/7712/6910 5318/7702/6900 3844/7692/6890 +f 4087/7713/6911 7443/7705/6903 4088/7712/6910 +f 7443/7705/6903 5317/7704/6902 5318/7702/6900 +f 5321/7714/6912 4086/7715/6913 3843/7716/6914 +f 5320/7717/6915 7445/7708/6906 5321/7714/6912 +f 7445/7708/6906 4087/7713/6911 4086/7715/6913 +f 5316/7703/6901 5319/7718/6916 3986/7648/6846 +f 5316/7703/6901 7448/7707/6905 7447/7710/6908 +f 7447/7710/6908 5320/7717/6915 5319/7718/6916 +f 7450/7719/6917 7449/7720/6918 7455/7721/6919 +f 7452/7722/6920 7449/7720/6918 7451/7723/6921 +f 7454/7724/6922 7449/7720/6918 7453/7725/6923 +f 5319/7718/6916 5280/7668/6866 3986/7648/6846 +f 5320/7717/6915 7450/7719/6917 5319/7718/6916 +f 5280/7668/6866 7455/7721/6919 5281/7669/6867 +f 5324/7726/6924 5321/7714/6912 3843/7716/6914 +f 5323/7727/6925 7452/7722/6920 5324/7726/6924 +f 7452/7722/6920 5320/7717/6915 5321/7714/6912 +f 5282/7670/6868 5322/7728/6926 3861/6829/6053 +f 5281/7669/6867 7454/7724/6922 5282/7670/6868 +f 7454/7724/6922 5323/7727/6925 5322/7728/6926 +f 7457/7729/6927 7456/7730/6928 7462/7731/6929 +f 7459/7732/6930 7456/7730/6928 7458/7733/6931 +f 7461/7734/6932 7456/7730/6928 7460/7735/6933 +f 4085/7736/6934 5324/7726/6924 3843/7716/6914 +f 4084/7737/6935 7457/7729/6927 4085/7736/6934 +f 7457/7729/6927 5323/7727/6925 5324/7726/6924 +f 4137/6852/6075 4083/7738/6936 3833/6853/3523 +f 4137/6852/6075 7460/7735/6933 7459/7732/6930 +f 4083/7738/6936 7458/7733/6931 4084/7737/6935 +f 5322/7728/6926 4139/6849/6073 3861/6829/6053 +f 5323/7727/6925 7461/7734/6932 5322/7728/6926 +f 7461/7734/6932 4138/6850/6074 4139/6849/6073 +f 7464/7739/6937 7463/7740/6938 7469/7741/6939 +f 7466/7742/6940 7463/7740/6938 7465/7743/6941 +f 7468/7744/6942 7463/7740/6938 7467/7745/6943 +f 5325/7746/6944 4112/7193/6413 3852/7173/6393 +f 5326/7747/6945 7464/7739/6937 5325/7746/6944 +f 7464/7739/6937 4111/7194/6414 4112/7193/6413 +f 4005/7748/6424 5327/7749/6946 3857/7750/6425 +f 4006/7751/6427 7466/7742/6940 4005/7748/6424 +f 5327/7749/6946 7465/7743/6941 5326/7747/6945 +f 4110/7195/6415 4007/7752/6429 3836/4264/3580 +f 4110/7195/6415 7469/7741/6939 7468/7744/6942 +f 4007/7752/6429 7467/7745/6943 4006/7751/6427 +f 7471/7753/6947 7470/7754/6948 7476/7755/6949 +f 7473/7756/6950 7470/7754/6948 7472/7757/6951 +f 7475/7758/6952 7470/7754/6948 7474/7759/6953 +f 5331/7760/6954 4115/7169/6389 3853/7148/6368 +f 5332/7761/6955 7471/7753/6947 5331/7760/6954 +f 7471/7753/6947 4114/7170/6390 4115/7169/6389 +f 5345/7762/6956 5333/7763/6957 3987/7764/6958 +f 5344/7765/6959 7473/7756/6950 5345/7762/6956 +f 7473/7756/6950 5332/7761/6955 5333/7763/6957 +f 4113/7172/6392 5343/7766/6960 3852/7173/6393 +f 4114/7170/6390 7475/7758/6952 4113/7172/6392 +f 7475/7758/6952 5344/7765/6959 5343/7766/6960 +f 7478/7767/6961 7477/7768/6962 7483/7769/6963 +f 7480/7770/6964 7477/7768/6962 7479/7771/6965 +f 7482/7772/6966 7477/7768/6962 7481/7773/6967 +f 5337/7774/6968 4118/7145/6365 3854/4125/3456 +f 5338/7775/6969 7478/7767/6961 5337/7774/6968 +f 7478/7767/6961 4117/7150/6370 4118/7145/6365 +f 5351/7776/6970 5339/7777/6971 3988/7778/6972 +f 5350/7779/6973 7480/7770/6964 5351/7776/6970 +f 7480/7770/6964 5338/7775/6969 5339/7777/6971 +f 4116/7147/6367 5349/7780/6974 3853/7148/6368 +f 4117/7150/6370 7482/7772/6966 4116/7147/6367 +f 7482/7772/6966 5350/7779/6973 5349/7780/6974 +f 7485/7781/6975 7484/7782/6976 7490/7783/6977 +f 7487/7784/6978 7484/7782/6976 7486/7785/6979 +f 7489/7786/6980 7484/7782/6976 7488/7787/6981 +f 5343/7766/6960 5325/7746/6944 3852/7173/6393 +f 5344/7765/6959 7485/7781/6975 5343/7766/6960 +f 7485/7781/6975 5326/7747/6945 5325/7746/6944 +f 5348/7788/6982 5345/7762/6956 3987/7764/6958 +f 5348/7788/6982 7488/7787/6981 7487/7784/6978 +f 7487/7784/6978 5344/7765/6959 5345/7762/6956 +f 5327/7749/6946 5346/7789/6983 3857/7750/6425 +f 5326/7747/6945 7489/7786/6980 5327/7749/6946 +f 7489/7786/6980 5347/7790/6984 5346/7789/6983 +f 7492/7791/6985 7491/7792/6986 7497/7793/6987 +f 7494/7794/6988 7491/7792/6986 7493/7795/6989 +f 7496/7796/6990 7491/7792/6986 7495/7797/6991 +f 5328/7798/6992 5348/7788/6982 3987/7764/6958 +f 5329/7799/6993 7492/7791/6985 5328/7798/6992 +f 7492/7791/6985 5347/7790/6984 5348/7788/6982 +f 4125/7800/6438 5330/7801/6994 3856/7802/6439 +f 4126/7803/6441 7494/7794/6988 4125/7800/6438 +f 7494/7794/6988 5329/7799/6993 5330/7801/6994 +f 5346/7789/6983 4127/7804/6446 3857/7750/6425 +f 5346/7789/6983 7497/7793/6987 7496/7796/6990 +f 4127/7804/6446 7495/7797/6991 4126/7803/6441 +f 7499/7805/6995 7498/7806/6996 7504/7807/6997 +f 7501/7808/6998 7498/7806/6996 7500/7809/6999 +f 7503/7810/7000 7498/7806/6996 7502/7811/7001 +f 5349/7780/6974 5331/7760/6954 3853/7148/6368 +f 5350/7779/6973 7499/7805/6995 5349/7780/6974 +f 7499/7805/6995 5332/7761/6955 5331/7760/6954 +f 5354/7812/7002 5351/7776/6970 3988/7778/6972 +f 5353/7813/7003 7501/7808/6998 5354/7812/7002 +f 7501/7808/6998 5350/7779/6973 5351/7776/6970 +f 5333/7763/6957 5352/7814/7004 3987/7764/6958 +f 5332/7761/6955 7503/7810/7000 5333/7763/6957 +f 7503/7810/7000 5353/7813/7003 5352/7814/7004 +f 7506/7815/7005 7505/7816/7006 7511/7817/7007 +f 7508/7818/7008 7505/7816/7006 7507/7819/7009 +f 7510/7820/7010 7505/7816/7006 7509/7821/7011 +f 5340/7822/7012 5354/7812/7002 3988/7778/6972 +f 5340/7822/7012 7507/7819/7009 7506/7815/7005 +f 7506/7815/7005 5353/7813/7003 5354/7812/7002 +f 5357/7823/7013 5342/7824/7014 3989/7825/7015 +f 5356/7826/7016 7508/7818/7008 5357/7823/7013 +f 7508/7818/7008 5341/7827/7017 5342/7824/7014 +f 5352/7814/7004 5355/7828/7018 3987/7764/6958 +f 5353/7813/7003 7510/7820/7010 5352/7814/7004 +f 5355/7828/7018 7509/7821/7011 5356/7826/7016 +f 7513/7829/7019 7512/7830/7020 7518/7831/7021 +f 7515/7832/7022 7512/7830/7020 7514/7833/7023 +f 7517/7834/7024 7512/7830/7020 7516/7835/7025 +f 5355/7828/7018 5328/7798/6992 3987/7764/6958 +f 5356/7826/7016 7513/7829/7019 5355/7828/7018 +f 7513/7829/7019 5329/7799/6993 5328/7798/6992 +f 5360/7836/7026 5357/7823/7013 3989/7825/7015 +f 5360/7836/7026 7516/7835/7025 7515/7832/7022 +f 5357/7823/7013 7514/7833/7023 5356/7826/7016 +f 5330/7801/6994 5358/7837/7027 3856/7802/6439 +f 5329/7799/6993 7517/7834/7024 5330/7801/6994 +f 7517/7834/7024 5359/7838/7028 5358/7837/7027 +f 7520/7839/7029 7519/7840/7030 7525/7841/7031 +f 7522/7842/7032 7519/7840/7030 7521/7843/7033 +f 7524/7844/7034 7519/7840/7030 7523/7845/7035 +f 5334/7846/7036 5360/7836/7026 3989/7825/7015 +f 5335/7847/7037 7520/7839/7029 5334/7846/7036 +f 7520/7839/7029 5359/7838/7028 5360/7836/7026 +f 4122/7848/6456 5336/7849/7038 3855/7850/3499 +f 4123/7851/6457 7522/7842/7032 4122/7848/6456 +f 7522/7842/7032 5335/7847/7037 5336/7849/7038 +f 5358/7837/7027 4124/7852/6463 3856/7802/6439 +f 5358/7837/7027 7525/7841/7031 7524/7844/7034 +f 7524/7844/7034 4123/7851/6457 4124/7852/6463 +f 7527/7853/7039 7526/7854/7040 7532/7855/7041 +f 7529/7856/7042 7526/7854/7040 7528/7857/7043 +f 7531/7858/7044 7526/7854/7040 7530/7859/7045 +f 5361/4124/3455 5337/7774/6968 3854/4125/3456 +f 5361/4124/3455 7528/7857/7043 7527/7853/7039 +f 7527/7853/7039 5338/7775/6969 5337/7774/6968 +f 5366/7860/7046 5363/4119/3450 3848/4121/3452 +f 5365/7861/7047 7529/7856/7042 5366/7860/7046 +f 7529/7856/7042 5362/4126/3457 5363/4119/3450 +f 5339/7777/6971 5364/7862/7048 3988/7778/6972 +f 5338/7775/6969 7531/7858/7044 5339/7777/6971 +f 5364/7862/7048 7530/7859/7045 5365/7861/7047 +f 7534/7863/7049 7533/7864/7050 7539/7865/7051 +f 7536/7866/7052 7533/7864/7050 7535/7867/7053 +f 7538/7868/7054 7533/7864/7050 7537/7869/7055 +f 4100/7870/7056 5366/7860/7046 3848/4121/3452 +f 4099/7871/7057 7534/7863/7049 4100/7870/7056 +f 5366/7860/7046 7539/7865/7051 5365/7861/7047 +f 5369/7872/7058 4098/7873/7059 3847/7874/7060 +f 5368/7875/7061 7536/7866/7052 5369/7872/7058 +f 7536/7866/7052 4099/7871/7057 4098/7873/7059 +f 5364/7862/7048 5367/7876/7062 3988/7778/6972 +f 5365/7861/7047 7538/7868/7054 5364/7862/7048 +f 7538/7868/7054 5368/7875/7061 5367/7876/7062 +f 7541/7877/7063 7540/7878/7064 7546/7879/7065 +f 7543/7880/7066 7540/7878/7064 7542/7881/7067 +f 7545/7882/7068 7540/7878/7064 7544/7883/7069 +f 5367/7876/7062 5340/7822/7012 3988/7778/6972 +f 5368/7875/7061 7541/7877/7063 5367/7876/7062 +f 7541/7877/7063 5341/7827/7017 5340/7822/7012 +f 5372/7884/7070 5369/7872/7058 3847/7874/7060 +f 5371/7885/7071 7543/7880/7066 5372/7884/7070 +f 7543/7880/7066 5368/7875/7061 5369/7872/7058 +f 5342/7824/7014 5370/7886/7072 3989/7825/7015 +f 5342/7824/7014 7546/7879/7065 7545/7882/7068 +f 7545/7882/7068 5371/7885/7071 5370/7886/7072 +f 7548/7887/7073 7547/7888/7074 7553/7889/7075 +f 7550/7890/7076 7547/7888/7074 7549/7891/7077 +f 7552/7892/7078 7547/7888/7074 7551/7893/7079 +f 4097/7894/7080 5372/7884/7070 3847/7874/7060 +f 4096/7895/7081 7548/7887/7073 4097/7894/7080 +f 7548/7887/7073 5371/7885/7071 5372/7884/7070 +f 5375/7896/7082 4095/7897/7083 3846/7898/3433 +f 5374/7899/7084 7550/7890/7076 5375/7896/7082 +f 7550/7890/7076 4096/7895/7081 4095/7897/7083 +f 5370/7886/7072 5373/7900/7085 3989/7825/7015 +f 5371/7885/7071 7552/7892/7078 5370/7886/7072 +f 7552/7892/7078 5374/7899/7084 5373/7900/7085 +f 7555/7901/7086 7554/7902/7087 7560/7903/7088 +f 7557/7904/7089 7554/7902/7087 7556/7905/7090 +f 7559/7906/7091 7554/7902/7087 7558/7907/7092 +f 5373/7900/7085 5334/7846/7036 3989/7825/7015 +f 5374/7899/7084 7555/7901/7086 5373/7900/7085 +f 7555/7901/7086 5335/7847/7037 5334/7846/7036 +f 5378/7908/7093 5375/7896/7082 3846/7898/3433 +f 5377/7909/7094 7557/7904/7089 5378/7908/7093 +f 7557/7904/7089 5374/7899/7084 5375/7896/7082 +f 5336/7849/7038 5376/7910/7095 3855/7850/3499 +f 5335/7847/7037 7559/7906/7091 5336/7849/7038 +f 7559/7906/7091 5377/7909/7094 5376/7910/7095 +f 7562/7911/7096 7561/7912/7097 7567/7913/7098 +f 7564/7914/7099 7561/7912/7097 7563/7915/7100 +f 7566/7916/7101 7561/7912/7097 7565/7917/7102 +f 4094/7918/3432 5378/7908/7093 3846/7898/3433 +f 4093/7919/3435 7562/7911/7096 4094/7918/3432 +f 7562/7911/7096 5377/7909/7094 5378/7908/7093 +f 4119/7920/3493 4092/7921/3427 3831/7922/3429 +f 4119/7920/3493 7565/7917/7102 7564/7914/7099 +f 4092/7921/3427 7563/7915/7100 4093/7919/3435 +f 5376/7910/7095 4121/7923/3497 3855/7850/3499 +f 5377/7909/7094 7566/7916/7101 5376/7910/7095 +f 7566/7916/7101 4120/7924/3494 4121/7923/3497 +f 7569/7925/7103 7568/7926/7104 7574/7927/7105 +f 7571/7928/7106 7568/7926/7104 7570/7929/7107 +f 7573/7930/7108 7568/7926/7104 7572/7931/7109 +f 5379/7932/7110 4085/7933/6934 3843/7934/6914 +f 5380/7935/7111 7569/7925/7103 5379/7932/7110 +f 7569/7925/7103 4084/7936/6935 4085/7933/6934 +f 3999/4211/3527 5381/7937/7112 3851/4212/3528 +f 4000/4208/3524 7571/7928/7106 3999/4211/3527 +f 7571/7928/7106 5380/7935/7111 5381/7937/7112 +f 4083/7938/6936 4001/4205/3521 3833/4207/3523 +f 4083/7938/6936 7574/7927/7105 7573/7930/7108 +f 4001/4205/3521 7572/7931/7109 4000/4208/3524 +f 7576/7939/7113 7575/7940/7114 7581/7941/7115 +f 7578/7942/7116 7575/7940/7114 7577/7943/7117 +f 7580/7944/7118 7575/7940/7114 7579/7945/7119 +f 5385/7946/7120 4088/7947/6910 3844/7948/6890 +f 5386/7949/7121 7576/7939/7113 5385/7946/7120 +f 7576/7939/7113 4087/7950/6911 4088/7947/6910 +f 5399/7951/7122 5387/7952/7123 3990/7953/7124 +f 5398/7954/7125 7578/7942/7116 5399/7951/7122 +f 5387/7952/7123 7577/7943/7117 5386/7949/7121 +f 4086/7955/6913 5397/7956/7126 3843/7934/6914 +f 4087/7950/6911 7580/7944/7118 4086/7955/6913 +f 7580/7944/7118 5398/7954/7125 5397/7956/7126 +f 7583/7957/7127 7582/7958/7128 7588/7959/7129 +f 7585/7960/7130 7582/7958/7128 7584/7961/7131 +f 7587/7962/7132 7582/7958/7128 7586/7963/7133 +f 5391/7964/7134 4091/7965/6886 3845/4107/3438 +f 5392/7966/7135 7583/7957/7127 5391/7964/7134 +f 7583/7957/7127 4090/7967/6887 4091/7965/6886 +f 5405/7968/7136 5393/7969/7137 3991/7970/7138 +f 5404/7971/7139 7585/7960/7130 5405/7968/7136 +f 7585/7960/7130 5392/7966/7135 5393/7969/7137 +f 4089/7972/6889 5403/7973/7140 3844/7948/6890 +f 4090/7967/6887 7587/7962/7132 4089/7972/6889 +f 7587/7962/7132 5404/7971/7139 5403/7973/7140 +f 7590/7974/7141 7589/7975/7142 7595/7976/7143 +f 7592/7977/7144 7589/7975/7142 7591/7978/7145 +f 7594/7979/7146 7589/7975/7142 7593/7980/7147 +f 5397/7956/7126 5379/7932/7110 3843/7934/6914 +f 5398/7954/7125 7590/7974/7141 5397/7956/7126 +f 7590/7974/7141 5380/7935/7111 5379/7932/7110 +f 5402/7981/7148 5399/7951/7122 3990/7953/7124 +f 5401/7982/7149 7592/7977/7144 5402/7981/7148 +f 7592/7977/7144 5398/7954/7125 5399/7951/7122 +f 5381/7937/7112 5400/7983/7150 3851/4212/3528 +f 5380/7935/7111 7594/7979/7146 5381/7937/7112 +f 7594/7979/7146 5401/7982/7149 5400/7983/7150 +f 7597/7984/7151 7596/7985/7152 7602/7986/7153 +f 7599/7987/7154 7596/7985/7152 7598/7988/7155 +f 7601/7989/7156 7596/7985/7152 7600/7990/7157 +f 5382/7991/7158 5402/7981/7148 3990/7953/7124 +f 5383/7992/7159 7597/7984/7151 5382/7991/7158 +f 7597/7984/7151 5401/7982/7149 5402/7981/7148 +f 4107/6978/6198 5384/7993/7160 3850/6979/6199 +f 4108/6976/6196 7599/7987/7154 4107/6978/6198 +f 7599/7987/7154 5383/7992/7159 5384/7993/7160 +f 5400/7983/7150 4109/6975/6195 3851/4212/3528 +f 5401/7982/7149 7601/7989/7156 5400/7983/7150 +f 4109/6975/6195 7600/7990/7157 4108/6976/6196 +f 7604/7994/7161 7603/7995/7162 7609/7996/7163 +f 7606/7997/7164 7603/7995/7162 7605/7998/7165 +f 7608/7999/7166 7603/7995/7162 7607/8000/7167 +f 5403/7973/7140 5385/7946/7120 3844/7948/6890 +f 5404/7971/7139 7604/7994/7161 5403/7973/7140 +f 5385/7946/7120 7609/7996/7163 5386/7949/7121 +f 5408/8001/7168 5405/7968/7136 3991/7970/7138 +f 5407/8002/7169 7606/7997/7164 5408/8001/7168 +f 7606/7997/7164 5404/7971/7139 5405/7968/7136 +f 5387/7952/7123 5406/8003/7170 3990/7953/7124 +f 5386/7949/7121 7608/7999/7166 5387/7952/7123 +f 7608/7999/7166 5407/8002/7169 5406/8003/7170 +f 7611/8004/7171 7610/8005/7172 7616/8006/7173 +f 7613/8007/7174 7610/8005/7172 7612/8008/7175 +f 7615/8009/7176 7610/8005/7172 7614/8010/7177 +f 5394/8011/7178 5408/8001/7168 3991/7970/7138 +f 5395/8012/7179 7611/8004/7171 5394/8011/7178 +f 7611/8004/7171 5407/8002/7169 5408/8001/7168 +f 5411/8013/7180 5396/8014/7181 3992/8015/7182 +f 5410/8016/7183 7613/8007/7174 5411/8013/7180 +f 7613/8007/7174 5395/8012/7179 5396/8014/7181 +f 5406/8003/7170 5409/8017/7184 3990/7953/7124 +f 5407/8002/7169 7615/8009/7176 5406/8003/7170 +f 7615/8009/7176 5410/8016/7183 5409/8017/7184 +f 7618/8018/7185 7617/8019/7186 7623/8020/7187 +f 7620/8021/7188 7617/8019/7186 7619/8022/7189 +f 7622/8023/7190 7617/8019/7186 7621/8024/7191 +f 5409/8017/7184 5382/7991/7158 3990/7953/7124 +f 5410/8016/7183 7618/8018/7185 5409/8017/7184 +f 7618/8018/7185 5383/7992/7159 5382/7991/7158 +f 5414/8025/7192 5411/8013/7180 3992/8015/7182 +f 5413/8026/7193 7620/8021/7188 5414/8025/7192 +f 7620/8021/7188 5410/8016/7183 5411/8013/7180 +f 5384/7993/7160 5412/8027/7194 3850/6979/6199 +f 5384/7993/7160 7623/8020/7187 7622/8023/7190 +f 7622/8023/7190 5413/8026/7193 5412/8027/7194 +f 7625/8028/7195 7624/8029/7196 7630/8030/7197 +f 7627/8031/7198 7624/8029/7196 7626/8032/7199 +f 7629/8033/7200 7624/8029/7196 7628/8034/7201 +f 5388/8035/7202 5414/8025/7192 3992/8015/7182 +f 5389/8036/7203 7625/8028/7195 5388/8035/7202 +f 7625/8028/7195 5413/8026/7193 5414/8025/7192 +f 4104/7002/6222 5390/8037/7204 3849/7003/6223 +f 4105/7000/6220 7627/8031/7198 4104/7002/6222 +f 7627/8031/7198 5389/8036/7203 5390/8037/7204 +f 5412/8027/7194 4106/6999/6219 3850/6979/6199 +f 5413/8026/7193 7629/8033/7200 5412/8027/7194 +f 7629/8033/7200 4105/7000/6220 4106/6999/6219 +f 7632/8038/7205 7631/8039/7206 7637/8040/7207 +f 7634/8041/7208 7631/8039/7206 7633/8042/7209 +f 7636/8043/7210 7631/8039/7206 7635/8044/7211 +f 5415/4106/3437 5391/7964/7134 3845/4107/3438 +f 5416/4103/3434 7632/8038/7205 5415/4106/3437 +f 7632/8038/7205 5392/7966/7135 5391/7964/7134 +f 5420/8045/7212 5417/4100/3431 3846/4102/3433 +f 5419/8046/7213 7634/8041/7208 5420/8045/7212 +f 7634/8041/7208 5416/4103/3434 5417/4100/3431 +f 5393/7969/7137 5418/8047/7214 3991/7970/7138 +f 5392/7966/7135 7636/8043/7210 5393/7969/7137 +f 7636/8043/7210 5419/8046/7213 5418/8047/7214 +f 7639/8048/7215 7638/8049/7216 7644/8050/7217 +f 7641/8051/7218 7638/8049/7216 7640/8052/7219 +f 7643/8053/7220 7638/8049/7216 7642/8054/7221 +f 4095/8055/7083 5420/8045/7212 3846/4102/3433 +f 4096/8056/7081 7639/8048/7215 4095/8055/7083 +f 7639/8048/7215 5419/8046/7213 5420/8045/7212 +f 5423/8057/7222 4097/8058/7080 3847/8059/7060 +f 5422/8060/7223 7641/8051/7218 5423/8057/7222 +f 7641/8051/7218 4096/8056/7081 4097/8058/7080 +f 5418/8047/7214 5421/8061/7224 3991/7970/7138 +f 5419/8046/7213 7643/8053/7220 5418/8047/7214 +f 7643/8053/7220 5422/8060/7223 5421/8061/7224 +f 7646/8062/7225 7645/8063/7226 7651/8064/7227 +f 7648/8065/7228 7645/8063/7226 7647/8066/7229 +f 7650/8067/7230 7645/8063/7226 7649/8068/7231 +f 5421/8061/7224 5394/8011/7178 3991/7970/7138 +f 5422/8060/7223 7646/8062/7225 5421/8061/7224 +f 7646/8062/7225 5395/8012/7179 5394/8011/7178 +f 5426/8069/7232 5423/8057/7222 3847/8059/7060 +f 5425/8070/7233 7648/8065/7228 5426/8069/7232 +f 7648/8065/7228 5422/8060/7223 5423/8057/7222 +f 5396/8014/7181 5424/8071/7234 3992/8015/7182 +f 5395/8012/7179 7650/8067/7230 5396/8014/7181 +f 7650/8067/7230 5425/8070/7233 5424/8071/7234 +f 7653/8072/7235 7652/8073/7236 7658/8074/7237 +f 7655/8075/7238 7652/8073/7236 7654/8076/7239 +f 7657/8077/7240 7652/8073/7236 7656/8078/7241 +f 4098/8079/7059 5426/8069/7232 3847/8059/7060 +f 4099/8080/7057 7653/8072/7235 4098/8079/7059 +f 7653/8072/7235 5425/8070/7233 5426/8069/7232 +f 5429/8081/7242 4100/8082/7056 3848/8083/3452 +f 5429/8081/7242 7656/8078/7241 7655/8075/7238 +f 7655/8075/7238 4099/8080/7057 4100/8082/7056 +f 5424/8071/7234 5427/8084/7243 3992/8015/7182 +f 5425/8070/7233 7657/8077/7240 5424/8071/7234 +f 7657/8077/7240 5428/8085/7244 5427/8084/7243 +f 7660/8086/7245 7659/8087/7246 7665/8088/7247 +f 7662/8089/7248 7659/8087/7246 7661/8090/7249 +f 7664/8091/7250 7659/8087/7246 7663/8092/7251 +f 5427/8084/7243 5388/8035/7202 3992/8015/7182 +f 5428/8085/7244 7660/8086/7245 5427/8084/7243 +f 7660/8086/7245 5389/8036/7203 5388/8035/7202 +f 5432/8093/7252 5429/8081/7242 3848/8083/3452 +f 5431/8094/7253 7662/8089/7248 5432/8093/7252 +f 7662/8089/7248 5428/8085/7244 5429/8081/7242 +f 5390/8037/7204 5430/8095/7254 3849/7003/6223 +f 5389/8036/7203 7664/8091/7250 5390/8037/7204 +f 7664/8091/7250 5431/8094/7253 5430/8095/7254 +f 7667/8096/7255 7666/8097/7256 7672/8098/7257 +f 7669/8099/7258 7666/8097/7256 7668/8100/7259 +f 7671/8101/7260 7666/8097/7256 7670/8102/7261 +f 3996/8103/3451 5432/8093/7252 3848/8083/3452 +f 3997/8104/3453 7667/8096/7255 3996/8103/3451 +f 7667/8096/7255 5431/8094/7253 5432/8093/7252 +f 4101/7025/6245 3998/8105/3446 3832/4117/3448 +f 4101/7025/6245 7670/8102/7261 7669/8099/7258 +f 3998/8105/3446 7668/8100/7259 3997/8104/3453 +f 5430/8095/7254 4103/7023/6243 3849/7003/6223 +f 5431/8094/7253 7671/8101/7260 5430/8095/7254 +f 7671/8101/7260 4102/7024/6244 4103/7023/6243 +f 5434/4089/3420 5435/4093/3424 5433/4090/3421 +f 5436/4092/3423 5437/4095/3426 5433/4090/3421 +f 5438/4094/3425 5439/4091/3422 5433/4090/3421 +f 4092/4096/3427 5434/4089/3420 3995/4097/3428 +f 4092/4096/3427 4093/4104/3435 5435/4093/3424 +f 5434/4089/3420 5439/4091/3422 3994/4099/3430 +f 5417/4100/3431 5436/4092/3423 4094/4101/3432 +f 5416/4103/3434 5437/4095/3426 5436/4092/3423 +f 5436/4092/3423 5435/4093/3424 4093/4104/3435 +f 3993/4105/3436 5438/4094/3425 5415/4106/3437 +f 3994/4099/3430 5439/4091/3422 5438/4094/3425 +f 5438/4094/3425 5437/4095/3426 5416/4103/3434 +f 5441/4108/3439 5442/4112/3443 5440/4109/3440 +f 5443/4111/3442 5444/4114/3445 5440/4109/3440 +f 5445/4113/3444 5446/4110/3441 5440/4109/3440 +f 3998/4115/3446 5441/4108/3439 4004/4116/3447 +f 3998/4115/3446 3997/4122/3453 5442/4112/3443 +f 4004/4116/3447 5441/4108/3439 5446/4110/3441 +f 5363/4119/3450 5443/4111/3442 3996/4120/3451 +f 5363/4119/3450 5362/4126/3457 5444/4114/3445 +f 5443/4111/3442 5442/4112/3443 3997/4122/3453 +f 4002/4123/3454 5445/4113/3444 5361/4124/3455 +f 4003/4118/3449 5446/4110/3441 5445/4113/3444 +f 5445/4113/3444 5444/4114/3445 5362/4126/3457 +f 5448/4127/3458 5449/4131/3462 5447/4128/3459 +f 5451/4130/3461 5447/4128/3459 5449/4131/3462 +f 5452/4133/3464 5453/4129/3460 5447/4128/3459 +f 3995/4134/3428 5448/4127/3458 4010/4135/3465 +f 3995/4134/3428 3994/4142/3430 5449/4131/3462 +f 4010/4135/3465 5448/4127/3458 5453/4129/3460 +f 5309/4138/3467 5450/4132/3463 3993/4139/3436 +f 5308/4141/3468 5451/4130/3461 5450/4132/3463 +f 5450/4132/3463 5449/4131/3462 3994/4142/3430 +f 4008/4143/3469 5452/4133/3464 5307/4144/3470 +f 4009/4137/3466 5453/4129/3460 5452/4133/3464 +f 5307/4144/3470 5452/4133/3464 5451/4130/3461 +f 5455/4146/3472 5456/4150/3476 5454/4147/3473 +f 5457/4149/3475 5458/4151/3477 5454/4147/3473 +f 5460/4148/3474 5454/4147/3473 5458/4151/3477 +f 4010/4153/3465 5455/4146/3472 4016/4154/3479 +f 4010/4153/3465 4009/4161/3466 5456/4150/3476 +f 4016/4154/3479 5455/4146/3472 5460/4148/3474 +f 5255/4157/3481 5457/4149/3475 4008/4158/3469 +f 5254/4160/3482 5458/4151/3477 5457/4149/3475 +f 5457/4149/3475 5456/4150/3476 4009/4161/3466 +f 4014/4162/3483 5459/4152/3478 5253/4163/3484 +f 4015/4156/3480 5460/4148/3474 5459/4152/3478 +f 5459/4152/3478 5458/4151/3477 5254/4160/3482 +f 5462/4165/3486 5463/4169/3490 5461/4166/3487 +f 5464/4168/3489 5465/4171/3492 5461/4166/3487 +f 5466/4170/3491 5467/4167/3488 5461/4166/3487 +f 4016/4172/3479 5462/4165/3486 4119/4173/3493 +f 4015/4175/3480 5463/4169/3490 5462/4165/3486 +f 5462/4165/3486 5467/4167/3488 4120/4176/3494 +f 5201/4177/3495 5464/4168/3489 4014/4178/3483 +f 5200/4180/3496 5465/4171/3492 5464/4168/3489 +f 5464/4168/3489 5463/4169/3490 4015/4175/3480 +f 4121/4181/3497 5466/4170/3491 5199/4182/3498 +f 4120/4176/3494 5467/4167/3488 5466/4170/3491 +f 5466/4170/3491 5465/4171/3492 5200/4180/3496 +f 5469/4184/3500 5470/4188/3504 5468/4185/3501 +f 5471/4187/3503 5472/4190/3506 5468/4185/3501 +f 5473/4189/3505 5474/4186/3502 5468/4185/3501 +f 4004/4116/3447 5469/4184/3500 4025/4191/3507 +f 4004/4116/3447 4003/4118/3449 5470/4188/3504 +f 4025/4191/3507 5469/4184/3500 5474/4186/3502 +f 5147/4193/3509 5471/4187/3503 4002/4123/3454 +f 5146/4194/3510 5472/4190/3506 5471/4187/3503 +f 5471/4187/3503 5470/4188/3504 4003/4118/3449 +f 4023/4195/3511 5473/4189/3505 5145/4196/3512 +f 4024/4192/3508 5474/4186/3502 5473/4189/3505 +f 5473/4189/3505 5472/4190/3506 5146/4194/3510 +f 5476/4198/3514 5477/4202/3518 5475/4199/3515 +f 5478/4201/3517 5479/4204/3520 5475/4199/3515 +f 5480/4203/3519 5481/4200/3516 5475/4199/3515 +f 4001/4205/3521 5476/4198/3514 4031/4206/3522 +f 4000/4208/3524 5477/4202/3518 5476/4198/3514 +f 4031/4206/3522 5476/4198/3514 5481/4200/3516 +f 5093/4210/3526 5478/4201/3517 3999/4211/3527 +f 5092/4213/3529 5479/4204/3520 5478/4201/3517 +f 5478/4201/3517 5477/4202/3518 4000/4208/3524 +f 4029/4214/3530 5480/4203/3519 5091/4215/3531 +f 4030/4209/3525 5481/4200/3516 5480/4203/3519 +f 5480/4203/3519 5479/4204/3520 5092/4213/3529 +f 5483/4217/3533 5484/4221/3537 5482/4218/3534 +f 5485/4220/3536 5486/4223/3539 5482/4218/3534 +f 5487/4222/3538 5488/4219/3535 5482/4218/3534 +f 4013/4224/3540 5483/4217/3533 4037/4225/3541 +f 4012/4227/3543 5484/4221/3537 5483/4217/3533 +f 5483/4217/3533 5488/4219/3535 4036/4228/3544 +f 5039/4229/3545 5485/4220/3536 4011/4230/3546 +f 5038/4232/3548 5486/4223/3539 5485/4220/3536 +f 5485/4220/3536 5484/4221/3537 4012/4227/3543 +f 4035/4233/3549 5487/4222/3538 5037/4234/3550 +f 4036/4228/3544 5488/4219/3535 5487/4222/3538 +f 5487/4222/3538 5486/4223/3539 5038/4232/3548 +f 5490/4236/3552 5491/4240/3556 5489/4237/3553 +f 5492/4239/3555 5493/4242/3558 5489/4237/3553 +f 5494/4241/3557 5495/4238/3554 5489/4237/3553 +f 4019/4243/3559 5490/4236/3552 4043/4244/3560 +f 4019/4243/3559 4018/4251/3567 5491/4240/3556 +f 4043/4244/3560 5490/4236/3552 5495/4238/3554 +f 4985/4247/3563 5492/4239/3555 4017/4248/3564 +f 4984/4250/3566 5493/4242/3558 5492/4239/3555 +f 5492/4239/3555 5491/4240/3556 4018/4251/3567 +f 4041/4252/3568 5494/4241/3557 4983/4253/3569 +f 4042/4246/3562 5495/4238/3554 5494/4241/3557 +f 5494/4241/3557 5493/4242/3558 4984/4250/3566 +f 5497/4255/3571 5498/4259/3575 5496/4256/3572 +f 5499/4258/3574 5500/4261/3577 5496/4256/3572 +f 5501/4260/3576 5502/4257/3573 5496/4256/3572 +f 4022/4262/3578 5497/4255/3571 4049/4263/3579 +f 4022/4262/3578 4021/4270/3586 5498/4259/3575 +f 4049/4263/3579 5497/4255/3571 5502/4257/3573 +f 4931/4266/3582 5499/4258/3574 4020/4267/3583 +f 4930/4269/3585 5500/4261/3577 5499/4258/3574 +f 5499/4258/3574 5498/4259/3575 4021/4270/3586 +f 4047/4271/3587 5501/4260/3576 4929/4272/3588 +f 4048/4265/3581 5502/4257/3573 5501/4260/3576 +f 4929/4272/3588 5501/4260/3576 5500/4261/3577 +f 5504/4274/3590 5505/4278/3594 5503/4275/3591 +f 5506/4277/3593 5507/4280/3596 5503/4275/3591 +f 5508/4279/3595 5509/4276/3592 5503/4275/3591 +f 4025/4191/3507 5504/4274/3590 4200/4281/3597 +f 4025/4191/3507 4024/4192/3508 5505/4278/3594 +f 4200/4281/3597 5504/4274/3590 5509/4276/3592 +f 4877/4283/3599 5506/4277/3593 4023/4195/3511 +f 4876/4284/3600 5507/4280/3596 5506/4277/3593 +f 5506/4277/3593 5505/4278/3594 4024/4192/3508 +f 4202/4285/3601 5508/4279/3595 4875/4286/3602 +f 4201/4282/3598 5509/4276/3592 5508/4279/3595 +f 5508/4279/3595 5507/4280/3596 4876/4284/3600 +f 5511/4288/3604 5512/4292/3608 5510/4289/3605 +f 5513/4291/3607 5514/4294/3610 5510/4289/3605 +f 5515/4293/3609 5516/4290/3606 5510/4289/3605 +f 4031/4206/3522 5511/4288/3604 4218/4295/3611 +f 4031/4206/3522 4030/4209/3525 5512/4292/3608 +f 4218/4295/3611 5511/4288/3604 5516/4290/3606 +f 4823/4297/3613 5513/4291/3607 4029/4214/3530 +f 4822/4298/3614 5514/4294/3610 5513/4291/3607 +f 5513/4291/3607 5512/4292/3608 4030/4209/3525 +f 4220/4299/3615 5515/4293/3609 4821/4300/3616 +f 4219/4296/3612 5516/4290/3606 5515/4293/3609 +f 5515/4293/3609 5514/4294/3610 4822/4298/3614 +f 5518/4302/3618 5519/4306/3622 5517/4303/3619 +f 5520/4305/3621 5521/4308/3624 5517/4303/3619 +f 5522/4307/3623 5523/4304/3620 5517/4303/3619 +f 4037/4225/3541 5518/4302/3618 4236/4309/3625 +f 4037/4225/3541 4036/4228/3544 5519/4306/3622 +f 4236/4309/3625 5518/4302/3618 5523/4304/3620 +f 4769/4311/3627 5520/4305/3621 4035/4233/3549 +f 4768/4312/3628 5521/4308/3624 5520/4305/3621 +f 5520/4305/3621 5519/4306/3622 4036/4228/3544 +f 4238/4313/3629 5522/4307/3623 4767/4314/3630 +f 4237/4310/3626 5523/4304/3620 5522/4307/3623 +f 5522/4307/3623 5521/4308/3624 4768/4312/3628 +f 5525/4316/3632 5526/4320/3636 5524/4317/3633 +f 5527/4319/3635 5528/4322/3638 5524/4317/3633 +f 5529/4321/3637 5530/4318/3634 5524/4317/3633 +f 4043/4244/3560 5525/4316/3632 4254/4323/3639 +f 4043/4244/3560 4042/4246/3562 5526/4320/3636 +f 4254/4323/3639 5525/4316/3632 5530/4318/3634 +f 4715/4325/3641 5527/4319/3635 4041/4252/3568 +f 4714/4326/3642 5528/4322/3638 5527/4319/3635 +f 5527/4319/3635 5526/4320/3636 4042/4246/3562 +f 4256/4327/3643 5529/4321/3637 4713/4328/3644 +f 4255/4324/3640 5530/4318/3634 5529/4321/3637 +f 5529/4321/3637 5528/4322/3638 4714/4326/3642 +f 5532/4330/3646 5533/4334/3650 5531/4331/3647 +f 5534/4333/3649 5535/4336/3652 5531/4331/3647 +f 5536/4335/3651 5537/4332/3648 5531/4331/3647 +f 4049/4263/3579 5532/4330/3646 4182/4337/3653 +f 4049/4263/3579 4048/4265/3581 5533/4334/3650 +f 4182/4337/3653 5532/4330/3646 5537/4332/3648 +f 4661/4339/3655 5534/4333/3649 4047/4271/3587 +f 4660/4340/3656 5535/4336/3652 5534/4333/3649 +f 5534/4333/3649 5533/4334/3650 4048/4265/3581 +f 4184/4341/3657 5536/4335/3651 4659/4342/3658 +f 4183/4338/3654 5537/4332/3648 5536/4335/3651 +f 5536/4335/3651 5535/4336/3652 4660/4340/3656 +f 5539/4344/3660 5540/4348/3664 5538/4345/3661 +f 5541/4347/3663 5542/4350/3666 5538/4345/3661 +f 5543/4349/3665 5544/4346/3662 5538/4345/3661 +f 4055/4351/3667 5539/4344/3660 4070/4352/3668 +f 4055/4351/3667 4054/4359/3675 5540/4348/3664 +f 4070/4352/3668 5539/4344/3660 5544/4346/3662 +f 4607/4355/3671 5541/4347/3663 4053/4356/3672 +f 4606/4358/3674 5542/4350/3666 5541/4347/3663 +f 5541/4347/3663 5540/4348/3664 4054/4359/3675 +f 4068/4360/3676 5543/4349/3665 4605/4361/3677 +f 4069/4354/3670 5544/4346/3662 5543/4349/3665 +f 5543/4349/3665 5542/4350/3666 4606/4358/3674 +f 5546/4363/3679 5547/4367/3683 5545/4364/3680 +f 5548/4366/3682 5549/4369/3685 5545/4364/3680 +f 5550/4368/3684 5551/4365/3681 5545/4364/3680 +f 4058/4370/3686 5546/4363/3679 4076/4371/3687 +f 4057/4373/3689 5547/4367/3683 5546/4363/3679 +f 5546/4363/3679 5551/4365/3681 4075/4374/3690 +f 4553/4375/3691 5548/4366/3682 4056/4376/3692 +f 4553/4375/3691 4552/4381/3697 5549/4369/3685 +f 4056/4376/3692 5548/4366/3682 5547/4367/3683 +f 4074/4378/3694 5550/4368/3684 4551/4379/3695 +f 4075/4374/3690 5551/4365/3681 5550/4368/3684 +f 5550/4368/3684 5549/4369/3685 4552/4381/3697 +f 5553/4382/3698 5554/4386/3702 5552/4383/3699 +f 5555/4385/3701 5556/4388/3704 5552/4383/3699 +f 5557/4387/3703 5558/4384/3700 5552/4383/3699 +f 4061/4389/3705 5553/4382/3698 4079/4390/3706 +f 4061/4389/3705 4060/4397/3713 5554/4386/3702 +f 4079/4390/3706 5553/4382/3698 5558/4384/3700 +f 4499/4393/3709 5555/4385/3701 4059/4394/3710 +f 4498/4396/3712 5556/4388/3704 5555/4385/3701 +f 5555/4385/3701 5554/4386/3702 4060/4397/3713 +f 4077/4398/3714 5557/4387/3703 4497/4399/3715 +f 4078/4392/3708 5558/4384/3700 5557/4387/3703 +f 5557/4387/3703 5556/4388/3704 4498/4396/3712 +f 5560/4401/3717 5561/4405/3721 5559/4402/3718 +f 5562/4404/3720 5563/4407/3723 5559/4402/3718 +f 5564/4406/3722 5565/4403/3719 5559/4402/3718 +f 4064/4408/3724 5560/4401/3717 4082/4409/3725 +f 4064/4408/3724 4063/4416/3732 5561/4405/3721 +f 4082/4409/3725 5560/4401/3717 5565/4403/3719 +f 4445/4412/3728 5562/4404/3720 4062/4413/3729 +f 4444/4415/3731 5563/4407/3723 5562/4404/3720 +f 5562/4404/3720 5561/4405/3721 4063/4416/3732 +f 4080/4417/3733 5564/4406/3722 4443/4418/3734 +f 4081/4411/3727 5565/4403/3719 5564/4406/3722 +f 5564/4406/3722 5563/4407/3723 4444/4415/3731 +f 5567/4420/3736 5568/4424/3740 5566/4421/3737 +f 5569/4423/3739 5570/4425/3741 5566/4421/3737 +f 5572/4422/3738 5566/4421/3737 5570/4425/3741 +f 4067/4427/3743 5567/4420/3736 4317/4428/3744 +f 4067/4427/3743 4066/4435/3751 5568/4424/3740 +f 4317/4428/3744 5567/4420/3736 5572/4422/3738 +f 4391/4431/3747 5569/4423/3739 4065/4432/3748 +f 4390/4434/3750 5570/4425/3741 5569/4423/3739 +f 5569/4423/3739 5568/4424/3740 4066/4435/3751 +f 4319/4436/3752 5571/4426/3742 4389/4437/3753 +f 4318/4430/3746 5572/4422/3738 5571/4426/3742 +f 5571/4426/3742 5570/4425/3741 4390/4434/3750 +f 5574/4439/3755 5575/4443/3759 5573/4440/3756 +f 5576/4442/3758 5577/4445/3761 5573/4440/3756 +f 5578/4444/3760 5579/4441/3757 5573/4440/3756 +f 4353/4446/3762 5574/4439/3755 4071/4447/3763 +f 4354/4449/3765 5575/4443/3759 5574/4439/3755 +f 5574/4439/3755 5579/4441/3757 4072/4450/3766 +f 4346/4451/3767 5576/4442/3758 4355/4452/3768 +f 4345/4454/3770 5577/4445/3761 5576/4442/3758 +f 5576/4442/3758 5575/4443/3759 4354/4449/3765 +f 4073/4455/3771 5578/4444/3760 4344/4456/3772 +f 4073/4455/3771 4072/4450/3766 5579/4441/3757 +f 4344/4456/3772 5578/4444/3760 5577/4445/3761 +f 5581/4458/3774 5582/4462/3778 5580/4459/3775 +f 5583/4461/3777 5584/4464/3780 5580/4459/3775 +f 5585/4463/3779 5586/4460/3776 5580/4459/3775 +f 4359/4465/3781 5581/4458/3774 4323/4466/3782 +f 4360/4468/3784 5582/4462/3778 5581/4458/3774 +f 5581/4458/3774 5586/4460/3776 4324/4469/3785 +f 4373/4470/3786 5583/4461/3777 4361/4471/3787 +f 4372/4473/3789 5584/4464/3780 5583/4461/3777 +f 5583/4461/3777 5582/4462/3778 4360/4468/3784 +f 4325/4474/3790 5585/4463/3779 4371/4475/3791 +f 4324/4469/3785 5586/4460/3776 5585/4463/3779 +f 4371/4475/3791 5585/4463/3779 5584/4464/3780 +f 5588/4476/3792 5589/4480/3796 5587/4477/3793 +f 5590/4479/3795 5591/4482/3798 5587/4477/3793 +f 5592/4481/3797 5593/4478/3794 5587/4477/3793 +f 4365/4483/3799 5588/4476/3792 4320/4484/3800 +f 4365/4483/3799 4366/4490/3806 5589/4480/3796 +f 5588/4476/3792 5593/4478/3794 4321/4485/3801 +f 4379/4486/3802 5590/4479/3795 4367/4487/3803 +f 4378/4489/3805 5591/4482/3798 5590/4479/3795 +f 5590/4479/3795 5589/4480/3796 4366/4490/3806 +f 4322/4491/3807 5592/4481/3797 4377/4492/3808 +f 4321/4485/3801 5593/4478/3794 5592/4481/3797 +f 5592/4481/3797 5591/4482/3798 4378/4489/3805 +f 5595/4493/3809 5596/4497/3813 5594/4494/3810 +f 5597/4496/3812 5598/4499/3815 5594/4494/3810 +f 5599/4498/3814 5600/4495/3811 5594/4494/3810 +f 4371/4475/3791 5595/4493/3809 4353/4446/3762 +f 4372/4473/3789 5596/4497/3813 5595/4493/3809 +f 5595/4493/3809 5600/4495/3811 4354/4449/3765 +f 4376/4500/3816 5597/4496/3812 4373/4470/3786 +f 4376/4500/3816 4375/4502/3818 5598/4499/3815 +f 4373/4470/3786 5597/4496/3812 5596/4497/3813 +f 4355/4452/3768 5599/4498/3814 4374/4501/3817 +f 4354/4449/3765 5600/4495/3811 5599/4498/3814 +f 5599/4498/3814 5598/4499/3815 4375/4502/3818 +f 5602/4503/3819 5603/4507/3823 5601/4504/3820 +f 5604/4506/3822 5605/4509/3825 5601/4504/3820 +f 5606/4508/3824 5607/4505/3821 5601/4504/3820 +f 4356/4510/3826 5602/4503/3819 4376/4500/3816 +f 4357/4511/3827 5603/4507/3823 5602/4503/3819 +f 5602/4503/3819 5607/4505/3821 4375/4502/3818 +f 4349/4512/3828 5604/4506/3822 4358/4513/3829 +f 4348/4515/3831 5605/4509/3825 5604/4506/3822 +f 5604/4506/3822 5603/4507/3823 4357/4511/3827 +f 4374/4501/3817 5606/4508/3824 4347/4516/3832 +f 4374/4501/3817 4375/4502/3818 5607/4505/3821 +f 4347/4516/3832 5606/4508/3824 5605/4509/3825 +f 5609/4517/3833 5610/4521/3837 5608/4518/3834 +f 5611/4520/3836 5612/4523/3839 5608/4518/3834 +f 5613/4522/3838 5614/4519/3835 5608/4518/3834 +f 4377/4492/3808 5609/4517/3833 4359/4465/3781 +f 4378/4489/3805 5610/4521/3837 5609/4517/3833 +f 5609/4517/3833 5614/4519/3835 4360/4468/3784 +f 4382/4524/3840 5611/4520/3836 4379/4486/3802 +f 4381/4525/3841 5612/4523/3839 5611/4520/3836 +f 5611/4520/3836 5610/4521/3837 4378/4489/3805 +f 4361/4471/3787 5613/4522/3838 4380/4526/3842 +f 4360/4468/3784 5614/4519/3835 5613/4522/3838 +f 5613/4522/3838 5612/4523/3839 4381/4525/3841 +f 5616/4527/3843 5617/4531/3847 5615/4528/3844 +f 5618/4530/3846 5619/4533/3849 5615/4528/3844 +f 5620/4532/3848 5621/4529/3845 5615/4528/3844 +f 4368/4534/3850 5616/4527/3843 4382/4524/3840 +f 4369/4535/3851 5617/4531/3847 5616/4527/3843 +f 5616/4527/3843 5621/4529/3845 4381/4525/3841 +f 4385/4536/3852 5618/4530/3846 4370/4537/3853 +f 4384/4539/3855 5619/4533/3849 5618/4530/3846 +f 5618/4530/3846 5617/4531/3847 4369/4535/3851 +f 4380/4526/3842 5620/4532/3848 4383/4540/3856 +f 4381/4525/3841 5621/4529/3845 5620/4532/3848 +f 5620/4532/3848 5619/4533/3849 4384/4539/3855 +f 5623/4541/3857 5624/4545/3861 5622/4542/3858 +f 5625/4544/3860 5626/4547/3863 5622/4542/3858 +f 5627/4546/3862 5628/4543/3859 5622/4542/3858 +f 4383/4540/3856 5623/4541/3857 4356/4510/3826 +f 4384/4539/3855 5624/4545/3861 5623/4541/3857 +f 5623/4541/3857 5628/4543/3859 4357/4511/3827 +f 4388/4548/3864 5625/4544/3860 4385/4536/3852 +f 4387/4549/3865 5626/4547/3863 5625/4544/3860 +f 5625/4544/3860 5624/4545/3861 4384/4539/3855 +f 4358/4513/3829 5627/4546/3862 4386/4550/3866 +f 4357/4511/3827 5628/4543/3859 5627/4546/3862 +f 5627/4546/3862 5626/4547/3863 4387/4549/3865 +f 5630/4551/3867 5631/4555/3871 5629/4552/3868 +f 5632/4554/3870 5633/4557/3873 5629/4552/3868 +f 5634/4556/3872 5635/4553/3869 5629/4552/3868 +f 4362/4558/3874 5630/4551/3867 4388/4548/3864 +f 4363/4559/3875 5631/4555/3871 5630/4551/3867 +f 5630/4551/3867 5635/4553/3869 4387/4549/3865 +f 4352/4560/3876 5632/4554/3870 4364/4561/3877 +f 4351/4563/3878 5633/4557/3873 5632/4554/3870 +f 5632/4554/3870 5631/4555/3871 4363/4559/3875 +f 4386/4550/3866 5634/4556/3872 4350/4564/3879 +f 4387/4549/3865 5635/4553/3869 5634/4556/3872 +f 4350/4564/3879 5634/4556/3872 5633/4557/3873 +f 5637/4565/3880 5638/4569/3884 5636/4566/3881 +f 5639/4568/3883 5640/4571/3886 5636/4566/3881 +f 5641/4570/3885 5642/4567/3882 5636/4566/3881 +f 4389/4437/3753 5637/4565/3880 4365/4483/3799 +f 4390/4434/3750 5638/4569/3884 5637/4565/3880 +f 5637/4565/3880 5642/4567/3882 4366/4490/3806 +f 4394/4572/3887 5639/4568/3883 4391/4431/3747 +f 4393/4573/3888 5640/4571/3886 5639/4568/3883 +f 5639/4568/3883 5638/4569/3884 4390/4434/3750 +f 4367/4487/3803 5641/4570/3885 4392/4574/3889 +f 4367/4487/3803 4366/4490/3806 5642/4567/3882 +f 4392/4574/3889 5641/4570/3885 5640/4571/3886 +f 5644/4575/3890 5645/4579/3894 5643/4576/3891 +f 5646/4578/3893 5647/4581/3896 5643/4576/3891 +f 5648/4580/3895 5649/4577/3892 5643/4576/3891 +f 4307/4582/3897 5644/4575/3890 4394/4572/3887 +f 4307/4582/3897 4306/4587/3902 5645/4579/3894 +f 4394/4572/3887 5644/4575/3890 5649/4577/3892 +f 4397/4583/3898 5646/4578/3893 4305/4584/3899 +f 4396/4586/3901 5647/4581/3896 5646/4578/3893 +f 5646/4578/3893 5645/4579/3894 4306/4587/3902 +f 4392/4574/3889 5648/4580/3895 4395/4588/3903 +f 4393/4573/3888 5649/4577/3892 5648/4580/3895 +f 5648/4580/3895 5647/4581/3896 4396/4586/3901 +f 5651/4589/3904 5652/4593/3908 5650/4590/3905 +f 5653/4592/3907 5654/4595/3910 5650/4590/3905 +f 5655/4594/3909 5656/4591/3906 5650/4590/3905 +f 4395/4588/3903 5651/4589/3904 4368/4534/3850 +f 4396/4586/3901 5652/4593/3908 5651/4589/3904 +f 5651/4589/3904 5656/4591/3906 4369/4535/3851 +f 4400/4596/3911 5653/4592/3907 4397/4583/3898 +f 4399/4597/3912 5654/4595/3910 5653/4592/3907 +f 5653/4592/3907 5652/4593/3908 4396/4586/3901 +f 4370/4537/3853 5655/4594/3909 4398/4598/3913 +f 4369/4535/3851 5656/4591/3906 5655/4594/3909 +f 5655/4594/3909 5654/4595/3910 4399/4597/3912 +f 5658/4599/3914 5659/4603/3918 5657/4600/3915 +f 5660/4602/3917 5661/4605/3920 5657/4600/3915 +f 5662/4604/3919 5663/4601/3916 5657/4600/3915 +f 4304/4606/3921 5658/4599/3914 4400/4596/3911 +f 4303/4607/3922 5659/4603/3918 5658/4599/3914 +f 5658/4599/3914 5663/4601/3916 4399/4597/3912 +f 4403/4608/3923 5660/4602/3917 4302/4609/3924 +f 4402/4611/3926 5661/4605/3920 5660/4602/3917 +f 5660/4602/3917 5659/4603/3918 4303/4607/3922 +f 4398/4598/3913 5662/4604/3919 4401/4612/3927 +f 4399/4597/3912 5663/4601/3916 5662/4604/3919 +f 5662/4604/3919 5661/4605/3920 4402/4611/3926 +f 5665/4613/3928 5666/4617/3932 5664/4614/3929 +f 5667/4616/3931 5668/4619/3934 5664/4614/3929 +f 5669/4618/3933 5670/4615/3930 5664/4614/3929 +f 4401/4612/3927 5665/4613/3928 4362/4558/3874 +f 4402/4611/3926 5666/4617/3932 5665/4613/3928 +f 4362/4558/3874 5665/4613/3928 5670/4615/3930 +f 4406/4620/3935 5667/4616/3931 4403/4608/3923 +f 4406/4620/3935 4405/4622/3937 5668/4619/3934 +f 5667/4616/3931 5666/4617/3932 4402/4611/3926 +f 4364/4561/3877 5669/4618/3933 4404/4621/3936 +f 4363/4559/3875 5670/4615/3930 5669/4618/3933 +f 5669/4618/3933 5668/4619/3934 4405/4622/3937 +f 5672/4623/3938 5673/4627/3942 5671/4624/3939 +f 5674/4626/3941 5675/4629/3944 5671/4624/3939 +f 5676/4628/3943 5677/4625/3940 5671/4624/3939 +f 4301/4630/3945 5672/4623/3938 4406/4620/3935 +f 4300/4631/3946 5673/4627/3942 5672/4623/3938 +f 5672/4623/3938 5677/4625/3940 4405/4622/3937 +f 4082/4632/3725 5674/4626/3941 4299/4633/3947 +f 4082/4632/3725 4081/4635/3727 5675/4629/3944 +f 4299/4633/3947 5674/4626/3941 5673/4627/3942 +f 4404/4621/3936 5676/4628/3943 4080/4634/3733 +f 4404/4621/3936 4405/4622/3937 5677/4625/3940 +f 5676/4628/3943 5675/4629/3944 4081/4635/3727 +f 5679/4636/3948 5680/4640/3952 5678/4637/3949 +f 5682/4639/3951 5678/4637/3949 5680/4640/3952 +f 5683/4642/3954 5684/4638/3950 5678/4637/3949 +f 4407/4643/3955 5679/4636/3948 4346/4644/3767 +f 4407/4643/3955 4408/4651/3960 5680/4640/3952 +f 5679/4636/3948 5684/4638/3950 4345/4646/3770 +f 4337/4647/3956 5681/4641/3953 4409/4648/3957 +f 4336/4650/3959 5682/4639/3951 5681/4641/3953 +f 5681/4641/3953 5680/4640/3952 4408/4651/3960 +f 4344/4652/3772 5683/4642/3954 4335/4653/3961 +f 4344/4652/3772 4345/4646/3770 5684/4638/3950 +f 4335/4653/3961 5683/4642/3954 5682/4639/3951 +f 5686/4655/3962 5687/4659/3966 5685/4656/3963 +f 5689/4658/3965 5685/4656/3963 5687/4659/3966 +f 5690/4661/3968 5691/4657/3964 5685/4656/3963 +f 4413/4662/3969 5686/4655/3962 4349/4663/3828 +f 4413/4662/3969 4414/4670/3974 5687/4659/3966 +f 4349/4663/3828 5686/4655/3962 5691/4657/3964 +f 4427/4666/3970 5688/4660/3967 4415/4667/3971 +f 4426/4669/3973 5689/4658/3965 5688/4660/3967 +f 5688/4660/3967 5687/4659/3966 4414/4670/3974 +f 4347/4671/3832 5690/4661/3968 4425/4672/3975 +f 4348/4665/3831 5691/4657/3964 5690/4661/3968 +f 4425/4672/3975 5690/4661/3968 5689/4658/3965 +f 5693/4673/3976 5694/4677/3980 5692/4674/3977 +f 5695/4676/3979 5696/4679/3982 5692/4674/3977 +f 5697/4678/3981 5698/4675/3978 5692/4674/3977 +f 4419/4680/3983 5693/4673/3976 4352/4681/3876 +f 4419/4680/3983 4420/4687/3988 5694/4677/3980 +f 4352/4681/3876 5693/4673/3976 5698/4675/3978 +f 4433/4683/3984 5695/4676/3979 4421/4684/3985 +f 4432/4686/3987 5696/4679/3982 5695/4676/3979 +f 5695/4676/3979 5694/4677/3980 4420/4687/3988 +f 4350/4688/3879 5697/4678/3981 4431/4689/3989 +f 4351/4682/3878 5698/4675/3978 5697/4678/3981 +f 4431/4689/3989 5697/4678/3981 5696/4679/3982 +f 5700/4690/3990 5701/4694/3994 5699/4691/3991 +f 5702/4693/3993 5703/4696/3996 5699/4691/3991 +f 5704/4695/3995 5705/4692/3992 5699/4691/3991 +f 4425/4672/3975 5700/4690/3990 4407/4643/3955 +f 4426/4669/3973 5701/4694/3994 5700/4690/3990 +f 5700/4690/3990 5705/4692/3992 4408/4651/3960 +f 4430/4697/3997 5702/4693/3993 4427/4666/3970 +f 4429/4698/3998 5703/4696/3996 5702/4693/3993 +f 4427/4666/3970 5702/4693/3993 5701/4694/3994 +f 4409/4648/3957 5704/4695/3995 4428/4699/3999 +f 4409/4648/3957 4408/4651/3960 5705/4692/3992 +f 4428/4699/3999 5704/4695/3995 5703/4696/3996 +f 5707/4700/4000 5708/4704/4004 5706/4701/4001 +f 5709/4703/4003 5710/4706/4006 5706/4701/4001 +f 5711/4705/4005 5712/4702/4002 5706/4701/4001 +f 4410/4707/4007 5707/4700/4000 4430/4697/3997 +f 4411/4708/4008 5708/4704/4004 5707/4700/4000 +f 5707/4700/4000 5712/4702/4002 4429/4698/3998 +f 4340/4709/4009 5709/4703/4003 4412/4710/4010 +f 4339/4712/4012 5710/4706/4006 5709/4703/4003 +f 5709/4703/4003 5708/4704/4004 4411/4708/4008 +f 4428/4699/3999 5711/4705/4005 4338/4713/4013 +f 4429/4698/3998 5712/4702/4002 5711/4705/4005 +f 5711/4705/4005 5710/4706/4006 4339/4712/4012 +f 5714/4714/4014 5715/4718/4018 5713/4715/4015 +f 5716/4717/4017 5717/4720/4020 5713/4715/4015 +f 5718/4719/4019 5719/4716/4016 5713/4715/4015 +f 4431/4689/3989 5714/4714/4014 4413/4662/3969 +f 4432/4686/3987 5715/4718/4018 5714/4714/4014 +f 5714/4714/4014 5719/4716/4016 4414/4670/3974 +f 4436/4721/4021 5716/4717/4017 4433/4683/3984 +f 4435/4722/4022 5717/4720/4020 5716/4717/4017 +f 5716/4717/4017 5715/4718/4018 4432/4686/3987 +f 4415/4667/3971 5718/4719/4019 4434/4723/4023 +f 4415/4667/3971 4414/4670/3974 5719/4716/4016 +f 5718/4719/4019 5717/4720/4020 4435/4722/4022 +f 5721/4724/4024 5722/4728/4028 5720/4725/4025 +f 5723/4727/4027 5724/4730/4030 5720/4725/4025 +f 5725/4729/4029 5726/4726/4026 5720/4725/4025 +f 4422/4731/4031 5721/4724/4024 4436/4721/4021 +f 4423/4732/4032 5722/4728/4028 5721/4724/4024 +f 5721/4724/4024 5726/4726/4026 4435/4722/4022 +f 4439/4733/4033 5723/4727/4027 4424/4734/4034 +f 4438/4736/4036 5724/4730/4030 5723/4727/4027 +f 5723/4727/4027 5722/4728/4028 4423/4732/4032 +f 4434/4723/4023 5725/4729/4029 4437/4737/4037 +f 4435/4722/4022 5726/4726/4026 5725/4729/4029 +f 5725/4729/4029 5724/4730/4030 4438/4736/4036 +f 5728/4738/4038 5729/4742/4042 5727/4739/4039 +f 5730/4741/4041 5731/4744/4044 5727/4739/4039 +f 5732/4743/4043 5733/4740/4040 5727/4739/4039 +f 4437/4737/4037 5728/4738/4038 4410/4707/4007 +f 4438/4736/4036 5729/4742/4042 5728/4738/4038 +f 5728/4738/4038 5733/4740/4040 4411/4708/4008 +f 4442/4745/4045 5730/4741/4041 4439/4733/4033 +f 4441/4746/4046 5731/4744/4044 5730/4741/4041 +f 5730/4741/4041 5729/4742/4042 4438/4736/4036 +f 4412/4710/4010 5732/4743/4043 4440/4747/4047 +f 4411/4708/4008 5733/4740/4040 5732/4743/4043 +f 5732/4743/4043 5731/4744/4044 4441/4746/4046 +f 5735/4748/4048 5736/4752/4052 5734/4749/4049 +f 5737/4751/4051 5738/4754/4054 5734/4749/4049 +f 5739/4753/4053 5740/4750/4050 5734/4749/4049 +f 4416/4755/4055 5735/4748/4048 4442/4745/4045 +f 4417/4756/4056 5736/4752/4052 5735/4748/4048 +f 5735/4748/4048 5740/4750/4050 4441/4746/4046 +f 4343/4757/4057 5737/4751/4051 4418/4758/4058 +f 4342/4760/4059 5738/4754/4054 5737/4751/4051 +f 5737/4751/4051 5736/4752/4052 4417/4756/4056 +f 4440/4747/4047 5739/4753/4053 4341/4761/4060 +f 4441/4746/4046 5740/4750/4050 5739/4753/4053 +f 5739/4753/4053 5738/4754/4054 4342/4760/4059 +f 5742/4762/4061 5743/4766/4065 5741/4763/4062 +f 5744/4765/4064 5745/4768/4067 5741/4763/4062 +f 5746/4767/4066 5747/4764/4063 5741/4763/4062 +f 4443/4418/3734 5742/4762/4061 4419/4680/3983 +f 4444/4415/3731 5743/4766/4065 5742/4762/4061 +f 5742/4762/4061 5747/4764/4063 4420/4687/3988 +f 4448/4769/4068 5744/4765/4064 4445/4412/3728 +f 4447/4770/4069 5745/4768/4067 5744/4765/4064 +f 5744/4765/4064 5743/4766/4065 4444/4415/3731 +f 4421/4684/3985 5746/4767/4066 4446/4771/4070 +f 4420/4687/3988 5747/4764/4063 5746/4767/4066 +f 5746/4767/4066 5745/4768/4067 4447/4770/4069 +f 5749/4772/4071 5750/4776/4075 5748/4773/4072 +f 5751/4775/4074 5752/4778/4077 5748/4773/4072 +f 5753/4777/4076 5754/4774/4073 5748/4773/4072 +f 4298/4779/4078 5749/4772/4071 4448/4769/4068 +f 4297/4780/4079 5750/4776/4075 5749/4772/4071 +f 5749/4772/4071 5754/4774/4073 4447/4770/4069 +f 4451/4781/4080 5751/4775/4074 4296/4782/4081 +f 4450/4784/4083 5752/4778/4077 5751/4775/4074 +f 5751/4775/4074 5750/4776/4075 4297/4780/4079 +f 4446/4771/4070 5753/4777/4076 4449/4785/4084 +f 4447/4770/4069 5754/4774/4073 5753/4777/4076 +f 5753/4777/4076 5752/4778/4077 4450/4784/4083 +f 5756/4786/4085 5757/4790/4089 5755/4787/4086 +f 5758/4789/4088 5759/4792/4091 5755/4787/4086 +f 5760/4791/4090 5761/4788/4087 5755/4787/4086 +f 4449/4785/4084 5756/4786/4085 4422/4731/4031 +f 4450/4784/4083 5757/4790/4089 5756/4786/4085 +f 5756/4786/4085 5761/4788/4087 4423/4732/4032 +f 4454/4793/4092 5758/4789/4088 4451/4781/4080 +f 4453/4794/4093 5759/4792/4091 5758/4789/4088 +f 5758/4789/4088 5757/4790/4089 4450/4784/4083 +f 4424/4734/4034 5760/4791/4090 4452/4795/4094 +f 4423/4732/4032 5761/4788/4087 5760/4791/4090 +f 5760/4791/4090 5759/4792/4091 4453/4794/4093 +f 5763/4796/4095 5764/4800/4099 5762/4797/4096 +f 5765/4799/4098 5766/4802/4101 5762/4797/4096 +f 5767/4801/4100 5768/4798/4097 5762/4797/4096 +f 4295/4803/4102 5763/4796/4095 4454/4793/4092 +f 4294/4804/4103 5764/4800/4099 5763/4796/4095 +f 5763/4796/4095 5768/4798/4097 4453/4794/4093 +f 4457/4805/4104 5765/4799/4098 4293/4806/4105 +f 4456/4808/4107 5766/4802/4101 5765/4799/4098 +f 5765/4799/4098 5764/4800/4099 4294/4804/4103 +f 4452/4795/4094 5767/4801/4100 4455/4809/4108 +f 4453/4794/4093 5768/4798/4097 5767/4801/4100 +f 5767/4801/4100 5766/4802/4101 4456/4808/4107 +f 5770/4810/4109 5771/4814/4113 5769/4811/4110 +f 5772/4813/4112 5773/4816/4115 5769/4811/4110 +f 5774/4815/4114 5775/4812/4111 5769/4811/4110 +f 4455/4809/4108 5770/4810/4109 4416/4755/4055 +f 4456/4808/4107 5771/4814/4113 5770/4810/4109 +f 5770/4810/4109 5775/4812/4111 4417/4756/4056 +f 4460/4817/4116 5772/4813/4112 4457/4805/4104 +f 4459/4818/4117 5773/4816/4115 5772/4813/4112 +f 5772/4813/4112 5771/4814/4113 4456/4808/4107 +f 4418/4758/4058 5774/4815/4114 4458/4819/4118 +f 4417/4756/4056 5775/4812/4111 5774/4815/4114 +f 5774/4815/4114 5773/4816/4115 4459/4818/4117 +f 5777/4820/4119 5778/4824/4123 5776/4821/4120 +f 5779/4823/4122 5780/4826/4125 5776/4821/4120 +f 5781/4825/4124 5782/4822/4121 5776/4821/4120 +f 4292/4827/4126 5777/4820/4119 4460/4817/4116 +f 4291/4828/4127 5778/4824/4123 5777/4820/4119 +f 5777/4820/4119 5782/4822/4121 4459/4818/4117 +f 4079/4829/3706 5779/4823/4122 4290/4830/4128 +f 4079/4829/3706 4078/4832/3708 5780/4826/4125 +f 4290/4830/4128 5779/4823/4122 5778/4824/4123 +f 4458/4819/4118 5781/4825/4124 4077/4831/3714 +f 4459/4818/4117 5782/4822/4121 5781/4825/4124 +f 5781/4825/4124 5780/4826/4125 4078/4832/3708 +f 5784/4833/4129 5785/4837/4133 5783/4834/4130 +f 5786/4836/4132 5787/4839/4135 5783/4834/4130 +f 5788/4838/4134 5789/4835/4131 5783/4834/4130 +f 4461/4840/4136 5784/4833/4129 4337/4841/3956 +f 4462/4843/4137 5785/4837/4133 5784/4833/4129 +f 5784/4833/4129 5789/4835/4131 4336/4844/3959 +f 4328/4845/4138 5786/4836/4132 4463/4846/4139 +f 4327/4848/4141 5787/4839/4135 5786/4836/4132 +f 5786/4836/4132 5785/4837/4133 4462/4843/4137 +f 4335/4849/3961 5788/4838/4134 4326/4850/4142 +f 4335/4849/3961 4336/4844/3959 5789/4835/4131 +f 5788/4838/4134 5787/4839/4135 4327/4848/4141 +f 5791/4852/4143 5792/4856/4147 5790/4853/4144 +f 5793/4855/4146 5794/4858/4149 5790/4853/4144 +f 5795/4857/4148 5796/4854/4145 5790/4853/4144 +f 4467/4859/4150 5791/4852/4143 4340/4860/4009 +f 4468/4862/4151 5792/4856/4147 5791/4852/4143 +f 5791/4852/4143 5796/4854/4145 4339/4863/4012 +f 4481/4864/4152 5793/4855/4146 4469/4865/4153 +f 4480/4867/4155 5794/4858/4149 5793/4855/4146 +f 5793/4855/4146 5792/4856/4147 4468/4862/4151 +f 4338/4868/4013 5795/4857/4148 4479/4869/4156 +f 4338/4868/4013 4339/4863/4012 5796/4854/4145 +f 4479/4869/4156 5795/4857/4148 5794/4858/4149 +f 5798/4870/4157 5799/4874/4161 5797/4871/4158 +f 5800/4873/4160 5801/4876/4163 5797/4871/4158 +f 5802/4875/4162 5803/4872/4159 5797/4871/4158 +f 4473/4877/4164 5798/4870/4157 4343/4878/4057 +f 4473/4877/4164 4474/4883/4168 5799/4874/4161 +f 4343/4878/4057 5798/4870/4157 5803/4872/4159 +f 4487/4880/4165 5800/4873/4160 4475/4881/4166 +f 4487/4880/4165 4486/4886/4170 5801/4876/4163 +f 5800/4873/4160 5799/4874/4161 4474/4883/4168 +f 4341/4884/4060 5802/4875/4162 4485/4885/4169 +f 4342/4879/4059 5803/4872/4159 5802/4875/4162 +f 5802/4875/4162 5801/4876/4163 4486/4886/4170 +f 5805/4887/4171 5806/4891/4175 5804/4888/4172 +f 5807/4890/4174 5808/4893/4177 5804/4888/4172 +f 5809/4892/4176 5810/4889/4173 5804/4888/4172 +f 4479/4869/4156 5805/4887/4171 4461/4840/4136 +f 4480/4867/4155 5806/4891/4175 5805/4887/4171 +f 5805/4887/4171 5810/4889/4173 4462/4843/4137 +f 4484/4894/4178 5807/4890/4174 4481/4864/4152 +f 4484/4894/4178 4483/4896/4180 5808/4893/4177 +f 4481/4864/4152 5807/4890/4174 5806/4891/4175 +f 4463/4846/4139 5809/4892/4176 4482/4895/4179 +f 4462/4843/4137 5810/4889/4173 5809/4892/4176 +f 5809/4892/4176 5808/4893/4177 4483/4896/4180 +f 5812/4897/4181 5813/4901/4185 5811/4898/4182 +f 5814/4900/4184 5815/4903/4187 5811/4898/4182 +f 5816/4902/4186 5817/4899/4183 5811/4898/4182 +f 4464/4904/4188 5812/4897/4181 4484/4894/4178 +f 4465/4905/4189 5813/4901/4185 5812/4897/4181 +f 5812/4897/4181 5817/4899/4183 4483/4896/4180 +f 4331/4906/4190 5814/4900/4184 4466/4907/4191 +f 4330/4909/4193 5815/4903/4187 5814/4900/4184 +f 5814/4900/4184 5813/4901/4185 4465/4905/4189 +f 4482/4895/4179 5816/4902/4186 4329/4910/4194 +f 4482/4895/4179 4483/4896/4180 5817/4899/4183 +f 4329/4910/4194 5816/4902/4186 5815/4903/4187 +f 5819/4911/4195 5820/4915/4199 5818/4912/4196 +f 5821/4914/4198 5822/4917/4201 5818/4912/4196 +f 5823/4916/4200 5824/4913/4197 5818/4912/4196 +f 4485/4885/4169 5819/4911/4195 4467/4859/4150 +f 4486/4886/4170 5820/4915/4199 5819/4911/4195 +f 5819/4911/4195 5824/4913/4197 4468/4862/4151 +f 4490/4918/4202 5821/4914/4198 4487/4880/4165 +f 4489/4919/4203 5822/4917/4201 5821/4914/4198 +f 5821/4914/4198 5820/4915/4199 4486/4886/4170 +f 4469/4865/4153 5823/4916/4200 4488/4920/4204 +f 4468/4862/4151 5824/4913/4197 5823/4916/4200 +f 5823/4916/4200 5822/4917/4201 4489/4919/4203 +f 5826/4921/4205 5827/4925/4209 5825/4922/4206 +f 5828/4924/4208 5829/4927/4211 5825/4922/4206 +f 5830/4926/4210 5831/4923/4207 5825/4922/4206 +f 4476/4928/4212 5826/4921/4205 4490/4918/4202 +f 4477/4929/4213 5827/4925/4209 5826/4921/4205 +f 5826/4921/4205 5831/4923/4207 4489/4919/4203 +f 4493/4930/4214 5828/4924/4208 4478/4931/4215 +f 4492/4933/4217 5829/4927/4211 5828/4924/4208 +f 5828/4924/4208 5827/4925/4209 4477/4929/4213 +f 4488/4920/4204 5830/4926/4210 4491/4934/4218 +f 4489/4919/4203 5831/4923/4207 5830/4926/4210 +f 5830/4926/4210 5829/4927/4211 4492/4933/4217 +f 5833/4935/4219 5834/4939/4223 5832/4936/4220 +f 5835/4938/4222 5836/4941/4225 5832/4936/4220 +f 5837/4940/4224 5838/4937/4221 5832/4936/4220 +f 4491/4934/4218 5833/4935/4219 4464/4904/4188 +f 4492/4933/4217 5834/4939/4223 5833/4935/4219 +f 5833/4935/4219 5838/4937/4221 4465/4905/4189 +f 4496/4942/4226 5835/4938/4222 4493/4930/4214 +f 4495/4943/4227 5836/4941/4225 5835/4938/4222 +f 5835/4938/4222 5834/4939/4223 4492/4933/4217 +f 4466/4907/4191 5837/4940/4224 4494/4944/4228 +f 4465/4905/4189 5838/4937/4221 5837/4940/4224 +f 5837/4940/4224 5836/4941/4225 4495/4943/4227 +f 5840/4945/4229 5841/4949/4233 5839/4946/4230 +f 5842/4948/4232 5843/4951/4235 5839/4946/4230 +f 5844/4950/4234 5845/4947/4231 5839/4946/4230 +f 4470/4952/4236 5840/4945/4229 4496/4942/4226 +f 4471/4953/4237 5841/4949/4233 5840/4945/4229 +f 5840/4945/4229 5845/4947/4231 4495/4943/4227 +f 4334/4954/4238 5842/4948/4232 4472/4955/4239 +f 4333/4957/4240 5843/4951/4235 5842/4948/4232 +f 4472/4955/4239 5842/4948/4232 5841/4949/4233 +f 4494/4944/4228 5844/4950/4234 4332/4958/4241 +f 4495/4943/4227 5845/4947/4231 5844/4950/4234 +f 5844/4950/4234 5843/4951/4235 4333/4957/4240 +f 5847/4959/4242 5848/4963/4246 5846/4960/4243 +f 5849/4962/4245 5850/4965/4248 5846/4960/4243 +f 5851/4964/4247 5852/4961/4244 5846/4960/4243 +f 4497/4399/3715 5847/4959/4242 4473/4877/4164 +f 4498/4396/3712 5848/4963/4246 5847/4959/4242 +f 5847/4959/4242 5852/4961/4244 4474/4883/4168 +f 4502/4966/4249 5849/4962/4245 4499/4393/3709 +f 4501/4967/4250 5850/4965/4248 5849/4962/4245 +f 5849/4962/4245 5848/4963/4246 4498/4396/3712 +f 4475/4881/4166 5851/4964/4247 4500/4968/4251 +f 4474/4883/4168 5852/4961/4244 5851/4964/4247 +f 4500/4968/4251 5851/4964/4247 5850/4965/4248 +f 5854/4969/4252 5855/4973/4256 5853/4970/4253 +f 5856/4972/4255 5857/4975/4258 5853/4970/4253 +f 5858/4974/4257 5859/4971/4254 5853/4970/4253 +f 4289/4976/4259 5854/4969/4252 4502/4966/4249 +f 4288/4977/4260 5855/4973/4256 5854/4969/4252 +f 4502/4966/4249 5854/4969/4252 5859/4971/4254 +f 4505/4978/4261 5856/4972/4255 4287/4979/4262 +f 4504/4981/4264 5857/4975/4258 5856/4972/4255 +f 5856/4972/4255 5855/4973/4256 4288/4977/4260 +f 4500/4968/4251 5858/4974/4257 4503/4982/4265 +f 4501/4967/4250 5859/4971/4254 5858/4974/4257 +f 5858/4974/4257 5857/4975/4258 4504/4981/4264 +f 5861/4983/4266 5862/4987/4270 5860/4984/4267 +f 5863/4986/4269 5864/4989/4272 5860/4984/4267 +f 5865/4988/4271 5866/4985/4268 5860/4984/4267 +f 4503/4982/4265 5861/4983/4266 4476/4928/4212 +f 4504/4981/4264 5862/4987/4270 5861/4983/4266 +f 5861/4983/4266 5866/4985/4268 4477/4929/4213 +f 4508/4990/4273 5863/4986/4269 4505/4978/4261 +f 4507/4991/4274 5864/4989/4272 5863/4986/4269 +f 5863/4986/4269 5862/4987/4270 4504/4981/4264 +f 4478/4931/4215 5865/4988/4271 4506/4992/4275 +f 4477/4929/4213 5866/4985/4268 5865/4988/4271 +f 5865/4988/4271 5864/4989/4272 4507/4991/4274 +f 5868/4993/4276 5869/4997/4280 5867/4994/4277 +f 5870/4996/4279 5871/4999/4282 5867/4994/4277 +f 5872/4998/4281 5873/4995/4278 5867/4994/4277 +f 4286/5000/4283 5868/4993/4276 4508/4990/4273 +f 4285/5001/4284 5869/4997/4280 5868/4993/4276 +f 5868/4993/4276 5873/4995/4278 4507/4991/4274 +f 4511/5002/4285 5870/4996/4279 4284/5003/4286 +f 4510/5005/4288 5871/4999/4282 5870/4996/4279 +f 5870/4996/4279 5869/4997/4280 4285/5001/4284 +f 4506/4992/4275 5872/4998/4281 4509/5006/4289 +f 4507/4991/4274 5873/4995/4278 5872/4998/4281 +f 5872/4998/4281 5871/4999/4282 4510/5005/4288 +f 5875/5007/4290 5876/5011/4294 5874/5008/4291 +f 5877/5010/4293 5878/5013/4296 5874/5008/4291 +f 5879/5012/4295 5880/5009/4292 5874/5008/4291 +f 4509/5006/4289 5875/5007/4290 4470/4952/4236 +f 4509/5006/4289 4510/5005/4288 5876/5011/4294 +f 4470/4952/4236 5875/5007/4290 5880/5009/4292 +f 4514/5014/4297 5877/5010/4293 4511/5002/4285 +f 4513/5015/4298 5878/5013/4296 5877/5010/4293 +f 5877/5010/4293 5876/5011/4294 4510/5005/4288 +f 4472/4955/4239 5879/5012/4295 4512/5016/4299 +f 4471/4953/4237 5880/5009/4292 5879/5012/4295 +f 5879/5012/4295 5878/5013/4296 4513/5015/4298 +f 5882/5017/4300 5883/5021/4304 5881/5018/4301 +f 5884/5020/4303 5885/5023/4306 5881/5018/4301 +f 5886/5022/4305 5887/5019/4302 5881/5018/4301 +f 4283/5024/4307 5882/5017/4300 4514/5014/4297 +f 4282/5025/4308 5883/5021/4304 5882/5017/4300 +f 5882/5017/4300 5887/5019/4302 4513/5015/4298 +f 4076/5026/3687 5884/5020/4303 4281/5027/4309 +f 4076/5026/3687 4075/5030/3690 5885/5023/4306 +f 4281/5027/4309 5884/5020/4303 5883/5021/4304 +f 4512/5016/4299 5886/5022/4305 4074/5029/3694 +f 4513/5015/4298 5887/5019/4302 5886/5022/4305 +f 5886/5022/4305 5885/5023/4306 4075/5030/3690 +f 5889/5031/4310 5890/5035/4314 5888/5032/4311 +f 5891/5034/4313 5892/5037/4316 5888/5032/4311 +f 5893/5036/4315 5894/5033/4312 5888/5032/4311 +f 4515/5038/4317 5889/5031/4310 4328/5039/4138 +f 4516/5041/4318 5890/5035/4314 5889/5031/4310 +f 5889/5031/4310 5894/5033/4312 4327/5042/4141 +f 4310/5043/4319 5891/5034/4313 4517/5044/4320 +f 4309/5046/4322 5892/5037/4316 5891/5034/4313 +f 5891/5034/4313 5890/5035/4314 4516/5041/4318 +f 4326/5047/4142 5893/5036/4315 4308/5048/4323 +f 4326/5047/4142 4327/5042/4141 5894/5033/4312 +f 4308/5048/4323 5893/5036/4315 5892/5037/4316 +f 5896/5050/4324 5897/5054/4328 5895/5051/4325 +f 5898/5053/4327 5899/5056/4330 5895/5051/4325 +f 5900/5055/4329 5901/5052/4326 5895/5051/4325 +f 4521/5057/4331 5896/5050/4324 4331/5058/4190 +f 4522/5060/4332 5897/5054/4328 5896/5050/4324 +f 5896/5050/4324 5901/5052/4326 4330/5061/4193 +f 4535/5062/4333 5898/5053/4327 4523/5063/4334 +f 4534/5065/4336 5899/5056/4330 5898/5053/4327 +f 5898/5053/4327 5897/5054/4328 4522/5060/4332 +f 4329/5066/4194 5900/5055/4329 4533/5067/4337 +f 4330/5061/4193 5901/5052/4326 5900/5055/4329 +f 4533/5067/4337 5900/5055/4329 5899/5056/4330 +f 5903/5068/4338 5904/5072/4342 5902/5069/4339 +f 5905/5071/4341 5906/5074/4344 5902/5069/4339 +f 5907/5073/4343 5908/5070/4340 5902/5069/4339 +f 4527/5075/4345 5903/5068/4338 4334/5076/4238 +f 4528/5077/4346 5904/5072/4342 5903/5068/4338 +f 5903/5068/4338 5908/5070/4340 4333/5078/4240 +f 4541/5079/4347 5905/5071/4341 4529/5080/4348 +f 4540/5082/4350 5906/5074/4344 5905/5071/4341 +f 5905/5071/4341 5904/5072/4342 4528/5077/4346 +f 4332/5083/4241 5907/5073/4343 4539/5084/4351 +f 4333/5078/4240 5908/5070/4340 5907/5073/4343 +f 5907/5073/4343 5906/5074/4344 4540/5082/4350 +f 5910/5085/4352 5911/5089/4356 5909/5086/4353 +f 5912/5088/4355 5913/5091/4358 5909/5086/4353 +f 5914/5090/4357 5915/5087/4354 5909/5086/4353 +f 4533/5067/4337 5910/5085/4352 4515/5038/4317 +f 4534/5065/4336 5911/5089/4356 5910/5085/4352 +f 5910/5085/4352 5915/5087/4354 4516/5041/4318 +f 4538/5092/4359 5912/5088/4355 4535/5062/4333 +f 4538/5092/4359 4537/5094/4361 5913/5091/4358 +f 4535/5062/4333 5912/5088/4355 5911/5089/4356 +f 4517/5044/4320 5914/5090/4357 4536/5093/4360 +f 4516/5041/4318 5915/5087/4354 5914/5090/4357 +f 5914/5090/4357 5913/5091/4358 4537/5094/4361 +f 5917/5095/4362 5918/5099/4366 5916/5096/4363 +f 5919/5098/4365 5920/5101/4368 5916/5096/4363 +f 5921/5100/4367 5922/5097/4364 5916/5096/4363 +f 4518/5102/4369 5917/5095/4362 4538/5092/4359 +f 4519/5103/4370 5918/5099/4366 5917/5095/4362 +f 5917/5095/4362 5922/5097/4364 4537/5094/4361 +f 4313/5104/4371 5919/5098/4365 4520/5105/4372 +f 4312/5107/4374 5920/5101/4368 5919/5098/4365 +f 5919/5098/4365 5918/5099/4366 4519/5103/4370 +f 4536/5093/4360 5921/5100/4367 4311/5108/4375 +f 4536/5093/4360 4537/5094/4361 5922/5097/4364 +f 5921/5100/4367 5920/5101/4368 4312/5107/4374 +f 5924/5109/4376 5925/5113/4380 5923/5110/4377 +f 5926/5112/4379 5927/5115/4382 5923/5110/4377 +f 5928/5114/4381 5929/5111/4378 5923/5110/4377 +f 4539/5084/4351 5924/5109/4376 4521/5057/4331 +f 4540/5082/4350 5925/5113/4380 5924/5109/4376 +f 5924/5109/4376 5929/5111/4378 4522/5060/4332 +f 4544/5116/4383 5926/5112/4379 4541/5079/4347 +f 4543/5117/4384 5927/5115/4382 5926/5112/4379 +f 5926/5112/4379 5925/5113/4380 4540/5082/4350 +f 4523/5063/4334 5928/5114/4381 4542/5118/4385 +f 4522/5060/4332 5929/5111/4378 5928/5114/4381 +f 5928/5114/4381 5927/5115/4382 4543/5117/4384 +f 5931/5119/4386 5932/5123/4390 5930/5120/4387 +f 5933/5122/4389 5934/5125/4392 5930/5120/4387 +f 5935/5124/4391 5936/5121/4388 5930/5120/4387 +f 4530/5126/4393 5931/5119/4386 4544/5116/4383 +f 4531/5127/4394 5932/5123/4390 5931/5119/4386 +f 5931/5119/4386 5936/5121/4388 4543/5117/4384 +f 4547/5128/4395 5933/5122/4389 4532/5129/4396 +f 4546/5131/4398 5934/5125/4392 5933/5122/4389 +f 5933/5122/4389 5932/5123/4390 4531/5127/4394 +f 4542/5118/4385 5935/5124/4391 4545/5132/4399 +f 4543/5117/4384 5936/5121/4388 5935/5124/4391 +f 5935/5124/4391 5934/5125/4392 4546/5131/4398 +f 5938/5133/4400 5939/5137/4404 5937/5134/4401 +f 5940/5136/4403 5941/5139/4406 5937/5134/4401 +f 5942/5138/4405 5943/5135/4402 5937/5134/4401 +f 4545/5132/4399 5938/5133/4400 4518/5102/4369 +f 4546/5131/4398 5939/5137/4404 5938/5133/4400 +f 5938/5133/4400 5943/5135/4402 4519/5103/4370 +f 4550/5140/4407 5940/5136/4403 4547/5128/4395 +f 4549/5141/4408 5941/5139/4406 5940/5136/4403 +f 5940/5136/4403 5939/5137/4404 4546/5131/4398 +f 4520/5105/4372 5942/5138/4405 4548/5142/4409 +f 4519/5103/4370 5943/5135/4402 5942/5138/4405 +f 5942/5138/4405 5941/5139/4406 4549/5141/4408 +f 5945/5143/4410 5946/5147/4414 5944/5144/4411 +f 5947/5146/4413 5948/5149/4416 5944/5144/4411 +f 5949/5148/4415 5950/5145/4412 5944/5144/4411 +f 4524/5150/4417 5945/5143/4410 4550/5140/4407 +f 4525/5151/4418 5946/5147/4414 5945/5143/4410 +f 5945/5143/4410 5950/5145/4412 4549/5141/4408 +f 4316/5152/4419 5947/5146/4413 4526/5153/4420 +f 4315/5155/4421 5948/5149/4416 5947/5146/4413 +f 5947/5146/4413 5946/5147/4414 4525/5151/4418 +f 4548/5142/4409 5949/5148/4415 4314/5156/4422 +f 4549/5141/4408 5950/5145/4412 5949/5148/4415 +f 5949/5148/4415 5948/5149/4416 4315/5155/4421 +f 5952/5157/4423 5953/5161/4427 5951/5158/4424 +f 5954/5160/4426 5955/5163/4429 5951/5158/4424 +f 5956/5162/4428 5957/5159/4425 5951/5158/4424 +f 4551/4379/3695 5952/5157/4423 4527/5075/4345 +f 4552/4381/3697 5953/5161/4427 5952/5157/4423 +f 5952/5157/4423 5957/5159/4425 4528/5077/4346 +f 4556/5164/4430 5954/5160/4426 4553/4375/3691 +f 4555/5165/4431 5955/5163/4429 5954/5160/4426 +f 5954/5160/4426 5953/5161/4427 4552/4381/3697 +f 4529/5080/4348 5956/5162/4428 4554/5166/4432 +f 4528/5077/4346 5957/5159/4425 5956/5162/4428 +f 5956/5162/4428 5955/5163/4429 4555/5165/4431 +f 5959/5167/4433 5960/5171/4437 5958/5168/4434 +f 5961/5170/4436 5962/5173/4439 5958/5168/4434 +f 5963/5172/4438 5964/5169/4435 5958/5168/4434 +f 4280/5174/4440 5959/5167/4433 4556/5164/4430 +f 4279/5175/4441 5960/5171/4437 5959/5167/4433 +f 5959/5167/4433 5964/5169/4435 4555/5165/4431 +f 4559/5176/4442 5961/5170/4436 4278/5177/4443 +f 4558/5179/4445 5962/5173/4439 5961/5170/4436 +f 5961/5170/4436 5960/5171/4437 4279/5175/4441 +f 4554/5166/4432 5963/5172/4438 4557/5180/4446 +f 4555/5165/4431 5964/5169/4435 5963/5172/4438 +f 5963/5172/4438 5962/5173/4439 4558/5179/4445 +f 5966/5181/4447 5967/5185/4451 5965/5182/4448 +f 5968/5184/4450 5969/5187/4453 5965/5182/4448 +f 5970/5186/4452 5971/5183/4449 5965/5182/4448 +f 4557/5180/4446 5966/5181/4447 4530/5126/4393 +f 4558/5179/4445 5967/5185/4451 5966/5181/4447 +f 5966/5181/4447 5971/5183/4449 4531/5127/4394 +f 4562/5188/4454 5968/5184/4450 4559/5176/4442 +f 4562/5188/4454 4561/5190/4456 5969/5187/4453 +f 4559/5176/4442 5968/5184/4450 5967/5185/4451 +f 4532/5129/4396 5970/5186/4452 4560/5189/4455 +f 4531/5127/4394 5971/5183/4449 5970/5186/4452 +f 5970/5186/4452 5969/5187/4453 4561/5190/4456 +f 5973/5191/4457 5974/5195/4461 5972/5192/4458 +f 5975/5194/4460 5976/5197/4463 5972/5192/4458 +f 5977/5196/4462 5978/5193/4459 5972/5192/4458 +f 4277/5198/4464 5973/5191/4457 4562/5188/4454 +f 4276/5199/4465 5974/5195/4461 5973/5191/4457 +f 5973/5191/4457 5978/5193/4459 4561/5190/4456 +f 4565/5200/4466 5975/5194/4460 4275/5201/4467 +f 4565/5200/4466 4564/5204/4470 5976/5197/4463 +f 5975/5194/4460 5974/5195/4461 4276/5199/4465 +f 4560/5189/4455 5977/5196/4462 4563/5203/4469 +f 4560/5189/4455 4561/5190/4456 5978/5193/4459 +f 5977/5196/4462 5976/5197/4463 4564/5204/4470 +f 5980/5205/4471 5981/5209/4475 5979/5206/4472 +f 5982/5208/4474 5983/5211/4477 5979/5206/4472 +f 5984/5210/4476 5985/5207/4473 5979/5206/4472 +f 4563/5203/4469 5980/5205/4471 4524/5150/4417 +f 4564/5204/4470 5981/5209/4475 5980/5205/4471 +f 4524/5150/4417 5980/5205/4471 5985/5207/4473 +f 4568/5212/4478 5982/5208/4474 4565/5200/4466 +f 4567/5213/4479 5983/5211/4477 5982/5208/4474 +f 5982/5208/4474 5981/5209/4475 4564/5204/4470 +f 4526/5153/4420 5984/5210/4476 4566/5214/4480 +f 4525/5151/4418 5985/5207/4473 5984/5210/4476 +f 5984/5210/4476 5983/5211/4477 4567/5213/4479 +f 5987/5215/4481 5988/5219/4485 5986/5216/4482 +f 5989/5218/4484 5990/5221/4487 5986/5216/4482 +f 5991/5220/4486 5992/5217/4483 5986/5216/4482 +f 4274/5222/4488 5987/5215/4481 4568/5212/4478 +f 4273/5223/4489 5988/5219/4485 5987/5215/4481 +f 5987/5215/4481 5992/5217/4483 4567/5213/4479 +f 4070/5224/3668 5989/5218/4484 4272/5225/4490 +f 4070/5224/3668 4069/5227/3670 5990/5221/4487 +f 4272/5225/4490 5989/5218/4484 5988/5219/4485 +f 4566/5214/4480 5991/5220/4486 4068/5226/3676 +f 4567/5213/4479 5992/5217/4483 5991/5220/4486 +f 5991/5220/4486 5990/5221/4487 4069/5227/3670 +f 5994/5228/4491 5995/5232/4495 5993/5229/4492 +f 5996/5231/4494 5997/5234/4497 5993/5229/4492 +f 5998/5233/4496 5999/5230/4493 5993/5229/4492 +f 4569/5235/4498 5994/5228/4491 4310/5236/4319 +f 4570/5238/4499 5995/5232/4495 5994/5228/4491 +f 5994/5228/4491 5999/5230/4493 4309/5239/4322 +f 4071/5240/3763 5996/5231/4494 4571/5241/4500 +f 4072/5243/3766 5997/5234/4497 5996/5231/4494 +f 5996/5231/4494 5995/5232/4495 4570/5238/4499 +f 4308/5244/4323 5998/5233/4496 4073/5245/3771 +f 4308/5244/4323 4309/5239/4322 5999/5230/4493 +f 4073/5245/3771 5998/5233/4496 5997/5234/4497 +f 6001/5247/4501 6002/5251/4505 6000/5248/4502 +f 6003/5250/4504 6004/5253/4507 6000/5248/4502 +f 6005/5252/4506 6006/5249/4503 6000/5248/4502 +f 4575/5254/4508 6001/5247/4501 4313/5255/4371 +f 4576/5257/4509 6002/5251/4505 6001/5247/4501 +f 6001/5247/4501 6006/5249/4503 4312/5258/4374 +f 4589/5259/4510 6003/5250/4504 4577/5260/4511 +f 4588/5262/4513 6004/5253/4507 6003/5250/4504 +f 6003/5250/4504 6002/5251/4505 4576/5257/4509 +f 4311/5263/4375 6005/5252/4506 4587/5264/4514 +f 4311/5263/4375 4312/5258/4374 6006/5249/4503 +f 4587/5264/4514 6005/5252/4506 6004/5253/4507 +f 6008/5265/4515 6009/5269/4519 6007/5266/4516 +f 6010/5268/4518 6011/5271/4521 6007/5266/4516 +f 6012/5270/4520 6013/5267/4517 6007/5266/4516 +f 4581/5272/4522 6008/5265/4515 4316/5273/4419 +f 4582/5274/4523 6009/5269/4519 6008/5265/4515 +f 6008/5265/4515 6013/5267/4517 4315/5275/4421 +f 4595/5276/4524 6010/5268/4518 4583/5277/4525 +f 4594/5279/4527 6011/5271/4521 6010/5268/4518 +f 6010/5268/4518 6009/5269/4519 4582/5274/4523 +f 4314/5280/4422 6012/5270/4520 4593/5281/4528 +f 4315/5275/4421 6013/5267/4517 6012/5270/4520 +f 6012/5270/4520 6011/5271/4521 4594/5279/4527 +f 6015/5282/4529 6016/5286/4533 6014/5283/4530 +f 6017/5285/4532 6018/5288/4535 6014/5283/4530 +f 6019/5287/4534 6020/5284/4531 6014/5283/4530 +f 4587/5264/4514 6015/5282/4529 4569/5235/4498 +f 4588/5262/4513 6016/5286/4533 6015/5282/4529 +f 6015/5282/4529 6020/5284/4531 4570/5238/4499 +f 4592/5289/4536 6017/5285/4532 4589/5259/4510 +f 4592/5289/4536 4591/5291/4538 6018/5288/4535 +f 4589/5259/4510 6017/5285/4532 6016/5286/4533 +f 4571/5241/4500 6019/5287/4534 4590/5290/4537 +f 4570/5238/4499 6020/5284/4531 6019/5287/4534 +f 6019/5287/4534 6018/5288/4535 4591/5291/4538 +f 6022/5292/4539 6023/5296/4543 6021/5293/4540 +f 6024/5295/4542 6025/5298/4545 6021/5293/4540 +f 6026/5297/4544 6027/5294/4541 6021/5293/4540 +f 4572/5299/4546 6022/5292/4539 4592/5289/4536 +f 4573/5300/4547 6023/5296/4543 6022/5292/4539 +f 6022/5292/4539 6027/5294/4541 4591/5291/4538 +f 4323/5301/3782 6024/5295/4542 4574/5302/4548 +f 4324/5304/3785 6025/5298/4545 6024/5295/4542 +f 6024/5295/4542 6023/5296/4543 4573/5300/4547 +f 4590/5290/4537 6026/5297/4544 4325/5305/3790 +f 4590/5290/4537 4591/5291/4538 6027/5294/4541 +f 6026/5297/4544 6025/5298/4545 4324/5304/3785 +f 6029/5306/4549 6030/5310/4553 6028/5307/4550 +f 6031/5309/4552 6032/5312/4555 6028/5307/4550 +f 6033/5311/4554 6034/5308/4551 6028/5307/4550 +f 4593/5281/4528 6029/5306/4549 4575/5254/4508 +f 4594/5279/4527 6030/5310/4553 6029/5306/4549 +f 6029/5306/4549 6034/5308/4551 4576/5257/4509 +f 4598/5313/4556 6031/5309/4552 4595/5276/4524 +f 4597/5314/4557 6032/5312/4555 6031/5309/4552 +f 6031/5309/4552 6030/5310/4553 4594/5279/4527 +f 4577/5260/4511 6033/5311/4554 4596/5315/4558 +f 4576/5257/4509 6034/5308/4551 6033/5311/4554 +f 6033/5311/4554 6032/5312/4555 4597/5314/4557 +f 6036/5316/4559 6037/5320/4563 6035/5317/4560 +f 6038/5319/4562 6039/5322/4565 6035/5317/4560 +f 6040/5321/4564 6041/5318/4561 6035/5317/4560 +f 4584/5323/4566 6036/5316/4559 4598/5313/4556 +f 4585/5324/4567 6037/5320/4563 6036/5316/4559 +f 6036/5316/4559 6041/5318/4561 4597/5314/4557 +f 4601/5325/4568 6038/5319/4562 4586/5326/4569 +f 4600/5328/4571 6039/5322/4565 6038/5319/4562 +f 6038/5319/4562 6037/5320/4563 4585/5324/4567 +f 4596/5315/4558 6040/5321/4564 4599/5329/4572 +f 4597/5314/4557 6041/5318/4561 6040/5321/4564 +f 6040/5321/4564 6039/5322/4565 4600/5328/4571 +f 6043/5330/4573 6044/5334/4577 6042/5331/4574 +f 6045/5333/4576 6046/5336/4579 6042/5331/4574 +f 6047/5335/4578 6048/5332/4575 6042/5331/4574 +f 4599/5329/4572 6043/5330/4573 4572/5299/4546 +f 4600/5328/4571 6044/5334/4577 6043/5330/4573 +f 4572/5299/4546 6043/5330/4573 6048/5332/4575 +f 4604/5337/4580 6045/5333/4576 4601/5325/4568 +f 4603/5338/4581 6046/5336/4579 6045/5333/4576 +f 6045/5333/4576 6044/5334/4577 4600/5328/4571 +f 4574/5302/4548 6047/5335/4578 4602/5339/4582 +f 4573/5300/4547 6048/5332/4575 6047/5335/4578 +f 6047/5335/4578 6046/5336/4579 4603/5338/4581 +f 6050/5340/4583 6051/5344/4587 6049/5341/4584 +f 6052/5343/4586 6053/5346/4589 6049/5341/4584 +f 6054/5345/4588 6055/5342/4585 6049/5341/4584 +f 4578/5347/4590 6050/5340/4583 4604/5337/4580 +f 4579/5348/4591 6051/5344/4587 6050/5340/4583 +f 6050/5340/4583 6055/5342/4585 4603/5338/4581 +f 4320/5349/3800 6052/5343/4586 4580/5350/4592 +f 4321/5352/3801 6053/5346/4589 6052/5343/4586 +f 4580/5350/4592 6052/5343/4586 6051/5344/4587 +f 4602/5339/4582 6054/5345/4588 4322/5353/3807 +f 4603/5338/4581 6055/5342/4585 6054/5345/4588 +f 6054/5345/4588 6053/5346/4589 4321/5352/3801 +f 6057/5354/4593 6058/5358/4597 6056/5355/4594 +f 6059/5357/4596 6060/5360/4599 6056/5355/4594 +f 6061/5359/4598 6062/5356/4595 6056/5355/4594 +f 4605/4361/3677 6057/5354/4593 4581/5272/4522 +f 4606/4358/3674 6058/5358/4597 6057/5354/4593 +f 6057/5354/4593 6062/5356/4595 4582/5274/4523 +f 4610/5361/4600 6059/5357/4596 4607/4355/3671 +f 4609/5362/4601 6060/5360/4599 6059/5357/4596 +f 6059/5357/4596 6058/5358/4597 4606/4358/3674 +f 4583/5277/4525 6061/5359/4598 4608/5363/4602 +f 4582/5274/4523 6062/5356/4595 6061/5359/4598 +f 6061/5359/4598 6060/5360/4599 4609/5362/4601 +f 6064/5364/4603 6065/5368/4607 6063/5365/4604 +f 6066/5367/4606 6067/5370/4609 6063/5365/4604 +f 6068/5369/4608 6069/5366/4605 6063/5365/4604 +f 4271/5371/4610 6064/5364/4603 4610/5361/4600 +f 4270/5372/4611 6065/5368/4607 6064/5364/4603 +f 4610/5361/4600 6064/5364/4603 6069/5366/4605 +f 4613/5373/4612 6066/5367/4606 4269/5374/4613 +f 4612/5376/4615 6067/5370/4609 6066/5367/4606 +f 6066/5367/4606 6065/5368/4607 4270/5372/4611 +f 4608/5363/4602 6068/5369/4608 4611/5377/4616 +f 4609/5362/4601 6069/5366/4605 6068/5369/4608 +f 6068/5369/4608 6067/5370/4609 4612/5376/4615 +f 6071/5378/4617 6072/5382/4621 6070/5379/4618 +f 6073/5381/4620 6074/5384/4623 6070/5379/4618 +f 6075/5383/4622 6076/5380/4619 6070/5379/4618 +f 4611/5377/4616 6071/5378/4617 4584/5323/4566 +f 4612/5376/4615 6072/5382/4621 6071/5378/4617 +f 6071/5378/4617 6076/5380/4619 4585/5324/4567 +f 4616/5385/4624 6073/5381/4620 4613/5373/4612 +f 4615/5386/4625 6074/5384/4623 6073/5381/4620 +f 6073/5381/4620 6072/5382/4621 4612/5376/4615 +f 4586/5326/4569 6075/5383/4622 4614/5387/4626 +f 4585/5324/4567 6076/5380/4619 6075/5383/4622 +f 6075/5383/4622 6074/5384/4623 4615/5386/4625 +f 6078/5388/4627 6079/5392/4631 6077/5389/4628 +f 6080/5391/4630 6081/5394/4633 6077/5389/4628 +f 6082/5393/4632 6083/5390/4629 6077/5389/4628 +f 4268/5395/4634 6078/5388/4627 4616/5385/4624 +f 4267/5396/4635 6079/5392/4631 6078/5388/4627 +f 6078/5388/4627 6083/5390/4629 4615/5386/4625 +f 4619/5397/4636 6080/5391/4630 4266/5398/4637 +f 4619/5397/4636 4618/5401/4640 6081/5394/4633 +f 4266/5398/4637 6080/5391/4630 6079/5392/4631 +f 4614/5387/4626 6082/5393/4632 4617/5400/4639 +f 4615/5386/4625 6083/5390/4629 6082/5393/4632 +f 6082/5393/4632 6081/5394/4633 4618/5401/4640 +f 6085/5402/4641 6086/5406/4645 6084/5403/4642 +f 6087/5405/4644 6088/5408/4647 6084/5403/4642 +f 6089/5407/4646 6090/5404/4643 6084/5403/4642 +f 4617/5400/4639 6085/5402/4641 4578/5347/4590 +f 4617/5400/4639 4618/5401/4640 6086/5406/4645 +f 4578/5347/4590 6085/5402/4641 6090/5404/4643 +f 4622/5409/4648 6087/5405/4644 4619/5397/4636 +f 4621/5410/4649 6088/5408/4647 6087/5405/4644 +f 6087/5405/4644 6086/5406/4645 4618/5401/4640 +f 4580/5350/4592 6089/5407/4646 4620/5411/4650 +f 4579/5348/4591 6090/5404/4643 6089/5407/4646 +f 6089/5407/4646 6088/5408/4647 4621/5410/4649 +f 6092/5412/4651 6093/5416/4655 6091/5413/4652 +f 6094/5415/4654 6095/5417/4656 6091/5413/4652 +f 6097/5414/4653 6091/5413/4652 6095/5417/4656 +f 4265/5419/4658 6092/5412/4651 4622/5409/4648 +f 4264/5420/4659 6093/5416/4655 6092/5412/4651 +f 6092/5412/4651 6097/5414/4653 4621/5410/4649 +f 4317/5421/3744 6094/5415/4654 4263/5422/4660 +f 4317/5421/3744 4318/5424/3746 6095/5417/4656 +f 4263/5422/4660 6094/5415/4654 6093/5416/4655 +f 4620/5411/4650 6096/5418/4657 4319/5423/3752 +f 4621/5410/4649 6097/5414/4653 6096/5418/4657 +f 6096/5418/4657 6095/5417/4656 4318/5424/3746 +f 6099/5425/4661 6100/5429/4665 6098/5426/4662 +f 6101/5428/4664 6102/5431/4667 6098/5426/4662 +f 6103/5430/4666 6104/5427/4663 6098/5426/4662 +f 4623/5432/4668 6099/5425/4661 4026/5433/4669 +f 4624/5435/4671 6100/5429/4665 6099/5425/4661 +f 6099/5425/4661 6104/5427/4663 4027/5436/4672 +f 4065/4432/3748 6101/5428/4664 4625/5437/4673 +f 4065/4432/3748 4066/4435/3751 6102/5431/4667 +f 6101/5428/4664 6100/5429/4665 4624/5435/4671 +f 4028/5438/4674 6103/5430/4666 4067/4427/3743 +f 4028/5438/4674 4027/5436/4672 6104/5427/4663 +f 6103/5430/4666 6102/5431/4667 4066/4435/3751 +f 6106/5439/4675 6107/5443/4679 6105/5440/4676 +f 6108/5442/4678 6109/5445/4681 6105/5440/4676 +f 6110/5444/4680 6111/5441/4677 6105/5440/4676 +f 4629/5446/4682 6106/5439/4675 4188/5447/4683 +f 4630/5449/4685 6107/5443/4679 6106/5439/4675 +f 6106/5439/4675 6111/5441/4677 4189/5450/4686 +f 4643/5451/4687 6108/5442/4678 4631/5452/4688 +f 4642/5454/4690 6109/5445/4681 6108/5442/4678 +f 6108/5442/4678 6107/5443/4679 4630/5449/4685 +f 4190/5455/4691 6110/5444/4680 4641/5456/4692 +f 4189/5450/4686 6111/5441/4677 6110/5444/4680 +f 6110/5444/4680 6109/5445/4681 4642/5454/4690 +f 6113/5457/4693 6114/5461/4697 6112/5458/4694 +f 6115/5460/4696 6116/5463/4699 6112/5458/4694 +f 6117/5462/4698 6118/5459/4695 6112/5458/4694 +f 4635/5464/4700 6113/5457/4693 4185/5465/4701 +f 4635/5464/4700 4636/5471/4707 6114/5461/4697 +f 6113/5457/4693 6118/5459/4695 4186/5466/4702 +f 4649/5467/4703 6115/5460/4696 4637/5468/4704 +f 4648/5470/4706 6116/5463/4699 6115/5460/4696 +f 6115/5460/4696 6114/5461/4697 4636/5471/4707 +f 4187/5472/4708 6117/5462/4698 4647/5473/4709 +f 4186/5466/4702 6118/5459/4695 6117/5462/4698 +f 6117/5462/4698 6116/5463/4699 4648/5470/4706 +f 6120/5474/4710 6121/5478/4714 6119/5475/4711 +f 6122/5477/4713 6123/5480/4716 6119/5475/4711 +f 6124/5479/4715 6125/5476/4712 6119/5475/4711 +f 4641/5456/4692 6120/5474/4710 4623/5432/4668 +f 4642/5454/4690 6121/5478/4714 6120/5474/4710 +f 6120/5474/4710 6125/5476/4712 4624/5435/4671 +f 4646/5481/4717 6122/5477/4713 4643/5451/4687 +f 4645/5482/4718 6123/5480/4716 6122/5477/4713 +f 6122/5477/4713 6121/5478/4714 4642/5454/4690 +f 4625/5437/4673 6124/5479/4715 4644/5483/4719 +f 4624/5435/4671 6125/5476/4712 6124/5479/4715 +f 6124/5479/4715 6123/5480/4716 4645/5482/4718 +f 6127/5484/4720 6128/5488/4724 6126/5485/4721 +f 6129/5487/4723 6130/5490/4726 6126/5485/4721 +f 6131/5489/4725 6132/5486/4722 6126/5485/4721 +f 4626/5491/4727 6127/5484/4720 4646/5481/4717 +f 4627/5492/4728 6128/5488/4724 6127/5484/4720 +f 6127/5484/4720 6132/5486/4722 4645/5482/4718 +f 4305/4584/3899 6129/5487/4723 4628/5493/4729 +f 4306/4587/3902 6130/5490/4726 6129/5487/4723 +f 6129/5487/4723 6128/5488/4724 4627/5492/4728 +f 4644/5483/4719 6131/5489/4725 4307/4582/3897 +f 4645/5482/4718 6132/5486/4722 6131/5489/4725 +f 6131/5489/4725 6130/5490/4726 4306/4587/3902 +f 6134/5494/4730 6135/5498/4734 6133/5495/4731 +f 6136/5497/4733 6137/5500/4736 6133/5495/4731 +f 6138/5499/4735 6139/5496/4732 6133/5495/4731 +f 4647/5473/4709 6134/5494/4730 4629/5446/4682 +f 4648/5470/4706 6135/5498/4734 6134/5494/4730 +f 6134/5494/4730 6139/5496/4732 4630/5449/4685 +f 4652/5501/4737 6136/5497/4733 4649/5467/4703 +f 4651/5502/4738 6137/5500/4736 6136/5497/4733 +f 6136/5497/4733 6135/5498/4734 4648/5470/4706 +f 4631/5452/4688 6138/5499/4735 4650/5503/4739 +f 4630/5449/4685 6139/5496/4732 6138/5499/4735 +f 6138/5499/4735 6137/5500/4736 4651/5502/4738 +f 6141/5504/4740 6142/5508/4744 6140/5505/4741 +f 6143/5507/4743 6144/5510/4746 6140/5505/4741 +f 6145/5509/4745 6146/5506/4742 6140/5505/4741 +f 4638/5511/4747 6141/5504/4740 4652/5501/4737 +f 4639/5512/4748 6142/5508/4744 6141/5504/4740 +f 6141/5504/4740 6146/5506/4742 4651/5502/4738 +f 4655/5513/4749 6143/5507/4743 4640/5514/4750 +f 4654/5516/4752 6144/5510/4746 6143/5507/4743 +f 6143/5507/4743 6142/5508/4744 4639/5512/4748 +f 4650/5503/4739 6145/5509/4745 4653/5517/4753 +f 4651/5502/4738 6146/5506/4742 6145/5509/4745 +f 6145/5509/4745 6144/5510/4746 4654/5516/4752 +f 6148/5518/4754 6149/5522/4758 6147/5519/4755 +f 6150/5521/4757 6151/5524/4760 6147/5519/4755 +f 6152/5523/4759 6153/5520/4756 6147/5519/4755 +f 4653/5517/4753 6148/5518/4754 4626/5491/4727 +f 4654/5516/4752 6149/5522/4758 6148/5518/4754 +f 6148/5518/4754 6153/5520/4756 4627/5492/4728 +f 4658/5525/4761 6150/5521/4757 4655/5513/4749 +f 4657/5526/4762 6151/5524/4760 6150/5521/4757 +f 6150/5521/4757 6149/5522/4758 4654/5516/4752 +f 4628/5493/4729 6152/5523/4759 4656/5527/4763 +f 4627/5492/4728 6153/5520/4756 6152/5523/4759 +f 6152/5523/4759 6151/5524/4760 4657/5526/4762 +f 6155/5528/4764 6156/5532/4768 6154/5529/4765 +f 6157/5531/4767 6158/5534/4770 6154/5529/4765 +f 6159/5533/4769 6160/5530/4766 6154/5529/4765 +f 4632/5535/4771 6155/5528/4764 4658/5525/4761 +f 4633/5536/4772 6156/5532/4768 6155/5528/4764 +f 6155/5528/4764 6160/5530/4766 4657/5526/4762 +f 4302/4609/3924 6157/5531/4767 4634/5537/4773 +f 4303/4607/3922 6158/5534/4770 6157/5531/4767 +f 6157/5531/4767 6156/5532/4768 4633/5536/4772 +f 4656/5527/4763 6159/5533/4769 4304/4606/3921 +f 4657/5526/4762 6160/5530/4766 6159/5533/4769 +f 6159/5533/4769 6158/5534/4770 4303/4607/3922 +f 6162/5538/4774 6163/5542/4778 6161/5539/4775 +f 6164/5541/4777 6165/5544/4780 6161/5539/4775 +f 6166/5543/4779 6167/5540/4776 6161/5539/4775 +f 4659/4342/3658 6162/5538/4774 4635/5464/4700 +f 4660/4340/3656 6163/5542/4778 6162/5538/4774 +f 6162/5538/4774 6167/5540/4776 4636/5471/4707 +f 4664/5545/4781 6164/5541/4777 4661/4339/3655 +f 4663/5546/4782 6165/5544/4780 6164/5541/4777 +f 6164/5541/4777 6163/5542/4778 4660/4340/3656 +f 4637/5468/4704 6166/5543/4779 4662/5547/4783 +f 4636/5471/4707 6167/5540/4776 6166/5543/4779 +f 6166/5543/4779 6165/5544/4780 4663/5546/4782 +f 6169/5548/4784 6170/5552/4788 6168/5549/4785 +f 6171/5551/4787 6172/5554/4790 6168/5549/4785 +f 6173/5553/4789 6174/5550/4786 6168/5549/4785 +f 4253/5555/4791 6169/5548/4784 4664/5545/4781 +f 4253/5555/4791 4252/5560/4796 6170/5552/4788 +f 4664/5545/4781 6169/5548/4784 6174/5550/4786 +f 4667/5556/4792 6171/5551/4787 4251/5557/4793 +f 4666/5559/4795 6172/5554/4790 6171/5551/4787 +f 6171/5551/4787 6170/5552/4788 4252/5560/4796 +f 4662/5547/4783 6173/5553/4789 4665/5561/4797 +f 4663/5546/4782 6174/5550/4786 6173/5553/4789 +f 6173/5553/4789 6172/5554/4790 4666/5559/4795 +f 6176/5562/4798 6177/5566/4802 6175/5563/4799 +f 6178/5565/4801 6179/5568/4804 6175/5563/4799 +f 6180/5567/4803 6181/5564/4800 6175/5563/4799 +f 4665/5561/4797 6176/5562/4798 4638/5511/4747 +f 4666/5559/4795 6177/5566/4802 6176/5562/4798 +f 6176/5562/4798 6181/5564/4800 4639/5512/4748 +f 4670/5569/4805 6178/5565/4801 4667/5556/4792 +f 4669/5570/4806 6179/5568/4804 6178/5565/4801 +f 6178/5565/4801 6177/5566/4802 4666/5559/4795 +f 4640/5514/4750 6180/5567/4803 4668/5571/4807 +f 4639/5512/4748 6181/5564/4800 6180/5567/4803 +f 6180/5567/4803 6179/5568/4804 4669/5570/4806 +f 6183/5572/4808 6184/5576/4812 6182/5573/4809 +f 6185/5575/4811 6186/5578/4814 6182/5573/4809 +f 6187/5577/4813 6188/5574/4810 6182/5573/4809 +f 4250/5579/4815 6183/5572/4808 4670/5569/4805 +f 4249/5580/4816 6184/5576/4812 6183/5572/4808 +f 6183/5572/4808 6188/5574/4810 4669/5570/4806 +f 4673/5581/4817 6185/5575/4811 4248/5582/4818 +f 4673/5581/4817 4672/5585/4821 6186/5578/4814 +f 6185/5575/4811 6184/5576/4812 4249/5580/4816 +f 4668/5571/4807 6187/5577/4813 4671/5584/4820 +f 4669/5570/4806 6188/5574/4810 6187/5577/4813 +f 6187/5577/4813 6186/5578/4814 4672/5585/4821 +f 6190/5586/4822 6191/5590/4826 6189/5587/4823 +f 6192/5589/4825 6193/5592/4828 6189/5587/4823 +f 6194/5591/4827 6195/5588/4824 6189/5587/4823 +f 4671/5584/4820 6190/5586/4822 4632/5535/4771 +f 4671/5584/4820 4672/5585/4821 6191/5590/4826 +f 6190/5586/4822 6195/5588/4824 4633/5536/4772 +f 4676/5593/4829 6192/5589/4825 4673/5581/4817 +f 4675/5594/4830 6193/5592/4828 6192/5589/4825 +f 6192/5589/4825 6191/5590/4826 4672/5585/4821 +f 4634/5537/4773 6194/5591/4827 4674/5595/4831 +f 4633/5536/4772 6195/5588/4824 6194/5591/4827 +f 6194/5591/4827 6193/5592/4828 4675/5594/4830 +f 6197/5596/4832 6198/5600/4836 6196/5597/4833 +f 6199/5599/4835 6200/5602/4838 6196/5597/4833 +f 6201/5601/4837 6202/5598/4834 6196/5597/4833 +f 4247/5603/4839 6197/5596/4832 4676/5593/4829 +f 4246/5604/4840 6198/5600/4836 6197/5596/4832 +f 4676/5593/4829 6197/5596/4832 6202/5598/4834 +f 4299/4633/3947 6199/5599/4835 4245/5605/4841 +f 4299/4633/3947 4300/4631/3946 6200/5602/4838 +f 6199/5599/4835 6198/5600/4836 4246/5604/4840 +f 4674/5595/4831 6201/5601/4837 4301/4630/3945 +f 4675/5594/4830 6202/5598/4834 6201/5601/4837 +f 6201/5601/4837 6200/5602/4838 4300/4631/3946 +f 6204/5606/4842 6205/5610/4846 6203/5607/4843 +f 6206/5609/4845 6207/5612/4848 6203/5607/4843 +f 6208/5611/4847 6209/5608/4844 6203/5607/4843 +f 4677/5613/4849 6204/5606/4842 4050/5614/4850 +f 4678/5616/4852 6205/5610/4846 6204/5606/4842 +f 6204/5606/4842 6209/5608/4844 4051/5617/4853 +f 4062/4413/3729 6206/5609/4845 4679/5618/4854 +f 4063/4416/3732 6207/5612/4848 6206/5609/4845 +f 6206/5609/4845 6205/5610/4846 4678/5616/4852 +f 4052/5619/4855 6208/5611/4847 4064/4408/3724 +f 4052/5619/4855 4051/5617/4853 6209/5608/4844 +f 4064/4408/3724 6208/5611/4847 6207/5612/4848 +f 6211/5620/4856 6212/5624/4860 6210/5621/4857 +f 6213/5623/4859 6214/5626/4862 6210/5621/4857 +f 6215/5625/4861 6216/5622/4858 6210/5621/4857 +f 4683/5627/4863 6211/5620/4856 4260/5628/4864 +f 4684/5630/4866 6212/5624/4860 6211/5620/4856 +f 6211/5620/4856 6216/5622/4858 4261/5631/4867 +f 4697/5632/4868 6213/5623/4859 4685/5633/4869 +f 4696/5635/4871 6214/5626/4862 6213/5623/4859 +f 6213/5623/4859 6212/5624/4860 4684/5630/4866 +f 4262/5636/4872 6215/5625/4861 4695/5637/4873 +f 4261/5631/4867 6216/5622/4858 6215/5625/4861 +f 4695/5637/4873 6215/5625/4861 6214/5626/4862 +f 6218/5638/4874 6219/5642/4878 6217/5639/4875 +f 6220/5641/4877 6221/5644/4880 6217/5639/4875 +f 6222/5643/4879 6223/5640/4876 6217/5639/4875 +f 4689/5645/4881 6218/5638/4874 4257/5646/4882 +f 4689/5645/4881 4690/5652/4888 6219/5642/4878 +f 6218/5638/4874 6223/5640/4876 4258/5647/4883 +f 4703/5648/4884 6220/5641/4877 4691/5649/4885 +f 4702/5651/4887 6221/5644/4880 6220/5641/4877 +f 6220/5641/4877 6219/5642/4878 4690/5652/4888 +f 4259/5653/4889 6222/5643/4879 4701/5654/4890 +f 4258/5647/4883 6223/5640/4876 6222/5643/4879 +f 6222/5643/4879 6221/5644/4880 4702/5651/4887 +f 6225/5655/4891 6226/5659/4895 6224/5656/4892 +f 6227/5658/4894 6228/5661/4897 6224/5656/4892 +f 6229/5660/4896 6230/5657/4893 6224/5656/4892 +f 4695/5637/4873 6225/5655/4891 4677/5613/4849 +f 4696/5635/4871 6226/5659/4895 6225/5655/4891 +f 6225/5655/4891 6230/5657/4893 4678/5616/4852 +f 4700/5662/4898 6227/5658/4894 4697/5632/4868 +f 4700/5662/4898 4699/5664/4900 6228/5661/4897 +f 6227/5658/4894 6226/5659/4895 4696/5635/4871 +f 4679/5618/4854 6229/5660/4896 4698/5663/4899 +f 4678/5616/4852 6230/5657/4893 6229/5660/4896 +f 6229/5660/4896 6228/5661/4897 4699/5664/4900 +f 6232/5665/4901 6233/5669/4905 6231/5666/4902 +f 6234/5668/4904 6235/5671/4907 6231/5666/4902 +f 6236/5670/4906 6237/5667/4903 6231/5666/4902 +f 4680/5672/4908 6232/5665/4901 4700/5662/4898 +f 4681/5673/4909 6233/5669/4905 6232/5665/4901 +f 6232/5665/4901 6237/5667/4903 4699/5664/4900 +f 4296/4782/4081 6234/5668/4904 4682/5674/4910 +f 4297/4780/4079 6235/5671/4907 6234/5668/4904 +f 6234/5668/4904 6233/5669/4905 4681/5673/4909 +f 4698/5663/4899 6236/5670/4906 4298/4779/4078 +f 4698/5663/4899 4699/5664/4900 6237/5667/4903 +f 6236/5670/4906 6235/5671/4907 4297/4780/4079 +f 6239/5675/4911 6240/5679/4915 6238/5676/4912 +f 6241/5678/4914 6242/5681/4917 6238/5676/4912 +f 6243/5680/4916 6244/5677/4913 6238/5676/4912 +f 4701/5654/4890 6239/5675/4911 4683/5627/4863 +f 4702/5651/4887 6240/5679/4915 6239/5675/4911 +f 6239/5675/4911 6244/5677/4913 4684/5630/4866 +f 4706/5682/4918 6241/5678/4914 4703/5648/4884 +f 4705/5683/4919 6242/5681/4917 6241/5678/4914 +f 6241/5678/4914 6240/5679/4915 4702/5651/4887 +f 4685/5633/4869 6243/5680/4916 4704/5684/4920 +f 4684/5630/4866 6244/5677/4913 6243/5680/4916 +f 6243/5680/4916 6242/5681/4917 4705/5683/4919 +f 6246/5685/4921 6247/5689/4925 6245/5686/4922 +f 6248/5688/4924 6249/5691/4927 6245/5686/4922 +f 6250/5690/4926 6251/5687/4923 6245/5686/4922 +f 4692/5692/4928 6246/5685/4921 4706/5682/4918 +f 4693/5693/4929 6247/5689/4925 6246/5685/4921 +f 6246/5685/4921 6251/5687/4923 4705/5683/4919 +f 4709/5694/4930 6248/5688/4924 4694/5695/4931 +f 4708/5697/4933 6249/5691/4927 6248/5688/4924 +f 6248/5688/4924 6247/5689/4925 4693/5693/4929 +f 4704/5684/4920 6250/5690/4926 4707/5698/4934 +f 4705/5683/4919 6251/5687/4923 6250/5690/4926 +f 6250/5690/4926 6249/5691/4927 4708/5697/4933 +f 6253/5699/4935 6254/5703/4939 6252/5700/4936 +f 6255/5702/4938 6256/5705/4941 6252/5700/4936 +f 6257/5704/4940 6258/5701/4937 6252/5700/4936 +f 4707/5698/4934 6253/5699/4935 4680/5672/4908 +f 4708/5697/4933 6254/5703/4939 6253/5699/4935 +f 6253/5699/4935 6258/5701/4937 4681/5673/4909 +f 4712/5706/4942 6255/5702/4938 4709/5694/4930 +f 4711/5707/4943 6256/5705/4941 6255/5702/4938 +f 6255/5702/4938 6254/5703/4939 4708/5697/4933 +f 4682/5674/4910 6257/5704/4940 4710/5708/4944 +f 4681/5673/4909 6258/5701/4937 6257/5704/4940 +f 6257/5704/4940 6256/5705/4941 4711/5707/4943 +f 6260/5709/4945 6261/5713/4949 6259/5710/4946 +f 6262/5712/4948 6263/5715/4951 6259/5710/4946 +f 6264/5714/4950 6265/5711/4947 6259/5710/4946 +f 4686/5716/4952 6260/5709/4945 4712/5706/4942 +f 4687/5717/4953 6261/5713/4949 6260/5709/4945 +f 6260/5709/4945 6265/5711/4947 4711/5707/4943 +f 4293/4806/4105 6262/5712/4948 4688/5718/4954 +f 4293/4806/4105 4294/4804/4103 6263/5715/4951 +f 4688/5718/4954 6262/5712/4948 6261/5713/4949 +f 4710/5708/4944 6264/5714/4950 4295/4803/4102 +f 4711/5707/4943 6265/5711/4947 6264/5714/4950 +f 6264/5714/4950 6263/5715/4951 4294/4804/4103 +f 6267/5719/4955 6268/5723/4959 6266/5720/4956 +f 6269/5722/4958 6270/5725/4961 6266/5720/4956 +f 6271/5724/4960 6272/5721/4957 6266/5720/4956 +f 4713/4328/3644 6267/5719/4955 4689/5645/4881 +f 4714/4326/3642 6268/5723/4959 6267/5719/4955 +f 6267/5719/4955 6272/5721/4957 4690/5652/4888 +f 4718/5726/4962 6269/5722/4958 4715/4325/3641 +f 4717/5727/4963 6270/5725/4961 6269/5722/4958 +f 6269/5722/4958 6268/5723/4959 4714/4326/3642 +f 4691/5649/4885 6271/5724/4960 4716/5728/4964 +f 4690/5652/4888 6272/5721/4957 6271/5724/4960 +f 4716/5728/4964 6271/5724/4960 6270/5725/4961 +f 6274/5729/4965 6275/5733/4969 6273/5730/4966 +f 6276/5732/4968 6277/5735/4971 6273/5730/4966 +f 6278/5734/4970 6279/5731/4967 6273/5730/4966 +f 4235/5736/4972 6274/5729/4965 4718/5726/4962 +f 4234/5737/4973 6275/5733/4969 6274/5729/4965 +f 4718/5726/4962 6274/5729/4965 6279/5731/4967 +f 4721/5738/4974 6276/5732/4968 4233/5739/4975 +f 4720/5741/4977 6277/5735/4971 6276/5732/4968 +f 6276/5732/4968 6275/5733/4969 4234/5737/4973 +f 4716/5728/4964 6278/5734/4970 4719/5742/4978 +f 4717/5727/4963 6279/5731/4967 6278/5734/4970 +f 6278/5734/4970 6277/5735/4971 4720/5741/4977 +f 6281/5743/4979 6282/5747/4983 6280/5744/4980 +f 6283/5746/4982 6284/5749/4985 6280/5744/4980 +f 6285/5748/4984 6286/5745/4981 6280/5744/4980 +f 4719/5742/4978 6281/5743/4979 4692/5692/4928 +f 4720/5741/4977 6282/5747/4983 6281/5743/4979 +f 6281/5743/4979 6286/5745/4981 4693/5693/4929 +f 4724/5750/4986 6283/5746/4982 4721/5738/4974 +f 4723/5751/4987 6284/5749/4985 6283/5746/4982 +f 6283/5746/4982 6282/5747/4983 4720/5741/4977 +f 4694/5695/4931 6285/5748/4984 4722/5752/4988 +f 4693/5693/4929 6286/5745/4981 6285/5748/4984 +f 6285/5748/4984 6284/5749/4985 4723/5751/4987 +f 6288/5753/4989 6289/5757/4993 6287/5754/4990 +f 6290/5756/4992 6291/5759/4995 6287/5754/4990 +f 6292/5758/4994 6293/5755/4991 6287/5754/4990 +f 4232/5760/4996 6288/5753/4989 4724/5750/4986 +f 4231/5761/4997 6289/5757/4993 6288/5753/4989 +f 6288/5753/4989 6293/5755/4991 4723/5751/4987 +f 4727/5762/4998 6290/5756/4992 4230/5763/4999 +f 4726/5765/5001 6291/5759/4995 6290/5756/4992 +f 6290/5756/4992 6289/5757/4993 4231/5761/4997 +f 4722/5752/4988 6292/5758/4994 4725/5766/5002 +f 4723/5751/4987 6293/5755/4991 6292/5758/4994 +f 6292/5758/4994 6291/5759/4995 4726/5765/5001 +f 6295/5767/5003 6296/5771/5007 6294/5768/5004 +f 6297/5770/5006 6298/5773/5009 6294/5768/5004 +f 6299/5772/5008 6300/5769/5005 6294/5768/5004 +f 4725/5766/5002 6295/5767/5003 4686/5716/4952 +f 4726/5765/5001 6296/5771/5007 6295/5767/5003 +f 6295/5767/5003 6300/5769/5005 4687/5717/4953 +f 4730/5774/5010 6297/5770/5006 4727/5762/4998 +f 4729/5775/5011 6298/5773/5009 6297/5770/5006 +f 6297/5770/5006 6296/5771/5007 4726/5765/5001 +f 4688/5718/4954 6299/5772/5008 4728/5776/5012 +f 4687/5717/4953 6300/5769/5005 6299/5772/5008 +f 6299/5772/5008 6298/5773/5009 4729/5775/5011 +f 6302/5777/5013 6303/5781/5017 6301/5778/5014 +f 6304/5780/5016 6305/5783/5019 6301/5778/5014 +f 6306/5782/5018 6307/5779/5015 6301/5778/5014 +f 4229/5784/5020 6302/5777/5013 4730/5774/5010 +f 4228/5785/5021 6303/5781/5017 6302/5777/5013 +f 6302/5777/5013 6307/5779/5015 4729/5775/5011 +f 4290/4830/4128 6304/5780/5016 4227/5786/5022 +f 4290/4830/4128 4291/4828/4127 6305/5783/5019 +f 4227/5786/5022 6304/5780/5016 6303/5781/5017 +f 4728/5776/5012 6306/5782/5018 4292/4827/4126 +f 4729/5775/5011 6307/5779/5015 6306/5782/5018 +f 6306/5782/5018 6305/5783/5019 4291/4828/4127 +f 6309/5787/5023 6310/5791/5027 6308/5788/5024 +f 6311/5790/5026 6312/5793/5029 6308/5788/5024 +f 6313/5792/5028 6314/5789/5025 6308/5788/5024 +f 4731/5794/5030 6309/5787/5023 4044/5795/5031 +f 4732/5797/5033 6310/5791/5027 6309/5787/5023 +f 6309/5787/5023 6314/5789/5025 4045/5798/5034 +f 4059/4394/3710 6311/5790/5026 4733/5799/5035 +f 4060/4397/3713 6312/5793/5029 6311/5790/5026 +f 6311/5790/5026 6310/5791/5027 4732/5797/5033 +f 4046/5800/5036 6313/5792/5028 4061/4389/3705 +f 4046/5800/5036 4045/5798/5034 6314/5789/5025 +f 4061/4389/3705 6313/5792/5028 6312/5793/5029 +f 6316/5801/5037 6317/5805/5041 6315/5802/5038 +f 6318/5804/5040 6319/5807/5043 6315/5802/5038 +f 6320/5806/5042 6321/5803/5039 6315/5802/5038 +f 4737/5808/5044 6316/5801/5037 4242/5809/5045 +f 4738/5811/5047 6317/5805/5041 6316/5801/5037 +f 6316/5801/5037 6321/5803/5039 4243/5812/5048 +f 4751/5813/5049 6318/5804/5040 4739/5814/5050 +f 4750/5816/5052 6319/5807/5043 6318/5804/5040 +f 6318/5804/5040 6317/5805/5041 4738/5811/5047 +f 4244/5817/5053 6320/5806/5042 4749/5818/5054 +f 4243/5812/5048 6321/5803/5039 6320/5806/5042 +f 4749/5818/5054 6320/5806/5042 6319/5807/5043 +f 6323/5819/5055 6324/5823/5059 6322/5820/5056 +f 6325/5822/5058 6326/5825/5061 6322/5820/5056 +f 6327/5824/5060 6328/5821/5057 6322/5820/5056 +f 4743/5826/5062 6323/5819/5055 4239/5827/5063 +f 4744/5828/5064 6324/5823/5059 6323/5819/5055 +f 6323/5819/5055 6328/5821/5057 4240/5829/5065 +f 4757/5830/5066 6325/5822/5058 4745/5831/5067 +f 4756/5833/5069 6326/5825/5061 6325/5822/5058 +f 6325/5822/5058 6324/5823/5059 4744/5828/5064 +f 4241/5834/5070 6327/5824/5060 4755/5835/5071 +f 4240/5829/5065 6328/5821/5057 6327/5824/5060 +f 6327/5824/5060 6326/5825/5061 4756/5833/5069 +f 6330/5836/5072 6331/5840/5076 6329/5837/5073 +f 6332/5839/5075 6333/5842/5078 6329/5837/5073 +f 6334/5841/5077 6335/5838/5074 6329/5837/5073 +f 4749/5818/5054 6330/5836/5072 4731/5794/5030 +f 4750/5816/5052 6331/5840/5076 6330/5836/5072 +f 6330/5836/5072 6335/5838/5074 4732/5797/5033 +f 4754/5843/5079 6332/5839/5075 4751/5813/5049 +f 4753/5844/5080 6333/5842/5078 6332/5839/5075 +f 6332/5839/5075 6331/5840/5076 4750/5816/5052 +f 4733/5799/5035 6334/5841/5077 4752/5845/5081 +f 4732/5797/5033 6335/5838/5074 6334/5841/5077 +f 6334/5841/5077 6333/5842/5078 4753/5844/5080 +f 6337/5846/5082 6338/5850/5086 6336/5847/5083 +f 6339/5849/5085 6340/5852/5088 6336/5847/5083 +f 6341/5851/5087 6342/5848/5084 6336/5847/5083 +f 4734/5853/5089 6337/5846/5082 4754/5843/5079 +f 4735/5854/5090 6338/5850/5086 6337/5846/5082 +f 6337/5846/5082 6342/5848/5084 4753/5844/5080 +f 4287/4979/4262 6339/5849/5085 4736/5855/5091 +f 4288/4977/4260 6340/5852/5088 6339/5849/5085 +f 6339/5849/5085 6338/5850/5086 4735/5854/5090 +f 4752/5845/5081 6341/5851/5087 4289/4976/4259 +f 4752/5845/5081 4753/5844/5080 6342/5848/5084 +f 6341/5851/5087 6340/5852/5088 4288/4977/4260 +f 6344/5856/5092 6345/5860/5096 6343/5857/5093 +f 6346/5859/5095 6347/5862/5098 6343/5857/5093 +f 6348/5861/5097 6349/5858/5094 6343/5857/5093 +f 4755/5835/5071 6344/5856/5092 4737/5808/5044 +f 4756/5833/5069 6345/5860/5096 6344/5856/5092 +f 6344/5856/5092 6349/5858/5094 4738/5811/5047 +f 4760/5863/5099 6346/5859/5095 4757/5830/5066 +f 4759/5864/5100 6347/5862/5098 6346/5859/5095 +f 6346/5859/5095 6345/5860/5096 4756/5833/5069 +f 4739/5814/5050 6348/5861/5097 4758/5865/5101 +f 4738/5811/5047 6349/5858/5094 6348/5861/5097 +f 6348/5861/5097 6347/5862/5098 4759/5864/5100 +f 6351/5866/5102 6352/5870/5106 6350/5867/5103 +f 6353/5869/5105 6354/5872/5108 6350/5867/5103 +f 6355/5871/5107 6356/5868/5104 6350/5867/5103 +f 4746/5873/5109 6351/5866/5102 4760/5863/5099 +f 4747/5874/5110 6352/5870/5106 6351/5866/5102 +f 6351/5866/5102 6356/5868/5104 4759/5864/5100 +f 4763/5875/5111 6353/5869/5105 4748/5876/5112 +f 4762/5878/5114 6354/5872/5108 6353/5869/5105 +f 6353/5869/5105 6352/5870/5106 4747/5874/5110 +f 4758/5865/5101 6355/5871/5107 4761/5879/5115 +f 4759/5864/5100 6356/5868/5104 6355/5871/5107 +f 6355/5871/5107 6354/5872/5108 4762/5878/5114 +f 6358/5880/5116 6359/5884/5120 6357/5881/5117 +f 6360/5883/5119 6361/5886/5122 6357/5881/5117 +f 6362/5885/5121 6363/5882/5118 6357/5881/5117 +f 4761/5879/5115 6358/5880/5116 4734/5853/5089 +f 4762/5878/5114 6359/5884/5120 6358/5880/5116 +f 6358/5880/5116 6363/5882/5118 4735/5854/5090 +f 4766/5887/5123 6360/5883/5119 4763/5875/5111 +f 4765/5888/5124 6361/5886/5122 6360/5883/5119 +f 6360/5883/5119 6359/5884/5120 4762/5878/5114 +f 4736/5855/5091 6362/5885/5121 4764/5889/5125 +f 4735/5854/5090 6363/5882/5118 6362/5885/5121 +f 6362/5885/5121 6361/5886/5122 4765/5888/5124 +f 6365/5890/5126 6366/5894/5130 6364/5891/5127 +f 6367/5893/5129 6368/5896/5132 6364/5891/5127 +f 6369/5895/5131 6370/5892/5128 6364/5891/5127 +f 4740/5897/5133 6365/5890/5126 4766/5887/5123 +f 4741/5898/5134 6366/5894/5130 6365/5890/5126 +f 6365/5890/5126 6370/5892/5128 4765/5888/5124 +f 4284/5003/4286 6367/5893/5129 4742/5899/5135 +f 4285/5001/4284 6368/5896/5132 6367/5893/5129 +f 4742/5899/5135 6367/5893/5129 6366/5894/5130 +f 4764/5889/5125 6369/5895/5131 4286/5000/4283 +f 4765/5888/5124 6370/5892/5128 6369/5895/5131 +f 6369/5895/5131 6368/5896/5132 4285/5001/4284 +f 6372/5900/5136 6373/5904/5140 6371/5901/5137 +f 6374/5903/5139 6375/5906/5142 6371/5901/5137 +f 6376/5905/5141 6377/5902/5138 6371/5901/5137 +f 4767/4314/3630 6372/5900/5136 4743/5826/5062 +f 4768/4312/3628 6373/5904/5140 6372/5900/5136 +f 6372/5900/5136 6377/5902/5138 4744/5828/5064 +f 4772/5907/5143 6374/5903/5139 4769/4311/3627 +f 4771/5908/5144 6375/5906/5142 6374/5903/5139 +f 6374/5903/5139 6373/5904/5140 4768/4312/3628 +f 4745/5831/5067 6376/5905/5141 4770/5909/5145 +f 4744/5828/5064 6377/5902/5138 6376/5905/5141 +f 6376/5905/5141 6375/5906/5142 4771/5908/5144 +f 6379/5910/5146 6380/5914/5150 6378/5911/5147 +f 6381/5913/5149 6382/5916/5152 6378/5911/5147 +f 6383/5915/5151 6384/5912/5148 6378/5911/5147 +f 4217/5917/5153 6379/5910/5146 4772/5907/5143 +f 4217/5917/5153 4216/5922/5158 6380/5914/5150 +f 4772/5907/5143 6379/5910/5146 6384/5912/5148 +f 4775/5918/5154 6381/5913/5149 4215/5919/5155 +f 4774/5921/5157 6382/5916/5152 6381/5913/5149 +f 6381/5913/5149 6380/5914/5150 4216/5922/5158 +f 4770/5909/5145 6383/5915/5151 4773/5923/5159 +f 4771/5908/5144 6384/5912/5148 6383/5915/5151 +f 6383/5915/5151 6382/5916/5152 4774/5921/5157 +f 6386/5924/5160 6387/5928/5164 6385/5925/5161 +f 6388/5927/5163 6389/5930/5166 6385/5925/5161 +f 6390/5929/5165 6391/5926/5162 6385/5925/5161 +f 4773/5923/5159 6386/5924/5160 4746/5873/5109 +f 4774/5921/5157 6387/5928/5164 6386/5924/5160 +f 6386/5924/5160 6391/5926/5162 4747/5874/5110 +f 4778/5931/5167 6388/5927/5163 4775/5918/5154 +f 4777/5932/5168 6389/5930/5166 6388/5927/5163 +f 6388/5927/5163 6387/5928/5164 4774/5921/5157 +f 4748/5876/5112 6390/5929/5165 4776/5933/5169 +f 4747/5874/5110 6391/5926/5162 6390/5929/5165 +f 6390/5929/5165 6389/5930/5166 4777/5932/5168 +f 6393/5934/5170 6394/5938/5174 6392/5935/5171 +f 6395/5937/5173 6396/5940/5176 6392/5935/5171 +f 6397/5939/5175 6398/5936/5172 6392/5935/5171 +f 4214/5941/5177 6393/5934/5170 4778/5931/5167 +f 4213/5942/5178 6394/5938/5174 6393/5934/5170 +f 6393/5934/5170 6398/5936/5172 4777/5932/5168 +f 4781/5943/5179 6395/5937/5173 4212/5944/5180 +f 4781/5943/5179 4780/5947/5183 6396/5940/5176 +f 6395/5937/5173 6394/5938/5174 4213/5942/5178 +f 4776/5933/5169 6397/5939/5175 4779/5946/5182 +f 4777/5932/5168 6398/5936/5172 6397/5939/5175 +f 6397/5939/5175 6396/5940/5176 4780/5947/5183 +f 6400/5948/5184 6401/5952/5188 6399/5949/5185 +f 6402/5951/5187 6403/5954/5190 6399/5949/5185 +f 6404/5953/5189 6405/5950/5186 6399/5949/5185 +f 4779/5946/5182 6400/5948/5184 4740/5897/5133 +f 4780/5947/5183 6401/5952/5188 6400/5948/5184 +f 6400/5948/5184 6405/5950/5186 4741/5898/5134 +f 4784/5955/5191 6402/5951/5187 4781/5943/5179 +f 4783/5956/5192 6403/5954/5190 6402/5951/5187 +f 6402/5951/5187 6401/5952/5188 4780/5947/5183 +f 4742/5899/5135 6404/5953/5189 4782/5957/5193 +f 4741/5898/5134 6405/5950/5186 6404/5953/5189 +f 6404/5953/5189 6403/5954/5190 4783/5956/5192 +f 6407/5958/5194 6408/5962/5198 6406/5959/5195 +f 6409/5961/5197 6410/5964/5200 6406/5959/5195 +f 6411/5963/5199 6412/5960/5196 6406/5959/5195 +f 4211/5965/5201 6407/5958/5194 4784/5955/5191 +f 4210/5966/5202 6408/5962/5198 6407/5958/5194 +f 6407/5958/5194 6412/5960/5196 4783/5956/5192 +f 4281/5027/4309 6409/5961/5197 4209/5967/5203 +f 4281/5027/4309 4282/5025/4308 6410/5964/5200 +f 4209/5967/5203 6409/5961/5197 6408/5962/5198 +f 4782/5957/5193 6411/5963/5199 4283/5024/4307 +f 4783/5956/5192 6412/5960/5196 6411/5963/5199 +f 6411/5963/5199 6410/5964/5200 4282/5025/4308 +f 6414/5968/5204 6415/5972/5208 6413/5969/5205 +f 6416/5971/5207 6417/5974/5210 6413/5969/5205 +f 6418/5973/5209 6419/5970/5206 6413/5969/5205 +f 4785/5975/5211 6414/5968/5204 4038/5976/5212 +f 4786/5978/5214 6415/5972/5208 6414/5968/5204 +f 6414/5968/5204 6419/5970/5206 4039/5979/5215 +f 4056/4376/3692 6416/5971/5207 4787/5980/5216 +f 4057/4373/3689 6417/5974/5210 6416/5971/5207 +f 6416/5971/5207 6415/5972/5208 4786/5978/5214 +f 4040/5981/5217 6418/5973/5209 4058/4370/3686 +f 4040/5981/5217 4039/5979/5215 6419/5970/5206 +f 4058/4370/3686 6418/5973/5209 6417/5974/5210 +f 6421/5982/5218 6422/5986/5222 6420/5983/5219 +f 6423/5985/5221 6424/5988/5224 6420/5983/5219 +f 6425/5987/5223 6426/5984/5220 6420/5983/5219 +f 4791/5989/5225 6421/5982/5218 4224/5990/5226 +f 4791/5989/5225 4792/5997/5233 6422/5986/5222 +f 4224/5990/5226 6421/5982/5218 6426/5984/5220 +f 4805/5993/5229 6423/5985/5221 4793/5994/5230 +f 4804/5996/5232 6424/5988/5224 6423/5985/5221 +f 6423/5985/5221 6422/5986/5222 4792/5997/5233 +f 4226/5998/5234 6425/5987/5223 4803/5999/5235 +f 4225/5992/5228 6426/5984/5220 6425/5987/5223 +f 6425/5987/5223 6424/5988/5224 4804/5996/5232 +f 6428/6000/5236 6429/6004/5240 6427/6001/5237 +f 6430/6003/5239 6431/6006/5242 6427/6001/5237 +f 6432/6005/5241 6433/6002/5238 6427/6001/5237 +f 4797/6007/5243 6428/6000/5236 4221/6008/5244 +f 4797/6007/5243 4798/6014/5250 6429/6004/5240 +f 4221/6008/5244 6428/6000/5236 6433/6002/5238 +f 4811/6010/5246 6430/6003/5239 4799/6011/5247 +f 4810/6013/5249 6431/6006/5242 6430/6003/5239 +f 6430/6003/5239 6429/6004/5240 4798/6014/5250 +f 4223/6015/5251 6432/6005/5241 4809/6016/5252 +f 4222/6009/5245 6433/6002/5238 6432/6005/5241 +f 6432/6005/5241 6431/6006/5242 4810/6013/5249 +f 6435/6017/5253 6436/6021/5257 6434/6018/5254 +f 6437/6020/5256 6438/6023/5259 6434/6018/5254 +f 6439/6022/5258 6440/6019/5255 6434/6018/5254 +f 4803/5999/5235 6435/6017/5253 4785/5975/5211 +f 4804/5996/5232 6436/6021/5257 6435/6017/5253 +f 6435/6017/5253 6440/6019/5255 4786/5978/5214 +f 4808/6024/5260 6437/6020/5256 4805/5993/5229 +f 4807/6025/5261 6438/6023/5259 6437/6020/5256 +f 6437/6020/5256 6436/6021/5257 4804/5996/5232 +f 4787/5980/5216 6439/6022/5258 4806/6026/5262 +f 4787/5980/5216 4786/5978/5214 6440/6019/5255 +f 4806/6026/5262 6439/6022/5258 6438/6023/5259 +f 6442/6027/5263 6443/6031/5267 6441/6028/5264 +f 6444/6030/5266 6445/6033/5269 6441/6028/5264 +f 6446/6032/5268 6447/6029/5265 6441/6028/5264 +f 4788/6034/5270 6442/6027/5263 4808/6024/5260 +f 4788/6034/5270 4789/6036/5272 6443/6031/5267 +f 4808/6024/5260 6442/6027/5263 6447/6029/5265 +f 4278/5177/4443 6444/6030/5266 4790/6035/5271 +f 4279/5175/4441 6445/6033/5269 6444/6030/5266 +f 6444/6030/5266 6443/6031/5267 4789/6036/5272 +f 4806/6026/5262 6446/6032/5268 4280/5174/4440 +f 4807/6025/5261 6447/6029/5265 6446/6032/5268 +f 6446/6032/5268 6445/6033/5269 4279/5175/4441 +f 6449/6037/5273 6450/6041/5277 6448/6038/5274 +f 6451/6040/5276 6452/6043/5279 6448/6038/5274 +f 6453/6042/5278 6454/6039/5275 6448/6038/5274 +f 4809/6016/5252 6449/6037/5273 4791/5989/5225 +f 4810/6013/5249 6450/6041/5277 6449/6037/5273 +f 6449/6037/5273 6454/6039/5275 4792/5997/5233 +f 4814/6044/5280 6451/6040/5276 4811/6010/5246 +f 4813/6045/5281 6452/6043/5279 6451/6040/5276 +f 6451/6040/5276 6450/6041/5277 4810/6013/5249 +f 4793/5994/5230 6453/6042/5278 4812/6046/5282 +f 4793/5994/5230 4792/5997/5233 6454/6039/5275 +f 4812/6046/5282 6453/6042/5278 6452/6043/5279 +f 6456/6047/5283 6457/6051/5287 6455/6048/5284 +f 6458/6050/5286 6459/6053/5289 6455/6048/5284 +f 6460/6052/5288 6461/6049/5285 6455/6048/5284 +f 4800/6054/5290 6456/6047/5283 4814/6044/5280 +f 4801/6055/5291 6457/6051/5287 6456/6047/5283 +f 4814/6044/5280 6456/6047/5283 6461/6049/5285 +f 4817/6056/5292 6458/6050/5286 4802/6057/5293 +f 4816/6059/5295 6459/6053/5289 6458/6050/5286 +f 6458/6050/5286 6457/6051/5287 4801/6055/5291 +f 4812/6046/5282 6460/6052/5288 4815/6060/5296 +f 4813/6045/5281 6461/6049/5285 6460/6052/5288 +f 6460/6052/5288 6459/6053/5289 4816/6059/5295 +f 6463/6061/5297 6464/6065/5301 6462/6062/5298 +f 6465/6064/5300 6466/6067/5303 6462/6062/5298 +f 6467/6066/5302 6468/6063/5299 6462/6062/5298 +f 4815/6060/5296 6463/6061/5297 4788/6034/5270 +f 4816/6059/5295 6464/6065/5301 6463/6061/5297 +f 6463/6061/5297 6468/6063/5299 4789/6036/5272 +f 4820/6068/5304 6465/6064/5300 4817/6056/5292 +f 4819/6069/5305 6466/6067/5303 6465/6064/5300 +f 6465/6064/5300 6464/6065/5301 4816/6059/5295 +f 4790/6035/5271 6467/6066/5302 4818/6070/5306 +f 4790/6035/5271 4789/6036/5272 6468/6063/5299 +f 4818/6070/5306 6467/6066/5302 6466/6067/5303 +f 6470/6071/5307 6471/6075/5311 6469/6072/5308 +f 6472/6074/5310 6473/6077/5313 6469/6072/5308 +f 6474/6076/5312 6475/6073/5309 6469/6072/5308 +f 4794/6078/5314 6470/6071/5307 4820/6068/5304 +f 4795/6079/5315 6471/6075/5311 6470/6071/5307 +f 4820/6068/5304 6470/6071/5307 6475/6073/5309 +f 4275/5201/4467 6472/6074/5310 4796/6080/5316 +f 4276/5199/4465 6473/6077/5313 6472/6074/5310 +f 6472/6074/5310 6471/6075/5311 4795/6079/5315 +f 4818/6070/5306 6474/6076/5312 4277/5198/4464 +f 4819/6069/5305 6475/6073/5309 6474/6076/5312 +f 6474/6076/5312 6473/6077/5313 4276/5199/4465 +f 6477/6081/5317 6478/6085/5321 6476/6082/5318 +f 6479/6084/5320 6480/6087/5323 6476/6082/5318 +f 6481/6086/5322 6482/6083/5319 6476/6082/5318 +f 4821/4300/3616 6477/6081/5317 4797/6007/5243 +f 4822/4298/3614 6478/6085/5321 6477/6081/5317 +f 6477/6081/5317 6482/6083/5319 4798/6014/5250 +f 4826/6088/5324 6479/6084/5320 4823/4297/3613 +f 4825/6089/5325 6480/6087/5323 6479/6084/5320 +f 6479/6084/5320 6478/6085/5321 4822/4298/3614 +f 4799/6011/5247 6481/6086/5322 4824/6090/5326 +f 4799/6011/5247 4798/6014/5250 6482/6083/5319 +f 4824/6090/5326 6481/6086/5322 6480/6087/5323 +f 6484/6091/5327 6485/6095/5331 6483/6092/5328 +f 6486/6094/5330 6487/6097/5333 6483/6092/5328 +f 6488/6096/5332 6489/6093/5329 6483/6092/5328 +f 4199/6098/5334 6484/6091/5327 4826/6088/5324 +f 4198/6099/5335 6485/6095/5331 6484/6091/5327 +f 6484/6091/5327 6489/6093/5329 4825/6089/5325 +f 4829/6100/5336 6486/6094/5330 4197/6101/5337 +f 4828/6103/5339 6487/6097/5333 6486/6094/5330 +f 6486/6094/5330 6485/6095/5331 4198/6099/5335 +f 4824/6090/5326 6488/6096/5332 4827/6104/5340 +f 4825/6089/5325 6489/6093/5329 6488/6096/5332 +f 6488/6096/5332 6487/6097/5333 4828/6103/5339 +f 6491/6105/5341 6492/6109/5345 6490/6106/5342 +f 6493/6108/5344 6494/6111/5347 6490/6106/5342 +f 6495/6110/5346 6496/6107/5343 6490/6106/5342 +f 4827/6104/5340 6491/6105/5341 4800/6054/5290 +f 4828/6103/5339 6492/6109/5345 6491/6105/5341 +f 6491/6105/5341 6496/6107/5343 4801/6055/5291 +f 4832/6112/5348 6493/6108/5344 4829/6100/5336 +f 4831/6113/5349 6494/6111/5347 6493/6108/5344 +f 6493/6108/5344 6492/6109/5345 4828/6103/5339 +f 4802/6057/5293 6495/6110/5346 4830/6114/5350 +f 4801/6055/5291 6496/6107/5343 6495/6110/5346 +f 6495/6110/5346 6494/6111/5347 4831/6113/5349 +f 6498/6115/5351 6499/6119/5355 6497/6116/5352 +f 6500/6118/5354 6501/6121/5357 6497/6116/5352 +f 6502/6120/5356 6503/6117/5353 6497/6116/5352 +f 4196/6122/5358 6498/6115/5351 4832/6112/5348 +f 4195/6123/5359 6499/6119/5355 6498/6115/5351 +f 6498/6115/5351 6503/6117/5353 4831/6113/5349 +f 4835/6124/5360 6500/6118/5354 4194/6125/5361 +f 4834/6127/5363 6501/6121/5357 6500/6118/5354 +f 6500/6118/5354 6499/6119/5355 4195/6123/5359 +f 4830/6114/5350 6502/6120/5356 4833/6128/5364 +f 4831/6113/5349 6503/6117/5353 6502/6120/5356 +f 6502/6120/5356 6501/6121/5357 4834/6127/5363 +f 6505/6129/5365 6506/6133/5369 6504/6130/5366 +f 6507/6132/5368 6508/6135/5371 6504/6130/5366 +f 6509/6134/5370 6510/6131/5367 6504/6130/5366 +f 4833/6128/5364 6505/6129/5365 4794/6078/5314 +f 4834/6127/5363 6506/6133/5369 6505/6129/5365 +f 6505/6129/5365 6510/6131/5367 4795/6079/5315 +f 4838/6136/5372 6507/6132/5368 4835/6124/5360 +f 4837/6137/5373 6508/6135/5371 6507/6132/5368 +f 6507/6132/5368 6506/6133/5369 4834/6127/5363 +f 4796/6080/5316 6509/6134/5370 4836/6138/5374 +f 4795/6079/5315 6510/6131/5367 6509/6134/5370 +f 6509/6134/5370 6508/6135/5371 4837/6137/5373 +f 6512/6139/5375 6513/6143/5379 6511/6140/5376 +f 6514/6142/5378 6515/6145/5381 6511/6140/5376 +f 6516/6144/5380 6517/6141/5377 6511/6140/5376 +f 4193/6146/5382 6512/6139/5375 4838/6136/5372 +f 4192/6147/5383 6513/6143/5379 6512/6139/5375 +f 6512/6139/5375 6517/6141/5377 4837/6137/5373 +f 4272/5225/4490 6514/6142/5378 4191/6148/5384 +f 4273/5223/4489 6515/6145/5381 6514/6142/5378 +f 4191/6148/5384 6514/6142/5378 6513/6143/5379 +f 4836/6138/5374 6516/6144/5380 4274/5222/4488 +f 4837/6137/5373 6517/6141/5377 6516/6144/5380 +f 6516/6144/5380 6515/6145/5381 4273/5223/4489 +f 6519/6149/5385 6520/6153/5389 6518/6150/5386 +f 6521/6152/5388 6522/6155/5391 6518/6150/5386 +f 6523/6154/5390 6524/6151/5387 6518/6150/5386 +f 4839/6156/5392 6519/6149/5385 4032/6157/5393 +f 4840/6159/5395 6520/6153/5389 6519/6149/5385 +f 6519/6149/5385 6524/6151/5387 4033/6160/5396 +f 4053/4356/3672 6521/6152/5388 4841/6161/5397 +f 4054/4359/3675 6522/6155/5391 6521/6152/5388 +f 6521/6152/5388 6520/6153/5389 4840/6159/5395 +f 4034/6162/5398 6523/6154/5390 4055/4351/3667 +f 4034/6162/5398 4033/6160/5396 6524/6151/5387 +f 4055/4351/3667 6523/6154/5390 6522/6155/5391 +f 6526/6163/5399 6527/6167/5403 6525/6164/5400 +f 6528/6166/5402 6529/6169/5405 6525/6164/5400 +f 6530/6168/5404 6531/6165/5401 6525/6164/5400 +f 4845/6170/5406 6526/6163/5399 4206/6171/5407 +f 4846/6173/5409 6527/6167/5403 6526/6163/5399 +f 6526/6163/5399 6531/6165/5401 4207/6174/5410 +f 4859/6175/5411 6528/6166/5402 4847/6176/5412 +f 4858/6178/5414 6529/6169/5405 6528/6166/5402 +f 6528/6166/5402 6527/6167/5403 4846/6173/5409 +f 4208/6179/5415 6530/6168/5404 4857/6180/5416 +f 4207/6174/5410 6531/6165/5401 6530/6168/5404 +f 4857/6180/5416 6530/6168/5404 6529/6169/5405 +f 6533/6181/5417 6534/6185/5421 6532/6182/5418 +f 6535/6184/5420 6536/6187/5423 6532/6182/5418 +f 6537/6186/5422 6538/6183/5419 6532/6182/5418 +f 4851/6188/5424 6533/6181/5417 4203/6189/5425 +f 4852/6190/5426 6534/6185/5421 6533/6181/5417 +f 6533/6181/5417 6538/6183/5419 4204/6191/5427 +f 4865/6192/5428 6535/6184/5420 4853/6193/5429 +f 4865/6192/5428 4864/6197/5433 6536/6187/5423 +f 6535/6184/5420 6534/6185/5421 4852/6190/5426 +f 4205/6195/5431 6537/6186/5422 4863/6196/5432 +f 4204/6191/5427 6538/6183/5419 6537/6186/5422 +f 6537/6186/5422 6536/6187/5423 4864/6197/5433 +f 6540/6198/5434 6541/6202/5438 6539/6199/5435 +f 6542/6201/5437 6543/6204/5440 6539/6199/5435 +f 6544/6203/5439 6545/6200/5436 6539/6199/5435 +f 4857/6180/5416 6540/6198/5434 4839/6156/5392 +f 4858/6178/5414 6541/6202/5438 6540/6198/5434 +f 6540/6198/5434 6545/6200/5436 4840/6159/5395 +f 4862/6205/5441 6542/6201/5437 4859/6175/5411 +f 4862/6205/5441 4861/6207/5443 6543/6204/5440 +f 6542/6201/5437 6541/6202/5438 4858/6178/5414 +f 4841/6161/5397 6544/6203/5439 4860/6206/5442 +f 4840/6159/5395 6545/6200/5436 6544/6203/5439 +f 6544/6203/5439 6543/6204/5440 4861/6207/5443 +f 6547/6208/5444 6548/6212/5448 6546/6209/5445 +f 6549/6211/5447 6550/6214/5450 6546/6209/5445 +f 6551/6213/5449 6552/6210/5446 6546/6209/5445 +f 4842/6215/5451 6547/6208/5444 4862/6205/5441 +f 4843/6216/5452 6548/6212/5448 6547/6208/5444 +f 6547/6208/5444 6552/6210/5446 4861/6207/5443 +f 4269/5374/4613 6549/6211/5447 4844/6217/5453 +f 4270/5372/4611 6550/6214/5450 6549/6211/5447 +f 6549/6211/5447 6548/6212/5448 4843/6216/5452 +f 4860/6206/5442 6551/6213/5449 4271/5371/4610 +f 4860/6206/5442 4861/6207/5443 6552/6210/5446 +f 6551/6213/5449 6550/6214/5450 4270/5372/4611 +f 6554/6218/5454 6555/6222/5458 6553/6219/5455 +f 6556/6221/5457 6557/6224/5460 6553/6219/5455 +f 6558/6223/5459 6559/6220/5456 6553/6219/5455 +f 4863/6196/5432 6554/6218/5454 4845/6170/5406 +f 4863/6196/5432 4864/6197/5433 6555/6222/5458 +f 4845/6170/5406 6554/6218/5454 6559/6220/5456 +f 4868/6225/5461 6556/6221/5457 4865/6192/5428 +f 4867/6226/5462 6557/6224/5460 6556/6221/5457 +f 6556/6221/5457 6555/6222/5458 4864/6197/5433 +f 4847/6176/5412 6558/6223/5459 4866/6227/5463 +f 4846/6173/5409 6559/6220/5456 6558/6223/5459 +f 6558/6223/5459 6557/6224/5460 4867/6226/5462 +f 6561/6228/5464 6562/6232/5468 6560/6229/5465 +f 6563/6231/5467 6564/6234/5470 6560/6229/5465 +f 6565/6233/5469 6566/6230/5466 6560/6229/5465 +f 4854/6235/5471 6561/6228/5464 4868/6225/5461 +f 4855/6236/5472 6562/6232/5468 6561/6228/5464 +f 6561/6228/5464 6566/6230/5466 4867/6226/5462 +f 4871/6237/5473 6563/6231/5467 4856/6238/5474 +f 4870/6240/5476 6564/6234/5470 6563/6231/5467 +f 6563/6231/5467 6562/6232/5468 4855/6236/5472 +f 4866/6227/5463 6565/6233/5469 4869/6241/5477 +f 4867/6226/5462 6566/6230/5466 6565/6233/5469 +f 6565/6233/5469 6564/6234/5470 4870/6240/5476 +f 6568/6242/5478 6569/6246/5482 6567/6243/5479 +f 6570/6245/5481 6571/6248/5484 6567/6243/5479 +f 6572/6247/5483 6573/6244/5480 6567/6243/5479 +f 4869/6241/5477 6568/6242/5478 4842/6215/5451 +f 4870/6240/5476 6569/6246/5482 6568/6242/5478 +f 6568/6242/5478 6573/6244/5480 4843/6216/5452 +f 4874/6249/5485 6570/6245/5481 4871/6237/5473 +f 4873/6250/5486 6571/6248/5484 6570/6245/5481 +f 6570/6245/5481 6569/6246/5482 4870/6240/5476 +f 4844/6217/5453 6572/6247/5483 4872/6251/5487 +f 4843/6216/5452 6573/6244/5480 6572/6247/5483 +f 6572/6247/5483 6571/6248/5484 4873/6250/5486 +f 6575/6252/5488 6576/6256/5492 6574/6253/5489 +f 6577/6255/5491 6578/6258/5494 6574/6253/5489 +f 6579/6257/5493 6580/6254/5490 6574/6253/5489 +f 4848/6259/5495 6575/6252/5488 4874/6249/5485 +f 4849/6260/5496 6576/6256/5492 6575/6252/5488 +f 6575/6252/5488 6580/6254/5490 4873/6250/5486 +f 4266/5398/4637 6577/6255/5491 4850/6261/5497 +f 4267/5396/4635 6578/6258/5494 6577/6255/5491 +f 6577/6255/5491 6576/6256/5492 4849/6260/5496 +f 4872/6251/5487 6579/6257/5493 4268/5395/4634 +f 4873/6250/5486 6580/6254/5490 6579/6257/5493 +f 4268/5395/4634 6579/6257/5493 6578/6258/5494 +f 6582/6262/5498 6583/6266/5502 6581/6263/5499 +f 6584/6265/5501 6585/6268/5504 6581/6263/5499 +f 6586/6267/5503 6587/6264/5500 6581/6263/5499 +f 4875/4286/3602 6582/6262/5498 4851/6188/5424 +f 4876/4284/3600 6583/6266/5502 6582/6262/5498 +f 6582/6262/5498 6587/6264/5500 4852/6190/5426 +f 4880/6269/5505 6584/6265/5501 4877/4283/3599 +f 4879/6270/5506 6585/6268/5504 6584/6265/5501 +f 6584/6265/5501 6583/6266/5502 4876/4284/3600 +f 4853/6193/5429 6586/6267/5503 4878/6271/5507 +f 4852/6190/5426 6587/6264/5500 6586/6267/5503 +f 6586/6267/5503 6585/6268/5504 4879/6270/5506 +f 6589/6272/5508 6590/6276/5512 6588/6273/5509 +f 6591/6275/5511 6592/6278/5514 6588/6273/5509 +f 6593/6277/5513 6594/6274/5510 6588/6273/5509 +f 4181/6279/5515 6589/6272/5508 4880/6269/5505 +f 4180/6280/5516 6590/6276/5512 6589/6272/5508 +f 6589/6272/5508 6594/6274/5510 4879/6270/5506 +f 4883/6281/5517 6591/6275/5511 4179/6282/5518 +f 4882/6284/5520 6592/6278/5514 6591/6275/5511 +f 6591/6275/5511 6590/6276/5512 4180/6280/5516 +f 4878/6271/5507 6593/6277/5513 4881/6285/5521 +f 4879/6270/5506 6594/6274/5510 6593/6277/5513 +f 6593/6277/5513 6592/6278/5514 4882/6284/5520 +f 6596/6286/5522 6597/6290/5526 6595/6287/5523 +f 6598/6289/5525 6599/6292/5528 6595/6287/5523 +f 6600/6291/5527 6601/6288/5524 6595/6287/5523 +f 4881/6285/5521 6596/6286/5522 4854/6235/5471 +f 4882/6284/5520 6597/6290/5526 6596/6286/5522 +f 6596/6286/5522 6601/6288/5524 4855/6236/5472 +f 4886/6293/5529 6598/6289/5525 4883/6281/5517 +f 4885/6294/5530 6599/6292/5528 6598/6289/5525 +f 6598/6289/5525 6597/6290/5526 4882/6284/5520 +f 4856/6238/5474 6600/6291/5527 4884/6295/5531 +f 4855/6236/5472 6601/6288/5524 6600/6291/5527 +f 6600/6291/5527 6599/6292/5528 4885/6294/5530 +f 6603/6296/5532 6604/6300/5536 6602/6297/5533 +f 6605/6299/5535 6606/6302/5538 6602/6297/5533 +f 6607/6301/5537 6608/6298/5534 6602/6297/5533 +f 4178/6303/5539 6603/6296/5532 4886/6293/5529 +f 4177/6304/5540 6604/6300/5536 6603/6296/5532 +f 6603/6296/5532 6608/6298/5534 4885/6294/5530 +f 4889/6305/5541 6605/6299/5535 4176/6306/5542 +f 4888/6308/5544 6606/6302/5538 6605/6299/5535 +f 6605/6299/5535 6604/6300/5536 4177/6304/5540 +f 4884/6295/5531 6607/6301/5537 4887/6309/5545 +f 4885/6294/5530 6608/6298/5534 6607/6301/5537 +f 6607/6301/5537 6606/6302/5538 4888/6308/5544 +f 6610/6310/5546 6611/6314/5550 6609/6311/5547 +f 6612/6313/5549 6613/6316/5552 6609/6311/5547 +f 6614/6315/5551 6615/6312/5548 6609/6311/5547 +f 4887/6309/5545 6610/6310/5546 4848/6259/5495 +f 4888/6308/5544 6611/6314/5550 6610/6310/5546 +f 6610/6310/5546 6615/6312/5548 4849/6260/5496 +f 4892/6317/5553 6612/6313/5549 4889/6305/5541 +f 4892/6317/5553 4891/6319/5555 6613/6316/5552 +f 6612/6313/5549 6611/6314/5550 4888/6308/5544 +f 4850/6261/5497 6614/6315/5551 4890/6318/5554 +f 4849/6260/5496 6615/6312/5548 6614/6315/5551 +f 6614/6315/5551 6613/6316/5552 4891/6319/5555 +f 6617/6320/5556 6618/6324/5560 6616/6321/5557 +f 6619/6323/5559 6620/6326/5562 6616/6321/5557 +f 6621/6325/5561 6622/6322/5558 6616/6321/5557 +f 4175/6327/5563 6617/6320/5556 4892/6317/5553 +f 4174/6328/5564 6618/6324/5560 6617/6320/5556 +f 6617/6320/5556 6622/6322/5558 4891/6319/5555 +f 4263/5422/4660 6619/6323/5559 4173/6329/5565 +f 4263/5422/4660 4264/5420/4659 6620/6326/5562 +f 4173/6329/5565 6619/6323/5559 6618/6324/5560 +f 4890/6318/5554 6621/6325/5561 4265/5419/4658 +f 4890/6318/5554 4891/6319/5555 6622/6322/5558 +f 6621/6325/5561 6620/6326/5562 4264/5420/4659 +f 6624/6330/5566 6625/6334/5570 6623/6331/5567 +f 6626/6333/5569 6627/6336/5572 6623/6331/5567 +f 6628/6335/5571 6629/6332/5568 6623/6331/5567 +f 4893/6337/5573 6624/6330/5566 4247/5603/4839 +f 4894/6338/5574 6625/6334/5570 6624/6330/5566 +f 6624/6330/5566 6629/6332/5568 4246/5604/4840 +f 4050/5614/4850 6626/6333/5569 4895/6339/5575 +f 4051/5617/4853 6627/6336/5572 6626/6333/5569 +f 6626/6333/5569 6625/6334/5570 4894/6338/5574 +f 4245/5605/4841 6628/6335/5571 4052/5619/4855 +f 4245/5605/4841 4246/5604/4840 6629/6332/5568 +f 4052/5619/4855 6628/6335/5571 6627/6336/5572 +f 6631/6340/5576 6632/6344/5580 6630/6341/5577 +f 6633/6343/5579 6634/6346/5582 6630/6341/5577 +f 6635/6345/5581 6636/6342/5578 6630/6341/5577 +f 4899/6347/5583 6631/6340/5576 4250/5579/4815 +f 4900/6348/5584 6632/6344/5580 6631/6340/5576 +f 6631/6340/5576 6636/6342/5578 4249/5580/4816 +f 4913/6349/5585 6633/6343/5579 4901/6350/5586 +f 4912/6352/5588 6634/6346/5582 6633/6343/5579 +f 6633/6343/5579 6632/6344/5580 4900/6348/5584 +f 4248/5582/4818 6635/6345/5581 4911/6353/5589 +f 4248/5582/4818 4249/5580/4816 6636/6342/5578 +f 4911/6353/5589 6635/6345/5581 6634/6346/5582 +f 6638/6354/5590 6639/6358/5594 6637/6355/5591 +f 6640/6357/5593 6641/6360/5596 6637/6355/5591 +f 6642/6359/5595 6643/6356/5592 6637/6355/5591 +f 4905/6361/5597 6638/6354/5590 4253/5555/4791 +f 4905/6361/5597 4906/6366/5602 6639/6358/5594 +f 6638/6354/5590 6643/6356/5592 4252/5560/4796 +f 4919/6362/5598 6640/6357/5593 4907/6363/5599 +f 4918/6365/5601 6641/6360/5596 6640/6357/5593 +f 6640/6357/5593 6639/6358/5594 4906/6366/5602 +f 4251/5557/4793 6642/6359/5595 4917/6367/5603 +f 4252/5560/4796 6643/6356/5592 6642/6359/5595 +f 4917/6367/5603 6642/6359/5595 6641/6360/5596 +f 6645/6368/5604 6646/6372/5608 6644/6369/5605 +f 6647/6371/5607 6648/6374/5610 6644/6369/5605 +f 6649/6373/5609 6650/6370/5606 6644/6369/5605 +f 4911/6353/5589 6645/6368/5604 4893/6337/5573 +f 4912/6352/5588 6646/6372/5608 6645/6368/5604 +f 6645/6368/5604 6650/6370/5606 4894/6338/5574 +f 4916/6375/5611 6647/6371/5607 4913/6349/5585 +f 4916/6375/5611 4915/6377/5613 6648/6374/5610 +f 4913/6349/5585 6647/6371/5607 6646/6372/5608 +f 4895/6339/5575 6649/6373/5609 4914/6376/5612 +f 4894/6338/5574 6650/6370/5606 6649/6373/5609 +f 6649/6373/5609 6648/6374/5610 4915/6377/5613 +f 6652/6378/5614 6653/6382/5618 6651/6379/5615 +f 6654/6381/5617 6655/6384/5620 6651/6379/5615 +f 6656/6383/5619 6657/6380/5616 6651/6379/5615 +f 4896/6385/5621 6652/6378/5614 4916/6375/5611 +f 4897/6386/5622 6653/6382/5618 6652/6378/5614 +f 6652/6378/5614 6657/6380/5616 4915/6377/5613 +f 4260/5628/4864 6654/6381/5617 4898/6387/5623 +f 4261/5631/4867 6655/6384/5620 6654/6381/5617 +f 6654/6381/5617 6653/6382/5618 4897/6386/5622 +f 4914/6376/5612 6656/6383/5619 4262/5636/4872 +f 4914/6376/5612 4915/6377/5613 6657/6380/5616 +f 6656/6383/5619 6655/6384/5620 4261/5631/4867 +f 6659/6388/5624 6660/6392/5628 6658/6389/5625 +f 6661/6391/5627 6662/6394/5630 6658/6389/5625 +f 6663/6393/5629 6664/6390/5626 6658/6389/5625 +f 4917/6367/5603 6659/6388/5624 4899/6347/5583 +f 4918/6365/5601 6660/6392/5628 6659/6388/5624 +f 6659/6388/5624 6664/6390/5626 4900/6348/5584 +f 4922/6395/5631 6661/6391/5627 4919/6362/5598 +f 4921/6396/5632 6662/6394/5630 6661/6391/5627 +f 6661/6391/5627 6660/6392/5628 4918/6365/5601 +f 4901/6350/5586 6663/6393/5629 4920/6397/5633 +f 4900/6348/5584 6664/6390/5626 6663/6393/5629 +f 6663/6393/5629 6662/6394/5630 4921/6396/5632 +f 6666/6398/5634 6667/6402/5638 6665/6399/5635 +f 6668/6401/5637 6669/6404/5640 6665/6399/5635 +f 6670/6403/5639 6671/6400/5636 6665/6399/5635 +f 4908/6405/5641 6666/6398/5634 4922/6395/5631 +f 4909/6406/5642 6667/6402/5638 6666/6398/5634 +f 6666/6398/5634 6671/6400/5636 4921/6396/5632 +f 4925/6407/5643 6668/6401/5637 4910/6408/5644 +f 4924/6410/5646 6669/6404/5640 6668/6401/5637 +f 6668/6401/5637 6667/6402/5638 4909/6406/5642 +f 4920/6397/5633 6670/6403/5639 4923/6411/5647 +f 4921/6396/5632 6671/6400/5636 6670/6403/5639 +f 6670/6403/5639 6669/6404/5640 4924/6410/5646 +f 6673/6412/5648 6674/6416/5652 6672/6413/5649 +f 6675/6415/5651 6676/6418/5654 6672/6413/5649 +f 6677/6417/5653 6678/6414/5650 6672/6413/5649 +f 4923/6411/5647 6673/6412/5648 4896/6385/5621 +f 4924/6410/5646 6674/6416/5652 6673/6412/5648 +f 6673/6412/5648 6678/6414/5650 4897/6386/5622 +f 4928/6419/5655 6675/6415/5651 4925/6407/5643 +f 4927/6420/5656 6676/6418/5654 6675/6415/5651 +f 6675/6415/5651 6674/6416/5652 4924/6410/5646 +f 4898/6387/5623 6677/6417/5653 4926/6421/5657 +f 4897/6386/5622 6678/6414/5650 6677/6417/5653 +f 6677/6417/5653 6676/6418/5654 4927/6420/5656 +f 6680/6422/5658 6681/6426/5662 6679/6423/5659 +f 6682/6425/5661 6683/6428/5664 6679/6423/5659 +f 6684/6427/5663 6685/6424/5660 6679/6423/5659 +f 4902/6429/5665 6680/6422/5658 4928/6419/5655 +f 4903/6430/5666 6681/6426/5662 6680/6422/5658 +f 6680/6422/5658 6685/6424/5660 4927/6420/5656 +f 4257/5646/4882 6682/6425/5661 4904/6431/5667 +f 4258/5647/4883 6683/6428/5664 6682/6425/5661 +f 6682/6425/5661 6681/6426/5662 4903/6430/5666 +f 4926/6421/5657 6684/6427/5663 4259/5653/4889 +f 4927/6420/5656 6685/6424/5660 6684/6427/5663 +f 6684/6427/5663 6683/6428/5664 4258/5647/4883 +f 6687/6432/5668 6688/6436/5672 6686/6433/5669 +f 6689/6435/5671 6690/6438/5674 6686/6433/5669 +f 6691/6437/5673 6692/6434/5670 6686/6433/5669 +f 4929/4272/3588 6687/6432/5668 4905/6361/5597 +f 4930/4269/3585 6688/6436/5672 6687/6432/5668 +f 6687/6432/5668 6692/6434/5670 4906/6366/5602 +f 4934/6439/5675 6689/6435/5671 4931/4266/3582 +f 4933/6440/5676 6690/6438/5674 6689/6435/5671 +f 6689/6435/5671 6688/6436/5672 4930/4269/3585 +f 4907/6363/5599 6691/6437/5673 4932/6441/5677 +f 4906/6366/5602 6692/6434/5670 6691/6437/5673 +f 6691/6437/5673 6690/6438/5674 4933/6440/5676 +f 6694/6442/5678 6695/6446/5682 6693/6443/5679 +f 6696/6445/5681 6697/6448/5684 6693/6443/5679 +f 6698/6447/5683 6699/6444/5680 6693/6443/5679 +f 4172/6449/5685 6694/6442/5678 4934/6439/5675 +f 4171/6450/5686 6695/6446/5682 6694/6442/5678 +f 6694/6442/5678 6699/6444/5680 4933/6440/5676 +f 4937/6451/5687 6696/6445/5681 4170/6452/5688 +f 4936/6454/5690 6697/6448/5684 6696/6445/5681 +f 6696/6445/5681 6695/6446/5682 4171/6450/5686 +f 4932/6441/5677 6698/6447/5683 4935/6455/5691 +f 4933/6440/5676 6699/6444/5680 6698/6447/5683 +f 6698/6447/5683 6697/6448/5684 4936/6454/5690 +f 6701/6456/5692 6702/6460/5696 6700/6457/5693 +f 6703/6459/5695 6704/6462/5698 6700/6457/5693 +f 6705/6461/5697 6706/6458/5694 6700/6457/5693 +f 4935/6455/5691 6701/6456/5692 4908/6405/5641 +f 4936/6454/5690 6702/6460/5696 6701/6456/5692 +f 6701/6456/5692 6706/6458/5694 4909/6406/5642 +f 4940/6463/5699 6703/6459/5695 4937/6451/5687 +f 4939/6464/5700 6704/6462/5698 6703/6459/5695 +f 6703/6459/5695 6702/6460/5696 4936/6454/5690 +f 4910/6408/5644 6705/6461/5697 4938/6465/5701 +f 4909/6406/5642 6706/6458/5694 6705/6461/5697 +f 6705/6461/5697 6704/6462/5698 4939/6464/5700 +f 6708/6466/5702 6709/6470/5706 6707/6467/5703 +f 6710/6469/5705 6711/6472/5708 6707/6467/5703 +f 6712/6471/5707 6713/6468/5704 6707/6467/5703 +f 4169/6473/5709 6708/6466/5702 4940/6463/5699 +f 4168/6474/5710 6709/6470/5706 6708/6466/5702 +f 6708/6466/5702 6713/6468/5704 4939/6464/5700 +f 4943/6475/5711 6710/6469/5705 4167/6476/5712 +f 4943/6475/5711 4942/6479/5715 6711/6472/5708 +f 6710/6469/5705 6709/6470/5706 4168/6474/5710 +f 4938/6465/5701 6712/6471/5707 4941/6478/5714 +f 4939/6464/5700 6713/6468/5704 6712/6471/5707 +f 6712/6471/5707 6711/6472/5708 4942/6479/5715 +f 6715/6480/5716 6716/6484/5720 6714/6481/5717 +f 6717/6483/5719 6718/6486/5722 6714/6481/5717 +f 6719/6485/5721 6720/6482/5718 6714/6481/5717 +f 4941/6478/5714 6715/6480/5716 4902/6429/5665 +f 4942/6479/5715 6716/6484/5720 6715/6480/5716 +f 6715/6480/5716 6720/6482/5718 4903/6430/5666 +f 4946/6487/5723 6717/6483/5719 4943/6475/5711 +f 4945/6488/5724 6718/6486/5722 6717/6483/5719 +f 6717/6483/5719 6716/6484/5720 4942/6479/5715 +f 4904/6431/5667 6719/6485/5721 4944/6489/5725 +f 4903/6430/5666 6720/6482/5718 6719/6485/5721 +f 6719/6485/5721 6718/6486/5722 4945/6488/5724 +f 6722/6490/5726 6723/6494/5730 6721/6491/5727 +f 6724/6493/5729 6725/6496/5732 6721/6491/5727 +f 6726/6495/5731 6727/6492/5728 6721/6491/5727 +f 4166/6497/5733 6722/6490/5726 4946/6487/5723 +f 4165/6498/5734 6723/6494/5730 6722/6490/5726 +f 6722/6490/5726 6727/6492/5728 4945/6488/5724 +f 4254/4323/3639 6724/6493/5729 4164/6499/5735 +f 4254/4323/3639 4255/4324/3640 6725/6496/5732 +f 4164/6499/5735 6724/6493/5729 6723/6494/5730 +f 4944/6489/5725 6726/6495/5731 4256/4327/3643 +f 4945/6488/5724 6727/6492/5728 6726/6495/5731 +f 6726/6495/5731 6725/6496/5732 4255/4324/3640 +f 6729/6500/5736 6730/6504/5740 6728/6501/5737 +f 6731/6503/5739 6732/6506/5742 6728/6501/5737 +f 6733/6505/5741 6734/6502/5738 6728/6501/5737 +f 4947/6507/5743 6729/6500/5736 4229/5784/5020 +f 4948/6508/5744 6730/6504/5740 6729/6500/5736 +f 6729/6500/5736 6734/6502/5738 4228/5785/5021 +f 4044/5795/5031 6731/6503/5739 4949/6509/5745 +f 4045/5798/5034 6732/6506/5742 6731/6503/5739 +f 6731/6503/5739 6730/6504/5740 4948/6508/5744 +f 4227/5786/5022 6733/6505/5741 4046/5800/5036 +f 4227/5786/5022 4228/5785/5021 6734/6502/5738 +f 4046/5800/5036 6733/6505/5741 6732/6506/5742 +f 6736/6510/5746 6737/6514/5750 6735/6511/5747 +f 6738/6513/5749 6739/6516/5752 6735/6511/5747 +f 6740/6515/5751 6741/6512/5748 6735/6511/5747 +f 4953/6517/5753 6736/6510/5746 4232/5760/4996 +f 4954/6518/5754 6737/6514/5750 6736/6510/5746 +f 6736/6510/5746 6741/6512/5748 4231/5761/4997 +f 4967/6519/5755 6738/6513/5749 4955/6520/5756 +f 4966/6522/5758 6739/6516/5752 6738/6513/5749 +f 6738/6513/5749 6737/6514/5750 4954/6518/5754 +f 4230/5763/4999 6740/6515/5751 4965/6523/5759 +f 4231/5761/4997 6741/6512/5748 6740/6515/5751 +f 4965/6523/5759 6740/6515/5751 6739/6516/5752 +f 6743/6524/5760 6744/6528/5764 6742/6525/5761 +f 6745/6527/5763 6746/6530/5766 6742/6525/5761 +f 6747/6529/5765 6748/6526/5762 6742/6525/5761 +f 4959/6531/5767 6743/6524/5760 4235/5736/4972 +f 4959/6531/5767 4960/6536/5772 6744/6528/5764 +f 6743/6524/5760 6748/6526/5762 4234/5737/4973 +f 4973/6532/5768 6745/6527/5763 4961/6533/5769 +f 4972/6535/5771 6746/6530/5766 6745/6527/5763 +f 6745/6527/5763 6744/6528/5764 4960/6536/5772 +f 4233/5739/4975 6747/6529/5765 4971/6537/5773 +f 4234/5737/4973 6748/6526/5762 6747/6529/5765 +f 6747/6529/5765 6746/6530/5766 4972/6535/5771 +f 6750/6538/5774 6751/6542/5778 6749/6539/5775 +f 6752/6541/5777 6753/6544/5780 6749/6539/5775 +f 6754/6543/5779 6755/6540/5776 6749/6539/5775 +f 4965/6523/5759 6750/6538/5774 4947/6507/5743 +f 4966/6522/5758 6751/6542/5778 6750/6538/5774 +f 6750/6538/5774 6755/6540/5776 4948/6508/5744 +f 4970/6545/5781 6752/6541/5777 4967/6519/5755 +f 4969/6546/5782 6753/6544/5780 6752/6541/5777 +f 6752/6541/5777 6751/6542/5778 4966/6522/5758 +f 4949/6509/5745 6754/6543/5779 4968/6547/5783 +f 4948/6508/5744 6755/6540/5776 6754/6543/5779 +f 6754/6543/5779 6753/6544/5780 4969/6546/5782 +f 6757/6548/5784 6758/6552/5788 6756/6549/5785 +f 6759/6551/5787 6760/6554/5790 6756/6549/5785 +f 6761/6553/5789 6762/6550/5786 6756/6549/5785 +f 4950/6555/5791 6757/6548/5784 4970/6545/5781 +f 4951/6556/5792 6758/6552/5788 6757/6548/5784 +f 6757/6548/5784 6762/6550/5786 4969/6546/5782 +f 4242/5809/5045 6759/6551/5787 4952/6557/5793 +f 4243/5812/5048 6760/6554/5790 6759/6551/5787 +f 6759/6551/5787 6758/6552/5788 4951/6556/5792 +f 4968/6547/5783 6761/6553/5789 4244/5817/5053 +f 4968/6547/5783 4969/6546/5782 6762/6550/5786 +f 6761/6553/5789 6760/6554/5790 4243/5812/5048 +f 6764/6558/5794 6765/6562/5798 6763/6559/5795 +f 6766/6561/5797 6767/6564/5800 6763/6559/5795 +f 6768/6563/5799 6769/6560/5796 6763/6559/5795 +f 4971/6537/5773 6764/6558/5794 4953/6517/5753 +f 4972/6535/5771 6765/6562/5798 6764/6558/5794 +f 6764/6558/5794 6769/6560/5796 4954/6518/5754 +f 4976/6565/5801 6766/6561/5797 4973/6532/5768 +f 4975/6566/5802 6767/6564/5800 6766/6561/5797 +f 6766/6561/5797 6765/6562/5798 4972/6535/5771 +f 4955/6520/5756 6768/6563/5799 4974/6567/5803 +f 4954/6518/5754 6769/6560/5796 6768/6563/5799 +f 6768/6563/5799 6767/6564/5800 4975/6566/5802 +f 6771/6568/5804 6772/6572/5808 6770/6569/5805 +f 6773/6571/5807 6774/6574/5810 6770/6569/5805 +f 6775/6573/5809 6776/6570/5806 6770/6569/5805 +f 4962/6575/5811 6771/6568/5804 4976/6565/5801 +f 4963/6576/5812 6772/6572/5808 6771/6568/5804 +f 6771/6568/5804 6776/6570/5806 4975/6566/5802 +f 4979/6577/5813 6773/6571/5807 4964/6578/5814 +f 4978/6580/5816 6774/6574/5810 6773/6571/5807 +f 6773/6571/5807 6772/6572/5808 4963/6576/5812 +f 4974/6567/5803 6775/6573/5809 4977/6581/5817 +f 4975/6566/5802 6776/6570/5806 6775/6573/5809 +f 6775/6573/5809 6774/6574/5810 4978/6580/5816 +f 6778/6582/5818 6779/6586/5822 6777/6583/5819 +f 6780/6585/5821 6781/6588/5824 6777/6583/5819 +f 6782/6587/5823 6783/6584/5820 6777/6583/5819 +f 4977/6581/5817 6778/6582/5818 4950/6555/5791 +f 4978/6580/5816 6779/6586/5822 6778/6582/5818 +f 6778/6582/5818 6783/6584/5820 4951/6556/5792 +f 4982/6589/5825 6780/6585/5821 4979/6577/5813 +f 4981/6590/5826 6781/6588/5824 6780/6585/5821 +f 6780/6585/5821 6779/6586/5822 4978/6580/5816 +f 4952/6557/5793 6782/6587/5823 4980/6591/5827 +f 4951/6556/5792 6783/6584/5820 6782/6587/5823 +f 6782/6587/5823 6781/6588/5824 4981/6590/5826 +f 6785/6592/5828 6786/6596/5832 6784/6593/5829 +f 6787/6595/5831 6788/6598/5834 6784/6593/5829 +f 6789/6597/5833 6790/6594/5830 6784/6593/5829 +f 4956/6599/5835 6785/6592/5828 4982/6589/5825 +f 4957/6600/5836 6786/6596/5832 6785/6592/5828 +f 6785/6592/5828 6790/6594/5830 4981/6590/5826 +f 4239/5827/5063 6787/6595/5831 4958/6601/5837 +f 4240/5829/5065 6788/6598/5834 6787/6595/5831 +f 6787/6595/5831 6786/6596/5832 4957/6600/5836 +f 4980/6591/5827 6789/6597/5833 4241/5834/5070 +f 4981/6590/5826 6790/6594/5830 6789/6597/5833 +f 6789/6597/5833 6788/6598/5834 4240/5829/5065 +f 6792/6602/5838 6793/6606/5842 6791/6603/5839 +f 6794/6605/5841 6795/6608/5844 6791/6603/5839 +f 6796/6607/5843 6797/6604/5840 6791/6603/5839 +f 4983/4253/3569 6792/6602/5838 4959/6531/5767 +f 4984/4250/3566 6793/6606/5842 6792/6602/5838 +f 6792/6602/5838 6797/6604/5840 4960/6536/5772 +f 4988/6609/5845 6794/6605/5841 4985/4247/3563 +f 4987/6610/5846 6795/6608/5844 6794/6605/5841 +f 6794/6605/5841 6793/6606/5842 4984/4250/3566 +f 4961/6533/5769 6796/6607/5843 4986/6611/5847 +f 4960/6536/5772 6797/6604/5840 6796/6607/5843 +f 6796/6607/5843 6795/6608/5844 4987/6610/5846 +f 6799/6612/5848 6800/6616/5852 6798/6613/5849 +f 6801/6615/5851 6802/6618/5854 6798/6613/5849 +f 6803/6617/5853 6804/6614/5850 6798/6613/5849 +f 4163/6619/5855 6799/6612/5848 4988/6609/5845 +f 4163/6619/5855 4162/6624/5860 6800/6616/5852 +f 4988/6609/5845 6799/6612/5848 6804/6614/5850 +f 4991/6620/5856 6801/6615/5851 4161/6621/5857 +f 4990/6623/5859 6802/6618/5854 6801/6615/5851 +f 6801/6615/5851 6800/6616/5852 4162/6624/5860 +f 4986/6611/5847 6803/6617/5853 4989/6625/5861 +f 4987/6610/5846 6804/6614/5850 6803/6617/5853 +f 6803/6617/5853 6802/6618/5854 4990/6623/5859 +f 6806/6626/5862 6807/6630/5866 6805/6627/5863 +f 6808/6629/5865 6809/6632/5868 6805/6627/5863 +f 6810/6631/5867 6811/6628/5864 6805/6627/5863 +f 4989/6625/5861 6806/6626/5862 4962/6575/5811 +f 4990/6623/5859 6807/6630/5866 6806/6626/5862 +f 6806/6626/5862 6811/6628/5864 4963/6576/5812 +f 4994/6633/5869 6808/6629/5865 4991/6620/5856 +f 4993/6634/5870 6809/6632/5868 6808/6629/5865 +f 6808/6629/5865 6807/6630/5866 4990/6623/5859 +f 4964/6578/5814 6810/6631/5867 4992/6635/5871 +f 4963/6576/5812 6811/6628/5864 6810/6631/5867 +f 6810/6631/5867 6809/6632/5868 4993/6634/5870 +f 6813/6636/5872 6814/6640/5876 6812/6637/5873 +f 6815/6639/5875 6816/6642/5878 6812/6637/5873 +f 6817/6641/5877 6818/6638/5874 6812/6637/5873 +f 4160/6643/5879 6813/6636/5872 4994/6633/5869 +f 4159/6644/5880 6814/6640/5876 6813/6636/5872 +f 6813/6636/5872 6818/6638/5874 4993/6634/5870 +f 4997/6645/5881 6815/6639/5875 4158/6646/5882 +f 4997/6645/5881 4996/6649/5885 6816/6642/5878 +f 6815/6639/5875 6814/6640/5876 4159/6644/5880 +f 4992/6635/5871 6817/6641/5877 4995/6648/5884 +f 4993/6634/5870 6818/6638/5874 6817/6641/5877 +f 6817/6641/5877 6816/6642/5878 4996/6649/5885 +f 6820/6650/5886 6821/6654/5890 6819/6651/5887 +f 6822/6653/5889 6823/6656/5892 6819/6651/5887 +f 6824/6655/5891 6825/6652/5888 6819/6651/5887 +f 4995/6648/5884 6820/6650/5886 4956/6599/5835 +f 4996/6649/5885 6821/6654/5890 6820/6650/5886 +f 6820/6650/5886 6825/6652/5888 4957/6600/5836 +f 5000/6657/5893 6822/6653/5889 4997/6645/5881 +f 4999/6658/5894 6823/6656/5892 6822/6653/5889 +f 6822/6653/5889 6821/6654/5890 4996/6649/5885 +f 4958/6601/5837 6824/6655/5891 4998/6659/5895 +f 4958/6601/5837 4957/6600/5836 6825/6652/5888 +f 6824/6655/5891 6823/6656/5892 4999/6658/5894 +f 6827/6660/5896 6828/6664/5900 6826/6661/5897 +f 6829/6663/5899 6830/6666/5902 6826/6661/5897 +f 6831/6665/5901 6832/6662/5898 6826/6661/5897 +f 4157/6667/5903 6827/6660/5896 5000/6657/5893 +f 4156/6668/5904 6828/6664/5900 6827/6660/5896 +f 6827/6660/5896 6832/6662/5898 4999/6658/5894 +f 4236/4309/3625 6829/6663/5899 4155/6669/5905 +f 4236/4309/3625 4237/4310/3626 6830/6666/5902 +f 4155/6669/5905 6829/6663/5899 6828/6664/5900 +f 4998/6659/5895 6831/6665/5901 4238/4313/3629 +f 4999/6658/5894 6832/6662/5898 6831/6665/5901 +f 6831/6665/5901 6830/6666/5902 4237/4310/3626 +f 6834/6670/5906 6835/6674/5910 6833/6671/5907 +f 6836/6673/5909 6837/6676/5912 6833/6671/5907 +f 6838/6675/5911 6839/6672/5908 6833/6671/5907 +f 5001/6677/5913 6834/6670/5906 4211/5965/5201 +f 5002/6678/5914 6835/6674/5910 6834/6670/5906 +f 6834/6670/5906 6839/6672/5908 4210/5966/5202 +f 4038/6679/5212 6836/6673/5909 5003/6680/5915 +f 4039/6682/5215 6837/6676/5912 6836/6673/5909 +f 6836/6673/5909 6835/6674/5910 5002/6678/5914 +f 4209/5967/5203 6838/6675/5911 4040/6683/5217 +f 4209/5967/5203 4210/5966/5202 6839/6672/5908 +f 4040/6683/5217 6838/6675/5911 6837/6676/5912 +f 6841/6684/5916 6842/6688/5920 6840/6685/5917 +f 6843/6687/5919 6844/6690/5922 6840/6685/5917 +f 6845/6689/5921 6846/6686/5918 6840/6685/5917 +f 5007/6691/5923 6841/6684/5916 4214/5941/5177 +f 5008/6692/5924 6842/6688/5920 6841/6684/5916 +f 6841/6684/5916 6846/6686/5918 4213/5942/5178 +f 5021/6693/5925 6843/6687/5919 5009/6694/5926 +f 5020/6696/5928 6844/6690/5922 6843/6687/5919 +f 6843/6687/5919 6842/6688/5920 5008/6692/5924 +f 4212/5944/5180 6845/6689/5921 5019/6697/5929 +f 4213/5942/5178 6846/6686/5918 6845/6689/5921 +f 5019/6697/5929 6845/6689/5921 6844/6690/5922 +f 6848/6698/5930 6849/6702/5934 6847/6699/5931 +f 6850/6701/5933 6851/6704/5936 6847/6699/5931 +f 6852/6703/5935 6853/6700/5932 6847/6699/5931 +f 5013/6705/5937 6848/6698/5930 4217/5917/5153 +f 5014/6706/5938 6849/6702/5934 6848/6698/5930 +f 6848/6698/5930 6853/6700/5932 4216/5922/5158 +f 5027/6707/5939 6850/6701/5933 5015/6708/5940 +f 5026/6710/5942 6851/6704/5936 6850/6701/5933 +f 6850/6701/5933 6849/6702/5934 5014/6706/5938 +f 4215/5919/5155 6852/6703/5935 5025/6711/5943 +f 4216/5922/5158 6853/6700/5932 6852/6703/5935 +f 6852/6703/5935 6851/6704/5936 5026/6710/5942 +f 6855/6712/5944 6856/6716/5948 6854/6713/5945 +f 6857/6715/5947 6858/6718/5950 6854/6713/5945 +f 6859/6717/5949 6860/6714/5946 6854/6713/5945 +f 5019/6697/5929 6855/6712/5944 5001/6677/5913 +f 5020/6696/5928 6856/6716/5948 6855/6712/5944 +f 6855/6712/5944 6860/6714/5946 5002/6678/5914 +f 5024/6719/5951 6857/6715/5947 5021/6693/5925 +f 5023/6720/5952 6858/6718/5950 6857/6715/5947 +f 6857/6715/5947 6856/6716/5948 5020/6696/5928 +f 5003/6680/5915 6859/6717/5949 5022/6721/5953 +f 5002/6678/5914 6860/6714/5946 6859/6717/5949 +f 6859/6717/5949 6858/6718/5950 5023/6720/5952 +f 6862/6722/5954 6863/6726/5958 6861/6723/5955 +f 6864/6725/5957 6865/6728/5960 6861/6723/5955 +f 6866/6727/5959 6867/6724/5956 6861/6723/5955 +f 5004/6729/5961 6862/6722/5954 5024/6719/5951 +f 5005/6730/5962 6863/6726/5958 6862/6722/5954 +f 6862/6722/5954 6867/6724/5956 5023/6720/5952 +f 4224/6731/5226 6864/6725/5957 5006/6732/5963 +f 4225/6734/5228 6865/6728/5960 6864/6725/5957 +f 6864/6725/5957 6863/6726/5958 5005/6730/5962 +f 5022/6721/5953 6866/6727/5959 4226/6735/5234 +f 5022/6721/5953 5023/6720/5952 6867/6724/5956 +f 4226/6735/5234 6866/6727/5959 6865/6728/5960 +f 6869/6736/5964 6870/6740/5968 6868/6737/5965 +f 6871/6739/5967 6872/6742/5970 6868/6737/5965 +f 6873/6741/5969 6874/6738/5966 6868/6737/5965 +f 5025/6711/5943 6869/6736/5964 5007/6691/5923 +f 5026/6710/5942 6870/6740/5968 6869/6736/5964 +f 6869/6736/5964 6874/6738/5966 5008/6692/5924 +f 5030/6743/5971 6871/6739/5967 5027/6707/5939 +f 5029/6744/5972 6872/6742/5970 6871/6739/5967 +f 6871/6739/5967 6870/6740/5968 5026/6710/5942 +f 5009/6694/5926 6873/6741/5969 5028/6745/5973 +f 5008/6692/5924 6874/6738/5966 6873/6741/5969 +f 6873/6741/5969 6872/6742/5970 5029/6744/5972 +f 6876/6746/5974 6877/6750/5978 6875/6747/5975 +f 6878/6749/5977 6879/6752/5980 6875/6747/5975 +f 6880/6751/5979 6881/6748/5976 6875/6747/5975 +f 5016/6753/5981 6876/6746/5974 5030/6743/5971 +f 5017/6754/5982 6877/6750/5978 6876/6746/5974 +f 6876/6746/5974 6881/6748/5976 5029/6744/5972 +f 5033/6755/5983 6878/6749/5977 5018/6756/5984 +f 5032/6758/5986 6879/6752/5980 6878/6749/5977 +f 6878/6749/5977 6877/6750/5978 5017/6754/5982 +f 5028/6745/5973 6880/6751/5979 5031/6759/5987 +f 5029/6744/5972 6881/6748/5976 6880/6751/5979 +f 6880/6751/5979 6879/6752/5980 5032/6758/5986 +f 6883/6760/5988 6884/6764/5992 6882/6761/5989 +f 6885/6763/5991 6886/6766/5994 6882/6761/5989 +f 6887/6765/5993 6888/6762/5990 6882/6761/5989 +f 5031/6759/5987 6883/6760/5988 5004/6729/5961 +f 5032/6758/5986 6884/6764/5992 6883/6760/5988 +f 6883/6760/5988 6888/6762/5990 5005/6730/5962 +f 5036/6767/5995 6885/6763/5991 5033/6755/5983 +f 5035/6768/5996 6886/6766/5994 6885/6763/5991 +f 6885/6763/5991 6884/6764/5992 5032/6758/5986 +f 5006/6732/5963 6887/6765/5993 5034/6769/5997 +f 5005/6730/5962 6888/6762/5990 6887/6765/5993 +f 6887/6765/5993 6886/6766/5994 5035/6768/5996 +f 6890/6770/5998 6891/6774/6002 6889/6771/5999 +f 6892/6773/6001 6893/6776/6004 6889/6771/5999 +f 6894/6775/6003 6895/6772/6000 6889/6771/5999 +f 5010/6777/6005 6890/6770/5998 5036/6767/5995 +f 5011/6778/6006 6891/6774/6002 6890/6770/5998 +f 6890/6770/5998 6895/6772/6000 5035/6768/5996 +f 4221/6779/5244 6892/6773/6001 5012/6780/6007 +f 4222/6782/5245 6893/6776/6004 6892/6773/6001 +f 5012/6780/6007 6892/6773/6001 6891/6774/6002 +f 5034/6769/5997 6894/6775/6003 4223/6783/5251 +f 5034/6769/5997 5035/6768/5996 6895/6772/6000 +f 4223/6783/5251 6894/6775/6003 6893/6776/6004 +f 6897/6784/6008 6898/6788/6012 6896/6785/6009 +f 6899/6787/6011 6900/6790/6014 6896/6785/6009 +f 6901/6789/6013 6902/6786/6010 6896/6785/6009 +f 5037/4234/3550 6897/6784/6008 5013/6705/5937 +f 5038/4232/3548 6898/6788/6012 6897/6784/6008 +f 6897/6784/6008 6902/6786/6010 5014/6706/5938 +f 5042/6791/6015 6899/6787/6011 5039/4229/3545 +f 5041/6792/6016 6900/6790/6014 6899/6787/6011 +f 6899/6787/6011 6898/6788/6012 5038/4232/3548 +f 5015/6708/5940 6901/6789/6013 5040/6793/6017 +f 5014/6706/5938 6902/6786/6010 6901/6789/6013 +f 6901/6789/6013 6900/6790/6014 5041/6792/6016 +f 6904/6794/6018 6905/6798/6022 6903/6795/6019 +f 6906/6797/6021 6907/6800/6024 6903/6795/6019 +f 6908/6799/6023 6909/6796/6020 6903/6795/6019 +f 4145/6801/6025 6904/6794/6018 5042/6791/6015 +f 4144/6802/6026 6905/6798/6022 6904/6794/6018 +f 6904/6794/6018 6909/6796/6020 5041/6792/6016 +f 5045/6803/6027 6906/6797/6021 4143/6804/6028 +f 5044/6806/6030 6907/6800/6024 6906/6797/6021 +f 6906/6797/6021 6905/6798/6022 4144/6802/6026 +f 5040/6793/6017 6908/6799/6023 5043/6807/6031 +f 5041/6792/6016 6909/6796/6020 6908/6799/6023 +f 6908/6799/6023 6907/6800/6024 5044/6806/6030 +f 6911/6808/6032 6912/6812/6036 6910/6809/6033 +f 6913/6811/6035 6914/6814/6038 6910/6809/6033 +f 6915/6813/6037 6916/6810/6034 6910/6809/6033 +f 5043/6807/6031 6911/6808/6032 5016/6753/5981 +f 5044/6806/6030 6912/6812/6036 6911/6808/6032 +f 6911/6808/6032 6916/6810/6034 5017/6754/5982 +f 5048/6815/6039 6913/6811/6035 5045/6803/6027 +f 5047/6816/6040 6914/6814/6038 6913/6811/6035 +f 6913/6811/6035 6912/6812/6036 5044/6806/6030 +f 5018/6756/5984 6915/6813/6037 5046/6817/6041 +f 5017/6754/5982 6916/6810/6034 6915/6813/6037 +f 6915/6813/6037 6914/6814/6038 5047/6816/6040 +f 6918/6818/6042 6919/6822/6046 6917/6819/6043 +f 6920/6821/6045 6921/6824/6048 6917/6819/6043 +f 6922/6823/6047 6923/6820/6044 6917/6819/6043 +f 4142/6825/6049 6918/6818/6042 5048/6815/6039 +f 4141/6826/6050 6919/6822/6046 6918/6818/6042 +f 6918/6818/6042 6923/6820/6044 5047/6816/6040 +f 5051/6827/6051 6920/6821/6045 4140/6828/6052 +f 5050/6830/6054 6921/6824/6048 6920/6821/6045 +f 6920/6821/6045 6919/6822/6046 4141/6826/6050 +f 5046/6817/6041 6922/6823/6047 5049/6831/6055 +f 5047/6816/6040 6923/6820/6044 6922/6823/6047 +f 6922/6823/6047 6921/6824/6048 5050/6830/6054 +f 6925/6832/6056 6926/6836/6060 6924/6833/6057 +f 6927/6835/6059 6928/6838/6062 6924/6833/6057 +f 6929/6837/6061 6930/6834/6058 6924/6833/6057 +f 5049/6831/6055 6925/6832/6056 5010/6777/6005 +f 5050/6830/6054 6926/6836/6060 6925/6832/6056 +f 6925/6832/6056 6930/6834/6058 5011/6778/6006 +f 5054/6839/6063 6927/6835/6059 5051/6827/6051 +f 5054/6839/6063 5053/6841/6065 6928/6838/6062 +f 6927/6835/6059 6926/6836/6060 5050/6830/6054 +f 5012/6780/6007 6929/6837/6061 5052/6840/6064 +f 5011/6778/6006 6930/6834/6058 6929/6837/6061 +f 6929/6837/6061 6928/6838/6062 5053/6841/6065 +f 6932/6842/6066 6933/6846/6070 6931/6843/6067 +f 6934/6845/6069 6935/6848/6072 6931/6843/6067 +f 6936/6847/6071 6937/6844/6068 6931/6843/6067 +f 4139/6849/6073 6932/6842/6066 5054/6839/6063 +f 4138/6850/6074 6933/6846/6070 6932/6842/6066 +f 6932/6842/6066 6937/6844/6068 5053/6841/6065 +f 4218/6851/3611 6934/6845/6069 4137/6852/6075 +f 4218/6851/3611 4219/6855/3612 6935/6848/6072 +f 4137/6852/6075 6934/6845/6069 6933/6846/6070 +f 5052/6840/6064 6936/6847/6071 4220/6854/3615 +f 5052/6840/6064 5053/6841/6065 6937/6844/6068 +f 6936/6847/6071 6935/6848/6072 4219/6855/3612 +f 6939/6856/6076 6940/6860/6080 6938/6857/6077 +f 6941/6859/6079 6942/6862/6082 6938/6857/6077 +f 6943/6861/6081 6944/6858/6078 6938/6857/6077 +f 5055/6863/6083 6939/6856/6076 4193/6146/5382 +f 5056/6864/6084 6940/6860/6080 6939/6856/6076 +f 6939/6856/6076 6944/6858/6078 4192/6147/5383 +f 4032/6157/5393 6941/6859/6079 5057/6865/6085 +f 4033/6160/5396 6942/6862/6082 6941/6859/6079 +f 6941/6859/6079 6940/6860/6080 5056/6864/6084 +f 4191/6148/5384 6943/6861/6081 4034/6162/5398 +f 4192/6147/5383 6944/6858/6078 6943/6861/6081 +f 6943/6861/6081 6942/6862/6082 4033/6160/5396 +f 6946/6866/6086 6947/6870/6090 6945/6867/6087 +f 6948/6869/6089 6949/6872/6092 6945/6867/6087 +f 6950/6871/6091 6951/6868/6088 6945/6867/6087 +f 5061/6873/6093 6946/6866/6086 4196/6122/5358 +f 5062/6874/6094 6947/6870/6090 6946/6866/6086 +f 6946/6866/6086 6951/6868/6088 4195/6123/5359 +f 5075/6875/6095 6948/6869/6089 5063/6876/6096 +f 5074/6878/6098 6949/6872/6092 6948/6869/6089 +f 6948/6869/6089 6947/6870/6090 5062/6874/6094 +f 4194/6125/5361 6950/6871/6091 5073/6879/6099 +f 4194/6125/5361 4195/6123/5359 6951/6868/6088 +f 6950/6871/6091 6949/6872/6092 5074/6878/6098 +f 6953/6880/6100 6954/6884/6104 6952/6881/6101 +f 6955/6883/6103 6956/6886/6106 6952/6881/6101 +f 6957/6885/6105 6958/6882/6102 6952/6881/6101 +f 5067/6887/6107 6953/6880/6100 4199/6098/5334 +f 5068/6888/6108 6954/6884/6104 6953/6880/6100 +f 6953/6880/6100 6958/6882/6102 4198/6099/5335 +f 5081/6889/6109 6955/6883/6103 5069/6890/6110 +f 5080/6892/6112 6956/6886/6106 6955/6883/6103 +f 6955/6883/6103 6954/6884/6104 5068/6888/6108 +f 4197/6101/5337 6957/6885/6105 5079/6893/6113 +f 4198/6099/5335 6958/6882/6102 6957/6885/6105 +f 6957/6885/6105 6956/6886/6106 5080/6892/6112 +f 6960/6894/6114 6961/6898/6118 6959/6895/6115 +f 6962/6897/6117 6963/6900/6120 6959/6895/6115 +f 6964/6899/6119 6965/6896/6116 6959/6895/6115 +f 5073/6879/6099 6960/6894/6114 5055/6863/6083 +f 5074/6878/6098 6961/6898/6118 6960/6894/6114 +f 6960/6894/6114 6965/6896/6116 5056/6864/6084 +f 5078/6901/6121 6962/6897/6117 5075/6875/6095 +f 5077/6902/6122 6963/6900/6120 6962/6897/6117 +f 6962/6897/6117 6961/6898/6118 5074/6878/6098 +f 5057/6865/6085 6964/6899/6119 5076/6903/6123 +f 5056/6864/6084 6965/6896/6116 6964/6899/6119 +f 6964/6899/6119 6963/6900/6120 5077/6902/6122 +f 6967/6904/6124 6968/6908/6128 6966/6905/6125 +f 6969/6907/6127 6970/6910/6130 6966/6905/6125 +f 6971/6909/6129 6972/6906/6126 6966/6905/6125 +f 5058/6911/6131 6967/6904/6124 5078/6901/6121 +f 5059/6912/6132 6968/6908/6128 6967/6904/6124 +f 6967/6904/6124 6972/6906/6126 5077/6902/6122 +f 4206/6171/5407 6969/6907/6127 5060/6913/6133 +f 4207/6174/5410 6970/6910/6130 6969/6907/6127 +f 6969/6907/6127 6968/6908/6128 5059/6912/6132 +f 5076/6903/6123 6971/6909/6129 4208/6179/5415 +f 5077/6902/6122 6972/6906/6126 6971/6909/6129 +f 6971/6909/6129 6970/6910/6130 4207/6174/5410 +f 6974/6914/6134 6975/6918/6138 6973/6915/6135 +f 6976/6917/6137 6977/6920/6140 6973/6915/6135 +f 6978/6919/6139 6979/6916/6136 6973/6915/6135 +f 5079/6893/6113 6974/6914/6134 5061/6873/6093 +f 5080/6892/6112 6975/6918/6138 6974/6914/6134 +f 6974/6914/6134 6979/6916/6136 5062/6874/6094 +f 5084/6921/6141 6976/6917/6137 5081/6889/6109 +f 5083/6922/6142 6977/6920/6140 6976/6917/6137 +f 6976/6917/6137 6975/6918/6138 5080/6892/6112 +f 5063/6876/6096 6978/6919/6139 5082/6923/6143 +f 5062/6874/6094 6979/6916/6136 6978/6919/6139 +f 6978/6919/6139 6977/6920/6140 5083/6922/6142 +f 6981/6924/6144 6982/6928/6148 6980/6925/6145 +f 6983/6927/6147 6984/6930/6150 6980/6925/6145 +f 6985/6929/6149 6986/6926/6146 6980/6925/6145 +f 5070/6931/6151 6981/6924/6144 5084/6921/6141 +f 5071/6932/6152 6982/6928/6148 6981/6924/6144 +f 6981/6924/6144 6986/6926/6146 5083/6922/6142 +f 5087/6933/6153 6983/6927/6147 5072/6934/6154 +f 5086/6936/6156 6984/6930/6150 6983/6927/6147 +f 6983/6927/6147 6982/6928/6148 5071/6932/6152 +f 5082/6923/6143 6985/6929/6149 5085/6937/6157 +f 5083/6922/6142 6986/6926/6146 6985/6929/6149 +f 6985/6929/6149 6984/6930/6150 5086/6936/6156 +f 6988/6938/6158 6989/6942/6162 6987/6939/6159 +f 6990/6941/6161 6991/6944/6164 6987/6939/6159 +f 6992/6943/6163 6993/6940/6160 6987/6939/6159 +f 5085/6937/6157 6988/6938/6158 5058/6911/6131 +f 5086/6936/6156 6989/6942/6162 6988/6938/6158 +f 6988/6938/6158 6993/6940/6160 5059/6912/6132 +f 5090/6945/6165 6990/6941/6161 5087/6933/6153 +f 5089/6946/6166 6991/6944/6164 6990/6941/6161 +f 6990/6941/6161 6989/6942/6162 5086/6936/6156 +f 5060/6913/6133 6992/6943/6163 5088/6947/6167 +f 5059/6912/6132 6993/6940/6160 6992/6943/6163 +f 5088/6947/6167 6992/6943/6163 6991/6944/6164 +f 6995/6948/6168 6996/6952/6172 6994/6949/6169 +f 6997/6951/6171 6998/6954/6174 6994/6949/6169 +f 6999/6953/6173 7000/6950/6170 6994/6949/6169 +f 5064/6955/6175 6995/6948/6168 5090/6945/6165 +f 5065/6956/6176 6996/6952/6172 6995/6948/6168 +f 6995/6948/6168 7000/6950/6170 5089/6946/6166 +f 4203/6189/5425 6997/6951/6171 5066/6957/6177 +f 4204/6191/5427 6998/6954/6174 6997/6951/6171 +f 6997/6951/6171 6996/6952/6172 5065/6956/6176 +f 5088/6947/6167 6999/6953/6173 4205/6195/5431 +f 5089/6946/6166 7000/6950/6170 6999/6953/6173 +f 6999/6953/6173 6998/6954/6174 4204/6191/5427 +f 7002/6958/6178 7003/6962/6182 7001/6959/6179 +f 7004/6961/6181 7005/6964/6184 7001/6959/6179 +f 7006/6963/6183 7007/6960/6180 7001/6959/6179 +f 5091/4215/3531 7002/6958/6178 5067/6887/6107 +f 5092/4213/3529 7003/6962/6182 7002/6958/6178 +f 7002/6958/6178 7007/6960/6180 5068/6888/6108 +f 5096/6965/6185 7004/6961/6181 5093/4210/3526 +f 5095/6966/6186 7005/6964/6184 7004/6961/6181 +f 7004/6961/6181 7003/6962/6182 5092/4213/3529 +f 5069/6890/6110 7006/6963/6183 5094/6967/6187 +f 5068/6888/6108 7007/6960/6180 7006/6963/6183 +f 7006/6963/6183 7005/6964/6184 5095/6966/6186 +f 7009/6968/6188 7010/6972/6192 7008/6969/6189 +f 7011/6971/6191 7012/6974/6194 7008/6969/6189 +f 7013/6973/6193 7014/6970/6190 7008/6969/6189 +f 4109/6975/6195 7009/6968/6188 5096/6965/6185 +f 4108/6976/6196 7010/6972/6192 7009/6968/6188 +f 7009/6968/6188 7014/6970/6190 5095/6966/6186 +f 5099/6977/6197 7011/6971/6191 4107/6978/6198 +f 5098/6980/6200 7012/6974/6194 7011/6971/6191 +f 7011/6971/6191 7010/6972/6192 4108/6976/6196 +f 5094/6967/6187 7013/6973/6193 5097/6981/6201 +f 5095/6966/6186 7014/6970/6190 7013/6973/6193 +f 7013/6973/6193 7012/6974/6194 5098/6980/6200 +f 7016/6982/6202 7017/6986/6206 7015/6983/6203 +f 7018/6985/6205 7019/6988/6208 7015/6983/6203 +f 7020/6987/6207 7021/6984/6204 7015/6983/6203 +f 5097/6981/6201 7016/6982/6202 5070/6931/6151 +f 5098/6980/6200 7017/6986/6206 7016/6982/6202 +f 7016/6982/6202 7021/6984/6204 5071/6932/6152 +f 5102/6989/6209 7018/6985/6205 5099/6977/6197 +f 5101/6990/6210 7019/6988/6208 7018/6985/6205 +f 7018/6985/6205 7017/6986/6206 5098/6980/6200 +f 5072/6934/6154 7020/6987/6207 5100/6991/6211 +f 5071/6932/6152 7021/6984/6204 7020/6987/6207 +f 7020/6987/6207 7019/6988/6208 5101/6990/6210 +f 7023/6992/6212 7024/6996/6216 7022/6993/6213 +f 7025/6995/6215 7026/6998/6218 7022/6993/6213 +f 7027/6997/6217 7028/6994/6214 7022/6993/6213 +f 4106/6999/6219 7023/6992/6212 5102/6989/6209 +f 4105/7000/6220 7024/6996/6216 7023/6992/6212 +f 7023/6992/6212 7028/6994/6214 5101/6990/6210 +f 5105/7001/6221 7025/6995/6215 4104/7002/6222 +f 5104/7004/6224 7026/6998/6218 7025/6995/6215 +f 7025/6995/6215 7024/6996/6216 4105/7000/6220 +f 5100/6991/6211 7027/6997/6217 5103/7005/6225 +f 5101/6990/6210 7028/6994/6214 7027/6997/6217 +f 7027/6997/6217 7026/6998/6218 5104/7004/6224 +f 7030/7006/6226 7031/7010/6230 7029/7007/6227 +f 7032/7009/6229 7033/7012/6232 7029/7007/6227 +f 7034/7011/6231 7035/7008/6228 7029/7007/6227 +f 5103/7005/6225 7030/7006/6226 5064/6955/6175 +f 5104/7004/6224 7031/7010/6230 7030/7006/6226 +f 7030/7006/6226 7035/7008/6228 5065/6956/6176 +f 5108/7013/6233 7032/7009/6229 5105/7001/6221 +f 5107/7014/6234 7033/7012/6232 7032/7009/6229 +f 7032/7009/6229 7031/7010/6230 5104/7004/6224 +f 5066/6957/6177 7034/7011/6231 5106/7015/6235 +f 5065/6956/6176 7035/7008/6228 7034/7011/6231 +f 7034/7011/6231 7033/7012/6232 5107/7014/6234 +f 7037/7016/6236 7038/7020/6240 7036/7017/6237 +f 7039/7019/6239 7040/7022/6242 7036/7017/6237 +f 7041/7021/6241 7042/7018/6238 7036/7017/6237 +f 4103/7023/6243 7037/7016/6236 5108/7013/6233 +f 4102/7024/6244 7038/7020/6240 7037/7016/6236 +f 7037/7016/6236 7042/7018/6238 5107/7014/6234 +f 4200/4281/3597 7039/7019/6239 4101/7025/6245 +f 4200/4281/3597 4201/4282/3598 7040/7022/6242 +f 4101/7025/6245 7039/7019/6239 7038/7020/6240 +f 5106/7015/6235 7041/7021/6241 4202/4285/3601 +f 5107/7014/6234 7042/7018/6238 7041/7021/6241 +f 7041/7021/6241 7040/7022/6242 4201/4282/3598 +f 7044/7026/6246 7045/7030/6250 7043/7027/6247 +f 7046/7029/6249 7047/7032/6252 7043/7027/6247 +f 7048/7031/6251 7049/7028/6248 7043/7027/6247 +f 5109/7033/6253 7044/7026/6246 4175/6327/5563 +f 5110/7034/6254 7045/7030/6250 7044/7026/6246 +f 7044/7026/6246 7049/7028/6248 4174/6328/5564 +f 4026/5433/4669 7046/7029/6249 5111/7035/6255 +f 4027/5436/4672 7047/7032/6252 7046/7029/6249 +f 7046/7029/6249 7045/7030/6250 5110/7034/6254 +f 4173/6329/5565 7048/7031/6251 4028/5438/4674 +f 4174/6328/5564 7049/7028/6248 7048/7031/6251 +f 7048/7031/6251 7047/7032/6252 4027/5436/4672 +f 7051/7036/6256 7052/7040/6260 7050/7037/6257 +f 7053/7039/6259 7054/7042/6262 7050/7037/6257 +f 7055/7041/6261 7056/7038/6258 7050/7037/6257 +f 5115/7043/6263 7051/7036/6256 4178/6303/5539 +f 5116/7044/6264 7052/7040/6260 7051/7036/6256 +f 7051/7036/6256 7056/7038/6258 4177/6304/5540 +f 5129/7045/6265 7053/7039/6259 5117/7046/6266 +f 5128/7048/6268 7054/7042/6262 7053/7039/6259 +f 7053/7039/6259 7052/7040/6260 5116/7044/6264 +f 4176/6306/5542 7055/7041/6261 5127/7049/6269 +f 4177/6304/5540 7056/7038/6258 7055/7041/6261 +f 7055/7041/6261 7054/7042/6262 5128/7048/6268 +f 7058/7050/6270 7059/7054/6274 7057/7051/6271 +f 7060/7053/6273 7061/7056/6276 7057/7051/6271 +f 7062/7055/6275 7063/7052/6272 7057/7051/6271 +f 5121/7057/6277 7058/7050/6270 4181/6279/5515 +f 5121/7057/6277 5122/7062/6282 7059/7054/6274 +f 4181/6279/5515 7058/7050/6270 7063/7052/6272 +f 5135/7058/6278 7060/7053/6273 5123/7059/6279 +f 5134/7061/6281 7061/7056/6276 7060/7053/6273 +f 7060/7053/6273 7059/7054/6274 5122/7062/6282 +f 4179/6282/5518 7062/7055/6275 5133/7063/6283 +f 4180/6280/5516 7063/7052/6272 7062/7055/6275 +f 7062/7055/6275 7061/7056/6276 5134/7061/6281 +f 7065/7064/6284 7066/7068/6288 7064/7065/6285 +f 7067/7067/6287 7068/7070/6290 7064/7065/6285 +f 7069/7069/6289 7070/7066/6286 7064/7065/6285 +f 5127/7049/6269 7065/7064/6284 5109/7033/6253 +f 5128/7048/6268 7066/7068/6288 7065/7064/6284 +f 7065/7064/6284 7070/7066/6286 5110/7034/6254 +f 5132/7071/6291 7067/7067/6287 5129/7045/6265 +f 5131/7072/6292 7068/7070/6290 7067/7067/6287 +f 7067/7067/6287 7066/7068/6288 5128/7048/6268 +f 5111/7035/6255 7069/7069/6289 5130/7073/6293 +f 5110/7034/6254 7070/7066/6286 7069/7069/6289 +f 7069/7069/6289 7068/7070/6290 5131/7072/6292 +f 7072/7074/6294 7073/7078/6298 7071/7075/6295 +f 7074/7077/6297 7075/7080/6300 7071/7075/6295 +f 7076/7079/6299 7077/7076/6296 7071/7075/6295 +f 5112/7081/6301 7072/7074/6294 5132/7071/6291 +f 5113/7082/6302 7073/7078/6298 7072/7074/6294 +f 7072/7074/6294 7077/7076/6296 5131/7072/6292 +f 4188/5447/4683 7074/7077/6297 5114/7083/6303 +f 4189/5450/4686 7075/7080/6300 7074/7077/6297 +f 7074/7077/6297 7073/7078/6298 5113/7082/6302 +f 5130/7073/6293 7076/7079/6299 4190/5455/4691 +f 5131/7072/6292 7077/7076/6296 7076/7079/6299 +f 7076/7079/6299 7075/7080/6300 4189/5450/4686 +f 7079/7084/6304 7080/7088/6308 7078/7085/6305 +f 7081/7087/6307 7082/7090/6310 7078/7085/6305 +f 7083/7089/6309 7084/7086/6306 7078/7085/6305 +f 5133/7063/6283 7079/7084/6304 5115/7043/6263 +f 5133/7063/6283 5134/7061/6281 7080/7088/6308 +f 7079/7084/6304 7084/7086/6306 5116/7044/6264 +f 5138/7091/6311 7081/7087/6307 5135/7058/6278 +f 5137/7092/6312 7082/7090/6310 7081/7087/6307 +f 7081/7087/6307 7080/7088/6308 5134/7061/6281 +f 5117/7046/6266 7083/7089/6309 5136/7093/6313 +f 5116/7044/6264 7084/7086/6306 7083/7089/6309 +f 7083/7089/6309 7082/7090/6310 5137/7092/6312 +f 7086/7094/6314 7087/7098/6318 7085/7095/6315 +f 7088/7097/6317 7089/7100/6320 7085/7095/6315 +f 7090/7099/6319 7091/7096/6316 7085/7095/6315 +f 5124/7101/6321 7086/7094/6314 5138/7091/6311 +f 5125/7102/6322 7087/7098/6318 7086/7094/6314 +f 7086/7094/6314 7091/7096/6316 5137/7092/6312 +f 5141/7103/6323 7088/7097/6317 5126/7104/6324 +f 5140/7106/6326 7089/7100/6320 7088/7097/6317 +f 7088/7097/6317 7087/7098/6318 5125/7102/6322 +f 5136/7093/6313 7090/7099/6319 5139/7107/6327 +f 5137/7092/6312 7091/7096/6316 7090/7099/6319 +f 7090/7099/6319 7089/7100/6320 5140/7106/6326 +f 7093/7108/6328 7094/7112/6332 7092/7109/6329 +f 7095/7111/6331 7096/7114/6334 7092/7109/6329 +f 7097/7113/6333 7098/7110/6330 7092/7109/6329 +f 5139/7107/6327 7093/7108/6328 5112/7081/6301 +f 5140/7106/6326 7094/7112/6332 7093/7108/6328 +f 7093/7108/6328 7098/7110/6330 5113/7082/6302 +f 5144/7115/6335 7095/7111/6331 5141/7103/6323 +f 5143/7116/6336 7096/7114/6334 7095/7111/6331 +f 7095/7111/6331 7094/7112/6332 5140/7106/6326 +f 5114/7083/6303 7097/7113/6333 5142/7117/6337 +f 5113/7082/6302 7098/7110/6330 7097/7113/6333 +f 7097/7113/6333 7096/7114/6334 5143/7116/6336 +f 7100/7118/6338 7101/7122/6342 7099/7119/6339 +f 7102/7121/6341 7103/7124/6344 7099/7119/6339 +f 7104/7123/6343 7105/7120/6340 7099/7119/6339 +f 5118/7125/6345 7100/7118/6338 5144/7115/6335 +f 5119/7126/6346 7101/7122/6342 7100/7118/6338 +f 7100/7118/6338 7105/7120/6340 5143/7116/6336 +f 4185/5465/4701 7102/7121/6341 5120/7127/6347 +f 4186/5466/4702 7103/7124/6344 7102/7121/6341 +f 5120/7127/6347 7102/7121/6341 7101/7122/6342 +f 5142/7117/6337 7104/7123/6343 4187/5472/4708 +f 5143/7116/6336 7105/7120/6340 7104/7123/6343 +f 7104/7123/6343 7103/7124/6344 4186/5466/4702 +f 7107/7128/6348 7108/7132/6352 7106/7129/6349 +f 7109/7131/6351 7110/7134/6354 7106/7129/6349 +f 7111/7133/6353 7112/7130/6350 7106/7129/6349 +f 5145/4196/3512 7107/7128/6348 5121/7057/6277 +f 5146/4194/3510 7108/7132/6352 7107/7128/6348 +f 7107/7128/6348 7112/7130/6350 5122/7062/6282 +f 5150/7135/6355 7109/7131/6351 5147/4193/3509 +f 5149/7136/6356 7110/7134/6354 7109/7131/6351 +f 7109/7131/6351 7108/7132/6352 5146/4194/3510 +f 5123/7059/6279 7111/7133/6353 5148/7137/6357 +f 5123/7059/6279 5122/7062/6282 7112/7130/6350 +f 5148/7137/6357 7111/7133/6353 7110/7134/6354 +f 7114/7138/6358 7115/7142/6362 7113/7139/6359 +f 7116/7141/6361 7117/7144/6364 7113/7139/6359 +f 7118/7143/6363 7119/7140/6360 7113/7139/6359 +f 4118/7145/6365 7114/7138/6358 5150/7135/6355 +f 4118/7145/6365 4117/7150/6370 7115/7142/6362 +f 5150/7135/6355 7114/7138/6358 7119/7140/6360 +f 5153/7146/6366 7116/7141/6361 4116/7147/6367 +f 5152/7149/6369 7117/7144/6364 7116/7141/6361 +f 7116/7141/6361 7115/7142/6362 4117/7150/6370 +f 5148/7137/6357 7118/7143/6363 5151/7151/6371 +f 5149/7136/6356 7119/7140/6360 7118/7143/6363 +f 7118/7143/6363 7117/7144/6364 5152/7149/6369 +f 7121/7152/6372 7122/7156/6376 7120/7153/6373 +f 7123/7155/6375 7124/7158/6378 7120/7153/6373 +f 7125/7157/6377 7126/7154/6374 7120/7153/6373 +f 5151/7151/6371 7121/7152/6372 5124/7101/6321 +f 5152/7149/6369 7122/7156/6376 7121/7152/6372 +f 7121/7152/6372 7126/7154/6374 5125/7102/6322 +f 5156/7159/6379 7123/7155/6375 5153/7146/6366 +f 5155/7160/6380 7124/7158/6378 7123/7155/6375 +f 7123/7155/6375 7122/7156/6376 5152/7149/6369 +f 5126/7104/6324 7125/7157/6377 5154/7161/6381 +f 5125/7102/6322 7126/7154/6374 7125/7157/6377 +f 7125/7157/6377 7124/7158/6378 5155/7160/6380 +f 7128/7162/6382 7129/7166/6386 7127/7163/6383 +f 7130/7165/6385 7131/7168/6388 7127/7163/6383 +f 7132/7167/6387 7133/7164/6384 7127/7163/6383 +f 4115/7169/6389 7128/7162/6382 5156/7159/6379 +f 4114/7170/6390 7129/7166/6386 7128/7162/6382 +f 7128/7162/6382 7133/7164/6384 5155/7160/6380 +f 5159/7171/6391 7130/7165/6385 4113/7172/6392 +f 5159/7171/6391 5158/7175/6395 7131/7168/6388 +f 4113/7172/6392 7130/7165/6385 7129/7166/6386 +f 5154/7161/6381 7132/7167/6387 5157/7174/6394 +f 5155/7160/6380 7133/7164/6384 7132/7167/6387 +f 7132/7167/6387 7131/7168/6388 5158/7175/6395 +f 7135/7176/6396 7136/7180/6400 7134/7177/6397 +f 7137/7179/6399 7138/7182/6402 7134/7177/6397 +f 7139/7181/6401 7140/7178/6398 7134/7177/6397 +f 5157/7174/6394 7135/7176/6396 5118/7125/6345 +f 5157/7174/6394 5158/7175/6395 7136/7180/6400 +f 5118/7125/6345 7135/7176/6396 7140/7178/6398 +f 5162/7183/6403 7137/7179/6399 5159/7171/6391 +f 5161/7184/6404 7138/7182/6402 7137/7179/6399 +f 7137/7179/6399 7136/7180/6400 5158/7175/6395 +f 5120/7127/6347 7139/7181/6401 5160/7185/6405 +f 5119/7126/6346 7140/7178/6398 7139/7181/6401 +f 7139/7181/6401 7138/7182/6402 5161/7184/6404 +f 7142/7186/6406 7143/7190/6410 7141/7187/6407 +f 7144/7189/6409 7145/7192/6412 7141/7187/6407 +f 7146/7191/6411 7147/7188/6408 7141/7187/6407 +f 4112/7193/6413 7142/7186/6406 5162/7183/6403 +f 4111/7194/6414 7143/7190/6410 7142/7186/6406 +f 7142/7186/6406 7147/7188/6408 5161/7184/6404 +f 4182/4337/3653 7144/7189/6409 4110/7195/6415 +f 4182/4337/3653 4183/4338/3654 7145/7192/6412 +f 4110/7195/6415 7144/7189/6409 7143/7190/6410 +f 5160/7185/6405 7146/7191/6411 4184/4341/3657 +f 5161/7184/6404 7147/7188/6408 7146/7191/6411 +f 7146/7191/6411 7145/7192/6412 4183/4338/3654 +f 7149/7196/6416 7150/7200/6420 7148/7197/6417 +f 7152/7199/6419 7148/7197/6417 7150/7200/6420 +f 7153/7202/6422 7154/7198/6418 7148/7197/6417 +f 5163/7203/6423 7149/7196/6416 4005/7204/6424 +f 5164/7206/6426 7150/7200/6420 7149/7196/6416 +f 7149/7196/6416 7154/7198/6418 4006/7207/6427 +f 4020/4267/3583 7151/7201/6421 5165/7208/6428 +f 4021/4270/3586 7152/7199/6419 7151/7201/6421 +f 7151/7201/6421 7150/7200/6420 5164/7206/6426 +f 4007/7209/6429 7153/7202/6422 4022/4262/3578 +f 4007/7209/6429 4006/7207/6427 7154/7198/6418 +f 4022/4262/3578 7153/7202/6422 7152/7199/6419 +f 7156/7210/6430 7157/7214/6434 7155/7211/6431 +f 7158/7213/6433 7159/7216/6436 7155/7211/6431 +f 7160/7215/6435 7161/7212/6432 7155/7211/6431 +f 5169/7217/6437 7156/7210/6430 4125/7218/6438 +f 5170/7220/6440 7157/7214/6434 7156/7210/6430 +f 7156/7210/6430 7161/7212/6432 4126/7221/6441 +f 5183/7222/6442 7158/7213/6433 5171/7223/6443 +f 5182/7225/6445 7159/7216/6436 7158/7213/6433 +f 7158/7213/6433 7157/7214/6434 5170/7220/6440 +f 4127/7226/6446 7160/7215/6435 5181/7227/6447 +f 4126/7221/6441 7161/7212/6432 7160/7215/6435 +f 5181/7227/6447 7160/7215/6435 7159/7216/6436 +f 7163/7228/6448 7164/7232/6452 7162/7229/6449 +f 7165/7231/6451 7166/7234/6454 7162/7229/6449 +f 7167/7233/6453 7168/7230/6450 7162/7229/6449 +f 5175/7235/6455 7163/7228/6448 4122/7236/6456 +f 5175/7235/6455 5176/7242/6462 7164/7232/6452 +f 7163/7228/6448 7168/7230/6450 4123/7237/6457 +f 5189/7238/6458 7165/7231/6451 5177/7239/6459 +f 5188/7241/6461 7166/7234/6454 7165/7231/6451 +f 7165/7231/6451 7164/7232/6452 5176/7242/6462 +f 4124/7243/6463 7167/7233/6453 5187/7244/6464 +f 4123/7237/6457 7168/7230/6450 7167/7233/6453 +f 7167/7233/6453 7166/7234/6454 5188/7241/6461 +f 7170/7245/6465 7171/7249/6469 7169/7246/6466 +f 7172/7248/6468 7173/7251/6471 7169/7246/6466 +f 7174/7250/6470 7175/7247/6467 7169/7246/6466 +f 5181/7227/6447 7170/7245/6465 5163/7203/6423 +f 5182/7225/6445 7171/7249/6469 7170/7245/6465 +f 7170/7245/6465 7175/7247/6467 5164/7206/6426 +f 5186/7252/6472 7172/7248/6468 5183/7222/6442 +f 5186/7252/6472 5185/7254/6474 7173/7251/6471 +f 5183/7222/6442 7172/7248/6468 7171/7249/6469 +f 5165/7208/6428 7174/7250/6470 5184/7253/6473 +f 5164/7206/6426 7175/7247/6467 7174/7250/6470 +f 7174/7250/6470 7173/7251/6471 5185/7254/6474 +f 7177/7255/6475 7178/7259/6479 7176/7256/6476 +f 7179/7258/6478 7180/7261/6481 7176/7256/6476 +f 7181/7260/6480 7182/7257/6477 7176/7256/6476 +f 5166/7262/6482 7177/7255/6475 5186/7252/6472 +f 5167/7263/6483 7178/7259/6479 7177/7255/6475 +f 7177/7255/6475 7182/7257/6477 5185/7254/6474 +f 4170/6452/5688 7179/7258/6478 5168/7264/6484 +f 4171/6450/5686 7180/7261/6481 7179/7258/6478 +f 7179/7258/6478 7178/7259/6479 5167/7263/6483 +f 5184/7253/6473 7181/7260/6480 4172/6449/5685 +f 5184/7253/6473 5185/7254/6474 7182/7257/6477 +f 4172/6449/5685 7181/7260/6480 7180/7261/6481 +f 7184/7265/6485 7185/7269/6489 7183/7266/6486 +f 7186/7268/6488 7187/7271/6491 7183/7266/6486 +f 7188/7270/6490 7189/7267/6487 7183/7266/6486 +f 5187/7244/6464 7184/7265/6485 5169/7217/6437 +f 5188/7241/6461 7185/7269/6489 7184/7265/6485 +f 7184/7265/6485 7189/7267/6487 5170/7220/6440 +f 5192/7272/6492 7186/7268/6488 5189/7238/6458 +f 5191/7273/6493 7187/7271/6491 7186/7268/6488 +f 7186/7268/6488 7185/7269/6489 5188/7241/6461 +f 5171/7223/6443 7188/7270/6490 5190/7274/6494 +f 5170/7220/6440 7189/7267/6487 7188/7270/6490 +f 7188/7270/6490 7187/7271/6491 5191/7273/6493 +f 7191/7275/6495 7192/7279/6499 7190/7276/6496 +f 7193/7278/6498 7194/7281/6501 7190/7276/6496 +f 7195/7280/6500 7196/7277/6497 7190/7276/6496 +f 5178/7282/6502 7191/7275/6495 5192/7272/6492 +f 5179/7283/6503 7192/7279/6499 7191/7275/6495 +f 7191/7275/6495 7196/7277/6497 5191/7273/6493 +f 5195/7284/6504 7193/7278/6498 5180/7285/6505 +f 5194/7287/6507 7194/7281/6501 7193/7278/6498 +f 7193/7278/6498 7192/7279/6499 5179/7283/6503 +f 5190/7274/6494 7195/7280/6500 5193/7288/6508 +f 5191/7273/6493 7196/7277/6497 7195/7280/6500 +f 7195/7280/6500 7194/7281/6501 5194/7287/6507 +f 7198/7289/6509 7199/7293/6513 7197/7290/6510 +f 7200/7292/6512 7201/7295/6515 7197/7290/6510 +f 7202/7294/6514 7203/7291/6511 7197/7290/6510 +f 5193/7288/6508 7198/7289/6509 5166/7262/6482 +f 5194/7287/6507 7199/7293/6513 7198/7289/6509 +f 7198/7289/6509 7203/7291/6511 5167/7263/6483 +f 5198/7296/6516 7200/7292/6512 5195/7284/6504 +f 5197/7297/6517 7201/7295/6515 7200/7292/6512 +f 7200/7292/6512 7199/7293/6513 5194/7287/6507 +f 5168/7264/6484 7202/7294/6514 5196/7298/6518 +f 5167/7263/6483 7203/7291/6511 7202/7294/6514 +f 7202/7294/6514 7201/7295/6515 5197/7297/6517 +f 7205/7299/6519 7206/7303/6523 7204/7300/6520 +f 7207/7302/6522 7208/7305/6525 7204/7300/6520 +f 7209/7304/6524 7210/7301/6521 7204/7300/6520 +f 5172/7306/6526 7205/7299/6519 5198/7296/6516 +f 5173/7307/6527 7206/7303/6523 7205/7299/6519 +f 7205/7299/6519 7210/7301/6521 5197/7297/6517 +f 4167/6476/5712 7207/7302/6522 5174/7308/6528 +f 4168/6474/5710 7208/7305/6525 7207/7302/6522 +f 5174/7308/6528 7207/7302/6522 7206/7303/6523 +f 5196/7298/6518 7209/7304/6524 4169/6473/5709 +f 5197/7297/6517 7210/7301/6521 7209/7304/6524 +f 7209/7304/6524 7208/7305/6525 4168/6474/5710 +f 7212/7309/6529 7213/7313/6533 7211/7310/6530 +f 7214/7312/6532 7215/7315/6535 7211/7310/6530 +f 7216/7314/6534 7217/7311/6531 7211/7310/6530 +f 5199/4182/3498 7212/7309/6529 5175/7235/6455 +f 5200/4180/3496 7213/7313/6533 7212/7309/6529 +f 7212/7309/6529 7217/7311/6531 5176/7242/6462 +f 5204/7316/6536 7214/7312/6532 5201/4177/3495 +f 5204/7316/6536 5203/7318/6538 7215/7315/6535 +f 7214/7312/6532 7213/7313/6533 5200/4180/3496 +f 5177/7239/6459 7216/7314/6534 5202/7317/6537 +f 5176/7242/6462 7217/7311/6531 7216/7314/6534 +f 7216/7314/6534 7215/7315/6535 5203/7318/6538 +f 7219/7319/6539 7220/7323/6543 7218/7320/6540 +f 7221/7322/6542 7222/7325/6545 7218/7320/6540 +f 7223/7324/6544 7224/7321/6541 7218/7320/6540 +f 4154/7326/6546 7219/7319/6539 5204/7316/6536 +f 4153/7327/6547 7220/7323/6543 7219/7319/6539 +f 7219/7319/6539 7224/7321/6541 5203/7318/6538 +f 5207/7328/6548 7221/7322/6542 4152/7329/6549 +f 5206/7331/6551 7222/7325/6545 7221/7322/6542 +f 7221/7322/6542 7220/7323/6543 4153/7327/6547 +f 5202/7317/6537 7223/7324/6544 5205/7332/6552 +f 5203/7318/6538 7224/7321/6541 7223/7324/6544 +f 7223/7324/6544 7222/7325/6545 5206/7331/6551 +f 7226/7333/6553 7227/7337/6557 7225/7334/6554 +f 7228/7336/6556 7229/7339/6559 7225/7334/6554 +f 7230/7338/6558 7231/7335/6555 7225/7334/6554 +f 5205/7332/6552 7226/7333/6553 5178/7282/6502 +f 5206/7331/6551 7227/7337/6557 7226/7333/6553 +f 7226/7333/6553 7231/7335/6555 5179/7283/6503 +f 5210/7340/6560 7228/7336/6556 5207/7328/6548 +f 5210/7340/6560 5209/7342/6562 7229/7339/6559 +f 7228/7336/6556 7227/7337/6557 5206/7331/6551 +f 5180/7285/6505 7230/7338/6558 5208/7341/6561 +f 5179/7283/6503 7231/7335/6555 7230/7338/6558 +f 7230/7338/6558 7229/7339/6559 5209/7342/6562 +f 7233/7343/6563 7234/7347/6567 7232/7344/6564 +f 7235/7346/6566 7236/7349/6569 7232/7344/6564 +f 7237/7348/6568 7238/7345/6565 7232/7344/6564 +f 4151/7350/6570 7233/7343/6563 5210/7340/6560 +f 4150/7351/6571 7234/7347/6567 7233/7343/6563 +f 7233/7343/6563 7238/7345/6565 5209/7342/6562 +f 5213/7352/6572 7235/7346/6566 4149/7353/6573 +f 5212/7355/6575 7236/7349/6569 7235/7346/6566 +f 7235/7346/6566 7234/7347/6567 4150/7351/6571 +f 5208/7341/6561 7237/7348/6568 5211/7356/6576 +f 5209/7342/6562 7238/7345/6565 7237/7348/6568 +f 7237/7348/6568 7236/7349/6569 5212/7355/6575 +f 7240/7357/6577 7241/7361/6581 7239/7358/6578 +f 7242/7360/6580 7243/7363/6583 7239/7358/6578 +f 7244/7362/6582 7245/7359/6579 7239/7358/6578 +f 5211/7356/6576 7240/7357/6577 5172/7306/6526 +f 5212/7355/6575 7241/7361/6581 7240/7357/6577 +f 5172/7306/6526 7240/7357/6577 7245/7359/6579 +f 5216/7364/6584 7242/7360/6580 5213/7352/6572 +f 5215/7365/6585 7243/7363/6583 7242/7360/6580 +f 7242/7360/6580 7241/7361/6581 5212/7355/6575 +f 5174/7308/6528 7244/7362/6582 5214/7366/6586 +f 5173/7307/6527 7245/7359/6579 7244/7362/6582 +f 7244/7362/6582 7243/7363/6583 5215/7365/6585 +f 7247/7367/6587 7248/7371/6591 7246/7368/6588 +f 7249/7370/6590 7250/7373/6593 7246/7368/6588 +f 7251/7372/6592 7252/7369/6589 7246/7368/6588 +f 4148/7374/6594 7247/7367/6587 5216/7364/6584 +f 4147/7375/6595 7248/7371/6591 7247/7367/6587 +f 7247/7367/6587 7252/7369/6589 5215/7365/6585 +f 4164/6499/5735 7249/7370/6590 4146/7376/6596 +f 4164/6499/5735 4165/6498/5734 7250/7373/6593 +f 4146/7376/6596 7249/7370/6590 7248/7371/6591 +f 5214/7366/6586 7251/7372/6592 4166/6497/5733 +f 5215/7365/6585 7252/7369/6589 7251/7372/6592 +f 7251/7372/6592 7250/7373/6593 4165/6498/5734 +f 7254/7377/6597 7255/7381/6601 7253/7378/6598 +f 7256/7380/6600 7257/7383/6603 7253/7378/6598 +f 7258/7382/6602 7259/7379/6599 7253/7378/6598 +f 5217/7384/6604 7254/7377/6597 4148/7385/6594 +f 5218/7387/6605 7255/7381/6601 7254/7377/6597 +f 7254/7377/6597 7259/7379/6599 4147/7388/6595 +f 4017/4248/3564 7256/7380/6600 5219/7389/6606 +f 4018/4251/3567 7257/7383/6603 7256/7380/6600 +f 7256/7380/6600 7255/7381/6601 5218/7387/6605 +f 4146/7390/6596 7258/7382/6602 4019/4243/3559 +f 4146/7390/6596 4147/7388/6595 7259/7379/6599 +f 4019/4243/3559 7258/7382/6602 7257/7383/6603 +f 7261/7391/6607 7262/7395/6611 7260/7392/6608 +f 7263/7394/6610 7264/7397/6613 7260/7392/6608 +f 7265/7396/6612 7266/7393/6609 7260/7392/6608 +f 5223/7398/6614 7261/7391/6607 4151/7399/6570 +f 5224/7401/6615 7262/7395/6611 7261/7391/6607 +f 7261/7391/6607 7266/7393/6609 4150/7402/6571 +f 5237/7403/6616 7263/7394/6610 5225/7404/6617 +f 5236/7406/6619 7264/7397/6613 7263/7394/6610 +f 7263/7394/6610 7262/7395/6611 5224/7401/6615 +f 4149/7407/6573 7265/7396/6612 5235/7408/6620 +f 4150/7402/6571 7266/7393/6609 7265/7396/6612 +f 7265/7396/6612 7264/7397/6613 5236/7406/6619 +f 7268/7409/6621 7269/7413/6625 7267/7410/6622 +f 7270/7412/6624 7271/7415/6627 7267/7410/6622 +f 7272/7414/6626 7273/7411/6623 7267/7410/6622 +f 5229/7416/6628 7268/7409/6621 4154/7417/6546 +f 5229/7416/6628 5230/7423/6633 7269/7413/6625 +f 4154/7417/6546 7268/7409/6621 7273/7411/6623 +f 5243/7419/6629 7270/7412/6624 5231/7420/6630 +f 5242/7422/6632 7271/7415/6627 7270/7412/6624 +f 7270/7412/6624 7269/7413/6625 5230/7423/6633 +f 4152/7424/6549 7272/7414/6626 5241/7425/6634 +f 4153/7418/6547 7273/7411/6623 7272/7414/6626 +f 7272/7414/6626 7271/7415/6627 5242/7422/6632 +f 7275/7426/6635 7276/7430/6639 7274/7427/6636 +f 7277/7429/6638 7278/7432/6641 7274/7427/6636 +f 7279/7431/6640 7280/7428/6637 7274/7427/6636 +f 5235/7408/6620 7275/7426/6635 5217/7384/6604 +f 5236/7406/6619 7276/7430/6639 7275/7426/6635 +f 7275/7426/6635 7280/7428/6637 5218/7387/6605 +f 5240/7433/6642 7277/7429/6638 5237/7403/6616 +f 5239/7434/6643 7278/7432/6641 7277/7429/6638 +f 7277/7429/6638 7276/7430/6639 5236/7406/6619 +f 5219/7389/6606 7279/7431/6640 5238/7435/6644 +f 5218/7387/6605 7280/7428/6637 7279/7431/6640 +f 7279/7431/6640 7278/7432/6641 5239/7434/6643 +f 7282/7436/6645 7283/7440/6649 7281/7437/6646 +f 7284/7439/6648 7285/7442/6651 7281/7437/6646 +f 7286/7441/6650 7287/7438/6647 7281/7437/6646 +f 5220/7443/6652 7282/7436/6645 5240/7433/6642 +f 5221/7444/6653 7283/7440/6649 7282/7436/6645 +f 7282/7436/6645 7287/7438/6647 5239/7434/6643 +f 4161/6621/5857 7284/7439/6648 5222/7445/6654 +f 4162/6624/5860 7285/7442/6651 7284/7439/6648 +f 7284/7439/6648 7283/7440/6649 5221/7444/6653 +f 5238/7435/6644 7286/7441/6650 4163/6619/5855 +f 5239/7434/6643 7287/7438/6647 7286/7441/6650 +f 7286/7441/6650 7285/7442/6651 4162/6624/5860 +f 7289/7446/6655 7290/7450/6659 7288/7447/6656 +f 7291/7449/6658 7292/7452/6661 7288/7447/6656 +f 7293/7451/6660 7294/7448/6657 7288/7447/6656 +f 5241/7425/6634 7289/7446/6655 5223/7398/6614 +f 5242/7422/6632 7290/7450/6659 7289/7446/6655 +f 7289/7446/6655 7294/7448/6657 5224/7401/6615 +f 5246/7453/6662 7291/7449/6658 5243/7419/6629 +f 5245/7454/6663 7292/7452/6661 7291/7449/6658 +f 7291/7449/6658 7290/7450/6659 5242/7422/6632 +f 5225/7404/6617 7293/7451/6660 5244/7455/6664 +f 5225/7404/6617 5224/7401/6615 7294/7448/6657 +f 5244/7455/6664 7293/7451/6660 7292/7452/6661 +f 7296/7456/6665 7297/7460/6669 7295/7457/6666 +f 7298/7459/6668 7299/7462/6671 7295/7457/6666 +f 7300/7461/6670 7301/7458/6667 7295/7457/6666 +f 5232/7463/6672 7296/7456/6665 5246/7453/6662 +f 5233/7464/6673 7297/7460/6669 7296/7456/6665 +f 5246/7453/6662 7296/7456/6665 7301/7458/6667 +f 5249/7465/6674 7298/7459/6668 5234/7466/6675 +f 5249/7465/6674 5248/7469/6678 7299/7462/6671 +f 7298/7459/6668 7297/7460/6669 5233/7464/6673 +f 5244/7455/6664 7300/7461/6670 5247/7468/6677 +f 5245/7454/6663 7301/7458/6667 7300/7461/6670 +f 7300/7461/6670 7299/7462/6671 5248/7469/6678 +f 7303/7470/6679 7304/7474/6683 7302/7471/6680 +f 7305/7473/6682 7306/7476/6685 7302/7471/6680 +f 7307/7475/6684 7308/7472/6681 7302/7471/6680 +f 5247/7468/6677 7303/7470/6679 5220/7443/6652 +f 5248/7469/6678 7304/7474/6683 7303/7470/6679 +f 7303/7470/6679 7308/7472/6681 5221/7444/6653 +f 5252/7477/6686 7305/7473/6682 5249/7465/6674 +f 5251/7478/6687 7306/7476/6685 7305/7473/6682 +f 7305/7473/6682 7304/7474/6683 5248/7469/6678 +f 5222/7445/6654 7307/7475/6684 5250/7479/6688 +f 5221/7444/6653 7308/7472/6681 7307/7475/6684 +f 7307/7475/6684 7306/7476/6685 5251/7478/6687 +f 7310/7480/6689 7311/7484/6693 7309/7481/6690 +f 7312/7483/6692 7313/7486/6695 7309/7481/6690 +f 7314/7485/6694 7315/7482/6691 7309/7481/6690 +f 5226/7487/6696 7310/7480/6689 5252/7477/6686 +f 5227/7488/6697 7311/7484/6693 7310/7480/6689 +f 7310/7480/6689 7315/7482/6691 5251/7478/6687 +f 4158/6646/5882 7312/7483/6692 5228/7489/6698 +f 4159/6644/5880 7313/7486/6695 7312/7483/6692 +f 5228/7489/6698 7312/7483/6692 7311/7484/6693 +f 5250/7479/6688 7314/7485/6694 4160/6643/5879 +f 5251/7478/6687 7315/7482/6691 7314/7485/6694 +f 7314/7485/6694 7313/7486/6695 4159/6644/5880 +f 7317/7490/6699 7318/7494/6703 7316/7491/6700 +f 7319/7493/6702 7320/7496/6705 7316/7491/6700 +f 7321/7495/6704 7322/7492/6701 7316/7491/6700 +f 5253/4163/3484 7317/7490/6699 5229/7416/6628 +f 5254/4160/3482 7318/7494/6703 7317/7490/6699 +f 7317/7490/6699 7322/7492/6701 5230/7423/6633 +f 5258/7497/6706 7319/7493/6702 5255/4157/3481 +f 5257/7498/6707 7320/7496/6705 7319/7493/6702 +f 7319/7493/6702 7318/7494/6703 5254/4160/3482 +f 5231/7420/6630 7321/7495/6704 5256/7499/6708 +f 5231/7420/6630 5230/7423/6633 7322/7492/6701 +f 5256/7499/6708 7321/7495/6704 7320/7496/6705 +f 7324/7500/6709 7325/7504/6713 7323/7501/6710 +f 7326/7503/6712 7327/7506/6715 7323/7501/6710 +f 7328/7505/6714 7329/7502/6711 7323/7501/6710 +f 4136/7507/6716 7324/7500/6709 5258/7497/6706 +f 4136/7507/6716 4135/7512/6721 7325/7504/6713 +f 5258/7497/6706 7324/7500/6709 7329/7502/6711 +f 5261/7508/6717 7326/7503/6712 4134/7509/6718 +f 5260/7511/6720 7327/7506/6715 7326/7503/6712 +f 7326/7503/6712 7325/7504/6713 4135/7512/6721 +f 5256/7499/6708 7328/7505/6714 5259/7513/6722 +f 5257/7498/6707 7329/7502/6711 7328/7505/6714 +f 7328/7505/6714 7327/7506/6715 5260/7511/6720 +f 7331/7514/6723 7332/7518/6727 7330/7515/6724 +f 7333/7517/6726 7334/7520/6729 7330/7515/6724 +f 7335/7519/6728 7336/7516/6725 7330/7515/6724 +f 5259/7513/6722 7331/7514/6723 5232/7463/6672 +f 5260/7511/6720 7332/7518/6727 7331/7514/6723 +f 7331/7514/6723 7336/7516/6725 5233/7464/6673 +f 5264/7521/6730 7333/7517/6726 5261/7508/6717 +f 5264/7521/6730 5263/7523/6732 7334/7520/6729 +f 7333/7517/6726 7332/7518/6727 5260/7511/6720 +f 5234/7466/6675 7335/7519/6728 5262/7522/6731 +f 5233/7464/6673 7336/7516/6725 7335/7519/6728 +f 7335/7519/6728 7334/7520/6729 5263/7523/6732 +f 7338/7524/6733 7339/7528/6737 7337/7525/6734 +f 7340/7527/6736 7341/7530/6739 7337/7525/6734 +f 7342/7529/6738 7343/7526/6735 7337/7525/6734 +f 4133/7531/6740 7338/7524/6733 5264/7521/6730 +f 4133/7531/6740 4132/7536/6745 7339/7528/6737 +f 7338/7524/6733 7343/7526/6735 5263/7523/6732 +f 5267/7532/6741 7340/7527/6736 4131/7533/6742 +f 5266/7535/6744 7341/7530/6739 7340/7527/6736 +f 7340/7527/6736 7339/7528/6737 4132/7536/6745 +f 5262/7522/6731 7342/7529/6738 5265/7537/6746 +f 5262/7522/6731 5263/7523/6732 7343/7526/6735 +f 5265/7537/6746 7342/7529/6738 7341/7530/6739 +f 7345/7538/6747 7346/7542/6751 7344/7539/6748 +f 7347/7541/6750 7348/7544/6753 7344/7539/6748 +f 7349/7543/6752 7350/7540/6749 7344/7539/6748 +f 5265/7537/6746 7345/7538/6747 5226/7487/6696 +f 5266/7535/6744 7346/7542/6751 7345/7538/6747 +f 7345/7538/6747 7350/7540/6749 5227/7488/6697 +f 5270/7545/6754 7347/7541/6750 5267/7532/6741 +f 5269/7546/6755 7348/7544/6753 7347/7541/6750 +f 7347/7541/6750 7346/7542/6751 5266/7535/6744 +f 5228/7489/6698 7349/7543/6752 5268/7547/6756 +f 5227/7488/6697 7350/7540/6749 7349/7543/6752 +f 7349/7543/6752 7348/7544/6753 5269/7546/6755 +f 7352/7548/6757 7353/7552/6761 7351/7549/6758 +f 7354/7551/6760 7355/7554/6763 7351/7549/6758 +f 7356/7553/6762 7357/7550/6759 7351/7549/6758 +f 4130/7555/6764 7352/7548/6757 5270/7545/6754 +f 4129/7556/6765 7353/7552/6761 7352/7548/6757 +f 7352/7548/6757 7357/7550/6759 5269/7546/6755 +f 4155/6669/5905 7354/7551/6760 4128/7557/6766 +f 4155/6669/5905 4156/6668/5904 7355/7554/6763 +f 7354/7551/6760 7353/7552/6761 4129/7556/6765 +f 5268/7547/6756 7356/7553/6762 4157/6667/5903 +f 5269/7546/6755 7357/7550/6759 7356/7553/6762 +f 7356/7553/6762 7355/7554/6763 4156/6668/5904 +f 7359/7558/6767 7360/7562/6771 7358/7559/6768 +f 7361/7561/6770 7362/7564/6773 7358/7559/6768 +f 7363/7563/6772 7364/7560/6769 7358/7559/6768 +f 5271/7565/6774 7359/7558/6767 4130/7566/6764 +f 5272/7568/6775 7360/7562/6771 7359/7558/6767 +f 7359/7558/6767 7364/7560/6769 4129/7569/6765 +f 4011/4230/3546 7361/7561/6770 5273/7570/6776 +f 4012/4227/3543 7362/7564/6773 7361/7561/6770 +f 7361/7561/6770 7360/7562/6771 5272/7568/6775 +f 4128/7571/6766 7363/7563/6772 4013/4224/3540 +f 4128/7571/6766 4129/7569/6765 7364/7560/6769 +f 4013/4224/3540 7363/7563/6772 7362/7564/6773 +f 7366/7572/6777 7367/7576/6781 7365/7573/6778 +f 7368/7575/6780 7369/7578/6783 7365/7573/6778 +f 7370/7577/6782 7371/7574/6779 7365/7573/6778 +f 5277/7579/6784 7366/7572/6777 4133/7580/6740 +f 5278/7582/6785 7367/7576/6781 7366/7572/6777 +f 7366/7572/6777 7371/7574/6779 4132/7583/6745 +f 5291/7584/6786 7368/7575/6780 5279/7585/6787 +f 5290/7587/6789 7369/7578/6783 7368/7575/6780 +f 7368/7575/6780 7367/7576/6781 5278/7582/6785 +f 4131/7588/6742 7370/7577/6782 5289/7589/6790 +f 4131/7588/6742 4132/7583/6745 7371/7574/6779 +f 5289/7589/6790 7370/7577/6782 7369/7578/6783 +f 7373/7590/6791 7374/7594/6795 7372/7591/6792 +f 7375/7593/6794 7376/7596/6797 7372/7591/6792 +f 7377/7595/6796 7378/7592/6793 7372/7591/6792 +f 5283/7597/6798 7373/7590/6791 4136/7598/6716 +f 5283/7597/6798 5284/7604/6803 7374/7594/6795 +f 7373/7590/6791 7378/7592/6793 4135/7599/6721 +f 5297/7600/6799 7375/7593/6794 5285/7601/6800 +f 5296/7603/6802 7376/7596/6797 7375/7593/6794 +f 7375/7593/6794 7374/7594/6795 5284/7604/6803 +f 4134/7605/6718 7377/7595/6796 5295/7606/6804 +f 4134/7605/6718 4135/7599/6721 7378/7592/6793 +f 5295/7606/6804 7377/7595/6796 7376/7596/6797 +f 7380/7607/6805 7381/7611/6809 7379/7608/6806 +f 7382/7610/6808 7383/7613/6811 7379/7608/6806 +f 7384/7612/6810 7385/7609/6807 7379/7608/6806 +f 5289/7589/6790 7380/7607/6805 5271/7565/6774 +f 5290/7587/6789 7381/7611/6809 7380/7607/6805 +f 7380/7607/6805 7385/7609/6807 5272/7568/6775 +f 5294/7614/6812 7382/7610/6808 5291/7584/6786 +f 5294/7614/6812 5293/7616/6814 7383/7613/6811 +f 5291/7584/6786 7382/7610/6808 7381/7611/6809 +f 5273/7570/6776 7384/7612/6810 5292/7615/6813 +f 5272/7568/6775 7385/7609/6807 7384/7612/6810 +f 7384/7612/6810 7383/7613/6811 5293/7616/6814 +f 7387/7617/6815 7388/7621/6819 7386/7618/6816 +f 7389/7620/6818 7390/7623/6821 7386/7618/6816 +f 7391/7622/6820 7392/7619/6817 7386/7618/6816 +f 5274/7624/6822 7387/7617/6815 5294/7614/6812 +f 5275/7625/6823 7388/7621/6819 7387/7617/6815 +f 7387/7617/6815 7392/7619/6817 5293/7616/6814 +f 4143/6804/6028 7389/7620/6818 5276/7626/6824 +f 4144/6802/6026 7390/7623/6821 7389/7620/6818 +f 7389/7620/6818 7388/7621/6819 5275/7625/6823 +f 5292/7615/6813 7391/7622/6820 4145/6801/6025 +f 5292/7615/6813 5293/7616/6814 7392/7619/6817 +f 4145/6801/6025 7391/7622/6820 7390/7623/6821 +f 7394/7627/6825 7395/7631/6829 7393/7628/6826 +f 7396/7630/6828 7397/7632/6830 7393/7628/6826 +f 7399/7629/6827 7393/7628/6826 7397/7632/6830 +f 5295/7606/6804 7394/7627/6825 5277/7579/6784 +f 5296/7603/6802 7395/7631/6829 7394/7627/6825 +f 5277/7579/6784 7394/7627/6825 7399/7629/6827 +f 5300/7634/6832 7396/7630/6828 5297/7600/6799 +f 5300/7634/6832 5299/7636/6834 7397/7632/6830 +f 5297/7600/6799 7396/7630/6828 7395/7631/6829 +f 5279/7585/6787 7398/7633/6831 5298/7635/6833 +f 5278/7582/6785 7399/7629/6827 7398/7633/6831 +f 7398/7633/6831 7397/7632/6830 5299/7636/6834 +f 7401/7637/6835 7402/7641/6839 7400/7638/6836 +f 7403/7640/6838 7404/7643/6841 7400/7638/6836 +f 7405/7642/6840 7406/7639/6837 7400/7638/6836 +f 5286/7644/6842 7401/7637/6835 5300/7634/6832 +f 5287/7645/6843 7402/7641/6839 7401/7637/6835 +f 7401/7637/6835 7406/7639/6837 5299/7636/6834 +f 5303/7646/6844 7403/7640/6838 5288/7647/6845 +f 5303/7646/6844 5302/7650/6848 7404/7643/6841 +f 5288/7647/6845 7403/7640/6838 7402/7641/6839 +f 5298/7635/6833 7405/7642/6840 5301/7649/6847 +f 5298/7635/6833 5299/7636/6834 7406/7639/6837 +f 7405/7642/6840 7404/7643/6841 5302/7650/6848 +f 7408/7651/6849 7409/7655/6853 7407/7652/6850 +f 7410/7654/6852 7411/7657/6855 7407/7652/6850 +f 7412/7656/6854 7413/7653/6851 7407/7652/6850 +f 5301/7649/6847 7408/7651/6849 5274/7624/6822 +f 5302/7650/6848 7409/7655/6853 7408/7651/6849 +f 5274/7624/6822 7408/7651/6849 7413/7653/6851 +f 5306/7658/6856 7410/7654/6852 5303/7646/6844 +f 5306/7658/6856 5305/7660/6858 7411/7657/6855 +f 7410/7654/6852 7409/7655/6853 5302/7650/6848 +f 5276/7626/6824 7412/7656/6854 5304/7659/6857 +f 5275/7625/6823 7413/7653/6851 7412/7656/6854 +f 7412/7656/6854 7411/7657/6855 5305/7660/6858 +f 7415/7661/6859 7416/7665/6863 7414/7662/6860 +f 7417/7664/6862 7418/7667/6865 7414/7662/6860 +f 7419/7666/6864 7420/7663/6861 7414/7662/6860 +f 5280/7668/6866 7415/7661/6859 5306/7658/6856 +f 5281/7669/6867 7416/7665/6863 7415/7661/6859 +f 7415/7661/6859 7420/7663/6861 5305/7660/6858 +f 4140/6828/6052 7417/7664/6862 5282/7670/6868 +f 4140/6828/6052 4141/6826/6050 7418/7667/6865 +f 5282/7670/6868 7417/7664/6862 7416/7665/6863 +f 5304/7659/6857 7419/7666/6864 4142/6825/6049 +f 5305/7660/6858 7420/7663/6861 7419/7666/6864 +f 7419/7666/6864 7418/7667/6865 4141/6826/6050 +f 7422/7671/6869 7423/7675/6873 7421/7672/6870 +f 7424/7674/6872 7425/7677/6875 7421/7672/6870 +f 7426/7676/6874 7427/7673/6871 7421/7672/6870 +f 5307/4144/3470 7422/7671/6869 5283/7597/6798 +f 5308/4141/3468 7423/7675/6873 7422/7671/6869 +f 7422/7671/6869 7427/7673/6871 5284/7604/6803 +f 5312/7678/6876 7424/7674/6872 5309/4138/3467 +f 5311/7679/6877 7425/7677/6875 7424/7674/6872 +f 7424/7674/6872 7423/7675/6873 5308/4141/3468 +f 5285/7601/6800 7426/7676/6874 5310/7680/6878 +f 5285/7601/6800 5284/7604/6803 7427/7673/6871 +f 7426/7676/6874 7425/7677/6875 5311/7679/6877 +f 7429/7681/6879 7430/7685/6883 7428/7682/6880 +f 7431/7684/6882 7432/7687/6885 7428/7682/6880 +f 7433/7686/6884 7434/7683/6881 7428/7682/6880 +f 4091/7688/6886 7429/7681/6879 5312/7678/6876 +f 4090/7689/6887 7430/7685/6883 7429/7681/6879 +f 7429/7681/6879 7434/7683/6881 5311/7679/6877 +f 5315/7690/6888 7431/7684/6882 4089/7691/6889 +f 5314/7693/6891 7432/7687/6885 7431/7684/6882 +f 7431/7684/6882 7430/7685/6883 4090/7689/6887 +f 5310/7680/6878 7433/7686/6884 5313/7694/6892 +f 5311/7679/6877 7434/7683/6881 7433/7686/6884 +f 7433/7686/6884 7432/7687/6885 5314/7693/6891 +f 7436/7695/6893 7437/7699/6897 7435/7696/6894 +f 7438/7698/6896 7439/7701/6899 7435/7696/6894 +f 7440/7700/6898 7441/7697/6895 7435/7696/6894 +f 5313/7694/6892 7436/7695/6893 5286/7644/6842 +f 5314/7693/6891 7437/7699/6897 7436/7695/6893 +f 5286/7644/6842 7436/7695/6893 7441/7697/6895 +f 5318/7702/6900 7438/7698/6896 5315/7690/6888 +f 5318/7702/6900 5317/7704/6902 7439/7701/6899 +f 7438/7698/6896 7437/7699/6897 5314/7693/6891 +f 5288/7647/6845 7440/7700/6898 5316/7703/6901 +f 5287/7645/6843 7441/7697/6895 7440/7700/6898 +f 7440/7700/6898 7439/7701/6899 5317/7704/6902 +f 7443/7705/6903 7444/7709/6907 7442/7706/6904 +f 7445/7708/6906 7446/7711/6909 7442/7706/6904 +f 7447/7710/6908 7448/7707/6905 7442/7706/6904 +f 4088/7712/6910 7443/7705/6903 5318/7702/6900 +f 4087/7713/6911 7444/7709/6907 7443/7705/6903 +f 7443/7705/6903 7448/7707/6905 5317/7704/6902 +f 5321/7714/6912 7445/7708/6906 4086/7715/6913 +f 5320/7717/6915 7446/7711/6909 7445/7708/6906 +f 7445/7708/6906 7444/7709/6907 4087/7713/6911 +f 5316/7703/6901 7447/7710/6908 5319/7718/6916 +f 5316/7703/6901 5317/7704/6902 7448/7707/6905 +f 7447/7710/6908 7446/7711/6909 5320/7717/6915 +f 7450/7719/6917 7451/7723/6921 7449/7720/6918 +f 7452/7722/6920 7453/7725/6923 7449/7720/6918 +f 7454/7724/6922 7455/7721/6919 7449/7720/6918 +f 5319/7718/6916 7450/7719/6917 5280/7668/6866 +f 5320/7717/6915 7451/7723/6921 7450/7719/6917 +f 5280/7668/6866 7450/7719/6917 7455/7721/6919 +f 5324/7726/6924 7452/7722/6920 5321/7714/6912 +f 5323/7727/6925 7453/7725/6923 7452/7722/6920 +f 7452/7722/6920 7451/7723/6921 5320/7717/6915 +f 5282/7670/6868 7454/7724/6922 5322/7728/6926 +f 5281/7669/6867 7455/7721/6919 7454/7724/6922 +f 7454/7724/6922 7453/7725/6923 5323/7727/6925 +f 7457/7729/6927 7458/7733/6931 7456/7730/6928 +f 7459/7732/6930 7460/7735/6933 7456/7730/6928 +f 7461/7734/6932 7462/7731/6929 7456/7730/6928 +f 4085/7736/6934 7457/7729/6927 5324/7726/6924 +f 4084/7737/6935 7458/7733/6931 7457/7729/6927 +f 7457/7729/6927 7462/7731/6929 5323/7727/6925 +f 4137/6852/6075 7459/7732/6930 4083/7738/6936 +f 4137/6852/6075 4138/6850/6074 7460/7735/6933 +f 4083/7738/6936 7459/7732/6930 7458/7733/6931 +f 5322/7728/6926 7461/7734/6932 4139/6849/6073 +f 5323/7727/6925 7462/7731/6929 7461/7734/6932 +f 7461/7734/6932 7460/7735/6933 4138/6850/6074 +f 7464/7739/6937 7465/7743/6941 7463/7740/6938 +f 7466/7742/6940 7467/7745/6943 7463/7740/6938 +f 7468/7744/6942 7469/7741/6939 7463/7740/6938 +f 5325/7746/6944 7464/7739/6937 4112/7193/6413 +f 5326/7747/6945 7465/7743/6941 7464/7739/6937 +f 7464/7739/6937 7469/7741/6939 4111/7194/6414 +f 4005/7748/6424 7466/7742/6940 5327/7749/6946 +f 4006/7751/6427 7467/7745/6943 7466/7742/6940 +f 5327/7749/6946 7466/7742/6940 7465/7743/6941 +f 4110/7195/6415 7468/7744/6942 4007/7752/6429 +f 4110/7195/6415 4111/7194/6414 7469/7741/6939 +f 4007/7752/6429 7468/7744/6942 7467/7745/6943 +f 7471/7753/6947 7472/7757/6951 7470/7754/6948 +f 7473/7756/6950 7474/7759/6953 7470/7754/6948 +f 7475/7758/6952 7476/7755/6949 7470/7754/6948 +f 5331/7760/6954 7471/7753/6947 4115/7169/6389 +f 5332/7761/6955 7472/7757/6951 7471/7753/6947 +f 7471/7753/6947 7476/7755/6949 4114/7170/6390 +f 5345/7762/6956 7473/7756/6950 5333/7763/6957 +f 5344/7765/6959 7474/7759/6953 7473/7756/6950 +f 7473/7756/6950 7472/7757/6951 5332/7761/6955 +f 4113/7172/6392 7475/7758/6952 5343/7766/6960 +f 4114/7170/6390 7476/7755/6949 7475/7758/6952 +f 7475/7758/6952 7474/7759/6953 5344/7765/6959 +f 7478/7767/6961 7479/7771/6965 7477/7768/6962 +f 7480/7770/6964 7481/7773/6967 7477/7768/6962 +f 7482/7772/6966 7483/7769/6963 7477/7768/6962 +f 5337/7774/6968 7478/7767/6961 4118/7145/6365 +f 5338/7775/6969 7479/7771/6965 7478/7767/6961 +f 7478/7767/6961 7483/7769/6963 4117/7150/6370 +f 5351/7776/6970 7480/7770/6964 5339/7777/6971 +f 5350/7779/6973 7481/7773/6967 7480/7770/6964 +f 7480/7770/6964 7479/7771/6965 5338/7775/6969 +f 4116/7147/6367 7482/7772/6966 5349/7780/6974 +f 4117/7150/6370 7483/7769/6963 7482/7772/6966 +f 7482/7772/6966 7481/7773/6967 5350/7779/6973 +f 7485/7781/6975 7486/7785/6979 7484/7782/6976 +f 7487/7784/6978 7488/7787/6981 7484/7782/6976 +f 7489/7786/6980 7490/7783/6977 7484/7782/6976 +f 5343/7766/6960 7485/7781/6975 5325/7746/6944 +f 5344/7765/6959 7486/7785/6979 7485/7781/6975 +f 7485/7781/6975 7490/7783/6977 5326/7747/6945 +f 5348/7788/6982 7487/7784/6978 5345/7762/6956 +f 5348/7788/6982 5347/7790/6984 7488/7787/6981 +f 7487/7784/6978 7486/7785/6979 5344/7765/6959 +f 5327/7749/6946 7489/7786/6980 5346/7789/6983 +f 5326/7747/6945 7490/7783/6977 7489/7786/6980 +f 7489/7786/6980 7488/7787/6981 5347/7790/6984 +f 7492/7791/6985 7493/7795/6989 7491/7792/6986 +f 7494/7794/6988 7495/7797/6991 7491/7792/6986 +f 7496/7796/6990 7497/7793/6987 7491/7792/6986 +f 5328/7798/6992 7492/7791/6985 5348/7788/6982 +f 5329/7799/6993 7493/7795/6989 7492/7791/6985 +f 7492/7791/6985 7497/7793/6987 5347/7790/6984 +f 4125/7800/6438 7494/7794/6988 5330/7801/6994 +f 4126/7803/6441 7495/7797/6991 7494/7794/6988 +f 7494/7794/6988 7493/7795/6989 5329/7799/6993 +f 5346/7789/6983 7496/7796/6990 4127/7804/6446 +f 5346/7789/6983 5347/7790/6984 7497/7793/6987 +f 4127/7804/6446 7496/7796/6990 7495/7797/6991 +f 7499/7805/6995 7500/7809/6999 7498/7806/6996 +f 7501/7808/6998 7502/7811/7001 7498/7806/6996 +f 7503/7810/7000 7504/7807/6997 7498/7806/6996 +f 5349/7780/6974 7499/7805/6995 5331/7760/6954 +f 5350/7779/6973 7500/7809/6999 7499/7805/6995 +f 7499/7805/6995 7504/7807/6997 5332/7761/6955 +f 5354/7812/7002 7501/7808/6998 5351/7776/6970 +f 5353/7813/7003 7502/7811/7001 7501/7808/6998 +f 7501/7808/6998 7500/7809/6999 5350/7779/6973 +f 5333/7763/6957 7503/7810/7000 5352/7814/7004 +f 5332/7761/6955 7504/7807/6997 7503/7810/7000 +f 7503/7810/7000 7502/7811/7001 5353/7813/7003 +f 7506/7815/7005 7507/7819/7009 7505/7816/7006 +f 7508/7818/7008 7509/7821/7011 7505/7816/7006 +f 7510/7820/7010 7511/7817/7007 7505/7816/7006 +f 5340/7822/7012 7506/7815/7005 5354/7812/7002 +f 5340/7822/7012 5341/7827/7017 7507/7819/7009 +f 7506/7815/7005 7511/7817/7007 5353/7813/7003 +f 5357/7823/7013 7508/7818/7008 5342/7824/7014 +f 5356/7826/7016 7509/7821/7011 7508/7818/7008 +f 7508/7818/7008 7507/7819/7009 5341/7827/7017 +f 5352/7814/7004 7510/7820/7010 5355/7828/7018 +f 5353/7813/7003 7511/7817/7007 7510/7820/7010 +f 5355/7828/7018 7510/7820/7010 7509/7821/7011 +f 7513/7829/7019 7514/7833/7023 7512/7830/7020 +f 7515/7832/7022 7516/7835/7025 7512/7830/7020 +f 7517/7834/7024 7518/7831/7021 7512/7830/7020 +f 5355/7828/7018 7513/7829/7019 5328/7798/6992 +f 5356/7826/7016 7514/7833/7023 7513/7829/7019 +f 7513/7829/7019 7518/7831/7021 5329/7799/6993 +f 5360/7836/7026 7515/7832/7022 5357/7823/7013 +f 5360/7836/7026 5359/7838/7028 7516/7835/7025 +f 5357/7823/7013 7515/7832/7022 7514/7833/7023 +f 5330/7801/6994 7517/7834/7024 5358/7837/7027 +f 5329/7799/6993 7518/7831/7021 7517/7834/7024 +f 7517/7834/7024 7516/7835/7025 5359/7838/7028 +f 7520/7839/7029 7521/7843/7033 7519/7840/7030 +f 7522/7842/7032 7523/7845/7035 7519/7840/7030 +f 7524/7844/7034 7525/7841/7031 7519/7840/7030 +f 5334/7846/7036 7520/7839/7029 5360/7836/7026 +f 5335/7847/7037 7521/7843/7033 7520/7839/7029 +f 7520/7839/7029 7525/7841/7031 5359/7838/7028 +f 4122/7848/6456 7522/7842/7032 5336/7849/7038 +f 4123/7851/6457 7523/7845/7035 7522/7842/7032 +f 7522/7842/7032 7521/7843/7033 5335/7847/7037 +f 5358/7837/7027 7524/7844/7034 4124/7852/6463 +f 5358/7837/7027 5359/7838/7028 7525/7841/7031 +f 7524/7844/7034 7523/7845/7035 4123/7851/6457 +f 7527/7853/7039 7528/7857/7043 7526/7854/7040 +f 7529/7856/7042 7530/7859/7045 7526/7854/7040 +f 7531/7858/7044 7532/7855/7041 7526/7854/7040 +f 5361/4124/3455 7527/7853/7039 5337/7774/6968 +f 5361/4124/3455 5362/4126/3457 7528/7857/7043 +f 7527/7853/7039 7532/7855/7041 5338/7775/6969 +f 5366/7860/7046 7529/7856/7042 5363/4119/3450 +f 5365/7861/7047 7530/7859/7045 7529/7856/7042 +f 7529/7856/7042 7528/7857/7043 5362/4126/3457 +f 5339/7777/6971 7531/7858/7044 5364/7862/7048 +f 5338/7775/6969 7532/7855/7041 7531/7858/7044 +f 5364/7862/7048 7531/7858/7044 7530/7859/7045 +f 7534/7863/7049 7535/7867/7053 7533/7864/7050 +f 7536/7866/7052 7537/7869/7055 7533/7864/7050 +f 7538/7868/7054 7539/7865/7051 7533/7864/7050 +f 4100/7870/7056 7534/7863/7049 5366/7860/7046 +f 4099/7871/7057 7535/7867/7053 7534/7863/7049 +f 5366/7860/7046 7534/7863/7049 7539/7865/7051 +f 5369/7872/7058 7536/7866/7052 4098/7873/7059 +f 5368/7875/7061 7537/7869/7055 7536/7866/7052 +f 7536/7866/7052 7535/7867/7053 4099/7871/7057 +f 5364/7862/7048 7538/7868/7054 5367/7876/7062 +f 5365/7861/7047 7539/7865/7051 7538/7868/7054 +f 7538/7868/7054 7537/7869/7055 5368/7875/7061 +f 7541/7877/7063 7542/7881/7067 7540/7878/7064 +f 7543/7880/7066 7544/7883/7069 7540/7878/7064 +f 7545/7882/7068 7546/7879/7065 7540/7878/7064 +f 5367/7876/7062 7541/7877/7063 5340/7822/7012 +f 5368/7875/7061 7542/7881/7067 7541/7877/7063 +f 7541/7877/7063 7546/7879/7065 5341/7827/7017 +f 5372/7884/7070 7543/7880/7066 5369/7872/7058 +f 5371/7885/7071 7544/7883/7069 7543/7880/7066 +f 7543/7880/7066 7542/7881/7067 5368/7875/7061 +f 5342/7824/7014 7545/7882/7068 5370/7886/7072 +f 5342/7824/7014 5341/7827/7017 7546/7879/7065 +f 7545/7882/7068 7544/7883/7069 5371/7885/7071 +f 7548/7887/7073 7549/7891/7077 7547/7888/7074 +f 7550/7890/7076 7551/7893/7079 7547/7888/7074 +f 7552/7892/7078 7553/7889/7075 7547/7888/7074 +f 4097/7894/7080 7548/7887/7073 5372/7884/7070 +f 4096/7895/7081 7549/7891/7077 7548/7887/7073 +f 7548/7887/7073 7553/7889/7075 5371/7885/7071 +f 5375/7896/7082 7550/7890/7076 4095/7897/7083 +f 5374/7899/7084 7551/7893/7079 7550/7890/7076 +f 7550/7890/7076 7549/7891/7077 4096/7895/7081 +f 5370/7886/7072 7552/7892/7078 5373/7900/7085 +f 5371/7885/7071 7553/7889/7075 7552/7892/7078 +f 7552/7892/7078 7551/7893/7079 5374/7899/7084 +f 7555/7901/7086 7556/7905/7090 7554/7902/7087 +f 7557/7904/7089 7558/7907/7092 7554/7902/7087 +f 7559/7906/7091 7560/7903/7088 7554/7902/7087 +f 5373/7900/7085 7555/7901/7086 5334/7846/7036 +f 5374/7899/7084 7556/7905/7090 7555/7901/7086 +f 7555/7901/7086 7560/7903/7088 5335/7847/7037 +f 5378/7908/7093 7557/7904/7089 5375/7896/7082 +f 5377/7909/7094 7558/7907/7092 7557/7904/7089 +f 7557/7904/7089 7556/7905/7090 5374/7899/7084 +f 5336/7849/7038 7559/7906/7091 5376/7910/7095 +f 5335/7847/7037 7560/7903/7088 7559/7906/7091 +f 7559/7906/7091 7558/7907/7092 5377/7909/7094 +f 7562/7911/7096 7563/7915/7100 7561/7912/7097 +f 7564/7914/7099 7565/7917/7102 7561/7912/7097 +f 7566/7916/7101 7567/7913/7098 7561/7912/7097 +f 4094/7918/3432 7562/7911/7096 5378/7908/7093 +f 4093/7919/3435 7563/7915/7100 7562/7911/7096 +f 7562/7911/7096 7567/7913/7098 5377/7909/7094 +f 4119/7920/3493 7564/7914/7099 4092/7921/3427 +f 4119/7920/3493 4120/7924/3494 7565/7917/7102 +f 4092/7921/3427 7564/7914/7099 7563/7915/7100 +f 5376/7910/7095 7566/7916/7101 4121/7923/3497 +f 5377/7909/7094 7567/7913/7098 7566/7916/7101 +f 7566/7916/7101 7565/7917/7102 4120/7924/3494 +f 7569/7925/7103 7570/7929/7107 7568/7926/7104 +f 7571/7928/7106 7572/7931/7109 7568/7926/7104 +f 7573/7930/7108 7574/7927/7105 7568/7926/7104 +f 5379/7932/7110 7569/7925/7103 4085/7933/6934 +f 5380/7935/7111 7570/7929/7107 7569/7925/7103 +f 7569/7925/7103 7574/7927/7105 4084/7936/6935 +f 3999/4211/3527 7571/7928/7106 5381/7937/7112 +f 4000/4208/3524 7572/7931/7109 7571/7928/7106 +f 7571/7928/7106 7570/7929/7107 5380/7935/7111 +f 4083/7938/6936 7573/7930/7108 4001/4205/3521 +f 4083/7938/6936 4084/7936/6935 7574/7927/7105 +f 4001/4205/3521 7573/7930/7108 7572/7931/7109 +f 7576/7939/7113 7577/7943/7117 7575/7940/7114 +f 7578/7942/7116 7579/7945/7119 7575/7940/7114 +f 7580/7944/7118 7581/7941/7115 7575/7940/7114 +f 5385/7946/7120 7576/7939/7113 4088/7947/6910 +f 5386/7949/7121 7577/7943/7117 7576/7939/7113 +f 7576/7939/7113 7581/7941/7115 4087/7950/6911 +f 5399/7951/7122 7578/7942/7116 5387/7952/7123 +f 5398/7954/7125 7579/7945/7119 7578/7942/7116 +f 5387/7952/7123 7578/7942/7116 7577/7943/7117 +f 4086/7955/6913 7580/7944/7118 5397/7956/7126 +f 4087/7950/6911 7581/7941/7115 7580/7944/7118 +f 7580/7944/7118 7579/7945/7119 5398/7954/7125 +f 7583/7957/7127 7584/7961/7131 7582/7958/7128 +f 7585/7960/7130 7586/7963/7133 7582/7958/7128 +f 7587/7962/7132 7588/7959/7129 7582/7958/7128 +f 5391/7964/7134 7583/7957/7127 4091/7965/6886 +f 5392/7966/7135 7584/7961/7131 7583/7957/7127 +f 7583/7957/7127 7588/7959/7129 4090/7967/6887 +f 5405/7968/7136 7585/7960/7130 5393/7969/7137 +f 5404/7971/7139 7586/7963/7133 7585/7960/7130 +f 7585/7960/7130 7584/7961/7131 5392/7966/7135 +f 4089/7972/6889 7587/7962/7132 5403/7973/7140 +f 4090/7967/6887 7588/7959/7129 7587/7962/7132 +f 7587/7962/7132 7586/7963/7133 5404/7971/7139 +f 7590/7974/7141 7591/7978/7145 7589/7975/7142 +f 7592/7977/7144 7593/7980/7147 7589/7975/7142 +f 7594/7979/7146 7595/7976/7143 7589/7975/7142 +f 5397/7956/7126 7590/7974/7141 5379/7932/7110 +f 5398/7954/7125 7591/7978/7145 7590/7974/7141 +f 7590/7974/7141 7595/7976/7143 5380/7935/7111 +f 5402/7981/7148 7592/7977/7144 5399/7951/7122 +f 5401/7982/7149 7593/7980/7147 7592/7977/7144 +f 7592/7977/7144 7591/7978/7145 5398/7954/7125 +f 5381/7937/7112 7594/7979/7146 5400/7983/7150 +f 5380/7935/7111 7595/7976/7143 7594/7979/7146 +f 7594/7979/7146 7593/7980/7147 5401/7982/7149 +f 7597/7984/7151 7598/7988/7155 7596/7985/7152 +f 7599/7987/7154 7600/7990/7157 7596/7985/7152 +f 7601/7989/7156 7602/7986/7153 7596/7985/7152 +f 5382/7991/7158 7597/7984/7151 5402/7981/7148 +f 5383/7992/7159 7598/7988/7155 7597/7984/7151 +f 7597/7984/7151 7602/7986/7153 5401/7982/7149 +f 4107/6978/6198 7599/7987/7154 5384/7993/7160 +f 4108/6976/6196 7600/7990/7157 7599/7987/7154 +f 7599/7987/7154 7598/7988/7155 5383/7992/7159 +f 5400/7983/7150 7601/7989/7156 4109/6975/6195 +f 5401/7982/7149 7602/7986/7153 7601/7989/7156 +f 4109/6975/6195 7601/7989/7156 7600/7990/7157 +f 7604/7994/7161 7605/7998/7165 7603/7995/7162 +f 7606/7997/7164 7607/8000/7167 7603/7995/7162 +f 7608/7999/7166 7609/7996/7163 7603/7995/7162 +f 5403/7973/7140 7604/7994/7161 5385/7946/7120 +f 5404/7971/7139 7605/7998/7165 7604/7994/7161 +f 5385/7946/7120 7604/7994/7161 7609/7996/7163 +f 5408/8001/7168 7606/7997/7164 5405/7968/7136 +f 5407/8002/7169 7607/8000/7167 7606/7997/7164 +f 7606/7997/7164 7605/7998/7165 5404/7971/7139 +f 5387/7952/7123 7608/7999/7166 5406/8003/7170 +f 5386/7949/7121 7609/7996/7163 7608/7999/7166 +f 7608/7999/7166 7607/8000/7167 5407/8002/7169 +f 7611/8004/7171 7612/8008/7175 7610/8005/7172 +f 7613/8007/7174 7614/8010/7177 7610/8005/7172 +f 7615/8009/7176 7616/8006/7173 7610/8005/7172 +f 5394/8011/7178 7611/8004/7171 5408/8001/7168 +f 5395/8012/7179 7612/8008/7175 7611/8004/7171 +f 7611/8004/7171 7616/8006/7173 5407/8002/7169 +f 5411/8013/7180 7613/8007/7174 5396/8014/7181 +f 5410/8016/7183 7614/8010/7177 7613/8007/7174 +f 7613/8007/7174 7612/8008/7175 5395/8012/7179 +f 5406/8003/7170 7615/8009/7176 5409/8017/7184 +f 5407/8002/7169 7616/8006/7173 7615/8009/7176 +f 7615/8009/7176 7614/8010/7177 5410/8016/7183 +f 7618/8018/7185 7619/8022/7189 7617/8019/7186 +f 7620/8021/7188 7621/8024/7191 7617/8019/7186 +f 7622/8023/7190 7623/8020/7187 7617/8019/7186 +f 5409/8017/7184 7618/8018/7185 5382/7991/7158 +f 5410/8016/7183 7619/8022/7189 7618/8018/7185 +f 7618/8018/7185 7623/8020/7187 5383/7992/7159 +f 5414/8025/7192 7620/8021/7188 5411/8013/7180 +f 5413/8026/7193 7621/8024/7191 7620/8021/7188 +f 7620/8021/7188 7619/8022/7189 5410/8016/7183 +f 5384/7993/7160 7622/8023/7190 5412/8027/7194 +f 5384/7993/7160 5383/7992/7159 7623/8020/7187 +f 7622/8023/7190 7621/8024/7191 5413/8026/7193 +f 7625/8028/7195 7626/8032/7199 7624/8029/7196 +f 7627/8031/7198 7628/8034/7201 7624/8029/7196 +f 7629/8033/7200 7630/8030/7197 7624/8029/7196 +f 5388/8035/7202 7625/8028/7195 5414/8025/7192 +f 5389/8036/7203 7626/8032/7199 7625/8028/7195 +f 7625/8028/7195 7630/8030/7197 5413/8026/7193 +f 4104/7002/6222 7627/8031/7198 5390/8037/7204 +f 4105/7000/6220 7628/8034/7201 7627/8031/7198 +f 7627/8031/7198 7626/8032/7199 5389/8036/7203 +f 5412/8027/7194 7629/8033/7200 4106/6999/6219 +f 5413/8026/7193 7630/8030/7197 7629/8033/7200 +f 7629/8033/7200 7628/8034/7201 4105/7000/6220 +f 7632/8038/7205 7633/8042/7209 7631/8039/7206 +f 7634/8041/7208 7635/8044/7211 7631/8039/7206 +f 7636/8043/7210 7637/8040/7207 7631/8039/7206 +f 5415/4106/3437 7632/8038/7205 5391/7964/7134 +f 5416/4103/3434 7633/8042/7209 7632/8038/7205 +f 7632/8038/7205 7637/8040/7207 5392/7966/7135 +f 5420/8045/7212 7634/8041/7208 5417/4100/3431 +f 5419/8046/7213 7635/8044/7211 7634/8041/7208 +f 7634/8041/7208 7633/8042/7209 5416/4103/3434 +f 5393/7969/7137 7636/8043/7210 5418/8047/7214 +f 5392/7966/7135 7637/8040/7207 7636/8043/7210 +f 7636/8043/7210 7635/8044/7211 5419/8046/7213 +f 7639/8048/7215 7640/8052/7219 7638/8049/7216 +f 7641/8051/7218 7642/8054/7221 7638/8049/7216 +f 7643/8053/7220 7644/8050/7217 7638/8049/7216 +f 4095/8055/7083 7639/8048/7215 5420/8045/7212 +f 4096/8056/7081 7640/8052/7219 7639/8048/7215 +f 7639/8048/7215 7644/8050/7217 5419/8046/7213 +f 5423/8057/7222 7641/8051/7218 4097/8058/7080 +f 5422/8060/7223 7642/8054/7221 7641/8051/7218 +f 7641/8051/7218 7640/8052/7219 4096/8056/7081 +f 5418/8047/7214 7643/8053/7220 5421/8061/7224 +f 5419/8046/7213 7644/8050/7217 7643/8053/7220 +f 7643/8053/7220 7642/8054/7221 5422/8060/7223 +f 7646/8062/7225 7647/8066/7229 7645/8063/7226 +f 7648/8065/7228 7649/8068/7231 7645/8063/7226 +f 7650/8067/7230 7651/8064/7227 7645/8063/7226 +f 5421/8061/7224 7646/8062/7225 5394/8011/7178 +f 5422/8060/7223 7647/8066/7229 7646/8062/7225 +f 7646/8062/7225 7651/8064/7227 5395/8012/7179 +f 5426/8069/7232 7648/8065/7228 5423/8057/7222 +f 5425/8070/7233 7649/8068/7231 7648/8065/7228 +f 7648/8065/7228 7647/8066/7229 5422/8060/7223 +f 5396/8014/7181 7650/8067/7230 5424/8071/7234 +f 5395/8012/7179 7651/8064/7227 7650/8067/7230 +f 7650/8067/7230 7649/8068/7231 5425/8070/7233 +f 7653/8072/7235 7654/8076/7239 7652/8073/7236 +f 7655/8075/7238 7656/8078/7241 7652/8073/7236 +f 7657/8077/7240 7658/8074/7237 7652/8073/7236 +f 4098/8079/7059 7653/8072/7235 5426/8069/7232 +f 4099/8080/7057 7654/8076/7239 7653/8072/7235 +f 7653/8072/7235 7658/8074/7237 5425/8070/7233 +f 5429/8081/7242 7655/8075/7238 4100/8082/7056 +f 5429/8081/7242 5428/8085/7244 7656/8078/7241 +f 7655/8075/7238 7654/8076/7239 4099/8080/7057 +f 5424/8071/7234 7657/8077/7240 5427/8084/7243 +f 5425/8070/7233 7658/8074/7237 7657/8077/7240 +f 7657/8077/7240 7656/8078/7241 5428/8085/7244 +f 7660/8086/7245 7661/8090/7249 7659/8087/7246 +f 7662/8089/7248 7663/8092/7251 7659/8087/7246 +f 7664/8091/7250 7665/8088/7247 7659/8087/7246 +f 5427/8084/7243 7660/8086/7245 5388/8035/7202 +f 5428/8085/7244 7661/8090/7249 7660/8086/7245 +f 7660/8086/7245 7665/8088/7247 5389/8036/7203 +f 5432/8093/7252 7662/8089/7248 5429/8081/7242 +f 5431/8094/7253 7663/8092/7251 7662/8089/7248 +f 7662/8089/7248 7661/8090/7249 5428/8085/7244 +f 5390/8037/7204 7664/8091/7250 5430/8095/7254 +f 5389/8036/7203 7665/8088/7247 7664/8091/7250 +f 7664/8091/7250 7663/8092/7251 5431/8094/7253 +f 7667/8096/7255 7668/8100/7259 7666/8097/7256 +f 7669/8099/7258 7670/8102/7261 7666/8097/7256 +f 7671/8101/7260 7672/8098/7257 7666/8097/7256 +f 3996/8103/3451 7667/8096/7255 5432/8093/7252 +f 3997/8104/3453 7668/8100/7259 7667/8096/7255 +f 7667/8096/7255 7672/8098/7257 5431/8094/7253 +f 4101/7025/6245 7669/8099/7258 3998/8105/3446 +f 4101/7025/6245 4102/7024/6244 7670/8102/7261 +f 3998/8105/3446 7669/8099/7258 7668/8100/7259 +f 5430/8095/7254 7671/8101/7260 4103/7023/6243 +f 5431/8094/7253 7672/8098/7257 7671/8101/7260 +f 7671/8101/7260 7670/8102/7261 4102/7024/6244 +g Cylinder_Cylinder.009 +v 4.346404 6.972321 -5.002706 +v 8.892768 6.972321 -0.457876 +v 4.328356 6.922321 -5.002694 +v 8.892756 6.922320 -0.436843 +v 4.281034 6.885718 -5.002692 +v 8.892767 6.885718 -0.391204 +v 4.225754 6.872321 -5.002688 +v 8.892756 6.872320 -0.341017 +v 4.159375 6.885718 -5.002667 +v 8.892769 6.885718 -0.286292 +v 4.118864 6.922321 -5.002659 +v 8.892767 6.922320 -0.245579 +v 4.099302 6.972321 -5.002657 +v 8.892769 6.972321 -0.226420 +v 4.118864 7.022321 -5.002659 +v 8.892767 7.022320 -0.245579 +v 4.159375 7.058923 -5.002667 +v 8.892769 7.058923 -0.286292 +v 4.225754 7.072321 -5.002688 +v 8.892756 7.072320 -0.341017 +v 4.281034 7.058923 -5.002692 +v 8.892767 7.058923 -0.391204 +v 4.328356 7.022321 -5.002694 +v 8.892756 7.022320 -0.436843 +vt 1.000000 1.000000 +vt 0.916667 0.500000 +vt 1.000000 0.500000 +vt 0.833333 1.000000 +vt 0.833333 0.500000 +vt 0.750000 1.000000 +vt 0.750000 0.500000 +vt 0.666667 1.000000 +vt 0.666667 0.500000 +vt 0.583333 1.000000 +vt 0.583333 0.500000 +vt 0.500000 1.000000 +vt 0.500000 0.500000 +vt 0.416667 0.500000 +vt 0.416667 1.000000 +vt 0.333333 0.500000 +vt 0.333333 1.000000 +vt 0.250000 0.500000 +vt 0.250000 1.000000 +vt 0.166667 0.500000 +vt 0.166667 1.000000 +vt 0.083333 0.500000 +vt 0.000000 1.000000 +vt 0.000000 0.500000 +vt 0.916667 1.000000 +vt 0.083333 1.000000 +vn 0.7072 0.0000 -0.7070 +vn 0.6008 -0.5271 -0.6009 +vn 0.7070 0.0000 -0.7072 +vn 0.3418 -0.8754 -0.3418 +vn 0.3241 -0.8887 -0.3243 +vn -0.1110 -0.9875 0.1112 +vn -0.0879 -0.9922 0.0884 +vn -0.4801 -0.7331 0.4817 +vn -0.4752 -0.7393 0.4769 +vn -0.6478 -0.3970 0.6501 +vn -0.6475 -0.3981 0.6498 +vn -0.7058 0.0000 0.7083 +vn -0.7058 0.0000 0.7084 +vn -0.6475 0.3981 0.6498 +vn -0.6478 0.3970 0.6501 +vn -0.4752 0.7393 0.4769 +vn -0.4801 0.7331 0.4817 +vn -0.0879 0.9922 0.0884 +vn -0.1110 0.9875 0.1112 +vn 0.3241 0.8886 -0.3243 +vn 0.3418 0.8754 -0.3418 +vn 0.6008 0.5271 -0.6009 +vn 0.5989 -0.5318 -0.5987 +vn 0.5989 0.5318 -0.5987 +g Cylinder_Cylinder.009_curtain-bar +usemtl curtain-bar +s 1 +f 7674/8106/7262 7675/8107/7263 7673/8108/7264 +f 7675/8107/7263 7678/8109/7265 7677/8110/7266 +f 7677/8110/7266 7680/8111/7267 7679/8112/7268 +f 7679/8112/7268 7682/8113/7269 7681/8114/7270 +f 7681/8114/7270 7684/8115/7271 7683/8116/7272 +f 7683/8116/7272 7686/8117/7273 7685/8118/7274 +f 7686/8117/7273 7687/8119/7275 7685/8118/7274 +f 7688/8120/7276 7689/8121/7277 7687/8119/7275 +f 7690/8122/7278 7691/8123/7279 7689/8121/7277 +f 7692/8124/7280 7693/8125/7281 7691/8123/7279 +f 7694/8126/7282 7695/8127/7283 7693/8125/7281 +f 7695/8127/7283 7674/8128/7262 7673/8129/7264 +f 7674/8106/7262 7676/8130/7284 7675/8107/7263 +f 7675/8107/7263 7676/8130/7284 7678/8109/7265 +f 7677/8110/7266 7678/8109/7265 7680/8111/7267 +f 7679/8112/7268 7680/8111/7267 7682/8113/7269 +f 7681/8114/7270 7682/8113/7269 7684/8115/7271 +f 7683/8116/7272 7684/8115/7271 7686/8117/7273 +f 7686/8117/7273 7688/8120/7276 7687/8119/7275 +f 7688/8120/7276 7690/8122/7278 7689/8121/7277 +f 7690/8122/7278 7692/8124/7280 7691/8123/7279 +f 7692/8124/7280 7694/8126/7282 7693/8125/7281 +f 7694/8126/7282 7696/8131/7285 7695/8127/7283 +f 7695/8127/7283 7696/8131/7285 7674/8128/7262 +g Plane +v 4.457127 0.862453 -4.850698 +v 8.562819 0.862453 -0.676594 +v 4.422921 6.993753 -4.816492 +v 8.532791 6.993753 -0.646567 +v 4.433544 6.897951 -4.827116 +v 4.443468 6.802150 -4.837039 +v 4.451936 6.706348 -4.845507 +v 4.458172 6.610546 -4.851743 +v 4.461449 6.514745 -4.855020 +v 4.461241 6.418943 -4.854812 +v 4.457407 6.323142 -4.850978 +v 4.450332 6.227341 -4.843903 +v 4.440845 6.131539 -4.834417 +v 4.429982 6.035737 -4.823553 +v 4.418897 5.939936 -4.812469 +v 4.408682 5.844134 -4.802253 +v 4.400253 5.748332 -4.793824 +v 4.394315 5.652531 -4.787886 +v 4.391363 5.556729 -4.784934 +v 4.391716 5.460928 -4.785287 +v 4.395512 5.365127 -4.789083 +v 4.402497 5.269324 -4.796068 +v 4.411916 5.173523 -4.805488 +v 4.422700 5.077722 -4.816271 +v 4.433688 4.981920 -4.827259 +v 4.443812 4.886119 -4.837384 +v 4.452207 4.790317 -4.845778 +v 4.458224 4.694515 -4.851796 +v 4.461420 4.598714 -4.854991 +v 4.461318 4.502913 -4.854889 +v 4.457726 4.407111 -4.851297 +v 4.450952 4.311309 -4.844523 +v 4.441745 4.215508 -4.835316 +v 4.431146 4.119706 -4.824717 +v 4.420300 4.023904 -4.813870 +v 4.410275 3.928103 -4.803845 +v 4.401857 3.832301 -4.795429 +v 4.395541 3.736500 -4.789112 +v 4.391844 3.640698 -4.785416 +v 4.391284 3.544897 -4.784855 +v 4.394199 3.449095 -4.787771 +v 4.400547 3.353294 -4.794119 +v 4.409731 3.257492 -4.803303 +v 4.420595 3.161691 -4.814167 +v 4.431803 3.065889 -4.825375 +v 4.442305 2.970088 -4.835876 +v 4.451180 2.874286 -4.844750 +v 4.457676 2.778484 -4.851247 +v 4.461235 2.682683 -4.854806 +v 4.461507 2.586882 -4.855078 +v 4.458381 2.491080 -4.851952 +v 4.452008 2.395278 -4.845580 +v 4.443067 2.299477 -4.836637 +v 4.432645 2.203675 -4.826217 +v 4.421749 2.107873 -4.815320 +v 4.411354 2.012072 -4.804925 +v 4.402374 1.916270 -4.795945 +v 4.395624 1.820469 -4.789196 +v 4.391786 1.724667 -4.785357 +v 4.391355 1.628865 -4.784926 +v 4.394456 1.533064 -4.788027 +v 4.400610 1.437263 -4.794182 +v 4.409137 1.341461 -4.802708 +v 4.419248 1.245659 -4.812819 +v 4.430067 1.149858 -4.823638 +v 4.440645 1.054056 -4.834217 +v 4.449992 0.958255 -4.843564 +v 4.515207 0.862453 -4.779407 +v 4.571224 0.862453 -4.706052 +v 4.625798 0.862453 -4.631255 +v 4.679684 0.862453 -4.555767 +v 4.733833 0.862453 -4.480546 +v 4.789368 0.862453 -4.406709 +v 4.847414 0.862453 -4.335383 +v 4.908842 0.862453 -4.267439 +v 4.974058 0.862453 -4.203284 +v 5.043145 0.862453 -4.142998 +v 5.115479 0.862453 -4.085961 +v 5.189907 0.862453 -4.031017 +v 5.265169 0.862453 -3.976907 +v 5.340217 0.862453 -3.922583 +v 5.414320 0.862453 -3.867315 +v 5.486983 0.862453 -3.810605 +v 5.557644 0.862453 -3.751894 +v 5.625648 0.862453 -3.690526 +v 5.690497 0.862453 -3.626004 +v 5.751930 0.862453 -3.558065 +v 5.810075 0.862453 -3.486838 +v 5.865547 0.862453 -3.412938 +v 5.919423 0.862453 -3.337443 +v 5.973057 0.862453 -3.261705 +v 6.027490 0.862453 -3.186766 +v 6.083416 0.862453 -3.113320 +v 6.141636 0.862453 -3.042169 +v 6.202809 0.862453 -2.973970 +v 6.267356 0.862453 -2.909145 +v 6.335371 0.862453 -2.847789 +v 6.406559 0.862453 -2.789604 +v 6.480223 0.862453 -2.733897 +v 6.555515 0.862453 -2.679817 +v 6.631430 0.862453 -2.626360 +v 6.706748 0.862453 -2.572306 +v 6.780365 0.862453 -2.516552 +v 6.851437 0.862453 -2.458251 +v 6.919439 0.862453 -2.396882 +v 6.984163 0.862453 -2.332234 +v 7.045661 0.862453 -2.264360 +v 7.104386 0.862453 -2.193713 +v 7.161022 0.862453 -2.120978 +v 7.216068 0.862453 -2.046652 +v 7.270117 0.862453 -1.971329 +v 7.324021 0.862453 -1.895861 +v 7.378920 0.862453 -1.821388 +v 7.436094 0.862453 -1.749190 +v 7.496639 0.862453 -1.680364 +v 7.561079 0.862453 -1.615431 +v 7.629244 0.862453 -1.554225 +v 7.700501 0.862453 -1.496110 +v 7.773979 0.862453 -1.440216 +v 7.848761 0.862453 -1.385626 +v 7.923997 0.862453 -1.331491 +v 7.998915 0.862453 -1.277036 +v 8.072742 0.862453 -1.221493 +v 8.144428 0.862453 -1.163807 +v 8.212971 0.862453 -1.102977 +v 8.277967 0.862453 -1.038602 +v 8.339490 0.862453 -0.970754 +v 8.397994 0.862453 -0.899885 +v 8.454173 0.862453 -0.826693 +v 8.508837 0.862453 -0.751984 +v 8.552826 0.958255 -0.666602 +v 8.544036 1.054056 -0.657811 +v 8.537004 1.149858 -0.650779 +v 8.532422 1.245659 -0.646198 +v 8.531012 1.341461 -0.644788 +v 8.533279 1.437263 -0.647055 +v 8.539221 1.533064 -0.652997 +v 8.548122 1.628865 -0.661898 +v 8.558971 1.724667 -0.672747 +v 8.570614 1.820469 -0.684390 +v 8.581602 1.916270 -0.695378 +v 8.590759 2.012072 -0.704535 +v 8.597332 2.107873 -0.711108 +v 8.600967 2.203675 -0.714743 +v 8.601561 2.299477 -0.715337 +v 8.599081 2.395278 -0.712857 +v 8.593728 2.491080 -0.707504 +v 8.586073 2.586882 -0.699849 +v 8.576602 2.682683 -0.690378 +v 8.565940 2.778484 -0.679716 +v 8.554975 2.874286 -0.668751 +v 8.544868 2.970088 -0.658645 +v 8.536894 3.065889 -0.650670 +v 8.532127 3.161691 -0.645903 +v 8.531081 3.257492 -0.644857 +v 8.533602 3.353293 -0.647378 +v 8.539217 3.449095 -0.652992 +v 8.547293 3.544897 -0.661069 +v 8.557100 3.640698 -0.670876 +v 8.567831 3.736500 -0.681607 +v 8.578606 3.832302 -0.692382 +v 8.588448 3.928103 -0.702224 +v 8.595994 4.023905 -0.709770 +v 8.600441 4.119706 -0.714217 +v 8.601683 4.215508 -0.715458 +v 8.599719 4.311309 -0.713495 +v 8.594667 4.407111 -0.708443 +v 8.586812 4.502913 -0.700588 +v 8.576692 4.598714 -0.690467 +v 8.565159 4.694516 -0.678935 +v 8.553591 4.790317 -0.667366 +v 8.543568 4.886119 -0.657343 +v 8.536174 4.981920 -0.649950 +v 8.531973 5.077722 -0.645749 +v 8.531072 5.173523 -0.644848 +v 8.533302 5.269325 -0.647079 +v 8.538406 5.365126 -0.652182 +v 8.546154 5.460928 -0.659929 +v 8.556183 5.556730 -0.669958 +v 8.567471 5.652531 -0.681247 +v 8.578675 5.748333 -0.692451 +v 8.588496 5.844134 -0.702272 +v 8.595933 5.939936 -0.709709 +v 8.600398 6.035737 -0.714174 +v 8.601690 6.131539 -0.715466 +v 8.599895 6.227340 -0.713671 +v 8.595166 6.323142 -0.708942 +v 8.587702 6.418943 -0.701478 +v 8.578032 6.514745 -0.691807 +v 8.567026 6.610547 -0.680801 +v 8.555830 6.706348 -0.669606 +v 8.545701 6.802150 -0.659477 +v 8.537766 6.897951 -0.651542 +v 8.473288 6.993753 -0.716435 +v 8.416721 6.993753 -0.789241 +v 8.362192 6.993753 -0.864083 +v 8.308558 6.993753 -0.939821 +v 8.254662 6.993752 -1.015297 +v 8.199492 6.993753 -1.089499 +v 8.142263 6.993752 -1.161641 +v 8.082408 6.993753 -1.231158 +v 8.019526 6.993753 -1.297647 +v 7.953343 6.993753 -1.360837 +v 7.883874 6.993753 -1.420740 +v 7.811502 6.993752 -1.477740 +v 7.736970 6.993753 -1.532579 +v 7.661300 6.993753 -1.586281 +v 7.585658 6.993752 -1.640011 +v 7.511179 6.993753 -1.694904 +v 7.438642 6.993752 -1.751738 +v 7.368703 6.993752 -1.811172 +v 7.301975 6.993752 -1.873815 +v 7.238722 6.993752 -1.939934 +v 7.178817 6.993752 -2.009401 +v 7.121755 6.993752 -2.081711 +v 7.066720 6.993753 -2.156046 +v 7.012698 6.993753 -2.231397 +v 6.958612 6.993753 -2.306683 +v 6.903606 6.993753 -2.381049 +v 6.846937 6.993753 -2.453751 +v 6.787861 6.993752 -2.524047 +v 6.725716 6.993753 -2.591274 +v 6.660057 6.993752 -2.654987 +v 6.590833 6.993752 -2.715135 +v 6.518499 6.993753 -2.772172 +v 6.443693 6.993752 -2.826739 +v 6.367413 6.993753 -2.879830 +v 6.291214 6.993753 -2.933003 +v 6.216494 6.993753 -2.987655 +v 6.144193 6.993753 -3.044725 +v 6.074752 6.993753 -3.104656 +v 6.008263 6.993753 -3.167539 +v 5.944691 6.993753 -3.233339 +v 5.883989 6.993753 -3.302009 +v 5.825967 6.993753 -3.373358 +v 5.770267 6.993753 -3.447030 +v 5.716237 6.993753 -3.522372 +v 5.662874 6.993753 -3.598381 +v 5.608903 6.993753 -3.673781 +v 5.553004 6.993753 -3.747254 +v 5.494157 6.993753 -3.817780 +v 5.431996 6.993753 -3.884991 +v 5.366392 6.993753 -3.948758 +v 5.297411 6.993753 -4.009149 +v 5.225493 6.993753 -4.066603 +v 5.151385 6.993753 -4.121866 +v 5.076031 6.993753 -4.175884 +v 5.000466 6.993753 -4.229692 +v 4.925712 6.993753 -4.284309 +v 4.852852 6.993752 -4.340820 +v 4.782476 6.993753 -4.399817 +v 4.714858 6.993752 -4.461570 +v 4.650321 6.993753 -4.526405 +v 4.589121 6.993753 -4.594578 +v 4.531242 6.993753 -4.666070 +v 4.476193 6.993752 -4.740394 +v 4.505795 0.958255 -4.769995 +v 4.560431 0.958255 -4.695259 +v 4.614612 0.958255 -4.620068 +v 4.669145 0.958254 -4.545230 +v 4.724961 0.958255 -4.471673 +v 4.783047 0.958255 -4.400388 +v 4.844273 0.958255 -4.332241 +v 4.909156 0.958255 -4.267753 +v 4.977798 0.958255 -4.207023 +v 5.049905 0.958255 -4.149758 +v 5.124477 0.958255 -4.094958 +v 5.200165 0.958255 -4.041275 +v 5.275688 0.958255 -3.987425 +v 5.350074 0.958255 -3.932439 +v 5.422698 0.958255 -3.875692 +v 5.493151 0.958255 -3.816773 +v 5.560998 0.958255 -3.755249 +v 5.625821 0.958255 -3.690700 +v 5.687407 0.958255 -3.622913 +v 5.745827 0.958255 -3.551962 +v 5.801551 0.958255 -3.478314 +v 5.855479 0.958255 -3.402871 +v 5.908849 0.958255 -3.326869 +v 5.963007 0.958255 -3.251656 +v 6.018853 0.958255 -3.178129 +v 6.076995 0.958255 -3.106899 +v 6.138123 0.958255 -3.038655 +v 6.202688 0.958255 -2.973849 +v 6.270805 0.958254 -2.912594 +v 6.342175 0.958255 -2.854593 +v 6.416085 0.958255 -2.799130 +v 6.491477 0.958255 -2.745151 +v 6.567342 0.958255 -2.691644 +v 6.642643 0.958255 -2.637573 +v 6.716218 0.958255 -2.581777 +v 6.787158 0.958255 -2.523344 +v 6.854906 0.958255 -2.461721 +v 6.919276 0.958255 -2.396719 +v 6.980396 0.958255 -2.328467 +v 7.038635 0.958255 -2.257334 +v 7.094815 0.958255 -2.184143 +v 7.149847 0.958255 -2.109802 +v 7.204300 0.958255 -2.034884 +v 7.258831 0.958255 -1.960042 +v 7.314290 0.958255 -1.886130 +v 7.371710 0.958255 -1.814179 +v 7.432128 0.958255 -1.745225 +v 7.496280 0.958255 -1.680005 +v 7.564285 0.958255 -1.618638 +v 7.635606 0.958255 -1.560586 +v 7.709332 0.958255 -1.504941 +v 7.784417 0.958255 -1.450654 +v 7.859848 0.958255 -1.396714 +v 7.934731 0.958255 -1.342225 +v 8.008281 0.958255 -1.286403 +v 8.079752 0.958255 -1.228502 +v 8.148276 0.958255 -1.167655 +v 8.213291 0.958255 -1.103298 +v 8.274841 0.958255 -1.035476 +v 8.333378 0.958254 -0.964640 +v 8.389610 0.958255 -0.891502 +v 8.444370 0.958255 -0.816889 +v 8.498501 0.958255 -0.741648 +v 4.495060 1.054056 -4.759259 +v 4.549237 1.054056 -4.684065 +v 4.603961 1.054056 -4.609416 +v 4.660051 1.054056 -4.536135 +v 4.718353 1.054056 -4.465066 +v 4.779628 1.054056 -4.396968 +v 4.844388 1.054056 -4.332356 +v 4.912727 1.054056 -4.271324 +v 4.984401 1.054056 -4.213626 +v 5.058788 1.054056 -4.158641 +v 5.134659 1.054056 -4.105140 +v 5.210628 1.054056 -4.051738 +v 5.285488 1.054056 -3.997226 +v 5.358379 1.054056 -3.940746 +v 5.428790 1.054056 -3.881784 +v 5.496423 1.054056 -3.820045 +v 5.561052 1.054056 -3.755302 +v 5.622599 1.054056 -3.687478 +v 5.681197 1.054056 -3.616704 +v 5.737248 1.054056 -3.543384 +v 5.791484 1.054056 -3.468247 +v 5.844950 1.054056 -3.392341 +v 5.898882 1.054056 -3.316902 +v 5.954484 1.054056 -3.243132 +v 6.012515 1.054056 -3.171791 +v 6.073507 1.054056 -3.103411 +v 6.137954 1.054056 -3.038487 +v 6.206015 1.054056 -2.977176 +v 6.277430 1.054056 -2.919219 +v 6.351501 1.054056 -2.863919 +v 6.427159 1.054056 -2.810205 +v 6.503122 1.054056 -2.756796 +v 6.578352 1.054056 -2.702654 +v 6.651891 1.054056 -2.646821 +v 6.722752 1.054056 -2.588310 +v 6.790318 1.054056 -2.526504 +v 6.854383 1.054056 -2.461198 +v 6.915122 1.054056 -2.392565 +v 6.972995 1.054056 -2.321066 +v 7.028660 1.054056 -2.247359 +v 7.083205 1.054056 -2.172533 +v 7.137656 1.054056 -2.097612 +v 7.192613 1.054056 -2.023197 +v 7.248722 1.054056 -1.949933 +v 7.306733 1.054056 -1.878573 +v 7.367446 1.054056 -1.809914 +v 7.431542 1.054056 -1.744639 +v 7.499348 1.054056 -1.683073 +v 7.570583 1.054056 -1.624936 +v 7.644403 1.054056 -1.569384 +v 7.719732 1.054056 -1.515341 +v 7.795447 1.054056 -1.461685 +v 7.870512 1.054056 -1.407378 +v 7.944039 1.054056 -1.351533 +v 8.015293 1.054056 -1.293415 +v 8.083644 1.054056 -1.232394 +v 8.148567 1.054056 -1.167945 +v 8.210034 1.054056 -1.100041 +v 8.268517 1.054056 -1.029152 +v 8.324759 1.054056 -0.956021 +v 8.379611 1.054056 -0.881502 +v 8.433922 1.054056 -0.806440 +v 8.488478 1.054056 -0.731626 +v 4.484069 1.149858 -4.748269 +v 4.538757 1.149858 -4.673584 +v 4.594958 1.149858 -4.600414 +v 4.653452 1.149858 -4.529537 +v 4.714896 1.149858 -4.461609 +v 4.779717 1.149858 -4.397058 +v 4.847997 1.149858 -4.335965 +v 4.919391 1.149858 -4.277987 +v 4.993345 1.149858 -4.222570 +v 5.069024 1.149858 -4.168878 +v 5.145137 1.149858 -4.115618 +v 5.220376 1.149858 -4.061485 +v 5.293663 1.149858 -4.005401 +v 5.364273 1.149858 -3.946640 +v 5.431831 1.149858 -3.884825 +v 5.496227 1.149858 -3.819849 +v 5.557551 1.149858 -3.751801 +v 5.616102 1.149858 -3.680981 +v 5.672333 1.149858 -3.607840 +v 5.726900 1.149858 -3.533035 +v 5.780680 1.149858 -3.457443 +v 5.834735 1.149858 -3.382126 +v 5.890190 1.149858 -3.308210 +v 5.948043 1.149858 -3.236691 +v 6.008914 1.149858 -3.168190 +v 6.073198 1.149858 -3.103102 +v 6.141086 1.149858 -3.041618 +v 6.212372 1.149858 -2.983533 +v 6.286420 1.149858 -2.928209 +v 6.362201 1.149858 -2.874618 +v 6.438429 1.149858 -2.821474 +v 6.513774 1.149858 -2.767448 +v 6.587279 1.149858 -2.711581 +v 6.658140 1.149858 -2.653070 +v 6.725662 1.149858 -2.591220 +v 6.789591 1.149858 -2.525777 +v 6.850095 1.149858 -2.456910 +v 6.907689 1.149858 -2.385131 +v 6.963113 1.149858 -2.311184 +v 7.017239 1.149858 -2.235938 +v 7.071272 1.149858 -2.160599 +v 7.126245 1.149858 -2.086201 +v 7.182749 1.149858 -2.013332 +v 7.241341 1.149858 -1.942552 +v 7.302568 1.149858 -1.874408 +v 7.366903 1.149858 -1.809371 +v 7.434619 1.149858 -1.747716 +v 7.505651 1.149858 -1.689376 +v 7.579379 1.149858 -1.633731 +v 7.654742 1.149858 -1.579723 +v 7.730615 1.149858 -1.526224 +v 7.805882 1.149858 -1.472120 +v 7.879548 1.149858 -1.416414 +v 7.950797 1.149858 -1.358290 +v 8.019022 1.149858 -1.297144 +v 8.083837 1.149858 -1.232587 +v 8.145167 1.149858 -1.164546 +v 8.203486 1.149858 -1.093493 +v 8.259592 1.149858 -1.020228 +v 8.314402 1.149858 -0.945664 +v 8.368799 1.149858 -0.870691 +v 8.423575 1.149858 -0.796095 +v 8.479423 1.149858 -0.722570 +v 4.473841 1.245659 -4.738041 +v 4.530001 1.245659 -4.664828 +v 4.588554 1.245659 -4.594010 +v 4.650140 1.245660 -4.526224 +v 4.715113 1.245659 -4.461825 +v 4.783482 1.245659 -4.400823 +v 4.854876 1.245659 -4.342844 +v 4.928576 1.245659 -4.287173 +v 5.003816 1.245659 -4.233041 +v 5.079693 1.245659 -4.179546 +v 5.154993 1.245660 -4.125474 +v 5.228559 1.245660 -4.069668 +v 5.299472 1.245660 -4.011210 +v 5.367163 1.245659 -3.949529 +v 5.431445 1.245659 -3.884439 +v 5.492489 1.245659 -3.816111 +v 5.550774 1.245659 -3.745024 +v 5.606932 1.245659 -3.671811 +v 5.661655 1.245660 -3.597162 +v 5.715738 1.245659 -3.521874 +v 5.770093 1.245660 -3.446856 +v 5.825701 1.245660 -3.373092 +v 5.883510 1.245659 -3.301529 +v 5.944286 1.245660 -3.232935 +v 6.008467 1.245660 -3.167743 +v 6.076188 1.245659 -3.106092 +v 6.147262 1.245659 -3.047795 +v 6.221117 1.245660 -2.992277 +v 6.296808 1.245660 -2.938597 +v 6.373118 1.245659 -2.885535 +v 6.448719 1.245660 -2.831764 +v 6.522393 1.245660 -2.776066 +v 6.593331 1.245660 -2.717633 +v 6.660953 1.245659 -2.655883 +v 6.724937 1.245660 -2.590495 +v 6.785417 1.245660 -2.521603 +v 6.842909 1.245659 -2.449724 +v 6.898200 1.245659 -2.375642 +v 6.952219 1.245659 -2.300290 +v 7.005952 1.245660 -2.224652 +v 7.060584 1.245660 -2.149911 +v 7.117078 1.245660 -2.077034 +v 7.175969 1.245660 -2.006553 +v 7.237648 1.245659 -1.938860 +v 7.302368 1.245660 -1.874209 +v 7.370220 1.245659 -1.812687 +v 7.441076 1.245659 -1.754172 +v 7.514544 1.245659 -1.698269 +v 7.589762 1.245659 -1.644114 +v 7.665571 1.245659 -1.590553 +v 7.740892 1.245660 -1.536501 +v 7.814689 1.245659 -1.480926 +v 7.886064 1.245660 -1.422930 +v 7.954341 1.245659 -1.361835 +v 8.019138 1.245659 -1.297260 +v 8.080416 1.245660 -1.229166 +v 8.138564 1.245659 -1.157943 +v 8.194427 1.245659 -1.084434 +v 8.249010 1.245659 -1.009644 +v 8.303297 1.245660 -0.934560 +v 8.358140 1.245659 -0.860031 +v 8.414229 1.245660 -0.786749 +v 8.472141 1.245659 -0.715288 +v 4.465283 1.341461 -4.729483 +v 4.523797 1.341461 -4.658625 +v 4.585414 1.341461 -4.590870 +v 4.650509 1.341461 -4.526594 +v 4.719042 1.341461 -4.465755 +v 4.790569 1.341461 -4.407910 +v 4.864326 1.341461 -4.352295 +v 4.939348 1.341461 -4.297946 +v 5.014789 1.341461 -4.244014 +v 5.089807 1.341461 -4.189660 +v 5.163357 1.341461 -4.133838 +v 5.234471 1.341461 -4.075581 +v 5.302410 1.341461 -4.014148 +v 5.366794 1.341461 -3.949159 +v 5.427692 1.341461 -3.880686 +v 5.485633 1.341461 -3.809256 +v 5.541481 1.341461 -3.735732 +v 5.596095 1.341461 -3.660974 +v 5.650292 1.341461 -3.585799 +v 5.704906 1.341461 -3.511042 +v 5.760791 1.341461 -3.437555 +v 5.818781 1.341461 -3.366173 +v 5.879606 1.341461 -3.297626 +v 5.943775 1.341461 -3.232424 +v 6.011445 1.341461 -3.170721 +v 6.082370 1.341461 -3.112275 +v 6.155986 1.341461 -3.056519 +v 6.231431 1.341461 -3.002592 +v 6.307599 1.341461 -2.949388 +v 6.383249 1.341461 -2.895667 +v 6.457170 1.341461 -2.840216 +v 6.528357 1.341461 -2.782031 +v 6.596193 1.341461 -2.720495 +v 6.660387 1.341461 -2.655317 +v 6.721025 1.341461 -2.586583 +v 6.778604 1.341461 -2.514790 +v 6.833910 1.341461 -2.440725 +v 6.887904 1.341461 -2.365346 +v 6.941598 1.341461 -2.289670 +v 6.995997 1.341461 -2.214696 +v 7.052171 1.341461 -2.141499 +v 7.110976 1.341461 -2.070931 +v 7.172829 1.341461 -2.003413 +v 7.237871 1.341461 -1.939082 +v 7.305999 1.341461 -1.877839 +v 7.376913 1.341461 -1.819381 +v 7.450140 1.341461 -1.763237 +v 7.525054 1.341461 -1.708778 +v 7.600665 1.341461 -1.655018 +v 7.675844 1.341461 -1.600825 +v 7.749628 1.341461 -1.545237 +v 7.821117 1.341461 -1.487354 +v 7.889567 1.341461 -1.426433 +v 7.954510 1.341461 -1.362004 +v 8.015862 1.341461 -1.293983 +v 8.073984 1.341461 -1.222734 +v 8.129653 1.341461 -1.149032 +v 8.183917 1.341461 -1.073923 +v 8.237892 1.341461 -0.998527 +v 8.292567 1.341461 -0.923830 +v 8.348713 1.341461 -0.850605 +v 8.406893 1.341461 -0.779412 +v 8.467530 1.341461 -0.710679 +v 4.459160 1.437263 -4.723360 +v 4.520734 1.437263 -4.655561 +v 4.585845 1.437262 -4.591301 +v 4.654498 1.437262 -4.530582 +v 4.726212 1.437263 -4.472924 +v 4.800146 1.437263 -4.417487 +v 4.875272 1.437263 -4.363240 +v 4.950541 1.437263 -4.309139 +v 5.025155 1.437263 -4.254379 +v 5.098413 1.437263 -4.198266 +v 5.169484 1.437262 -4.139965 +v 5.237606 1.437263 -4.078715 +v 5.302243 1.437263 -4.013981 +v 5.363259 1.437263 -3.945625 +v 5.421038 1.437263 -3.874032 +v 5.476486 1.437262 -3.800109 +v 5.530764 1.437262 -3.725014 +v 5.584820 1.437262 -3.649698 +v 5.639499 1.437263 -3.575006 +v 5.695590 1.437263 -3.501726 +v 5.753828 1.437263 -3.430591 +v 5.814846 1.437263 -3.362238 +v 5.879116 1.437262 -3.297136 +v 5.946845 1.437263 -3.235493 +v 6.017799 1.437263 -3.177075 +v 6.091298 1.437263 -3.121202 +v 6.166492 1.437263 -3.067025 +v 6.242379 1.437262 -3.013540 +v 6.317853 1.437262 -2.959642 +v 6.391804 1.437262 -2.904221 +v 6.463231 1.437263 -2.846276 +v 6.531382 1.437263 -2.785055 +v 6.595876 1.437263 -2.720177 +v 6.656775 1.437263 -2.651705 +v 6.714555 1.437262 -2.580113 +v 6.769998 1.437262 -2.506184 +v 6.824060 1.437263 -2.430875 +v 6.877764 1.437263 -2.355206 +v 6.932110 1.437263 -2.280181 +v 6.988044 1.437263 -2.206743 +v 7.046487 1.437263 -2.135814 +v 7.108148 1.437262 -2.068103 +v 7.173253 1.437263 -2.003837 +v 7.241622 1.437262 -1.942834 +v 7.312772 1.437263 -1.884613 +v 7.386052 1.437263 -1.828520 +v 7.460730 1.437263 -1.773827 +v 7.536050 1.437263 -1.719775 +v 7.611022 1.437263 -1.665375 +v 7.684642 1.437263 -1.609623 +v 7.756118 1.437263 -1.551727 +v 7.824727 1.437263 -1.490964 +v 7.889931 1.437262 -1.426797 +v 7.951527 1.437263 -1.359020 +v 8.009768 1.437262 -1.287889 +v 8.065410 1.437262 -1.214159 +v 8.119472 1.437263 -1.138850 +v 8.173071 1.437263 -1.063077 +v 8.227375 1.437263 -0.988010 +v 8.283329 1.437263 -0.914592 +v 8.341585 1.437263 -0.843476 +v 8.402530 1.437263 -0.775049 +v 8.466380 1.437263 -0.709528 +v 4.456070 1.533064 -4.720269 +v 4.521122 1.533064 -4.655949 +v 4.589769 1.533064 -4.595224 +v 4.661590 1.533064 -4.537674 +v 4.735715 1.533064 -4.482428 +v 4.811038 1.533064 -4.428379 +v 4.886439 1.533064 -4.374408 +v 4.960941 1.533064 -4.319538 +v 5.033872 1.533064 -4.263097 +v 5.104704 1.533064 -4.204557 +v 5.172823 1.533064 -4.143304 +v 5.237689 1.533064 -4.078798 +v 5.299014 1.533064 -4.010752 +v 5.356959 1.533064 -3.939325 +v 5.412246 1.533064 -3.865240 +v 5.466102 1.533064 -3.789724 +v 5.519828 1.533064 -3.714079 +v 5.574342 1.533064 -3.639221 +v 5.630445 1.533064 -3.565952 +v 5.688827 1.533064 -3.494962 +v 5.750046 1.533064 -3.426810 +v 5.814495 1.533064 -3.361887 +v 5.882327 1.533064 -3.300347 +v 5.953394 1.533064 -3.242042 +v 6.027009 1.533064 -3.186285 +v 6.102123 1.533064 -3.132027 +v 6.177767 1.533064 -3.078300 +v 6.252954 1.533064 -3.024115 +v 6.326718 1.533064 -2.968507 +v 6.398160 1.533064 -2.910578 +v 6.466537 1.533064 -2.849583 +v 6.531354 1.533064 -2.785028 +v 6.592525 1.533064 -2.716826 +v 6.650513 1.533064 -2.645442 +v 6.706111 1.533064 -2.571670 +v 6.760285 1.533064 -2.496472 +v 6.814050 1.533064 -2.420864 +v 6.868390 1.533064 -2.345833 +v 6.924221 1.533064 -2.272292 +v 6.982373 1.533064 -2.201072 +v 7.043608 1.533064 -2.132936 +v 7.108436 1.533064 -2.068391 +v 7.176803 1.533064 -2.007386 +v 7.248169 1.533064 -1.949381 +v 7.321707 1.533064 -1.893547 +v 7.396498 1.533064 -1.838966 +v 7.471668 1.533064 -1.784765 +v 7.546432 1.533064 -1.730157 +v 7.619894 1.533064 -1.674247 +v 7.691246 1.533064 -1.616227 +v 7.759897 1.533064 -1.555507 +v 7.825339 1.533064 -1.491576 +v 7.887285 1.533064 -1.424150 +v 7.945834 1.533064 -1.353328 +v 8.001578 1.533064 -1.279701 +v 8.055593 1.533064 -1.204343 +v 8.108997 1.533064 -1.128376 +v 8.162895 1.533064 -1.052902 +v 8.218460 1.533064 -0.979095 +v 8.276541 1.533064 -0.907804 +v 8.337607 1.533064 -0.839499 +v 8.401806 1.533064 -0.774325 +v 8.469067 1.533064 -0.712215 +v 4.456419 1.628865 -4.720619 +v 4.524974 1.628865 -4.659802 +v 4.596741 1.628866 -4.602196 +v 4.670915 1.628866 -4.546999 +v 4.746382 1.628865 -4.493094 +v 4.821961 1.628866 -4.439301 +v 4.896602 1.628866 -4.384571 +v 4.969495 1.628865 -4.328093 +v 5.040125 1.628866 -4.269351 +v 5.108117 1.628866 -4.207970 +v 5.173070 1.628866 -4.143552 +v 5.234701 1.628866 -4.075810 +v 5.293023 1.628866 -4.004761 +v 5.348528 1.628866 -3.930894 +v 5.402239 1.628866 -3.855233 +v 5.455570 1.628866 -3.779192 +v 5.509787 1.628866 -3.704038 +v 5.565697 1.628865 -3.630576 +v 5.624017 1.628865 -3.559524 +v 5.685294 1.628865 -3.491429 +v 5.749871 1.628865 -3.426635 +v 5.817838 1.628866 -3.365229 +v 5.888976 1.628866 -3.306995 +v 5.962736 1.628866 -3.251384 +v 6.038033 1.628866 -3.197310 +v 6.113645 1.628865 -3.143549 +v 6.188632 1.628865 -3.089164 +v 6.262140 1.628865 -3.033301 +v 6.333404 1.628866 -2.975192 +v 6.401771 1.628866 -2.914188 +v 6.466768 1.628866 -2.849813 +v 6.528173 1.628866 -2.781847 +v 6.586272 1.628866 -2.710573 +v 6.641931 1.628866 -2.636861 +v 6.696152 1.628865 -2.561710 +v 6.749968 1.628865 -2.486155 +v 6.804353 1.628866 -2.411168 +v 6.860182 1.628866 -2.337625 +v 6.918223 1.628866 -2.266294 +v 6.979152 1.628866 -2.197851 +v 7.043543 1.628866 -2.132871 +v 7.111613 1.628866 -2.071568 +v 7.182955 1.628865 -2.013538 +v 7.256701 1.628865 -1.957913 +v 7.331777 1.628865 -1.903617 +v 7.407133 1.628865 -1.849601 +v 7.481871 1.628866 -1.794967 +v 7.555255 1.628866 -1.738980 +v 7.626541 1.628866 -1.680894 +v 7.695147 1.628866 -1.620128 +v 7.760699 1.628866 -1.556309 +v 7.822943 1.628866 -1.489180 +v 7.881886 1.628866 -1.418751 +v 7.937943 1.628865 -1.345436 +v 7.991999 1.628866 -1.270122 +v 8.045332 1.628866 -1.194082 +v 8.099051 1.628866 -1.118429 +v 8.154211 1.628866 -1.044218 +v 8.211922 1.628866 -0.972557 +v 8.272854 1.628866 -0.904116 +v 8.337212 1.628866 -0.839102 +v 8.404826 1.628865 -0.777345 +v 8.475297 1.628866 -0.718445 +v 4.460249 1.724667 -4.724449 +v 4.531840 1.724667 -4.666669 +v 4.605888 1.724667 -4.611344 +v 4.681349 1.724667 -4.557433 +v 4.757037 1.724667 -4.503750 +v 4.831846 1.724667 -4.449186 +v 4.904885 1.724667 -4.392854 +v 4.975540 1.724667 -4.334136 +v 5.043450 1.724667 -4.272676 +v 5.108405 1.724667 -4.208258 +v 5.170235 1.724667 -4.140717 +v 5.228942 1.724667 -4.070052 +v 5.284864 1.724667 -3.996602 +v 5.338792 1.724667 -3.921158 +v 5.391952 1.724667 -3.844946 +v 5.445791 1.724667 -3.769413 +v 5.501411 1.724667 -3.695662 +v 5.559493 1.724667 -3.624371 +v 5.620635 1.724667 -3.556141 +v 5.685185 1.724667 -3.491320 +v 5.753197 1.724667 -3.429960 +v 5.824392 1.724667 -3.371784 +v 5.898159 1.724667 -3.316179 +v 5.973588 1.724667 -3.262235 +v 6.049404 1.724667 -3.208681 +v 6.124431 1.724667 -3.154335 +v 6.197836 1.724667 -3.098369 +v 6.268924 1.724667 -3.040085 +v 6.337134 1.724667 -2.978923 +v 6.402075 1.724667 -2.914492 +v 6.463580 1.724667 -2.846625 +v 6.521774 1.724667 -2.775448 +v 6.577371 1.724667 -2.701673 +v 6.631546 1.724667 -2.626477 +v 6.685362 1.724667 -2.550920 +v 6.739791 1.724667 -2.475978 +v 6.795683 1.724667 -2.402498 +v 6.853756 1.724667 -2.331199 +v 6.914609 1.724667 -2.262680 +v 6.978734 1.724667 -2.197433 +v 7.046453 1.724667 -2.135781 +v 7.117594 1.724667 -2.077550 +v 7.191382 1.724667 -2.021966 +v 7.266693 1.724667 -1.967905 +v 7.342338 1.724667 -1.914178 +v 7.417269 1.724667 -1.859738 +v 7.490672 1.724667 -1.803769 +v 7.561933 1.724667 -1.745658 +v 7.630493 1.724667 -1.684846 +v 7.696016 1.724667 -1.620997 +v 7.758372 1.724667 -1.553981 +v 7.817594 1.724667 -1.483831 +v 7.874006 1.724667 -1.410872 +v 7.928324 1.724667 -1.335818 +v 7.981643 1.724667 -1.259765 +v 8.035298 1.724667 -1.184049 +v 8.090321 1.724667 -1.109699 +v 8.147667 1.724667 -1.037674 +v 8.208265 1.724667 -0.968900 +v 8.272519 1.724667 -0.903782 +v 8.340315 1.724667 -0.842206 +v 8.411151 1.724667 -0.783670 +v 8.484303 1.724668 -0.727450 +v 4.467014 1.820469 -4.731214 +v 4.540850 1.820469 -4.675678 +v 4.616197 1.820469 -4.621653 +v 4.691914 1.820469 -4.567998 +v 4.766863 1.820469 -4.513576 +v 4.840078 1.820469 -4.457419 +v 4.910859 1.820469 -4.398828 +v 4.978790 1.820468 -4.337387 +v 5.043707 1.820469 -4.272932 +v 5.105605 1.820469 -4.205458 +v 5.164569 1.820469 -4.135050 +v 5.220885 1.820469 -4.061995 +v 5.275179 1.820469 -3.986917 +v 5.328468 1.820469 -3.910834 +v 5.382065 1.820469 -3.835060 +v 5.437327 1.820469 -3.760949 +v 5.495139 1.820469 -3.689390 +v 5.556043 1.820469 -3.620922 +v 5.620448 1.820469 -3.555955 +v 5.688408 1.820469 -3.494543 +v 5.759604 1.820469 -3.436367 +v 5.833369 1.820469 -3.380760 +v 5.908761 1.820469 -3.326781 +v 5.984669 1.820469 -3.273318 +v 6.059871 1.820469 -3.219147 +v 6.133358 1.820469 -3.163263 +v 6.204421 1.820469 -3.104954 +v 6.272523 1.820469 -3.043684 +v 6.337334 1.820469 -2.979122 +v 6.398765 1.820469 -2.911182 +v 6.457022 1.820469 -2.840067 +v 6.512635 1.820469 -2.766308 +v 6.566691 1.820469 -2.690993 +v 6.620473 1.820469 -2.615403 +v 6.674940 1.820469 -2.540498 +v 6.730909 1.820469 -2.467095 +v 6.789062 1.820469 -2.395876 +v 6.849953 1.820469 -2.327396 +v 6.914008 1.820469 -2.262079 +v 6.981496 1.820469 -2.200195 +v 7.052411 1.820469 -2.141738 +v 7.126150 1.820469 -2.086105 +v 7.201615 1.820469 -2.032199 +v 7.277526 1.820469 -1.978738 +v 7.352699 1.820469 -1.924539 +v 7.426209 1.820469 -1.868677 +v 7.497416 1.820469 -1.810513 +v 7.565889 1.820469 -1.749614 +v 7.631300 1.820469 -1.685653 +v 7.693580 1.820469 -1.618561 +v 7.752866 1.820469 -1.548476 +v 7.809498 1.820469 -1.475736 +v 7.864102 1.820469 -1.400968 +v 7.917624 1.820469 -1.325117 +v 7.971255 1.820469 -1.249377 +v 8.026256 1.820469 -1.175005 +v 8.083507 1.820469 -1.102885 +v 8.143791 1.820469 -1.033798 +v 8.207745 1.820469 -0.968379 +v 8.275451 1.820469 -0.906714 +v 8.346479 1.820469 -0.848371 +v 8.420025 1.820469 -0.792544 +v 8.495083 1.820469 -0.738231 +v 4.475979 1.916270 -4.740178 +v 4.551140 1.916270 -4.685967 +v 4.626796 1.916270 -4.632252 +v 4.701821 1.916270 -4.577905 +v 4.775193 1.916270 -4.521905 +v 4.846123 1.916270 -4.463464 +v 4.914118 1.916270 -4.402087 +v 4.978989 1.916270 -4.337586 +v 5.040817 1.916270 -4.270042 +v 5.099839 1.916270 -4.199693 +v 5.156392 1.916270 -4.126873 +v 5.211025 1.916270 -4.052135 +v 5.264592 1.916271 -3.976330 +v 5.318238 1.916270 -3.900604 +v 5.373250 1.916270 -3.826245 +v 5.430786 1.916270 -3.754408 +v 5.491479 1.916270 -3.685730 +v 5.555695 1.916270 -3.620574 +v 5.623550 1.916270 -3.559057 +v 5.694719 1.916270 -3.500854 +v 5.768487 1.916270 -3.445251 +v 5.843870 1.916270 -3.391261 +v 5.919743 1.916270 -3.337762 +v 5.994984 1.916270 -3.283632 +v 6.068582 1.916270 -3.227858 +v 6.139734 1.916270 -3.169639 +v 6.207859 1.916270 -3.108391 +v 6.272613 1.916270 -3.043773 +v 6.333943 1.916270 -2.975733 +v 6.392127 1.916270 -2.904544 +v 6.447770 1.916270 -2.830815 +v 6.501778 1.916270 -2.755451 +v 6.555445 1.916270 -2.679746 +v 6.609931 1.916270 -2.604861 +v 6.665992 1.916270 -2.531550 +v 6.724255 1.916270 -2.460441 +v 6.785235 1.916270 -2.392049 +v 6.849325 1.916270 -2.326767 +v 6.916744 1.916271 -2.264814 +v 6.987465 1.916270 -2.206165 +v 7.061086 1.916270 -2.150413 +v 7.136613 1.916270 -2.096569 +v 7.212728 1.916270 -2.043312 +v 7.288130 1.916270 -1.989342 +v 7.361778 1.916270 -1.933618 +v 7.432970 1.916270 -1.875439 +v 7.501307 1.916270 -1.814404 +v 7.566568 1.916270 -1.750293 +v 7.628674 1.916270 -1.683026 +v 7.687844 1.916270 -1.612824 +v 7.744494 1.916270 -1.540104 +v 7.799257 1.916270 -1.465494 +v 7.853001 1.916270 -1.389866 +v 7.906797 1.916270 -1.314291 +v 7.961806 1.916270 -1.239928 +v 8.019082 1.916270 -1.167832 +v 8.079298 1.916271 -1.098676 +v 8.142974 1.916270 -1.032981 +v 8.210381 1.916270 -0.971015 +v 8.281277 1.916270 -0.912540 +v 8.354956 1.916270 -0.856847 +v 8.430371 1.916270 -0.802891 +v 8.506314 1.916270 -0.749462 +v 4.486303 2.012072 -4.750503 +v 4.561822 2.012072 -4.696651 +v 4.636836 2.012072 -4.642292 +v 4.710303 2.012072 -4.586388 +v 4.781365 2.012072 -4.528078 +v 4.849438 2.012072 -4.466778 +v 4.914269 2.012072 -4.402238 +v 4.975942 2.012072 -4.334539 +v 5.034825 2.012072 -4.264050 +v 5.091399 2.012072 -4.191253 +v 5.146229 2.012072 -4.116711 +v 5.200078 2.012072 -4.041187 +v 5.253939 2.012072 -3.965677 +v 5.308975 2.012072 -3.891341 +v 5.366332 2.012072 -3.819327 +v 5.426875 2.012072 -3.750497 +v 5.490960 2.012072 -3.685211 +v 5.558707 2.012072 -3.623586 +v 5.629844 2.012072 -3.565351 +v 5.703638 2.012072 -3.509773 +v 5.779048 2.012072 -3.455812 +v 5.854916 2.012072 -3.402307 +v 5.930120 2.012072 -3.348140 +v 6.003696 2.012072 -3.292345 +v 6.074903 2.012072 -3.234179 +v 6.143128 2.012072 -3.173032 +v 6.207952 2.012072 -3.108485 +v 6.269281 2.012072 -3.040442 +v 6.327397 2.012072 -2.969186 +v 6.382956 2.012072 -2.895373 +v 6.436932 2.012072 -2.819977 +v 6.490484 2.012072 -2.744158 +v 6.544887 2.012072 -2.669189 +v 6.601021 2.012072 -2.595951 +v 6.659410 2.012072 -2.524968 +v 6.720500 2.012072 -2.456686 +v 6.784654 2.012072 -2.391468 +v 6.852080 2.012072 -2.329522 +v 6.922733 2.012072 -2.270803 +v 6.996212 2.012072 -2.214912 +v 7.071706 2.012072 -2.161033 +v 7.147946 2.012072 -2.107902 +v 7.223544 2.012072 -2.054128 +v 7.297336 2.012072 -1.998548 +v 7.368538 2.012072 -1.940378 +v 7.436745 2.012072 -1.879213 +v 7.501822 2.012072 -1.814918 +v 7.563763 2.012072 -1.747488 +v 7.622734 2.012072 -1.677087 +v 7.679251 2.012072 -1.604232 +v 7.734001 2.012072 -1.529610 +v 7.787856 2.012072 -1.454093 +v 7.841832 2.012072 -1.378698 +v 7.897000 2.012072 -1.304494 +v 7.954350 2.012072 -1.232473 +v 8.014639 2.012072 -1.163389 +v 8.078256 2.012072 -1.097634 +v 8.145391 2.012072 -1.035398 +v 8.215945 2.012072 -0.976579 +v 8.289398 2.012072 -0.920661 +v 8.364841 2.012072 -0.866732 +v 8.441073 2.012072 -0.813593 +v 8.516783 2.012072 -0.759930 +v 4.497085 2.107873 -4.761284 +v 4.571997 2.107873 -4.706825 +v 4.645472 2.107873 -4.650928 +v 4.716612 2.107873 -4.592696 +v 4.784751 2.107873 -4.531464 +v 4.849555 2.107874 -4.466895 +v 4.911061 2.107873 -4.399030 +v 4.969675 2.107874 -4.328272 +v 5.026062 2.107874 -4.255287 +v 5.080901 2.107874 -4.180755 +v 5.134936 2.107873 -4.105418 +v 5.189058 2.107874 -4.030168 +v 5.244298 2.107873 -3.956035 +v 5.301715 2.107873 -3.884081 +v 5.362205 2.107874 -3.815199 +v 5.426267 2.107874 -3.749889 +v 5.493951 2.107873 -3.688201 +v 5.565063 2.107873 -3.629941 +v 5.638903 2.107874 -3.574409 +v 5.714388 2.107873 -3.520524 +v 5.790298 2.107874 -3.467061 +v 5.865480 2.107874 -3.412872 +v 5.938990 2.107873 -3.357009 +v 6.010117 2.107874 -3.298764 +v 6.078373 2.107874 -3.237650 +v 6.143330 2.107873 -3.173234 +v 6.204788 2.107874 -3.105320 +v 6.262958 2.107874 -3.034118 +v 6.318476 2.107873 -2.960265 +v 6.372340 2.107874 -2.884757 +v 6.425767 2.107873 -2.808812 +v 6.479994 2.107873 -2.733667 +v 6.536081 2.107874 -2.660382 +v 6.594567 2.107874 -2.589497 +v 6.655769 2.107873 -2.521327 +v 6.719979 2.107873 -2.456166 +v 6.787399 2.107873 -2.394214 +v 6.858010 2.107873 -2.335452 +v 6.931433 2.107874 -2.279504 +v 7.006855 2.107874 -2.225555 +v 7.083127 2.107873 -2.172454 +v 7.158878 2.107873 -2.118834 +v 7.232824 2.107874 -2.063408 +v 7.304070 2.107873 -2.005282 +v 7.372172 2.107874 -1.944013 +v 7.437049 2.107873 -1.879517 +v 7.498824 2.107874 -1.811920 +v 7.557689 2.107873 -1.741414 +v 7.614041 2.107874 -1.668395 +v 7.668675 2.107873 -1.593656 +v 7.722508 2.107873 -1.518118 +v 7.776569 2.107873 -1.442806 +v 7.831894 2.107873 -1.368760 +v 7.889418 2.107873 -1.296912 +v 7.949852 2.107874 -1.227974 +v 8.013587 2.107873 -1.162337 +v 8.080670 2.107874 -1.100049 +v 8.150931 2.107873 -1.040938 +v 8.223967 2.107874 -0.984601 +v 8.299070 2.107873 -0.930333 +v 8.375221 2.107874 -0.877113 +v 8.451161 2.107873 -0.823681 +v 8.525572 2.107874 -0.768719 +v 4.507383 2.203675 -4.771583 +v 4.580763 2.203675 -4.715591 +v 4.651895 2.203675 -4.657351 +v 4.720063 2.203675 -4.596147 +v 4.784850 2.203675 -4.531563 +v 4.846223 2.203675 -4.463563 +v 4.904559 2.203675 -4.392528 +v 4.960606 2.203675 -4.319202 +v 5.015275 2.203675 -4.244500 +v 5.069364 2.203675 -4.169216 +v 5.123708 2.203675 -4.094190 +v 5.179228 2.203675 -4.020338 +v 5.236869 2.203675 -3.948607 +v 5.297477 2.203675 -3.879843 +v 5.361607 2.203675 -3.814601 +v 5.429347 2.203675 -3.752969 +v 5.500425 2.203675 -3.694675 +v 5.574297 2.203675 -3.639177 +v 5.649884 2.203675 -3.585391 +v 5.725893 2.203675 -3.532028 +v 5.801103 2.203675 -3.477866 +v 5.874543 2.203675 -3.421935 +v 5.945543 2.203675 -3.363563 +v 6.013683 2.203675 -3.302331 +v 6.078685 2.203675 -3.237961 +v 6.140319 2.203675 -3.170223 +v 6.198678 2.203675 -3.099211 +v 6.254303 2.203675 -3.025463 +v 6.308142 2.203675 -2.949931 +v 6.361422 2.203675 -2.873839 +v 6.415433 2.203675 -2.798479 +v 6.471302 2.203675 -2.724976 +v 6.529762 2.203675 -2.654064 +v 6.591045 2.203675 -2.585975 +v 6.655299 2.203675 -2.520857 +v 6.722671 2.203675 -2.458857 +v 6.793169 2.203675 -2.399983 +v 6.866490 2.203675 -2.343933 +v 6.941892 2.203675 -2.289962 +v 7.018180 2.203675 -2.236879 +v 7.094023 2.203675 -2.183350 +v 7.168141 2.203675 -2.128096 +v 7.239498 2.203675 -2.070082 +v 7.307566 2.203675 -2.008778 +v 7.372269 2.203675 -1.944109 +v 7.433836 2.203675 -1.876304 +v 7.492621 2.203675 -1.805718 +v 7.548992 2.203675 -1.732716 +v 7.603544 2.203675 -1.657897 +v 7.657305 2.203675 -1.582286 +v 7.711349 2.203675 -1.506959 +v 7.766742 2.203675 -1.432979 +v 7.824407 2.203675 -1.361273 +v 7.885023 2.203675 -1.292517 +v 7.948947 2.203675 -1.227069 +v 8.016190 2.203675 -1.164940 +v 8.086417 2.203675 -1.105796 +v 8.159132 2.203675 -1.049139 +v 8.233749 2.203675 -0.994384 +v 8.309476 2.203675 -0.940738 +v 8.385264 2.203675 -0.887156 +v 8.459880 2.203675 -0.832400 +v 8.532093 2.203675 -0.775240 +v 4.516252 2.299477 -4.780452 +v 4.587265 2.299476 -4.722092 +v 4.655387 2.299477 -4.660843 +v 4.720151 2.299476 -4.596235 +v 4.781445 2.299477 -4.528157 +v 4.839583 2.299476 -4.456924 +v 4.895298 2.299476 -4.383267 +v 4.949635 2.299477 -4.308232 +v 5.003643 2.299477 -4.232868 +v 5.058131 2.299477 -4.157984 +v 5.113928 2.299477 -4.084409 +v 5.171865 2.299476 -4.012975 +v 5.232697 2.299477 -3.944435 +v 5.296963 2.299477 -3.879329 +v 5.364825 2.299476 -3.817820 +v 5.435957 2.299476 -3.759579 +v 5.509774 2.299477 -3.704025 +v 5.585418 2.299477 -3.650297 +v 5.661556 2.299476 -3.597063 +v 5.736867 2.299476 -3.543003 +v 5.810298 2.299477 -3.487062 +v 5.881160 2.299477 -3.428552 +v 5.949098 2.299477 -3.367117 +v 6.013964 2.299476 -3.302612 +v 6.075671 2.299477 -3.234947 +v 6.134248 2.299476 -3.164152 +v 6.190116 2.299476 -3.090648 +v 6.244111 2.299477 -3.015271 +v 6.297386 2.299477 -2.939175 +v 6.351231 2.299476 -2.863647 +v 6.406834 2.299477 -2.789880 +v 6.465072 2.299476 -2.718745 +v 6.526335 2.299477 -2.650636 +v 6.590618 2.299477 -2.585548 +v 6.657926 2.299476 -2.523484 +v 6.728237 2.299476 -2.464423 +v 6.801323 2.299476 -2.408138 +v 6.876570 2.299477 -2.354013 +v 6.952897 2.299476 -2.300967 +v 7.028866 2.299476 -2.247565 +v 7.103157 2.299477 -2.192485 +v 7.174727 2.299477 -2.134683 +v 7.242895 2.299476 -2.073478 +v 7.307527 2.299476 -2.008739 +v 7.368906 2.299476 -1.940746 +v 7.427528 2.299476 -1.869997 +v 7.483939 2.299476 -1.797036 +v 7.538655 2.299476 -1.722380 +v 7.592432 2.299477 -1.646785 +v 7.646446 2.299477 -1.571427 +v 7.701816 2.299477 -1.497425 +v 7.759513 2.299477 -1.425750 +v 7.820230 2.299476 -1.357096 +v 7.884313 2.299477 -1.291806 +v 7.951738 2.299477 -1.229860 +v 8.022159 2.299477 -1.170908 +v 8.094886 2.299476 -1.114263 +v 8.169188 2.299476 -1.059194 +v 8.244415 2.299477 -1.005050 +v 8.319767 2.299477 -0.951029 +v 8.394229 2.299477 -0.896120 +v 8.466656 2.299476 -0.839174 +v 8.535986 2.299477 -0.779133 +v 4.522784 2.395278 -4.786983 +v 4.590749 2.395278 -4.725577 +v 4.655435 2.395278 -4.660891 +v 4.716684 2.395278 -4.592769 +v 4.774744 2.395278 -4.521457 +v 4.830282 2.395278 -4.447623 +v 4.884323 2.395278 -4.372292 +v 4.938083 2.395278 -4.296679 +v 4.992607 2.395278 -4.221833 +v 5.048622 2.395278 -4.148476 +v 5.106843 2.395278 -4.077324 +v 5.167915 2.395278 -4.009025 +v 5.232321 2.395278 -3.944058 +v 5.300245 2.395278 -3.882611 +v 5.371455 2.395278 -3.824450 +v 5.445249 2.395278 -3.768871 +v 5.520791 2.395278 -3.715041 +v 5.597008 2.395278 -3.661887 +v 5.672485 2.395278 -3.607992 +v 5.746025 2.395278 -3.552160 +v 5.816837 2.395278 -3.493601 +v 5.884559 2.395278 -3.431951 +v 5.949139 2.395278 -3.367159 +v 6.010686 2.395278 -3.299335 +v 6.069343 2.395278 -3.228619 +v 6.125457 2.395278 -3.155361 +v 6.179751 2.395278 -3.080283 +v 6.233247 2.395278 -3.004408 +v 6.287138 2.395278 -2.928927 +v 6.342598 2.395278 -2.855015 +v 6.400584 2.395278 -2.783629 +v 6.461665 2.395278 -2.715338 +v 6.525938 2.395278 -2.650239 +v 6.593215 2.395278 -2.588145 +v 6.663342 2.395278 -2.528900 +v 6.736098 2.395278 -2.472284 +v 6.810993 2.395278 -2.417807 +v 6.887131 2.395278 -2.364573 +v 6.963215 2.395278 -2.311286 +v 7.037768 2.395278 -2.256467 +v 7.109646 2.395278 -2.198973 +v 7.178115 2.395278 -2.138070 +v 7.242881 2.395278 -2.073465 +v 7.304195 2.395278 -2.005407 +v 7.362646 2.395278 -1.934486 +v 7.418951 2.395278 -1.861419 +v 7.473804 2.395278 -1.786901 +v 7.527844 2.395278 -1.711569 +v 7.581932 2.395278 -1.636284 +v 7.637269 2.395278 -1.562250 +v 7.694888 2.395278 -1.490497 +v 7.755548 2.395278 -1.421786 +v 7.819637 2.395278 -1.356503 +v 7.887142 2.395278 -1.294636 +v 7.957691 2.395278 -1.235812 +v 8.030635 2.395278 -1.179386 +v 8.105028 2.395278 -1.124407 +v 8.180027 2.395278 -1.070034 +v 8.254978 2.395278 -1.015612 +v 8.329094 2.395278 -0.960358 +v 8.401428 2.395278 -0.903319 +v 8.470984 2.395278 -0.843503 +v 8.536964 2.395278 -0.780113 +v 4.526130 2.491080 -4.790330 +v 4.590706 2.491080 -4.725534 +v 4.651941 2.491080 -4.657397 +v 4.710024 2.491080 -4.586109 +v 4.765550 2.491080 -4.512263 +v 4.819476 2.491080 -4.436817 +v 4.873001 2.491080 -4.360970 +v 4.927355 2.491079 -4.285953 +v 4.983460 2.491079 -4.212685 +v 5.041884 2.491080 -4.141738 +v 5.103156 2.491080 -4.073637 +v 5.167664 2.491080 -4.008773 +v 5.235570 2.491080 -3.947308 +v 5.306697 2.491080 -3.889063 +v 5.380454 2.491080 -3.833448 +v 5.455858 2.491080 -3.779481 +v 5.531941 2.491080 -3.726192 +v 5.607561 2.491080 -3.672439 +v 5.681354 2.491080 -3.616861 +v 5.752327 2.491080 -3.558462 +v 5.819977 2.491080 -3.496741 +v 5.884252 2.491080 -3.431643 +v 5.945404 2.491080 -3.363424 +v 6.003831 2.491080 -3.292479 +v 6.059979 2.491079 -3.219256 +v 6.114517 2.491080 -3.144421 +v 6.168355 2.491080 -3.068888 +v 6.222546 2.491080 -2.993706 +v 6.278148 2.491080 -2.919937 +v 6.336092 2.491080 -2.848510 +v 6.397035 2.491080 -2.780080 +v 6.461254 2.491079 -2.714928 +v 6.528601 2.491080 -2.652903 +v 6.598701 2.491080 -2.593631 +v 6.671218 2.491080 -2.536776 +v 6.745708 2.491080 -2.481895 +v 6.821448 2.491080 -2.428263 +v 6.897359 2.491080 -2.374802 +v 6.972098 2.491079 -2.320169 +v 7.044337 2.491080 -2.263036 +v 7.113211 2.491080 -2.202538 +v 7.178330 2.491080 -2.138286 +v 7.239799 2.491080 -2.070383 +v 7.298195 2.491080 -1.999407 +v 7.354339 2.491079 -1.926179 +v 7.409095 2.491080 -1.851564 +v 7.463261 2.491079 -1.776357 +v 7.517564 2.491079 -1.701288 +v 7.572906 2.491080 -1.627259 +v 7.630414 2.491080 -1.555395 +v 7.690935 2.491080 -1.486544 +v 7.754930 2.491080 -1.421167 +v 7.822423 2.491080 -1.359289 +v 7.893040 2.491080 -1.300534 +v 7.966100 2.491079 -1.244222 +v 8.040737 2.491080 -1.189487 +v 8.115875 2.491080 -1.135254 +v 8.190660 2.491080 -1.080667 +v 8.264461 2.491079 -1.025095 +v 8.336540 2.491080 -0.967803 +v 8.406079 2.491080 -0.907970 +v 8.472322 2.491080 -0.844841 +v 8.534829 2.491080 -0.777977 +v 4.525980 2.586881 -4.790179 +v 4.587232 2.586881 -4.722059 +v 4.645411 2.586881 -4.650867 +v 4.701033 2.586881 -4.577117 +v 4.754975 2.586881 -4.501687 +v 4.808386 2.586881 -4.425726 +v 4.862515 2.586881 -4.350484 +v 4.918485 2.586881 -4.277082 +v 4.976992 2.586881 -4.206217 +v 5.038405 2.586881 -4.138258 +v 5.103013 2.586881 -4.073494 +v 5.170907 2.586881 -4.012017 +v 5.241906 2.586881 -3.953644 +v 5.315490 2.586881 -3.897855 +v 5.390791 2.586881 -3.843785 +v 5.466676 2.586881 -3.790298 +v 5.542161 2.586881 -3.736411 +v 5.616150 2.586881 -3.681029 +v 5.687442 2.586881 -3.622948 +v 5.755287 2.586881 -3.561422 +v 5.819474 2.586881 -3.496237 +v 5.880260 2.586881 -3.427652 +v 5.938221 2.586881 -3.356242 +v 5.994086 2.586881 -3.282734 +v 6.048616 2.586881 -3.207892 +v 6.102675 2.586881 -3.132580 +v 6.157213 2.586881 -3.057746 +v 6.213158 2.586881 -2.984319 +v 6.271328 2.586881 -2.913117 +v 6.332348 2.586881 -2.844765 +v 6.396569 2.586881 -2.779614 +v 6.464023 2.586881 -2.717697 +v 6.534319 2.586881 -2.658620 +v 6.606860 2.586881 -2.601790 +v 6.681128 2.586881 -2.546686 +v 6.756477 2.586881 -2.492664 +v 6.832021 2.586881 -2.438836 +v 6.906625 2.586881 -2.384068 +v 6.979057 2.586881 -2.327128 +v 7.048278 2.586881 -2.266978 +v 7.113769 2.586881 -2.203096 +v 7.175531 2.586881 -2.135486 +v 7.234041 2.586881 -2.064625 +v 7.290116 2.586881 -1.991328 +v 7.344707 2.586881 -1.916547 +v 7.398748 2.586881 -1.841216 +v 7.453091 2.586881 -1.766188 +v 7.508529 2.586882 -1.692254 +v 7.565951 2.586881 -1.620303 +v 7.626324 2.586881 -1.551305 +v 7.690226 2.586881 -1.485835 +v 7.757727 2.586881 -1.423964 +v 7.828435 2.586881 -1.365301 +v 7.901619 2.586881 -1.309113 +v 7.976365 2.586881 -1.254487 +v 8.051712 2.586881 -1.200462 +v 8.126589 2.586882 -1.145967 +v 8.200198 2.586881 -1.090204 +v 8.271986 2.586881 -1.032620 +v 8.341337 2.586881 -0.972600 +v 8.407645 2.586881 -0.909536 +v 8.470475 2.586881 -0.842994 +v 8.529780 2.586881 -0.772928 +v 4.522494 2.682683 -4.786693 +v 4.580794 2.682683 -4.715621 +v 4.636583 2.682683 -4.642039 +v 4.690646 2.682683 -4.566730 +v 4.744060 2.682683 -4.490772 +v 4.798051 2.682683 -4.415391 +v 4.853797 2.682683 -4.341766 +v 4.912202 2.682683 -4.270799 +v 4.973675 2.682683 -4.202901 +v 5.038364 2.682683 -4.138217 +v 5.106288 2.682683 -4.076769 +v 5.177221 2.682683 -4.018331 +v 5.250652 2.682683 -3.962389 +v 5.325780 2.682683 -3.908146 +v 5.401569 2.682683 -3.854563 +v 5.476861 2.682683 -3.800483 +v 5.550748 2.682683 -3.744999 +v 5.622272 2.682683 -3.687151 +v 5.690479 2.682683 -3.625986 +v 5.754905 2.682683 -3.561040 +v 5.815635 2.682683 -3.492398 +v 5.873240 2.682683 -3.420632 +v 5.928620 2.682683 -3.346639 +v 5.982820 2.682683 -3.271468 +v 6.036828 2.682683 -3.196104 +v 6.091536 2.682683 -3.121440 +v 6.147789 2.682683 -3.048321 +v 6.206289 2.682683 -2.977450 +v 6.267563 2.682683 -2.909352 +v 6.331923 2.682683 -2.844340 +v 6.399443 2.682683 -2.782488 +v 6.469940 2.682683 -2.723614 +v 6.542770 2.682683 -2.667072 +v 6.617097 2.682683 -2.612027 +v 6.692243 2.682683 -2.557801 +v 6.767426 2.682683 -2.503612 +v 6.841701 2.682683 -2.448515 +v 6.914019 2.682683 -2.391461 +v 6.983392 2.682683 -2.331463 +v 7.049153 2.682683 -2.267852 +v 7.111182 2.682683 -2.200509 +v 7.169884 2.682683 -2.129840 +v 7.226020 2.682683 -2.056603 +v 7.280536 2.682683 -1.981748 +v 7.334428 2.682683 -1.906268 +v 7.388645 2.682683 -1.831113 +v 7.444059 2.682683 -1.757155 +v 7.501486 2.682683 -1.685210 +v 7.561734 2.682683 -1.616087 +v 7.625517 2.682683 -1.550498 +v 7.693021 2.682683 -1.488630 +v 7.763855 2.682683 -1.430092 +v 7.837214 2.682683 -1.374079 +v 7.912094 2.682683 -1.319588 +v 7.987484 2.682683 -1.265605 +v 8.062466 2.682683 -1.211216 +v 8.136094 2.682683 -1.155472 +v 8.207678 2.682683 -1.097685 +v 8.276777 2.682683 -1.037413 +v 8.342958 2.682683 -0.974222 +v 8.405890 2.682683 -0.907780 +v 8.465496 2.682683 -0.838016 +v 8.522123 2.682683 -0.765271 +v 4.516074 2.778484 -4.780274 +v 4.572052 2.778484 -4.706881 +v 4.626310 2.778485 -4.631766 +v 4.679832 2.778484 -4.555915 +v 4.733786 2.778484 -4.480498 +v 4.789365 2.778484 -4.406706 +v 4.847563 2.778485 -4.335532 +v 4.908973 2.778484 -4.267570 +v 4.973700 2.778484 -4.202926 +v 5.041668 2.778484 -4.141521 +v 5.112610 2.778484 -4.083091 +v 5.185987 2.778484 -4.027097 +v 5.261007 2.778484 -3.972745 +v 5.336679 2.778484 -3.919044 +v 5.411910 2.778484 -3.864905 +v 5.485644 2.778484 -3.809267 +v 5.557120 2.778484 -3.751371 +v 5.625596 2.778484 -3.690475 +v 5.690434 2.778484 -3.625942 +v 5.751482 2.778484 -3.557617 +v 5.809120 2.778484 -3.485883 +v 5.864205 2.778485 -3.411597 +v 5.917916 2.778484 -3.335936 +v 5.971531 2.778484 -3.260179 +v 6.026114 2.778484 -3.185391 +v 6.082449 2.778484 -3.112354 +v 6.141178 2.778484 -3.041711 +v 6.202732 2.778484 -2.973892 +v 6.267331 2.778484 -2.909120 +v 6.334995 2.778484 -2.847413 +v 6.405543 2.778484 -2.788589 +v 6.478587 2.778484 -2.732260 +v 6.553236 2.778484 -2.677538 +v 6.628442 2.778484 -2.623372 +v 6.703427 2.778484 -2.568985 +v 6.777367 2.778485 -2.513553 +v 6.849386 2.778484 -2.456200 +v 6.918644 2.778484 -2.396087 +v 6.984496 2.778484 -2.332567 +v 7.046677 2.778484 -2.265376 +v 7.105495 2.778484 -2.194823 +v 7.161724 2.778484 -2.121679 +v 7.216276 2.778484 -2.046860 +v 7.270130 2.778484 -1.971342 +v 7.324255 2.778484 -1.896095 +v 7.379577 2.778484 -1.822046 +v 7.436953 2.778484 -1.750049 +v 7.497147 2.778484 -1.680872 +v 7.560801 2.778484 -1.615154 +v 7.628261 2.778484 -1.553242 +v 7.699220 2.778484 -1.494828 +v 7.772814 2.778484 -1.439051 +v 7.847915 2.778484 -1.384780 +v 7.923399 2.778484 -1.330893 +v 7.998314 2.778484 -1.276436 +v 8.071906 2.778484 -1.220656 +v 8.143417 2.778484 -1.162796 +v 8.212302 2.778484 -1.102309 +v 8.278263 2.778484 -1.038897 +v 8.341092 2.778484 -0.972355 +v 8.400779 2.778484 -0.902670 +v 8.457625 2.778484 -0.830144 +v 8.512324 2.778484 -0.755472 +v 4.507320 2.874286 -4.771520 +v 4.561801 2.874286 -4.696629 +v 4.615511 2.874286 -4.620967 +v 4.669538 2.874286 -4.545621 +v 4.725039 2.874286 -4.471751 +v 4.783057 2.874286 -4.400398 +v 4.844309 2.874286 -4.332277 +v 4.909021 2.874286 -4.267618 +v 4.977007 2.874286 -4.206233 +v 5.047983 2.874286 -4.147836 +v 5.121391 2.874286 -4.091873 +v 5.196414 2.874286 -4.037524 +v 5.272053 2.874286 -3.983791 +v 5.347232 2.874286 -3.929598 +v 5.420928 2.874286 -3.873922 +v 5.492288 2.874286 -3.815910 +v 5.560766 2.874286 -3.755016 +v 5.625905 2.874286 -3.690783 +v 5.687424 2.874286 -3.622931 +v 5.745477 2.874286 -3.551612 +v 5.800705 2.874286 -3.477469 +v 5.854198 2.874286 -3.401589 +v 5.907313 2.874286 -3.325333 +v 5.961430 2.874286 -3.250078 +v 6.017545 2.874286 -3.176821 +v 6.076250 2.874286 -3.106155 +v 6.137941 2.874286 -3.038474 +v 6.202762 2.874286 -2.973922 +v 6.270634 2.874286 -2.912423 +v 6.341300 2.874286 -2.853717 +v 6.414332 2.874286 -2.797377 +v 6.489140 2.874286 -2.742814 +v 6.564633 2.874286 -2.688935 +v 6.639644 2.874286 -2.634574 +v 6.713378 2.874286 -2.578936 +v 6.785081 2.874286 -2.521268 +v 6.854067 2.874286 -2.460881 +v 6.919803 2.874286 -2.397245 +v 6.982028 2.874286 -2.330099 +v 7.040873 2.874286 -2.259571 +v 7.097062 2.874286 -2.186389 +v 7.151646 2.874286 -2.111602 +v 7.205562 2.874286 -2.036146 +v 7.259729 2.874286 -1.960942 +v 7.315050 2.874286 -1.886890 +v 7.372389 2.874286 -1.814858 +v 7.432529 2.874286 -1.745626 +v 7.496088 2.874286 -1.679813 +v 7.563433 2.874286 -1.617786 +v 7.634442 2.874286 -1.559423 +v 7.708280 2.874286 -1.503889 +v 7.783693 2.874286 -1.449931 +v 7.859395 2.874286 -1.396261 +v 7.934326 2.874286 -1.341820 +v 8.007730 2.874286 -1.285851 +v 8.079073 2.874286 -1.227823 +v 8.147807 2.874286 -1.167185 +v 8.213550 2.874286 -1.103556 +v 8.276179 2.874286 -1.036815 +v 8.335762 2.874286 -0.967025 +v 8.392629 2.874286 -0.894519 +v 8.447437 2.874286 -0.819957 +v 8.501162 2.874286 -0.744308 +v 4.496990 2.970088 -4.761189 +v 4.550933 2.970088 -4.685760 +v 4.605126 2.970088 -4.610582 +v 4.660664 2.970087 -4.536748 +v 4.718583 2.970088 -4.465296 +v 4.779679 2.970088 -4.397019 +v 4.844321 2.970088 -4.332289 +v 4.912346 2.970088 -4.270943 +v 4.983315 2.970087 -4.212540 +v 5.056760 2.970088 -4.156613 +v 5.131852 2.970087 -4.102333 +v 5.207555 2.970087 -4.048665 +v 5.282762 2.970088 -3.994500 +v 5.356438 2.970088 -3.938804 +v 5.427738 2.970088 -3.880732 +v 5.496099 2.970088 -3.819721 +v 5.561258 2.970088 -3.755509 +v 5.623090 2.970088 -3.687969 +v 5.681661 2.970088 -3.617168 +v 5.737391 2.970087 -3.543527 +v 5.791125 2.970088 -3.467888 +v 5.844082 2.970087 -3.391474 +v 5.897689 2.970088 -3.315709 +v 5.953276 2.970088 -3.241924 +v 6.011671 2.970088 -3.170947 +v 6.073246 2.970087 -3.103150 +v 6.138131 2.970088 -3.038664 +v 6.206180 2.970088 -2.977341 +v 6.277027 2.970088 -2.918816 +v 6.350144 2.970088 -2.862561 +v 6.424877 2.970088 -2.807922 +v 6.500449 2.970087 -2.754123 +v 6.575665 2.970088 -2.699967 +v 6.649375 2.970088 -2.644305 +v 6.720870 2.970088 -2.586428 +v 6.789572 2.970088 -2.525758 +v 6.855074 2.970088 -2.461889 +v 6.917203 2.970088 -2.394645 +v 6.976085 2.970088 -2.324156 +v 7.032199 2.970088 -2.250899 +v 7.086626 2.970088 -2.175953 +v 7.140562 2.970087 -2.100518 +v 7.194857 2.970088 -2.025440 +v 7.250317 2.970088 -1.951529 +v 7.307742 2.970088 -1.879582 +v 7.367889 2.970088 -1.810358 +v 7.431387 2.970088 -1.744483 +v 7.498593 2.970088 -1.682318 +v 7.569501 2.970087 -1.623854 +v 7.643478 2.970087 -1.568459 +v 7.719223 2.970088 -1.514833 +v 7.795268 2.970087 -1.461505 +v 7.870370 2.970087 -1.407236 +v 7.943695 2.970088 -1.351189 +v 8.014764 2.970087 -1.292886 +v 8.083263 2.970087 -1.232014 +v 8.148829 2.970088 -1.168207 +v 8.211267 2.970088 -1.101274 +v 8.270678 2.970088 -1.031312 +v 8.327427 2.970087 -0.958690 +v 8.382190 2.970087 -0.884081 +v 8.435924 2.970088 -0.808443 +v 8.489767 2.970087 -0.732914 +v 4.485981 3.065889 -4.750180 +v 4.540410 3.065889 -4.675237 +v 4.596096 3.065889 -4.601552 +v 4.654035 3.065889 -4.530119 +v 4.715047 3.065889 -4.461760 +v 4.779601 3.065889 -4.396942 +v 4.847678 3.065889 -4.335647 +v 4.918736 3.065889 -4.277333 +v 4.992136 3.065889 -4.221361 +v 5.067257 3.065889 -4.167109 +v 5.143045 3.065889 -4.113527 +v 5.218343 3.065889 -4.059453 +v 5.292055 3.065889 -4.003793 +v 5.363306 3.065889 -3.945672 +v 5.431530 3.065889 -3.884524 +v 5.496508 3.065889 -3.820130 +v 5.558322 3.065889 -3.752573 +v 5.617184 3.065889 -3.682063 +v 5.673448 3.065889 -3.608954 +v 5.727734 3.065889 -3.533869 +v 5.781001 3.065889 -3.457764 +v 5.834501 3.065889 -3.381893 +v 5.889597 3.065889 -3.307618 +v 5.947451 3.065889 -3.236099 +v 6.008664 3.065889 -3.167940 +v 6.073381 3.065889 -3.103285 +v 6.141455 3.065889 -3.041987 +v 6.212450 3.065889 -2.983610 +v 6.285726 3.065889 -2.927515 +v 6.360519 3.065889 -2.872936 +v 6.435986 3.065889 -2.819031 +v 6.511222 3.065889 -2.764895 +v 6.585061 3.065889 -2.709362 +v 6.656510 3.065889 -2.651440 +v 6.725039 3.065889 -2.590598 +v 6.790329 3.065889 -2.526515 +v 6.852297 3.065889 -2.459111 +v 6.911130 3.065889 -2.388573 +v 6.967308 3.065889 -2.315379 +v 7.021595 3.065889 -2.240294 +v 7.075306 3.065889 -2.164634 +v 7.129639 3.065889 -2.089594 +v 7.185288 3.065889 -2.015872 +v 7.242921 3.065889 -1.944133 +v 7.303194 3.065889 -1.875034 +v 7.366693 3.065889 -1.809161 +v 7.433795 3.065889 -1.746891 +v 7.504503 3.065889 -1.688228 +v 7.578383 3.065889 -1.632736 +v 7.654333 3.065889 -1.579314 +v 7.730756 3.065889 -1.526365 +v 7.806189 3.065889 -1.472426 +v 7.879621 3.065889 -1.416486 +v 7.950537 3.065889 -1.358031 +v 8.018744 3.065889 -1.296865 +v 8.084106 3.065889 -1.232857 +v 8.146418 3.065889 -1.165796 +v 8.205711 3.065889 -1.095718 +v 8.262344 3.065889 -1.022978 +v 8.316996 3.065889 -0.948258 +v 8.370637 3.065889 -0.872528 +v 8.424422 3.065889 -0.796942 +v 8.479518 3.065889 -0.722666 +v 4.475295 3.161690 -4.739494 +v 4.531229 3.161691 -4.666057 +v 4.589322 3.161691 -4.594777 +v 4.650373 3.161691 -4.526457 +v 4.714901 3.161690 -4.461614 +v 4.782996 3.161690 -4.400337 +v 4.854242 3.161691 -4.342211 +v 4.927762 3.161691 -4.286358 +v 5.002777 3.161691 -4.232002 +v 5.078550 3.161691 -4.178404 +v 5.153898 3.161690 -4.124379 +v 5.227661 3.161691 -4.068770 +v 5.298890 3.161691 -4.010627 +v 5.366973 3.161690 -3.949339 +v 5.431692 3.161690 -3.884686 +v 5.493199 3.161690 -3.816822 +v 5.551940 3.161691 -3.746191 +v 5.608427 3.161691 -3.673306 +v 5.663215 3.161690 -3.598722 +v 5.717046 3.161691 -3.523181 +v 5.770904 3.161690 -3.447668 +v 5.825971 3.161691 -3.373362 +v 5.883429 3.161691 -3.301449 +v 5.944177 3.161691 -3.232825 +v 6.008557 3.161691 -3.167833 +v 6.076465 3.161691 -3.106369 +v 6.147466 3.161690 -3.047998 +v 6.220855 3.161691 -2.992015 +v 6.295767 3.161691 -2.937556 +v 6.371268 3.161690 -2.883685 +v 6.446415 3.161691 -2.829460 +v 6.520281 3.161691 -2.773954 +v 6.591848 3.161691 -2.716150 +v 6.660390 3.161691 -2.655319 +v 6.725617 3.161691 -2.591176 +v 6.787502 3.161691 -2.523688 +v 6.846282 3.161690 -2.453097 +v 6.902471 3.161691 -2.379914 +v 6.956836 3.161691 -2.304907 +v 7.010357 3.161691 -2.229056 +v 7.064431 3.161690 -2.153758 +v 7.120119 3.161691 -2.080074 +v 7.177949 3.161690 -2.008533 +v 7.238424 3.161691 -1.939636 +v 7.302011 3.161690 -1.873850 +v 7.369038 3.161691 -1.811507 +v 7.439550 3.161690 -1.752647 +v 7.513148 3.161690 -1.696873 +v 7.588998 3.161691 -1.643351 +v 7.665669 3.161691 -1.590650 +v 7.741502 3.161691 -1.537111 +v 7.815238 3.161691 -1.481476 +v 7.886209 3.161690 -1.423075 +v 7.954233 3.161691 -1.361727 +v 8.019359 3.161691 -1.297481 +v 8.081594 3.161690 -1.230344 +v 8.140883 3.161690 -1.160262 +v 8.197526 3.161691 -1.087533 +v 8.252153 3.161690 -1.012788 +v 8.305717 3.161691 -0.936980 +v 8.359389 3.161691 -0.861280 +v 8.414383 3.161691 -0.786902 +v 8.471740 3.161690 -0.714887 +v 4.466008 3.257492 -4.730208 +v 4.524402 3.257492 -4.659229 +v 4.585640 3.257492 -4.591096 +v 4.650231 3.257492 -4.526316 +v 4.718327 3.257492 -4.465039 +v 4.789626 3.257492 -4.406966 +v 4.863368 3.257492 -4.351336 +v 4.938446 3.257492 -4.297043 +v 5.014019 3.257492 -4.243244 +v 5.089289 3.257492 -4.189142 +v 5.163067 3.257492 -4.133549 +v 5.234324 3.257492 -4.075434 +v 5.302359 3.257492 -4.014096 +v 5.366889 3.257492 -3.949255 +v 5.428066 3.257492 -3.881060 +v 5.486405 3.257492 -3.810027 +v 5.542678 3.257492 -3.736928 +v 5.597610 3.257492 -3.662488 +v 5.651878 3.257492 -3.587385 +v 5.706271 3.257492 -3.512407 +v 5.761722 3.257492 -3.438485 +v 5.819236 3.257492 -3.366627 +v 5.879720 3.257492 -3.297740 +v 5.943744 3.257492 -3.232391 +v 6.011359 3.257492 -3.170635 +v 6.082204 3.257492 -3.112108 +v 6.155595 3.257492 -3.056128 +v 6.230629 3.257492 -3.001790 +v 6.306290 3.257492 -2.948079 +v 6.381547 3.257492 -2.893965 +v 6.455428 3.257492 -2.838473 +v 6.527063 3.257492 -2.780736 +v 6.595692 3.257492 -2.719994 +v 6.660926 3.257492 -2.655856 +v 6.722761 3.257492 -2.588319 +v 6.781477 3.257492 -2.517663 +v 6.837623 3.257492 -2.444437 +v 6.891990 3.257492 -2.369432 +v 6.945560 3.257492 -2.293631 +v 6.999430 3.257492 -2.218130 +v 7.054908 3.257492 -2.144235 +v 7.112830 3.257492 -2.072786 +v 7.173550 3.257492 -2.004134 +v 7.237360 3.257492 -1.938571 +v 7.304451 3.257492 -1.876291 +v 7.374816 3.257492 -1.817284 +v 7.448117 3.257492 -1.761214 +v 7.523602 3.257492 -1.707327 +v 7.600141 3.257492 -1.654493 +v 7.676189 3.257492 -1.601170 +v 7.750290 3.257492 -1.545899 +v 7.821538 3.257492 -1.487775 +v 7.889617 3.257492 -1.426483 +v 7.954611 3.257492 -1.362105 +v 8.016735 3.257492 -1.294857 +v 8.076111 3.257492 -1.224862 +v 8.132883 3.257492 -1.152261 +v 8.187637 3.257492 -1.077644 +v 8.241261 3.257492 -1.001895 +v 8.294888 3.257492 -0.926150 +v 8.349751 3.257492 -0.851641 +v 8.406963 3.257492 -0.779482 +v 8.467310 3.257492 -0.710457 +v 4.459320 3.353294 -4.723519 +v 4.520857 3.353293 -4.655684 +v 4.585601 3.353294 -4.591057 +v 4.653707 3.353294 -4.529791 +v 4.724949 3.353294 -4.471662 +v 4.798692 3.353293 -4.416033 +v 4.873940 3.353293 -4.361908 +v 4.949492 3.353294 -4.308090 +v 5.024515 3.353294 -4.253740 +v 5.098217 3.353293 -4.198071 +v 5.169531 3.353294 -4.140012 +v 5.237654 3.353294 -4.078763 +v 5.302190 3.353294 -4.013927 +v 5.363210 3.353294 -3.945576 +v 5.421225 3.353294 -3.874219 +v 5.477073 3.353294 -3.800695 +v 5.531748 3.353294 -3.725999 +v 5.586081 3.353294 -3.650959 +v 5.640811 3.353294 -3.576318 +v 5.696709 3.353293 -3.502844 +v 5.754570 3.353294 -3.431334 +v 5.815143 3.353294 -3.362534 +v 5.878986 3.353294 -3.297006 +v 5.946314 3.353294 -3.234962 +v 6.016890 3.353294 -3.176166 +v 6.090121 3.353294 -3.120025 +v 6.165163 3.353294 -3.065695 +v 6.240990 3.353294 -3.012151 +v 6.316495 3.353293 -2.958285 +v 6.390596 3.353294 -2.903013 +v 6.462340 3.353294 -2.845386 +v 6.531014 3.353293 -2.784688 +v 6.596220 3.353294 -2.720521 +v 6.657951 3.353293 -2.652881 +v 6.716534 3.353293 -2.582092 +v 6.772570 3.353294 -2.508756 +v 6.826888 3.353293 -2.433703 +v 6.880484 3.353293 -2.357927 +v 6.934436 3.353294 -2.282507 +v 6.989814 3.353293 -2.208513 +v 7.047688 3.353294 -2.137015 +v 7.108626 3.353294 -2.068581 +v 7.172767 3.353293 -2.003350 +v 7.240120 3.353294 -1.941332 +v 7.310531 3.353294 -1.882371 +v 7.383615 3.353294 -1.826083 +v 7.458706 3.353294 -1.771802 +v 7.534834 3.353294 -1.718559 +v 7.610734 3.353293 -1.665087 +v 7.684986 3.353294 -1.609967 +v 7.756535 3.353294 -1.552144 +v 7.824864 3.353294 -1.491101 +v 7.889931 3.353293 -1.426796 +v 7.951976 3.353293 -1.359470 +v 8.011324 3.353294 -1.289446 +v 8.068247 3.353294 -1.216997 +v 8.123159 3.353294 -1.142537 +v 8.176931 3.353293 -1.066938 +v 8.230632 3.353294 -0.991267 +v 8.285447 3.353294 -0.916710 +v 8.342506 3.353294 -0.844398 +v 8.402679 3.353294 -0.775199 +v 8.466405 3.353294 -0.709553 +v 4.456059 3.449095 -4.720258 +v 4.521012 3.449095 -4.655840 +v 4.589179 3.449095 -4.594635 +v 4.660361 3.449095 -4.536446 +v 4.734008 3.449095 -4.480721 +v 4.809232 3.449095 -4.426573 +v 4.884913 3.449095 -4.372882 +v 4.959877 3.449095 -4.318474 +v 5.033355 3.449095 -4.262580 +v 5.104637 3.449095 -4.204491 +v 5.172884 3.449095 -4.143366 +v 5.237587 3.449095 -4.078697 +v 5.298682 3.449095 -4.010420 +v 5.356582 3.449095 -3.938948 +v 5.412113 3.449095 -3.865108 +v 5.466372 3.449095 -3.789994 +v 5.520434 3.449095 -3.714684 +v 5.575142 3.449095 -3.640021 +v 5.631259 3.449095 -3.566765 +v 5.689468 3.449095 -3.495603 +v 5.750347 3.449095 -3.427110 +v 5.814309 3.449095 -3.361700 +v 5.881531 3.449095 -3.299550 +v 5.951883 3.449095 -3.240532 +v 6.024863 3.449095 -3.184139 +v 6.099700 3.449095 -3.129605 +v 6.175474 3.449095 -3.076007 +v 6.251112 3.449095 -3.022273 +v 6.325472 3.449095 -2.967261 +v 6.397481 3.449095 -2.909899 +v 6.466308 3.449095 -2.849353 +v 6.531522 3.449095 -2.785196 +v 6.593162 3.449095 -2.717463 +v 6.651601 3.449095 -2.646530 +v 6.707500 3.449095 -2.573058 +v 6.761743 3.449095 -2.497930 +v 6.815351 3.449095 -2.422165 +v 6.869390 3.449095 -2.346833 +v 6.924893 3.449095 -2.272964 +v 6.982772 3.449095 -2.201471 +v 7.043785 3.449095 -2.133112 +v 7.108203 3.449095 -2.068159 +v 7.175907 3.449095 -2.006490 +v 7.246563 3.449095 -1.947775 +v 7.319649 3.449095 -1.891489 +v 7.394460 3.449095 -1.836928 +v 7.470126 3.449095 -1.783222 +v 7.545638 3.449095 -1.729363 +v 7.619779 3.449095 -1.674132 +v 7.691443 3.449095 -1.616424 +v 7.760022 3.449095 -1.555631 +v 7.825309 3.449095 -1.491546 +v 7.887424 3.449095 -1.424290 +v 7.946702 3.449095 -1.354196 +v 8.003589 3.449095 -1.281711 +v 8.058593 3.449095 -1.207343 +v 8.112462 3.449095 -1.131841 +v 8.166276 3.449095 -1.056282 +v 8.221146 3.449095 -0.981779 +v 8.278143 3.449095 -0.909406 +v 8.338146 3.449095 -0.840038 +v 8.401686 3.449095 -0.774205 +v 8.468841 3.449095 -0.711988 +v 4.456438 3.544897 -4.720638 +v 4.524691 3.544897 -4.659518 +v 4.595844 3.544897 -4.601300 +v 4.669394 3.544897 -4.545478 +v 4.744529 3.544897 -4.491241 +v 4.820203 3.544897 -4.437544 +v 4.895276 3.544897 -4.383245 +v 4.968693 3.544897 -4.327290 +v 5.039817 3.544897 -4.269042 +v 5.108104 3.544897 -4.207957 +v 5.173010 3.544896 -4.143492 +v 5.234352 3.544897 -4.075462 +v 5.292392 3.544897 -4.004129 +v 5.347841 3.544897 -3.930208 +v 5.401779 3.544897 -3.854773 +v 5.455459 3.544897 -3.779081 +v 5.509916 3.544897 -3.704166 +v 5.565943 3.544897 -3.630821 +v 5.624280 3.544897 -3.559788 +v 5.685447 3.544897 -3.491581 +v 5.749712 3.544897 -3.426475 +v 5.817102 3.544897 -3.364494 +v 5.887411 3.544897 -3.305430 +v 5.960208 3.544897 -3.248856 +v 6.034776 3.544897 -3.194052 +v 6.110252 3.544897 -3.140156 +v 6.185724 3.544897 -3.086257 +v 6.260139 3.544897 -3.031300 +v 6.332389 3.544897 -2.974178 +v 6.401499 3.544897 -2.913916 +v 6.466864 3.544897 -2.849910 +v 6.528465 3.544897 -2.782138 +v 6.586795 3.544897 -2.711097 +v 6.642558 3.544897 -2.637488 +v 6.696702 3.544897 -2.562260 +v 6.750290 3.544897 -2.486476 +v 6.804399 3.544897 -2.411213 +v 6.860023 3.544897 -2.337466 +v 6.918021 3.544897 -2.266092 +v 6.979063 3.544897 -2.197762 +v 7.043584 3.544897 -2.132912 +v 7.111561 3.544897 -2.071516 +v 7.182557 3.544897 -2.013140 +v 7.255878 3.544897 -1.957090 +v 7.330681 3.544897 -1.902521 +v 7.406058 3.544897 -1.848526 +v 7.481102 3.544897 -1.794199 +v 7.554924 3.544897 -1.738649 +v 7.626519 3.544897 -1.680872 +v 7.695188 3.544897 -1.620169 +v 7.760689 3.544897 -1.556299 +v 7.823010 3.544897 -1.489248 +v 7.882359 3.544897 -1.419225 +v 7.939161 3.544897 -1.346655 +v 7.994053 3.544897 -1.272175 +v 8.047870 3.544897 -1.196620 +v 8.101680 3.544897 -1.121058 +v 8.156614 3.544897 -1.046620 +v 8.213653 3.544897 -0.974287 +v 8.273596 3.544897 -0.904859 +v 8.336967 3.544897 -0.838859 +v 8.403930 3.544897 -0.776450 +v 8.474246 3.544897 -0.717393 +v 4.460155 3.640698 -4.724355 +v 4.531286 3.640698 -4.666114 +v 4.604762 3.640698 -4.610218 +v 4.679820 3.640698 -4.555904 +v 4.755464 3.640698 -4.502176 +v 4.830581 3.640698 -4.447922 +v 4.904101 3.640698 -4.392070 +v 4.975177 3.640698 -4.333774 +v 5.043379 3.640698 -4.272604 +v 5.108394 3.640698 -4.208247 +v 5.170008 3.640698 -4.140490 +v 5.228355 3.640698 -4.069464 +v 5.283984 3.640698 -3.995723 +v 5.337852 3.640698 -3.920218 +v 5.391196 3.640698 -3.844191 +v 5.445325 3.640698 -3.768947 +v 5.501137 3.640698 -3.695387 +v 5.559349 3.640698 -3.624227 +v 5.620607 3.640698 -3.556114 +v 5.685164 3.640698 -3.491300 +v 5.752910 3.640698 -3.429673 +v 5.823460 3.640698 -3.370851 +v 5.896258 3.640698 -3.314278 +v 5.970656 3.640698 -3.259305 +v 6.045811 3.640698 -3.205087 +v 6.120864 3.640698 -3.150769 +v 6.194996 3.640698 -3.095529 +v 6.267237 3.640698 -3.038397 +v 6.336586 3.640698 -2.978375 +v 6.402259 3.640699 -2.914676 +v 6.463982 3.640698 -2.847028 +v 6.522213 3.640698 -2.775887 +v 6.577867 3.640698 -2.702168 +v 6.631887 3.640698 -2.626817 +v 6.685405 3.640698 -2.550963 +v 6.739524 3.640698 -2.475711 +v 6.795229 3.640698 -2.402044 +v 6.853321 3.640698 -2.330763 +v 6.914401 3.640698 -2.262472 +v 6.978871 3.640698 -2.197571 +v 7.046884 3.640698 -2.136211 +v 7.118111 3.640698 -2.078067 +v 7.191773 3.640698 -2.022357 +v 7.266844 3.640698 -1.968055 +v 7.342261 3.640698 -1.914102 +v 7.417074 3.640698 -1.859542 +v 7.490489 3.640698 -1.803585 +v 7.561844 3.640698 -1.745569 +v 7.630460 3.640698 -1.684813 +v 7.696034 3.640698 -1.621015 +v 7.758562 3.640698 -1.554171 +v 7.818130 3.640698 -1.484368 +v 7.875022 3.640698 -1.411888 +v 7.929813 3.640698 -1.337307 +v 7.983412 3.640698 -1.261534 +v 8.037002 3.640698 -1.185752 +v 8.091850 3.640698 -1.111229 +v 8.148935 3.640698 -1.038942 +v 8.208935 3.640698 -0.969570 +v 8.272271 3.640698 -0.903534 +v 8.339080 3.640698 -0.840971 +v 8.409189 3.640698 -0.781709 +v 8.482120 3.640699 -0.725268 +v 4.466602 3.736500 -4.730801 +v 4.539989 3.736500 -4.674817 +v 4.614985 3.736500 -4.620441 +v 4.690625 3.736500 -4.566710 +v 4.765804 3.736500 -4.512516 +v 4.839427 3.736500 -4.456768 +v 4.910591 3.736500 -4.398560 +v 4.978735 3.736500 -4.337332 +v 5.043713 3.736500 -4.272938 +v 5.105479 3.736500 -4.205332 +v 5.164135 3.736500 -4.134616 +v 5.220097 3.736500 -4.061206 +v 5.274151 3.736500 -3.985889 +v 5.327418 3.736500 -3.909784 +v 5.381201 3.736500 -3.834196 +v 5.436747 3.736500 -3.760369 +v 5.494776 3.736500 -3.689026 +v 5.555900 3.736500 -3.620779 +v 5.620564 3.736500 -3.556071 +v 5.688655 3.736500 -3.494791 +v 5.759640 3.736500 -3.436403 +v 5.832753 3.736500 -3.380145 +v 5.907181 3.736500 -3.325201 +v 5.982162 3.736500 -3.270810 +v 6.056836 3.736500 -3.216113 +v 6.130456 3.736500 -3.160360 +v 6.202348 3.736500 -3.102880 +v 6.271685 3.736500 -3.042845 +v 6.337647 3.736500 -2.979437 +v 6.399727 3.736500 -2.912144 +v 6.458046 3.736500 -2.841092 +v 6.513528 3.736500 -2.767202 +v 6.567421 3.736500 -2.691722 +v 6.620802 3.736500 -2.615732 +v 6.674840 3.736500 -2.540399 +v 6.730537 3.736500 -2.466723 +v 6.788662 3.736500 -2.395477 +v 6.849752 3.736500 -2.327195 +v 6.914129 3.736500 -2.262200 +v 6.981931 3.736500 -2.200630 +v 7.053074 3.736500 -2.142401 +v 7.126930 3.736500 -2.086885 +v 7.202374 3.736500 -2.032958 +v 7.278135 3.736500 -1.979347 +v 7.353079 3.736500 -1.924919 +v 7.426356 3.736500 -1.868825 +v 7.497403 3.736500 -1.810500 +v 7.565838 3.736500 -1.749563 +v 7.631340 3.736500 -1.685693 +v 7.693933 3.736500 -1.618914 +v 7.753729 3.736500 -1.549338 +v 7.810885 3.736500 -1.477122 +v 7.865807 3.736500 -1.402672 +v 7.919299 3.736500 -1.326793 +v 7.972582 3.736500 -1.250704 +v 8.027098 3.736500 -1.175848 +v 8.084081 3.736500 -1.103459 +v 8.144157 3.736500 -1.034164 +v 8.207594 3.736500 -0.968229 +v 8.274406 3.736500 -0.905669 +v 8.344378 3.736500 -0.846269 +v 8.417078 3.736500 -0.789597 +v 8.491853 3.736500 -0.735000 +v 4.475080 3.832301 -4.739280 +v 4.549969 3.832302 -4.684797 +v 4.625602 3.832302 -4.631058 +v 4.700871 3.832301 -4.576955 +v 4.774641 3.832301 -4.521353 +v 4.845934 3.832301 -4.463275 +v 4.914108 3.832302 -4.402077 +v 4.978970 3.832301 -4.337567 +v 5.040700 3.832301 -4.269925 +v 5.099510 3.832302 -4.199363 +v 5.155777 3.832301 -4.126258 +v 5.210149 3.832301 -4.051259 +v 5.263584 3.832301 -3.975321 +v 5.317282 3.832301 -3.899648 +v 5.372512 3.832301 -3.825507 +v 5.430346 3.832301 -3.753968 +v 5.491304 3.832301 -3.685554 +v 5.555842 3.832301 -3.620721 +v 5.624069 3.832301 -3.559576 +v 5.695446 3.832301 -3.501582 +v 5.769043 3.832301 -3.445807 +v 5.843819 3.832302 -3.391211 +v 5.918837 3.832301 -3.336856 +v 5.993340 3.832301 -3.281988 +v 6.066563 3.832302 -3.225839 +v 6.137933 3.832301 -3.167837 +v 6.206957 3.832301 -3.107490 +v 6.272994 3.832301 -3.044154 +v 6.335469 3.832301 -2.977258 +v 6.394213 3.832301 -2.906630 +v 6.449754 3.832301 -2.832799 +v 6.503400 3.832301 -2.757073 +v 6.556597 3.832302 -2.680899 +v 6.610446 3.832301 -2.605376 +v 6.666008 3.832301 -2.531566 +v 6.724066 3.832301 -2.460252 +v 6.785112 3.832302 -2.391927 +v 6.849394 3.832301 -2.326837 +v 6.916963 3.832302 -2.265034 +v 6.987721 3.832301 -2.206420 +v 7.061378 3.832301 -2.150706 +v 7.137008 3.832301 -2.096963 +v 7.213204 3.832301 -2.043788 +v 7.288580 3.832301 -1.989792 +v 7.362078 3.832301 -1.933918 +v 7.433071 3.832301 -1.875539 +v 7.501284 3.832301 -1.814380 +v 7.566615 3.832301 -1.750339 +v 7.629082 3.832301 -1.683435 +v 7.688941 3.832301 -1.613922 +v 7.746363 3.832302 -1.541973 +v 7.801614 3.832302 -1.467852 +v 7.855298 3.832301 -1.392163 +v 7.908495 3.832302 -1.315989 +v 7.962673 3.832302 -1.240795 +v 8.019318 3.832301 -1.168068 +v 8.079352 3.832301 -1.098731 +v 8.142937 3.832301 -1.032943 +v 8.209911 3.832301 -0.970546 +v 8.279932 3.832301 -0.911195 +v 8.352511 3.832301 -0.854402 +v 8.427028 3.832301 -0.799547 +v 8.502708 3.832302 -0.745856 +v 4.484936 3.928103 -4.749135 +v 4.560466 3.928103 -4.695294 +v 4.635783 3.928103 -4.641239 +v 4.709710 3.928103 -4.585794 +v 4.781182 3.928103 -4.527895 +v 4.849446 3.928103 -4.466786 +v 4.914212 3.928103 -4.402181 +v 4.975712 3.928103 -4.334309 +v 5.034446 3.928103 -4.263672 +v 5.090831 3.928103 -4.190684 +v 5.145464 3.928103 -4.115946 +v 5.199175 3.928103 -4.040285 +v 5.253024 3.928103 -3.964761 +v 5.308201 3.928103 -3.890568 +v 5.365828 3.928103 -3.818823 +v 5.426690 3.928103 -3.750312 +v 5.491075 3.928103 -3.685326 +v 5.559186 3.928103 -3.624064 +v 5.630684 3.928103 -3.566191 +v 5.704636 3.928103 -3.510772 +v 5.779846 3.928103 -3.456609 +v 5.855171 3.928103 -3.402562 +v 5.929703 3.928103 -3.347723 +v 6.002793 3.928103 -3.291441 +v 6.073829 3.928103 -3.233105 +v 6.142439 3.928103 -3.172343 +v 6.208308 3.928103 -3.108840 +v 6.271012 3.928103 -3.042173 +v 6.330280 3.928103 -2.972069 +v 6.386308 3.928103 -2.898725 +v 6.439989 3.928103 -2.823034 +v 6.492870 3.928103 -2.746543 +v 6.546449 3.928103 -2.670750 +v 6.601738 3.928103 -2.596669 +v 6.659586 3.928103 -2.525145 +v 6.720496 3.928103 -2.456682 +v 6.784667 3.928103 -2.391481 +v 6.852068 3.928103 -2.329511 +v 6.922508 3.928103 -2.270579 +v 6.995661 3.928103 -2.214360 +v 7.071030 3.928103 -2.160357 +v 7.147430 3.928103 -2.107385 +v 7.223295 3.928103 -2.053879 +v 7.297281 3.928103 -1.998493 +v 7.368537 3.928103 -1.940377 +v 7.436725 3.928103 -1.879194 +v 7.501864 3.928103 -1.814960 +v 7.564106 3.928103 -1.747831 +v 7.623755 3.928103 -1.678108 +v 7.681227 3.928103 -1.606207 +v 7.736782 3.928103 -1.532391 +v 7.790867 3.928103 -1.457104 +v 7.844336 3.928103 -1.381201 +v 7.898490 3.928103 -1.305984 +v 7.954846 3.928103 -1.232968 +v 8.014640 3.928103 -1.163390 +v 8.078281 3.928103 -1.097660 +v 8.145478 3.928103 -1.035485 +v 8.215725 3.928103 -0.976359 +v 8.288406 3.928103 -0.919669 +v 8.362839 3.928103 -0.864730 +v 8.438258 3.928103 -0.810778 +v 8.513796 3.928103 -0.756943 +v 4.495564 4.023905 -4.759763 +v 4.570762 4.023904 -4.705590 +v 4.644726 4.023904 -4.650182 +v 4.716334 4.023905 -4.592419 +v 4.784731 4.023905 -4.531444 +v 4.849510 4.023904 -4.466850 +v 4.910802 4.023905 -4.398771 +v 4.969246 4.023904 -4.327843 +v 5.025568 4.023904 -4.254794 +v 5.080302 4.023904 -4.180156 +v 5.134216 4.023905 -4.104698 +v 5.188268 4.023904 -4.029377 +v 5.243556 4.023904 -3.955293 +v 5.301174 4.023905 -3.883540 +v 5.361986 4.023904 -3.814981 +v 5.426389 4.023905 -3.750011 +v 5.494364 4.023904 -3.688614 +v 5.565757 4.023904 -3.630635 +v 5.639795 4.023905 -3.575302 +v 5.715284 4.023905 -3.521419 +v 5.790956 4.023904 -3.467720 +v 5.865735 4.023904 -3.413127 +v 5.938841 4.023904 -3.356861 +v 6.009760 4.023904 -3.298408 +v 6.078063 4.023904 -3.237339 +v 6.143577 4.023904 -3.173482 +v 6.206174 4.023904 -3.106707 +v 6.265708 4.023904 -3.036869 +v 6.322268 4.023904 -2.964058 +v 6.376428 4.023904 -2.888845 +v 6.429349 4.023904 -2.812394 +v 6.482622 4.023904 -2.736295 +v 6.537626 4.023904 -2.661928 +v 6.595198 4.023904 -2.590128 +v 6.655902 4.023904 -2.521460 +v 6.719946 4.023904 -2.456132 +v 6.787253 4.023904 -2.394068 +v 6.857539 4.023905 -2.334982 +v 6.930377 4.023904 -2.278447 +v 7.005212 4.023904 -2.223911 +v 7.081346 4.023904 -2.170673 +v 7.157436 4.023904 -2.117392 +v 7.231922 4.023905 -2.062506 +v 7.303649 4.023905 -2.004861 +v 7.372057 4.023904 -1.943897 +v 7.437122 4.023904 -1.879590 +v 7.499139 4.023904 -1.812235 +v 7.558496 4.023904 -1.742220 +v 7.615711 4.023904 -1.670064 +v 7.671315 4.023904 -1.596296 +v 7.725719 4.023904 -1.521328 +v 7.779604 4.023904 -1.445842 +v 7.834044 4.023905 -1.370910 +v 7.890412 4.023904 -1.297906 +v 7.950022 4.023904 -1.228144 +v 8.013610 4.023904 -1.162360 +v 8.080993 4.023904 -1.100371 +v 8.151505 4.023904 -1.041512 +v 8.224390 4.023905 -0.985025 +v 8.298863 4.023904 -0.930127 +v 8.374128 4.023904 -0.876019 +v 8.449350 4.023904 -0.821869 +v 8.523631 4.023904 -0.766778 +v 4.506057 4.119706 -4.770256 +v 4.579884 4.119706 -4.714712 +v 4.651498 4.119706 -4.656954 +v 4.719990 4.119706 -4.596074 +v 4.784858 4.119706 -4.531569 +v 4.846123 4.119706 -4.463463 +v 4.904324 4.119706 -4.392292 +v 4.960392 4.119706 -4.318989 +v 5.015150 4.119706 -4.244375 +v 5.069192 4.119706 -4.169045 +v 5.123406 4.119706 -4.093888 +v 5.178816 4.119706 -4.019926 +v 5.236477 4.119706 -3.948215 +v 5.297285 4.119706 -3.879651 +v 5.361744 4.119706 -3.814738 +v 5.429783 4.119706 -3.753405 +v 5.501016 4.119706 -3.695267 +v 5.574937 4.119706 -3.639816 +v 5.650475 4.119706 -3.585982 +v 5.726360 4.119706 -3.532496 +v 5.801403 4.119706 -3.478167 +v 5.874674 4.119706 -3.422065 +v 5.945547 4.119706 -3.363567 +v 6.013648 4.119706 -3.302296 +v 6.078764 4.119706 -3.238040 +v 6.140952 4.119706 -3.170856 +v 6.200327 4.119706 -3.100860 +v 6.257097 4.119706 -3.028258 +v 6.311741 4.119706 -2.953530 +v 6.365139 4.119706 -2.877555 +v 6.418547 4.119706 -2.801592 +v 6.473386 4.119706 -2.727059 +v 6.530772 4.119706 -2.655073 +v 6.591302 4.119706 -2.586232 +v 6.655235 4.119706 -2.520793 +v 6.722500 4.119706 -2.458686 +v 6.792765 4.119706 -2.399579 +v 6.865512 4.119706 -2.342955 +v 6.940090 4.119706 -2.288162 +v 7.015728 4.119706 -2.234427 +v 7.091579 4.119706 -2.180907 +v 7.166295 4.119706 -2.126250 +v 7.238475 4.119706 -2.069058 +v 7.307264 4.119706 -2.008476 +v 7.372442 4.119706 -1.944282 +v 7.434295 4.119706 -1.876763 +v 7.493378 4.119706 -1.806475 +v 7.550299 4.119706 -1.734024 +v 7.605714 4.119706 -1.660067 +v 7.660223 4.119706 -1.585204 +v 7.714430 4.119706 -1.510039 +v 7.769234 4.119706 -1.435471 +v 7.825814 4.119706 -1.362680 +v 7.885411 4.119706 -1.292905 +v 7.948915 4.119706 -1.227037 +v 8.016429 4.119706 -1.165179 +v 8.087207 4.119706 -1.106585 +v 8.160317 4.119706 -1.050324 +v 8.234871 4.119706 -0.995505 +v 8.310027 4.119706 -0.941290 +v 8.384983 4.119706 -0.886874 +v 8.458932 4.119706 -0.831451 +v 8.531038 4.119706 -0.774185 +v 4.515294 4.215508 -4.779493 +v 4.586781 4.215508 -4.721609 +v 4.655271 4.215508 -4.660727 +v 4.720204 4.215508 -4.596288 +v 4.781518 4.215508 -4.528231 +v 4.839659 4.215508 -4.456999 +v 4.895478 4.215508 -4.383446 +v 4.950058 4.215508 -4.308655 +v 5.004219 4.215508 -4.233444 +v 5.058595 4.215508 -4.158449 +v 5.114136 4.215508 -4.084617 +v 5.171843 4.215508 -4.012953 +v 5.232621 4.215508 -3.944359 +v 5.297055 4.215508 -3.879421 +v 5.365209 4.215508 -3.818203 +v 5.436522 4.215508 -3.760145 +v 5.510250 4.215508 -3.704501 +v 5.585630 4.215508 -3.650509 +v 5.661496 4.215508 -3.597003 +v 5.736660 4.215508 -3.542796 +v 5.810104 4.215508 -3.486867 +v 5.881070 4.215508 -3.428462 +v 5.949091 4.215508 -3.367111 +v 6.013946 4.215508 -3.302594 +v 6.075672 4.215508 -3.234948 +v 6.134602 4.215508 -3.164506 +v 6.191173 4.215508 -3.091706 +v 6.245975 4.215508 -3.017136 +v 6.299815 4.215508 -2.941604 +v 6.353713 4.215508 -2.866130 +v 6.408814 4.215508 -2.791859 +v 6.466206 4.215508 -2.719880 +v 6.526669 4.215508 -2.650971 +v 6.590534 4.215508 -2.585464 +v 6.657776 4.215508 -2.523335 +v 6.728075 4.215508 -2.464261 +v 6.800872 4.215508 -2.407686 +v 6.875433 4.215508 -2.352876 +v 6.950902 4.215508 -2.298973 +v 7.026338 4.215508 -2.245037 +v 7.100847 4.215508 -2.190174 +v 7.173228 4.215508 -2.133184 +v 7.242381 4.215508 -2.072965 +v 7.307817 4.215508 -2.009029 +v 7.369665 4.215508 -1.941505 +v 7.428497 4.215508 -1.870965 +v 7.485096 4.215508 -1.798192 +v 7.540259 4.215508 -1.723984 +v 7.594708 4.215508 -1.649062 +v 7.649099 4.215508 -1.574080 +v 7.704219 4.215508 -1.499828 +v 7.761080 4.215508 -1.427317 +v 7.820779 4.215508 -1.357644 +v 7.884207 4.215508 -1.291701 +v 7.951683 4.215508 -1.229805 +v 8.022687 4.215508 -1.171437 +v 8.096070 4.215508 -1.115448 +v 8.170792 4.215508 -1.060799 +v 8.245951 4.215508 -1.006586 +v 8.320745 4.215508 -0.952009 +v 8.394431 4.215508 -0.896322 +v 8.466284 4.215508 -0.838804 +v 8.535591 4.215508 -0.778738 +v 4.522201 4.311309 -4.786401 +v 4.590594 4.311309 -4.725422 +v 4.655525 4.311309 -4.660981 +v 4.716874 4.311309 -4.592958 +v 4.775022 4.311309 -4.521734 +v 4.830759 4.311309 -4.448100 +v 4.885122 4.311309 -4.373091 +v 4.939207 4.311309 -4.297804 +v 4.993777 4.311309 -4.223002 +v 5.049492 4.311309 -4.149345 +v 5.107275 4.311309 -4.077757 +v 5.168005 4.311309 -4.009114 +v 5.232317 4.311309 -3.944055 +v 5.300402 4.311309 -3.882769 +v 5.371860 4.311309 -3.824854 +v 5.445707 4.311309 -3.769330 +v 5.520912 4.311309 -3.715162 +v 5.596604 4.311309 -3.661483 +v 5.671704 4.311309 -3.607211 +v 5.745214 4.311309 -3.551349 +v 5.816311 4.311309 -3.493075 +v 5.884415 4.311309 -3.431806 +v 5.949218 4.311309 -3.367237 +v 6.010697 4.311309 -3.299345 +v 6.069166 4.311309 -3.228442 +v 6.125268 4.311309 -3.155173 +v 6.179817 4.311309 -3.080350 +v 6.233742 4.311309 -3.004903 +v 6.288021 4.311309 -2.929810 +v 6.343609 4.311309 -2.856026 +v 6.401361 4.311309 -2.784406 +v 6.461962 4.311309 -2.715635 +v 6.525849 4.311309 -2.650151 +v 6.593089 4.311309 -2.588019 +v 6.663414 4.311309 -2.528973 +v 6.736287 4.311309 -2.472473 +v 6.810942 4.311309 -2.417757 +v 6.886452 4.311309 -2.363895 +v 6.961806 4.311309 -2.309877 +v 7.035990 4.311309 -2.254690 +v 7.108195 4.311309 -2.197523 +v 7.177502 4.311309 -2.137457 +v 7.243197 4.311309 -2.073781 +v 7.305183 4.311309 -2.006395 +v 7.363915 4.311309 -1.935755 +v 7.420211 4.311309 -1.862679 +v 7.475031 4.311309 -1.788128 +v 7.529310 4.311309 -1.713035 +v 7.583782 4.311309 -1.638135 +v 7.639136 4.311309 -1.564117 +v 7.696262 4.311309 -1.491871 +v 7.756113 4.311309 -1.422351 +v 7.819501 4.311309 -1.356367 +v 7.886818 4.311309 -1.294312 +v 7.957796 4.311309 -1.235918 +v 8.031442 4.311309 -1.180192 +v 8.106419 4.311309 -1.125796 +v 8.181713 4.311309 -1.071720 +v 8.256495 4.311309 -1.017130 +v 8.330044 4.311309 -0.961307 +v 8.401705 4.311309 -0.903596 +v 8.470872 4.311309 -0.843392 +v 8.537011 4.311309 -0.780159 +v 4.525949 4.407111 -4.790149 +v 4.590824 4.407111 -4.725652 +v 4.652166 4.407111 -4.657622 +v 4.710308 4.407111 -4.586392 +v 4.766007 4.407111 -4.512719 +v 4.820279 4.407111 -4.437620 +v 4.874211 4.407111 -4.362179 +v 4.928808 4.407111 -4.287405 +v 4.984752 4.407111 -4.213977 +v 5.042685 4.407111 -4.142538 +v 5.103406 4.407111 -4.073887 +v 5.167556 4.407111 -4.008666 +v 5.235421 4.407111 -3.947160 +v 5.306768 4.407111 -3.889135 +v 5.380784 4.407111 -3.833778 +v 5.456190 4.407111 -3.779812 +v 5.531792 4.407111 -3.726043 +v 5.606756 4.407111 -3.671635 +v 5.680210 4.407111 -3.615717 +v 5.751380 4.407111 -3.557516 +v 5.819642 4.407111 -3.496405 +v 5.884584 4.407111 -3.431976 +v 5.946093 4.407111 -3.364113 +v 6.004402 4.407111 -3.293050 +v 6.060108 4.407111 -3.219383 +v 6.114174 4.407111 -3.144079 +v 6.167777 4.407111 -3.068310 +v 6.222052 4.407111 -2.993212 +v 6.277944 4.407111 -2.919733 +v 6.336149 4.407111 -2.848566 +v 6.397132 4.407111 -2.780177 +v 6.461193 4.407111 -2.714867 +v 6.528476 4.407111 -2.652778 +v 6.598800 4.407111 -2.593730 +v 6.671692 4.407111 -2.537250 +v 6.746418 4.407111 -2.482605 +v 6.822031 4.407111 -2.428846 +v 6.897457 4.407111 -2.374900 +v 6.971619 4.407111 -2.319690 +v 7.043578 4.407111 -2.262277 +v 7.112741 4.407111 -2.202069 +v 7.178546 4.407111 -2.138502 +v 7.240705 4.407111 -2.071289 +v 7.299491 4.407111 -2.000704 +v 7.355640 4.407111 -1.927480 +v 7.410155 4.407111 -1.852624 +v 7.464114 4.407111 -1.777210 +v 7.518510 4.407111 -1.702235 +v 7.574047 4.407111 -1.628400 +v 7.631402 4.407111 -1.556383 +v 7.691416 4.407111 -1.487025 +v 7.754802 4.407111 -1.421040 +v 7.821943 4.407111 -1.358809 +v 7.892699 4.407111 -1.300192 +v 7.966326 4.407111 -1.244448 +v 8.041569 4.407111 -1.190319 +v 8.117100 4.407111 -1.136478 +v 8.192018 4.407111 -1.082024 +v 8.265585 4.407111 -1.026220 +v 8.337173 4.407111 -0.968436 +v 8.406235 4.407111 -0.908126 +v 8.472326 4.407111 -0.844845 +v 8.535156 4.407111 -0.778304 +v 4.526118 4.502912 -4.790318 +v 4.587446 4.502913 -4.722274 +v 4.645563 4.502913 -4.651019 +v 4.701200 4.502913 -4.577284 +v 4.755381 4.502912 -4.502093 +v 4.809217 4.502913 -4.426558 +v 4.863739 4.502912 -4.351707 +v 4.919791 4.502912 -4.278389 +v 4.977950 4.502913 -4.207176 +v 5.038768 4.502913 -4.138621 +v 5.102813 4.502913 -4.073295 +v 5.170408 4.502913 -4.011518 +v 5.241456 4.502913 -3.953195 +v 5.315340 4.502913 -3.897706 +v 5.390944 4.502913 -3.843939 +v 5.466856 4.502912 -3.790478 +v 5.541860 4.502913 -3.736110 +v 5.615256 4.502913 -3.680136 +v 5.686428 4.502912 -3.621934 +v 5.754819 4.502913 -3.560955 +v 5.819996 4.502912 -3.496760 +v 5.881740 4.502913 -3.429131 +v 5.940170 4.502912 -3.358190 +v 5.995836 4.502913 -3.284484 +v 6.049604 4.502913 -3.208880 +v 6.102716 4.502913 -3.132620 +v 6.156600 4.502913 -3.057133 +v 6.212404 4.502912 -2.983565 +v 6.270838 4.502913 -2.912627 +v 6.332215 4.502912 -2.844631 +v 6.396597 4.502913 -2.779642 +v 6.463981 4.502913 -2.717655 +v 6.534289 4.502912 -2.658591 +v 6.607116 4.502913 -2.602046 +v 6.681808 4.502913 -2.547366 +v 6.757455 4.502912 -2.493642 +v 6.832969 4.502913 -2.439784 +v 6.907212 4.502913 -2.384655 +v 6.979172 4.502913 -2.327243 +v 7.048148 4.502912 -2.266847 +v 7.113862 4.502912 -2.203189 +v 7.176114 4.502913 -2.136069 +v 7.235023 4.502912 -2.065607 +v 7.291187 4.502913 -1.992399 +v 7.345555 4.502913 -1.917396 +v 7.399252 4.502912 -1.841721 +v 7.453392 4.502913 -1.766489 +v 7.508939 4.502912 -1.692664 +v 7.566508 4.502913 -1.620862 +v 7.626690 4.502913 -1.551671 +v 7.690111 4.502912 -1.485720 +v 7.757112 4.502913 -1.423349 +v 7.827602 4.502913 -1.364468 +v 7.900996 4.502913 -1.308490 +v 7.976248 4.502913 -1.254370 +v 8.052038 4.502913 -1.200788 +v 8.127178 4.502912 -1.146557 +v 8.200898 4.502913 -1.090905 +v 8.272550 4.502912 -1.033184 +v 8.341598 4.502913 -0.972860 +v 8.407637 4.502913 -0.909528 +v 8.470447 4.502913 -0.842966 +v 8.530056 4.502913 -0.773204 +v 4.522791 4.598714 -4.786991 +v 4.580932 4.598714 -4.715759 +v 4.636504 4.598714 -4.641961 +v 4.690544 4.598714 -4.566628 +v 4.744223 4.598714 -4.490935 +v 4.798638 4.598714 -4.415979 +v 4.854686 4.598714 -4.342655 +v 4.913012 4.598714 -4.271609 +v 4.974033 4.598714 -4.203259 +v 5.038115 4.598714 -4.137967 +v 5.105520 4.598714 -4.076001 +v 5.176219 4.598714 -4.017328 +v 5.249763 4.598714 -3.961501 +v 5.325244 4.598714 -3.907610 +v 5.401386 4.598714 -3.854381 +v 5.476791 4.598714 -3.800414 +v 5.550350 4.598714 -3.744600 +v 5.621550 4.598714 -3.686429 +v 5.690012 4.598714 -3.625520 +v 5.755389 4.598714 -3.561524 +v 5.817445 4.598714 -3.494208 +v 5.876194 4.598714 -3.423585 +v 5.932045 4.598714 -3.350065 +v 5.985878 4.598714 -3.274526 +v 6.038778 4.598714 -3.198054 +v 6.092165 4.598714 -3.122069 +v 6.147528 4.598714 -3.048061 +v 6.205814 4.598714 -2.976974 +v 6.267357 4.598714 -2.909146 +v 6.332059 4.598714 -2.844477 +v 6.399650 4.598714 -2.782695 +v 6.469916 4.598714 -2.723590 +v 6.542620 4.598714 -2.666921 +v 6.617157 4.598714 -2.612087 +v 6.692705 4.598714 -2.558263 +v 6.768219 4.598714 -2.504405 +v 6.842543 4.598714 -2.449357 +v 6.914593 4.598714 -2.392036 +v 6.983572 4.598714 -2.331643 +v 7.049148 4.598714 -2.267847 +v 7.111390 4.598714 -2.200717 +v 7.170406 4.598714 -2.130362 +v 7.226672 4.598714 -2.057256 +v 7.281043 4.598714 -1.982255 +v 7.334617 4.598714 -1.906457 +v 7.388560 4.598714 -1.831028 +v 7.443935 4.598714 -1.757032 +v 7.501573 4.598714 -1.685297 +v 7.561935 4.598714 -1.616288 +v 7.625426 4.598714 -1.550407 +v 7.692341 4.598714 -1.487950 +v 7.762606 4.598714 -1.428843 +v 7.835722 4.598714 -1.372588 +v 7.910796 4.598714 -1.318290 +v 7.986654 4.598714 -1.264776 +v 8.062041 4.598714 -1.210792 +v 8.135965 4.598714 -1.155344 +v 8.207775 4.598714 -1.097781 +v 8.276906 4.598714 -1.037541 +v 8.342948 4.598714 -0.974212 +v 8.405701 4.598714 -0.907592 +v 8.465241 4.598714 -0.837761 +v 8.521986 4.598714 -0.765133 +v 4.516545 4.694515 -4.780745 +v 4.572165 4.694515 -4.706992 +v 4.626069 4.694515 -4.631525 +v 4.679495 4.694515 -4.555578 +v 4.733664 4.694516 -4.480376 +v 4.789586 4.694515 -4.406926 +v 4.847965 4.694515 -4.335934 +v 4.909203 4.694515 -4.267800 +v 4.973477 4.694515 -4.202703 +v 5.040876 4.694515 -4.140729 +v 5.111331 4.694515 -4.081813 +v 5.184488 4.694515 -4.025598 +v 5.259626 4.694515 -3.971364 +v 5.335669 4.694515 -3.918035 +v 5.411319 4.694515 -3.864313 +v 5.485306 4.694516 -3.808928 +v 5.556725 4.694515 -3.750975 +v 5.625261 4.694516 -3.690140 +v 5.690741 4.694516 -3.626248 +v 5.753024 4.694516 -3.559159 +v 5.812116 4.694516 -3.488879 +v 5.868320 4.694515 -3.415711 +v 5.922357 4.694515 -3.340377 +v 5.975382 4.694515 -3.264030 +v 6.028614 4.694515 -3.187890 +v 6.083483 4.694515 -3.113387 +v 6.141301 4.694516 -3.041833 +v 6.202651 4.694515 -2.973812 +v 6.267462 4.694515 -2.909251 +v 6.335294 4.694515 -2.847711 +v 6.405647 4.694515 -2.788692 +v 6.478174 4.694516 -2.731847 +v 6.552496 4.694515 -2.676798 +v 6.627833 4.694515 -2.622763 +v 6.703225 4.694515 -2.568783 +v 6.777560 4.694515 -2.513747 +v 6.849732 4.694516 -2.456547 +v 6.918851 4.694515 -2.396293 +v 6.984449 4.694515 -2.332520 +v 7.046619 4.694515 -2.265318 +v 7.105731 4.694515 -2.195058 +v 7.162122 4.694515 -2.122077 +v 7.216561 4.694516 -2.047145 +v 7.270103 4.694515 -1.971314 +v 7.323926 4.694516 -1.895766 +v 7.379155 4.694515 -1.821623 +v 7.436700 4.694515 -1.749797 +v 7.497152 4.694516 -1.680877 +v 7.560748 4.694515 -1.615101 +v 7.627629 4.694515 -1.552611 +v 7.697726 4.694515 -1.493336 +v 7.770604 4.694516 -1.436841 +v 7.845473 4.694516 -1.382339 +v 7.921272 4.694515 -1.328766 +v 7.996812 4.694515 -1.274934 +v 8.070961 4.694515 -1.219711 +v 8.142924 4.694515 -1.162303 +v 8.212173 4.694515 -1.102180 +v 8.278263 4.694516 -1.038898 +v 8.340976 4.694516 -0.972239 +v 8.400400 4.694516 -0.902291 +v 8.456985 4.694515 -0.829504 +v 8.511539 4.694515 -0.754687 +v 4.508091 4.790317 -4.772291 +v 4.562008 4.790317 -4.696836 +v 4.615197 4.790317 -4.620653 +v 4.669013 4.790317 -4.545097 +v 4.724649 4.790317 -4.471362 +v 4.782948 4.790317 -4.400288 +v 4.844344 4.790317 -4.332313 +v 4.908921 4.790317 -4.267519 +v 4.976537 4.790317 -4.205763 +v 5.046968 4.790317 -4.146821 +v 5.119847 4.790317 -4.090328 +v 5.194571 4.790317 -4.035681 +v 5.270265 4.790317 -3.982003 +v 5.345813 4.790317 -3.928179 +v 5.420011 4.790317 -3.873004 +v 5.491797 4.790317 -3.815420 +v 5.560525 4.790317 -3.754775 +v 5.626067 4.790317 -3.690946 +v 5.688435 4.790317 -3.623942 +v 5.747722 4.790317 -3.553857 +v 5.804227 4.790317 -3.480991 +v 5.858576 4.790317 -3.405967 +v 5.911772 4.790317 -3.329792 +v 5.965127 4.790317 -3.253774 +v 6.019836 4.790317 -3.179113 +v 6.077166 4.790317 -3.107070 +v 6.138077 4.790317 -3.038609 +v 6.202745 4.790317 -2.973906 +v 6.270744 4.790317 -2.912533 +v 6.341382 4.790317 -2.853799 +v 6.413996 4.790317 -2.797041 +v 6.488105 4.790317 -2.741779 +v 6.563198 4.790317 -2.687499 +v 6.638370 4.790317 -2.633300 +v 6.712593 4.790317 -2.578151 +v 6.784795 4.790317 -2.520982 +v 6.854052 4.790317 -2.460867 +v 6.919786 4.790317 -2.397229 +v 6.981932 4.790317 -2.330003 +v 7.040988 4.790317 -2.259687 +v 7.097547 4.790317 -2.186874 +v 7.152127 4.790317 -2.112083 +v 7.205723 4.790317 -2.036307 +v 7.259501 4.790317 -1.960712 +v 7.314615 4.790317 -1.886455 +v 7.372038 4.790317 -1.814507 +v 7.432430 4.790317 -1.745526 +v 7.496070 4.790317 -1.679795 +v 7.562931 4.790317 -1.617284 +v 7.632884 4.790317 -1.557865 +v 7.705538 4.790317 -1.501147 +v 7.780190 4.790317 -1.446427 +v 7.855873 4.790317 -1.392739 +v 7.931459 4.790317 -1.338953 +v 8.005816 4.790317 -1.283939 +v 8.077979 4.790317 -1.226729 +v 8.147365 4.790317 -1.166743 +v 8.213585 4.790317 -1.103591 +v 8.276370 4.790317 -1.037005 +v 8.335767 4.790317 -0.967030 +v 8.392210 4.790317 -0.894102 +v 8.446534 4.790317 -0.819054 +v 8.499894 4.790317 -0.743042 +v 4.498031 4.886118 -4.762230 +v 4.551202 4.886118 -4.686029 +v 4.604746 4.886118 -4.610202 +v 4.660038 4.886118 -4.536121 +v 4.718119 4.886118 -4.464831 +v 4.779548 4.886118 -4.396889 +v 4.844402 4.886119 -4.332371 +v 4.912388 4.886118 -4.270985 +v 4.983033 4.886118 -4.212258 +v 5.055852 4.886118 -4.155705 +v 5.130269 4.886119 -4.100750 +v 5.205544 4.886118 -4.046654 +v 5.280753 4.886118 -3.992491 +v 5.354843 4.886119 -3.937209 +v 5.426777 4.886118 -3.879771 +v 5.495749 4.886118 -3.819371 +v 5.561391 4.886118 -3.755642 +v 5.623768 4.886118 -3.688647 +v 5.683090 4.886118 -3.618597 +v 5.739725 4.886118 -3.545860 +v 5.794293 4.886118 -3.471057 +v 5.847714 4.886118 -3.395106 +v 5.901174 4.886118 -3.319193 +v 5.955971 4.886118 -3.244619 +v 6.013122 4.886118 -3.172397 +v 6.073595 4.886118 -3.103499 +v 6.137951 4.886118 -3.038483 +v 6.205978 4.886118 -2.977139 +v 6.276951 4.886118 -2.918740 +v 6.349970 4.886119 -2.862387 +v 6.424226 4.886118 -2.807271 +v 6.499096 4.886118 -2.752770 +v 6.573981 4.886118 -2.698283 +v 6.647964 4.886118 -2.642893 +v 6.720040 4.886118 -2.585598 +v 6.789302 4.886118 -2.525488 +v 6.855118 4.886118 -2.461933 +v 6.917305 4.886118 -2.394748 +v 6.976214 4.886118 -2.324286 +v 7.032693 4.886118 -2.251393 +v 7.087489 4.886118 -2.176817 +v 7.141254 4.886118 -2.101209 +v 7.195101 4.886118 -2.025685 +v 7.250181 4.886118 -1.951393 +v 7.307503 4.886118 -1.879343 +v 7.367788 4.886118 -1.810256 +v 7.431384 4.886119 -1.744480 +v 7.498245 4.886118 -1.681970 +v 7.568090 4.886118 -1.622443 +v 7.640553 4.886118 -1.565534 +v 7.714990 4.886118 -1.510599 +v 7.790515 4.886118 -1.456752 +v 7.866068 4.886119 -1.402933 +v 7.940541 4.886118 -1.348035 +v 8.012934 4.886118 -1.291055 +v 8.082502 4.886118 -1.231253 +v 8.148902 4.886118 -1.168280 +v 8.211910 4.886118 -1.101917 +v 8.271489 4.886118 -1.032124 +v 8.327989 4.886118 -0.959252 +v 8.382193 4.886118 -0.884084 +v 8.435273 4.886118 -0.807793 +v 8.488619 4.886119 -0.731767 +v 4.487198 4.981920 -4.751398 +v 4.540727 4.981920 -4.675554 +v 4.595761 4.981920 -4.601217 +v 4.653549 4.981920 -4.529634 +v 4.714843 4.981920 -4.461555 +v 4.779816 4.981920 -4.397156 +v 4.848141 4.981920 -4.336110 +v 4.919170 4.981920 -4.277767 +v 4.992170 4.981920 -4.221395 +v 5.066500 4.981920 -4.166352 +v 5.141474 4.981920 -4.111956 +v 5.216309 4.981920 -4.057419 +v 5.290108 4.981920 -4.001846 +v 5.361938 4.981920 -3.944304 +v 5.430980 4.981920 -3.883974 +v 5.496716 4.981920 -3.820338 +v 5.559081 4.981920 -3.753332 +v 5.618340 4.981920 -3.683219 +v 5.674948 4.981920 -3.610455 +v 5.729578 4.981920 -3.535713 +v 5.783143 4.981920 -3.459907 +v 5.836758 4.981920 -3.384150 +v 5.891623 4.981920 -3.309643 +v 5.948843 4.981920 -3.237491 +v 6.009139 4.981920 -3.168415 +v 6.073135 4.981920 -3.103040 +v 6.140978 4.981920 -3.041511 +v 6.212111 4.981920 -2.983273 +v 6.285566 4.981920 -2.927355 +v 6.360282 4.981920 -2.872699 +v 6.435331 4.981920 -2.818377 +v 6.509986 4.981920 -2.763660 +v 6.583642 4.981920 -2.707944 +v 6.655478 4.981920 -2.650408 +v 6.724624 4.981920 -2.590182 +v 6.790438 4.981920 -2.526624 +v 6.852667 4.981920 -2.459481 +v 6.911544 4.981920 -2.388987 +v 6.967796 4.981920 -2.315868 +v 7.022517 4.981920 -2.241216 +v 7.076525 4.981920 -2.165852 +v 7.130536 4.981920 -2.090491 +v 7.185671 4.981920 -2.016255 +v 7.242955 4.981920 -1.944167 +v 7.303158 4.981920 -1.874998 +v 7.366691 4.981920 -1.809160 +v 7.433566 4.981920 -1.746662 +v 7.503424 4.981920 -1.687148 +v 7.575762 4.981920 -1.630115 +v 7.650030 4.981920 -1.575011 +v 7.725403 4.981920 -1.521012 +v 7.800885 4.981920 -1.467122 +v 7.875401 4.981920 -1.412266 +v 7.947936 4.981920 -1.355430 +v 8.017690 4.981920 -1.295811 +v 8.084211 4.981920 -1.232962 +v 8.147412 4.981920 -1.166790 +v 8.207279 4.981920 -1.097286 +v 8.264058 4.981920 -1.024693 +v 8.318403 4.981920 -0.949667 +v 8.371398 4.981920 -0.873289 +v 8.424435 4.981920 -0.796953 +v 8.478965 4.981920 -0.722112 +v 4.476583 5.077722 -4.740784 +v 4.531607 5.077722 -4.666435 +v 4.589164 5.077722 -4.594620 +v 4.650217 5.077722 -4.526301 +v 4.715114 5.077722 -4.461825 +v 4.783597 5.077722 -4.400938 +v 4.854973 5.077722 -4.342942 +v 4.928329 5.077722 -4.286926 +v 5.002796 5.077722 -4.232021 +v 5.077677 5.077722 -4.177531 +v 5.152259 5.077722 -4.122740 +v 5.225761 5.077722 -4.066871 +v 5.297365 5.077722 -4.009103 +v 5.366306 5.077722 -3.948672 +v 5.432029 5.077722 -3.885024 +v 5.494359 5.077722 -3.817981 +v 5.553536 5.077722 -3.747787 +v 5.610041 5.077722 -3.674920 +v 5.664608 5.077722 -3.600115 +v 5.718196 5.077722 -3.524332 +v 5.771914 5.077722 -3.448677 +v 5.826904 5.077722 -3.374296 +v 5.884199 5.077722 -3.302219 +v 5.944557 5.077722 -3.233205 +v 6.008368 5.077722 -3.167644 +v 6.075912 5.077722 -3.105817 +v 6.146946 5.077722 -3.047479 +v 6.220625 5.077722 -2.991785 +v 6.295795 5.077722 -2.937585 +v 6.371294 5.077722 -2.883711 +v 6.446132 5.077722 -2.829177 +v 6.519560 5.077722 -2.773234 +v 6.591069 5.077722 -2.715370 +v 6.660009 5.077722 -2.654939 +v 6.725746 5.077722 -2.591304 +v 6.787985 5.077722 -2.524172 +v 6.846879 5.077722 -2.453693 +v 6.903049 5.077722 -2.380492 +v 6.957509 5.077722 -2.305579 +v 7.011472 5.077722 -2.230171 +v 7.065737 5.077722 -2.155064 +v 7.121015 5.077722 -2.080971 +v 7.178334 5.077722 -2.008917 +v 7.238505 5.077722 -1.939717 +v 7.302001 5.077722 -1.873842 +v 7.368892 5.077722 -1.811360 +v 7.438850 5.077722 -1.751947 +v 7.511236 5.077722 -1.694960 +v 7.585381 5.077722 -1.639733 +v 7.660616 5.077722 -1.585597 +v 7.736001 5.077722 -1.531610 +v 7.810498 5.077722 -1.476735 +v 7.883093 5.077722 -1.419959 +v 7.952943 5.077722 -1.360437 +v 8.019526 5.077722 -1.297647 +v 8.082741 5.077722 -1.231491 +v 8.142795 5.077722 -1.162173 +v 8.199916 5.077722 -1.089923 +v 8.254633 5.077722 -1.015268 +v 8.307853 5.077722 -0.939116 +v 8.360837 5.077722 -0.862728 +v 8.415034 5.077722 -0.787553 +v 8.471784 5.077722 -0.714931 +v 4.467267 5.173523 -4.731467 +v 4.524800 5.173523 -4.659628 +v 4.585639 5.173523 -4.591095 +v 4.650331 5.173523 -4.526415 +v 4.718767 5.173523 -4.465480 +v 4.790302 5.173523 -4.407643 +v 4.863972 5.173523 -4.351941 +v 4.938733 5.173523 -4.297330 +v 5.013706 5.173523 -4.242931 +v 5.088209 5.173523 -4.188062 +v 5.161530 5.173523 -4.132010 +v 5.232929 5.173523 -4.074039 +v 5.301708 5.173523 -4.013445 +v 5.367324 5.173523 -3.949690 +v 5.429555 5.173523 -3.882550 +v 5.488625 5.173523 -3.812247 +v 5.545059 5.173523 -3.739310 +v 5.599543 5.173523 -3.664421 +v 5.653080 5.173523 -3.588587 +v 5.706822 5.173523 -3.512957 +v 5.761914 5.173523 -3.438677 +v 5.819343 5.173523 -3.366735 +v 5.879815 5.173523 -3.297835 +v 5.943670 5.173523 -3.232319 +v 6.010990 5.173523 -3.170266 +v 6.081748 5.173523 -3.111652 +v 6.155355 5.173523 -3.055888 +v 6.230745 5.173523 -3.001906 +v 6.306652 5.173523 -2.948441 +v 6.381877 5.173523 -2.894295 +v 6.455467 5.173523 -2.838512 +v 6.526766 5.173523 -2.780439 +v 6.595435 5.173523 -2.719736 +v 6.661045 5.173523 -2.655975 +v 6.723269 5.173523 -2.588827 +v 6.782194 5.173523 -2.518380 +v 6.838360 5.173523 -2.445175 +v 6.892704 5.173523 -2.370147 +v 6.946405 5.173523 -2.294477 +v 7.000673 5.173523 -2.219372 +v 7.056202 5.173523 -2.145529 +v 7.113634 5.173523 -2.073590 +v 7.173825 5.173523 -2.004409 +v 7.237316 5.173523 -1.938528 +v 7.304240 5.173523 -1.876081 +v 7.374315 5.173523 -1.816783 +v 7.446898 5.173523 -1.759994 +v 7.521109 5.173523 -1.704834 +v 7.596194 5.173523 -1.650548 +v 7.671439 5.173523 -1.596420 +v 7.745848 5.173523 -1.541458 +v 7.818419 5.173523 -1.484656 +v 7.888278 5.173523 -1.425143 +v 7.954842 5.173523 -1.362336 +v 8.017942 5.173523 -1.296064 +v 8.077877 5.173523 -1.226627 +v 8.135168 5.173523 -1.154547 +v 8.190282 5.173523 -1.080288 +v 8.243958 5.173523 -1.004594 +v 8.297238 5.173523 -0.928501 +v 8.351407 5.173523 -0.853298 +v 8.407805 5.173523 -0.780324 +v 8.467522 5.173523 -0.710669 +v 4.460279 5.269325 -4.724478 +v 4.521056 5.269325 -4.655884 +v 4.585541 5.269325 -4.590997 +v 4.653799 5.269325 -4.529883 +v 4.725301 5.269325 -4.472014 +v 4.799112 5.269325 -4.416452 +v 4.874135 5.269325 -4.362103 +v 4.949322 5.269324 -4.307919 +v 5.023871 5.269325 -4.253096 +v 5.097141 5.269325 -4.196994 +v 5.168438 5.269325 -4.138920 +v 5.237104 5.269325 -4.078214 +v 5.302613 5.269325 -4.014351 +v 5.364724 5.269325 -3.947090 +v 5.423611 5.269324 -3.876606 +v 5.479927 5.269325 -3.803549 +v 5.534432 5.269325 -3.728683 +v 5.587956 5.269325 -3.652835 +v 5.641697 5.269325 -3.577204 +v 5.696842 5.269325 -3.502977 +v 5.754390 5.269325 -3.431153 +v 5.815017 5.269325 -3.362409 +v 5.879025 5.269325 -3.297045 +v 5.946347 5.269325 -3.234995 +v 6.016811 5.269325 -3.176087 +v 6.090131 5.269325 -3.120035 +v 6.165438 5.269325 -3.065970 +v 6.241518 5.269325 -3.012678 +v 6.317073 5.269325 -2.958862 +v 6.390967 5.269325 -2.903384 +v 6.462384 5.269325 -2.845429 +v 6.530882 5.269325 -2.784556 +v 6.596337 5.269325 -2.720639 +v 6.658546 5.269325 -2.653476 +v 6.717526 5.269325 -2.583085 +v 6.773738 5.269325 -2.509925 +v 6.828050 5.269325 -2.434864 +v 6.881605 5.269325 -2.359048 +v 6.935628 5.269325 -2.283699 +v 6.991204 5.269325 -2.209903 +v 7.048862 5.269325 -2.138189 +v 7.109129 5.269325 -2.069085 +v 7.172631 5.269325 -2.003215 +v 7.239590 5.269325 -1.940802 +v 7.309782 5.269325 -1.881622 +v 7.382581 5.269325 -1.825049 +v 7.457070 5.269325 -1.770167 +v 7.532202 5.269325 -1.715927 +v 7.607226 5.269325 -1.661580 +v 7.681448 5.269325 -1.606430 +v 7.753892 5.269325 -1.549502 +v 7.823674 5.269325 -1.489911 +v 7.890159 5.269325 -1.427024 +v 7.953107 5.269325 -1.360601 +v 8.012755 5.269325 -1.290878 +v 8.069803 5.269325 -1.218553 +v 8.125070 5.269325 -1.144448 +v 8.179190 5.269325 -1.069196 +v 8.232990 5.269325 -0.993624 +v 8.287496 5.269325 -0.918758 +v 8.343872 5.269325 -0.845763 +v 8.403228 5.269325 -0.775747 +v 8.466327 5.269325 -0.709474 +v 4.456417 5.365126 -4.720616 +v 4.520785 5.365126 -4.655613 +v 4.588844 5.365126 -4.594300 +v 4.660206 5.365127 -4.536290 +v 4.734011 5.365127 -4.480723 +v 4.809164 5.365126 -4.426504 +v 4.884560 5.365126 -4.372528 +v 4.959238 5.365127 -4.317836 +v 5.032514 5.365126 -4.261739 +v 5.103792 5.365127 -4.203645 +v 5.172435 5.365126 -4.142916 +v 5.237920 5.365126 -4.079029 +v 5.299977 5.365126 -4.011715 +v 5.358737 5.365126 -3.941103 +v 5.414806 5.365126 -3.867800 +v 5.469223 5.365126 -3.792846 +v 5.522891 5.365127 -3.717141 +v 5.576696 5.365127 -3.641574 +v 5.631879 5.365126 -3.567385 +v 5.689490 5.365126 -3.495625 +v 5.750231 5.365126 -3.426994 +v 5.814391 5.365127 -3.361783 +v 5.881873 5.365126 -3.299892 +v 5.952275 5.365127 -3.240923 +v 6.025235 5.365126 -3.184511 +v 6.100242 5.365126 -3.130146 +v 6.176224 5.365126 -3.076757 +v 6.251906 5.365126 -3.023067 +v 6.326056 5.365126 -2.967845 +v 6.397703 5.365126 -2.910120 +v 6.466274 5.365127 -2.849319 +v 6.531622 5.365127 -2.785296 +v 6.593837 5.365126 -2.718138 +v 6.652924 5.365126 -2.647854 +v 6.709248 5.365127 -2.574805 +v 6.763594 5.365126 -2.499780 +v 6.817066 5.365127 -2.423881 +v 6.870903 5.365126 -2.348345 +v 6.926253 5.365126 -2.274324 +v 6.983984 5.365126 -2.202682 +v 7.044418 5.365127 -2.133746 +v 7.107944 5.365126 -2.067900 +v 7.174904 5.365126 -2.005488 +v 7.245172 5.365126 -1.946384 +v 7.318166 5.365127 -1.890006 +v 7.392949 5.365126 -1.835417 +v 7.468400 5.365127 -1.781497 +v 7.543411 5.365127 -1.727135 +v 7.617318 5.365126 -1.671671 +v 7.689509 5.365126 -1.614490 +v 7.759115 5.365126 -1.554724 +v 7.825472 5.365126 -1.491709 +v 7.888274 5.365127 -1.425139 +v 7.947682 5.365127 -1.355176 +v 8.004344 5.365126 -1.282466 +v 8.059289 5.365127 -1.208038 +v 8.113544 5.365126 -1.132923 +v 8.167806 5.365126 -1.057812 +v 8.222842 5.365126 -0.983477 +v 8.279549 5.365126 -0.910811 +v 8.338871 5.365126 -0.840762 +v 8.401622 5.365126 -0.774141 +v 8.468206 5.365126 -0.711355 +v 4.456064 5.460927 -4.720264 +v 4.523957 5.460928 -4.658785 +v 4.595155 5.460928 -4.600611 +v 4.668896 5.460927 -4.544981 +v 4.744110 5.460928 -4.490822 +v 4.819653 5.460928 -4.436993 +v 4.894496 5.460928 -4.382464 +v 4.967819 5.460927 -4.326416 +v 5.039062 5.460928 -4.268288 +v 5.107711 5.460928 -4.207564 +v 5.173252 5.460927 -4.143733 +v 5.235386 5.460928 -4.076496 +v 5.294176 5.460928 -4.005914 +v 5.350146 5.460928 -3.932512 +v 5.404285 5.460928 -3.857280 +v 5.457895 5.460928 -3.781518 +v 5.511905 5.460928 -3.706155 +v 5.567162 5.460928 -3.632041 +v 5.624778 5.460928 -3.560285 +v 5.685521 5.460928 -3.491656 +v 5.749729 5.460928 -3.426492 +v 5.817311 5.460928 -3.364703 +v 5.887845 5.460928 -3.305865 +v 5.960686 5.460928 -3.249334 +v 6.035319 5.460928 -3.194596 +v 6.111040 5.460928 -3.140944 +v 6.186654 5.460928 -3.087187 +v 6.260921 5.460928 -3.032082 +v 6.332782 5.460927 -2.974571 +v 6.401537 5.460928 -2.913955 +v 6.466930 5.460928 -2.849976 +v 6.529132 5.460928 -2.782805 +v 6.588403 5.460928 -2.712704 +v 6.644939 5.460928 -2.639869 +v 6.699414 5.460927 -2.564973 +v 6.752868 5.460928 -2.489054 +v 6.806539 5.460928 -2.413353 +v 6.861645 5.460928 -2.339088 +v 6.919165 5.460928 -2.267236 +v 6.979665 5.460928 -2.198364 +v 7.043258 5.460928 -2.132585 +v 7.110169 5.460928 -2.070125 +v 7.180419 5.460928 -2.011003 +v 7.253520 5.460928 -1.954732 +v 7.328553 5.460928 -1.900393 +v 7.404338 5.460927 -1.846807 +v 7.479660 5.460928 -1.792756 +v 7.553473 5.460928 -1.737198 +v 7.625282 5.460927 -1.679635 +v 7.694602 5.460928 -1.619583 +v 7.760779 5.460928 -1.556389 +v 7.823468 5.460928 -1.489706 +v 7.882750 5.460927 -1.419615 +v 7.939183 5.460928 -1.346677 +v 7.993748 5.460928 -1.271870 +v 8.047672 5.460927 -1.196423 +v 8.102041 5.460928 -1.121419 +v 8.157490 5.460928 -1.047496 +v 8.214655 5.460927 -0.975290 +v 8.274242 5.460928 -0.905506 +v 8.336943 5.460928 -0.838834 +v 8.403238 5.460928 -0.775757 +v 8.473166 5.460927 -0.716313 +v 4.459090 5.556729 -4.723289 +v 4.530082 5.556729 -4.664910 +v 4.603721 5.556729 -4.609177 +v 4.678989 5.556729 -4.555073 +v 4.754712 5.556729 -4.501424 +v 4.829768 5.556729 -4.447109 +v 4.903240 5.556730 -4.391209 +v 4.974463 5.556729 -4.333060 +v 5.043030 5.556730 -4.272255 +v 5.108577 5.556729 -4.208430 +v 5.170821 5.556729 -4.141302 +v 5.229764 5.556729 -4.070873 +v 5.285821 5.556729 -3.997558 +v 5.339866 5.556729 -3.922231 +v 5.393147 5.556729 -3.846141 +v 5.447054 5.556730 -3.770677 +v 5.502468 5.556729 -3.696718 +v 5.560121 5.556729 -3.624999 +v 5.620845 5.556730 -3.556352 +v 5.685045 5.556729 -3.491180 +v 5.752678 5.556730 -3.429441 +v 5.823328 5.556729 -3.370720 +v 5.896325 5.556729 -3.314345 +v 5.970864 5.556729 -3.259512 +v 6.046273 5.556730 -3.205550 +v 6.121671 5.556729 -3.151576 +v 6.195867 5.556729 -3.096400 +v 6.267802 5.556729 -3.038963 +v 6.336723 5.556729 -2.978512 +v 6.402284 5.556730 -2.914700 +v 6.464550 5.556729 -2.847595 +v 6.523937 5.556729 -2.777610 +v 6.580821 5.556729 -2.705122 +v 6.635591 5.556729 -2.630521 +v 6.689164 5.556729 -2.554722 +v 6.742728 5.556729 -2.478914 +v 6.797546 5.556729 -2.404360 +v 6.854720 5.556729 -2.332163 +v 6.914984 5.556730 -2.263054 +v 6.978574 5.556729 -2.197273 +v 7.045401 5.556729 -2.134727 +v 7.115513 5.556729 -2.075468 +v 7.188565 5.556729 -2.019149 +v 7.263715 5.556730 -1.964927 +v 7.339772 5.556730 -1.911612 +v 7.415431 5.556729 -1.857899 +v 7.489517 5.556729 -1.802614 +v 7.561189 5.556729 -1.744914 +v 7.630147 5.556730 -1.684500 +v 7.696076 5.556729 -1.621057 +v 7.758640 5.556729 -1.554249 +v 7.817867 5.556730 -1.484105 +v 7.874227 5.556729 -1.411092 +v 7.928605 5.556729 -1.336099 +v 7.982187 5.556730 -1.260308 +v 8.036241 5.556729 -1.184990 +v 8.091765 5.556729 -1.111144 +v 8.149287 5.556729 -1.039294 +v 8.209287 5.556729 -0.969921 +v 8.272251 5.556729 -0.903514 +v 8.338559 5.556729 -0.840450 +v 8.408311 5.556729 -0.780830 +v 8.481149 5.556730 -0.724296 +v 4.465039 5.652531 -4.729239 +v 4.538454 5.652531 -4.673282 +v 4.613673 5.652531 -4.619129 +v 4.689546 5.652531 -4.565630 +v 4.764871 5.652531 -4.511584 +v 4.838599 5.652531 -4.455939 +v 4.909944 5.652531 -4.397913 +v 4.978435 5.652531 -4.337031 +v 5.043874 5.652531 -4.273099 +v 5.106135 5.652531 -4.205989 +v 5.165233 5.652531 -4.135714 +v 5.221490 5.652531 -4.062600 +v 5.275639 5.652531 -3.987377 +v 5.328803 5.652531 -3.911169 +v 5.382351 5.652531 -3.835345 +v 5.437616 5.652531 -3.761239 +v 5.495363 5.652531 -3.689613 +v 5.556134 5.652531 -3.621014 +v 5.620377 5.652531 -3.555883 +v 5.688081 5.652531 -3.494216 +v 5.758847 5.652531 -3.435610 +v 5.831995 5.652531 -3.379386 +v 5.906689 5.652531 -3.324708 +v 5.982040 5.652531 -3.270689 +v 6.057219 5.652531 -3.216494 +v 6.131227 5.652531 -3.161132 +v 6.203054 5.652531 -3.103587 +v 6.271973 5.652531 -3.043134 +v 6.337624 5.652531 -2.979413 +v 6.400019 5.652531 -2.912436 +v 6.459481 5.652531 -2.842526 +v 6.516552 5.652531 -2.770226 +v 6.571721 5.652531 -2.696023 +v 6.625599 5.652531 -2.620529 +v 6.679243 5.652531 -2.544801 +v 6.733870 5.652531 -2.470056 +v 6.790654 5.652531 -2.397469 +v 6.850506 5.652531 -2.327949 +v 6.913875 5.652531 -2.261946 +v 6.980661 5.652531 -2.199360 +v 7.050575 5.652531 -2.139902 +v 7.123439 5.652531 -2.083394 +v 7.198526 5.652531 -2.029109 +v 7.274696 5.652531 -1.975908 +v 7.350614 5.652531 -1.922454 +v 7.425002 5.652531 -1.867471 +v 7.496878 5.652531 -1.809975 +v 7.565693 5.652531 -1.749418 +v 7.631354 5.652531 -1.685707 +v 7.693758 5.652531 -1.618740 +v 7.752944 5.652531 -1.548553 +v 7.809320 5.652531 -1.475558 +v 7.863678 5.652531 -1.400543 +v 7.917120 5.652531 -1.324613 +v 7.970897 5.652531 -1.249019 +v 8.026189 5.652531 -1.174938 +v 8.083823 5.652531 -1.103202 +v 8.144191 5.652531 -1.034197 +v 8.207577 5.652531 -0.968210 +v 8.274168 5.652531 -0.905430 +v 8.343960 5.652531 -0.845851 +v 8.416639 5.652531 -0.789159 +v 8.491503 5.652531 -0.734650 +v 4.473346 5.748333 -4.737545 +v 4.548337 5.748333 -4.683165 +v 4.624188 5.748332 -4.629643 +v 4.699699 5.748332 -4.575783 +v 4.773714 5.748333 -4.520426 +v 4.845293 5.748332 -4.462633 +v 4.913838 5.748333 -4.401807 +v 4.979139 5.748332 -4.337736 +v 5.041288 5.748332 -4.270514 +v 5.100448 5.748333 -4.200302 +v 5.156937 5.748333 -4.127419 +v 5.211360 5.748332 -4.052469 +v 5.264668 5.748333 -3.976407 +v 5.318113 5.748332 -3.900479 +v 5.373045 5.748333 -3.826040 +v 5.430623 5.748333 -3.754245 +v 5.491423 5.748333 -3.685673 +v 5.555711 5.748333 -3.620590 +v 5.623488 5.748333 -3.558995 +v 5.694351 5.748333 -3.500487 +v 5.767611 5.748332 -3.444374 +v 5.842410 5.748332 -3.389802 +v 5.917835 5.748333 -3.335855 +v 5.992970 5.748333 -3.281618 +v 6.066874 5.748333 -3.226150 +v 6.138568 5.748333 -3.168473 +v 6.207358 5.748333 -3.107891 +v 6.272925 5.748333 -3.044086 +v 6.335310 5.748333 -2.977098 +v 6.394826 5.748333 -2.907243 +v 6.451969 5.748333 -2.835015 +v 6.507336 5.748333 -2.761009 +v 6.561561 5.748332 -2.685862 +v 6.615478 5.748333 -2.610408 +v 6.670157 5.748333 -2.535715 +v 6.726724 5.748332 -2.462910 +v 6.786174 5.748333 -2.392988 +v 6.849163 5.748333 -2.326606 +v 6.915833 5.748333 -2.263904 +v 6.985748 5.748333 -2.204448 +v 7.058389 5.748333 -2.147716 +v 7.133294 5.748333 -2.093250 +v 7.209407 5.748332 -2.039991 +v 7.285425 5.748333 -1.986637 +v 7.360035 5.748332 -1.931876 +v 7.432155 5.748333 -1.874623 +v 7.501093 5.748332 -1.814190 +v 7.566627 5.748333 -1.750352 +v 7.628878 5.748332 -1.683231 +v 7.688017 5.748332 -1.612998 +v 7.744455 5.748333 -1.540064 +v 7.798919 5.748332 -1.465156 +v 7.852412 5.748333 -1.389277 +v 7.906113 5.748333 -1.313607 +v 7.961212 5.748332 -1.239334 +v 8.018710 5.748332 -1.167460 +v 8.079216 5.748332 -1.098595 +v 8.142948 5.748333 -1.032955 +v 8.209926 5.748333 -0.970560 +v 8.279963 5.748332 -0.911227 +v 8.352649 5.748332 -0.854540 +v 8.427306 5.748333 -0.799825 +v 8.503015 5.748332 -0.746163 +v 4.483320 5.844134 -4.747519 +v 4.558928 5.844134 -4.693756 +v 4.634410 5.844134 -4.639866 +v 4.708599 5.844134 -4.584683 +v 4.780435 5.844134 -4.527147 +v 4.849154 5.844134 -4.466494 +v 4.914412 5.844134 -4.402380 +v 4.976339 5.844134 -4.334937 +v 5.035387 5.844134 -4.264612 +v 5.091999 5.844134 -4.191852 +v 5.146737 5.844134 -4.117218 +v 5.200391 5.844134 -4.041500 +v 5.254015 5.844134 -3.965753 +v 5.308857 5.844134 -3.891223 +v 5.366138 5.844134 -3.819133 +v 5.426758 5.844134 -3.750380 +v 5.491028 5.844134 -3.685278 +v 5.558854 5.844134 -3.623733 +v 5.629802 5.844134 -3.565310 +v 5.703150 5.844134 -3.509285 +v 5.778014 5.844134 -3.454777 +v 5.853459 5.844134 -3.400851 +v 5.928564 5.844134 -3.346584 +v 6.002438 5.844134 -3.291086 +v 6.074119 5.844134 -3.233395 +v 6.142802 5.844134 -3.172707 +v 6.208188 5.844134 -3.108721 +v 6.270377 5.844134 -3.041538 +v 6.329761 5.844134 -2.971550 +v 6.386884 5.844134 -2.899302 +v 6.442351 5.844134 -2.825396 +v 6.496776 5.844134 -2.750450 +v 6.550971 5.844134 -2.675272 +v 6.605916 5.844134 -2.600846 +v 6.662559 5.844134 -2.528117 +v 6.721832 5.844134 -2.458018 +v 6.784479 5.844134 -2.391293 +v 6.850860 5.844134 -2.328302 +v 6.920797 5.844134 -2.268867 +v 6.993530 5.844134 -2.212229 +v 7.068267 5.844134 -2.157594 +v 7.144245 5.844134 -2.104200 +v 7.220219 5.844134 -2.050802 +v 7.294907 5.844134 -1.996118 +v 7.367201 5.844134 -1.939041 +v 7.436330 5.844134 -1.878799 +v 7.501941 5.844134 -1.815038 +v 7.564101 5.844134 -1.747826 +v 7.623168 5.844134 -1.677520 +v 7.679639 5.844134 -1.604620 +v 7.734237 5.844134 -1.529846 +v 7.787889 5.844134 -1.454127 +v 7.841675 5.844134 -1.378541 +v 7.896722 5.844134 -1.304216 +v 7.954062 5.844134 -1.232183 +v 8.014465 5.844134 -1.163215 +v 8.078309 5.844134 -1.097687 +v 8.145581 5.844134 -1.035588 +v 8.215960 5.844134 -0.976594 +v 8.288855 5.844134 -0.920118 +v 8.363489 5.844134 -0.865380 +v 8.438954 5.844134 -0.811474 +v 8.514282 5.844134 -0.757430 +v 4.494127 5.939936 -4.758327 +v 4.569339 5.939936 -4.704167 +v 4.643468 5.939936 -4.648924 +v 4.715444 5.939936 -4.591527 +v 4.784374 5.939935 -4.531086 +v 4.849738 5.939936 -4.467079 +v 4.911520 5.939936 -4.399488 +v 4.970245 5.939935 -4.328842 +v 5.026734 5.939936 -4.255959 +v 5.081647 5.939936 -4.181501 +v 5.135681 5.939936 -4.106162 +v 5.189686 5.939936 -4.030796 +v 5.244706 5.939936 -3.956444 +v 5.301878 5.939935 -3.884244 +v 5.362212 5.939936 -3.815206 +v 5.426297 5.939935 -3.749920 +v 5.494103 5.939936 -3.688354 +v 5.565125 5.939936 -3.630004 +v 5.638571 5.939936 -3.574078 +v 5.713502 5.939936 -3.519638 +v 5.788956 5.939936 -3.465719 +v 5.864005 5.939936 -3.411397 +v 5.937783 5.939935 -3.355803 +v 6.009466 5.939936 -3.298114 +v 6.078185 5.939936 -3.237461 +v 6.143443 5.939936 -3.173348 +v 6.205356 5.939936 -3.105889 +v 6.264410 5.939936 -3.035570 +v 6.321281 5.939936 -2.963069 +v 6.376681 5.939936 -2.889098 +v 6.431277 5.939936 -2.814323 +v 6.485702 5.939936 -2.739375 +v 6.540900 5.939935 -2.665202 +v 6.597851 5.939936 -2.592781 +v 6.657268 5.939936 -2.522825 +v 6.719810 5.939936 -2.455996 +v 6.785927 5.939936 -2.392742 +v 6.855665 5.939936 -2.333108 +v 6.928524 5.939936 -2.276595 +v 7.003454 5.939936 -2.222153 +v 7.079370 5.939936 -2.168698 +v 7.155267 5.939936 -2.115223 +v 7.229917 5.939936 -2.060501 +v 7.302255 5.939936 -2.003467 +v 7.371514 5.939936 -1.943355 +v 7.437289 5.939936 -1.879758 +v 7.499540 5.939936 -1.812637 +v 7.558557 5.939936 -1.742281 +v 7.614962 5.939936 -1.669315 +v 7.669607 5.939936 -1.594588 +v 7.723403 5.939936 -1.519012 +v 7.777342 5.939936 -1.443579 +v 7.832449 5.939936 -1.369315 +v 7.889700 5.939936 -1.297194 +v 7.949908 5.939936 -1.228030 +v 8.013599 5.939936 -1.162349 +v 8.080907 5.939936 -1.100285 +v 8.151525 5.939936 -1.041532 +v 8.224741 5.939936 -0.985376 +v 8.299594 5.939936 -0.930857 +v 8.375057 5.939936 -0.876948 +v 8.450158 5.939936 -0.822677 +v 8.524035 5.939936 -0.767183 +v 4.504797 6.035737 -4.768996 +v 4.578625 6.035737 -4.713452 +v 4.650510 6.035737 -4.655966 +v 4.719554 6.035737 -4.595638 +v 4.785102 6.035737 -4.531815 +v 4.846947 6.035737 -4.464287 +v 4.905447 6.035737 -4.393416 +v 4.961517 6.035737 -4.320114 +v 5.016283 6.035737 -4.245508 +v 5.070515 6.035737 -4.170368 +v 5.124914 6.035737 -4.095395 +v 5.180290 6.035737 -4.021400 +v 5.237583 6.035737 -3.949321 +v 5.297746 6.035737 -3.880112 +v 5.361519 6.035737 -3.814513 +v 5.429153 6.035737 -3.752776 +v 5.500211 6.035737 -3.694462 +v 5.573783 6.035737 -3.638661 +v 5.648836 6.035737 -3.584343 +v 5.724345 6.035737 -3.530480 +v 5.799364 6.035737 -3.476128 +v 5.873054 6.035737 -3.420445 +v 5.944652 6.035737 -3.362671 +v 6.013440 6.035737 -3.302088 +v 6.078753 6.035737 -3.238029 +v 6.140487 6.035737 -3.170391 +v 6.199151 6.035737 -3.099683 +v 6.255563 6.035737 -3.026725 +v 6.310622 6.035737 -2.952411 +v 6.365148 6.035737 -2.877565 +v 6.419839 6.035737 -2.802885 +v 6.475328 6.035737 -2.729002 +v 6.532577 6.035737 -2.656878 +v 6.592369 6.035737 -2.587298 +v 6.655118 6.035737 -2.520676 +v 6.721181 6.035737 -2.457367 +v 6.790696 6.035737 -2.397510 +v 6.863392 6.035737 -2.340835 +v 6.938471 6.035737 -2.286542 +v 7.014647 6.035737 -2.233346 +v 7.090592 6.035737 -2.179919 +v 7.165207 6.035737 -2.125163 +v 7.237496 6.035737 -2.068079 +v 7.306759 6.035737 -2.007971 +v 7.372626 6.035737 -1.944467 +v 7.435042 6.035737 -1.877510 +v 7.494219 6.035737 -1.807316 +v 7.550607 6.035737 -1.734332 +v 7.605116 6.035737 -1.659469 +v 7.658909 6.035737 -1.583891 +v 7.712947 6.035737 -1.508556 +v 7.768154 6.035737 -1.434391 +v 7.825400 6.035737 -1.362266 +v 7.885446 6.035737 -1.292940 +v 7.948858 6.035737 -1.226980 +v 8.015908 6.035737 -1.164658 +v 8.086475 6.035737 -1.105854 +v 8.159903 6.035737 -1.049910 +v 8.235098 6.035737 -0.995732 +v 8.310834 6.035737 -0.942097 +v 8.386000 6.035737 -0.887891 +v 8.459721 6.035737 -0.832240 +v 8.531353 6.035737 -0.774501 +v 4.514270 6.131539 -4.778470 +v 4.585844 6.131539 -4.720672 +v 4.654792 6.131539 -4.660248 +v 4.720460 6.131539 -4.596543 +v 4.782502 6.131539 -4.529214 +v 4.841070 6.131538 -4.458410 +v 4.896889 6.131539 -4.384857 +v 4.951172 6.131539 -4.309770 +v 5.005224 6.131539 -4.234449 +v 5.059801 6.131539 -4.159654 +v 5.115517 6.131538 -4.085998 +v 5.173072 6.131538 -4.014181 +v 5.233245 6.131539 -3.944983 +v 5.296758 6.131539 -3.879124 +v 5.364038 6.131539 -3.817032 +v 5.434966 6.131539 -3.758588 +v 5.508675 6.131539 -3.702926 +v 5.583927 6.131539 -3.648806 +v 5.659590 6.131539 -3.595097 +v 5.734665 6.131539 -3.540801 +v 5.808316 6.131539 -3.485080 +v 5.879843 6.131539 -3.427235 +v 5.948635 6.131539 -3.366655 +v 6.014131 6.131539 -3.302778 +v 6.075943 6.131539 -3.235219 +v 6.134386 6.131539 -3.164290 +v 6.190321 6.131539 -3.090854 +v 6.244837 6.131539 -3.015998 +v 6.298986 6.131539 -2.940775 +v 6.353638 6.131539 -2.866055 +v 6.409473 6.131539 -2.792519 +v 6.467081 6.131539 -2.720754 +v 6.527251 6.131539 -2.651552 +v 6.590416 6.131539 -2.585346 +v 6.656688 6.131538 -2.522246 +v 6.726129 6.131539 -2.462315 +v 6.798575 6.131539 -2.405389 +v 6.873458 6.131539 -2.350900 +v 6.949722 6.131539 -2.297793 +v 7.025932 6.131539 -2.244632 +v 7.100663 6.131539 -2.189990 +v 7.172928 6.131539 -2.132884 +v 7.242113 6.131539 -2.072697 +v 7.307940 6.131539 -2.009151 +v 7.370415 6.131538 -1.942255 +v 7.429771 6.131539 -1.872239 +v 7.486415 6.131538 -1.799512 +v 7.540921 6.131539 -1.724646 +v 7.594476 6.131539 -1.648829 +v 7.648442 6.131539 -1.573423 +v 7.703690 6.131539 -1.499299 +v 7.760977 6.131539 -1.427214 +v 7.820957 6.131539 -1.357822 +v 7.884141 6.131539 -1.291635 +v 7.950833 6.131539 -1.228955 +v 8.021044 6.131539 -1.169794 +v 8.094366 6.131539 -1.113745 +v 8.169778 6.131539 -1.059785 +v 8.245898 6.131539 -1.006533 +v 8.321402 6.131539 -0.952664 +v 8.395264 6.131538 -0.897155 +v 8.466832 6.131539 -0.839351 +v 8.535729 6.131539 -0.778877 +v 4.521517 6.227340 -4.785716 +v 4.590176 6.227341 -4.725003 +v 4.655783 6.227340 -4.661239 +v 4.717994 6.227340 -4.594078 +v 4.776821 6.227340 -4.523534 +v 4.832767 6.227341 -4.450107 +v 4.886841 6.227341 -4.374810 +v 4.940408 6.227340 -4.299005 +v 4.994771 6.227340 -4.223996 +v 5.050591 6.227340 -4.150443 +v 5.108359 6.227340 -4.078840 +v 5.168645 6.227340 -4.009755 +v 5.232038 6.227340 -3.943776 +v 5.298982 6.227341 -3.881349 +v 5.369542 6.227341 -3.822536 +v 5.443199 6.227340 -3.766821 +v 5.518700 6.227341 -3.712951 +v 5.594627 6.227341 -3.659506 +v 5.669881 6.227341 -3.605388 +v 5.743590 6.227341 -3.549725 +v 5.815089 6.227340 -3.491853 +v 5.883866 6.227340 -3.431257 +v 5.949502 6.227340 -3.367522 +v 6.011644 6.227341 -3.300292 +v 6.070225 6.227340 -3.229501 +v 6.125943 6.227341 -3.155848 +v 6.179958 6.227340 -3.080491 +v 6.233547 6.227340 -3.004708 +v 6.287835 6.227340 -2.929624 +v 6.343667 6.227340 -2.856084 +v 6.401630 6.227340 -2.784676 +v 6.462178 6.227340 -2.715852 +v 6.525764 6.227340 -2.650066 +v 6.592412 6.227340 -2.587342 +v 6.661981 6.227340 -2.527539 +v 6.734268 6.227340 -2.470454 +v 6.808830 6.227341 -2.415645 +v 6.884833 6.227340 -2.362276 +v 6.961038 6.227340 -2.309109 +v 7.035986 6.227340 -2.254685 +v 7.108373 6.227340 -2.197701 +v 7.177521 6.227340 -2.137476 +v 7.243231 6.227340 -2.073814 +v 7.305609 6.227340 -2.006821 +v 7.364974 6.227340 -1.936814 +v 7.421787 6.227340 -1.864255 +v 7.476622 6.227340 -1.789718 +v 7.530185 6.227341 -1.713909 +v 7.583858 6.227340 -1.638211 +v 7.639010 6.227340 -1.563991 +v 7.696324 6.227340 -1.491933 +v 7.756335 6.227341 -1.422573 +v 7.819448 6.227341 -1.356314 +v 7.885909 6.227340 -1.293403 +v 7.955740 6.227340 -1.233862 +v 8.028666 6.227340 -1.177416 +v 8.103967 6.227340 -1.123345 +v 8.180310 6.227341 -1.070317 +v 8.256207 6.227340 -1.016841 +v 8.330424 6.227340 -0.961687 +v 8.402173 6.227340 -0.904064 +v 8.471076 6.227340 -0.843595 +v 8.537006 6.227340 -0.780154 +v 4.525707 6.323142 -4.789907 +v 4.591047 6.323142 -4.725875 +v 4.653220 6.323142 -4.658676 +v 4.712249 6.323142 -4.588333 +v 4.768505 6.323142 -4.515217 +v 4.822776 6.323142 -4.440117 +v 4.876215 6.323142 -4.364183 +v 4.930148 6.323142 -4.288745 +v 4.985738 6.323142 -4.214962 +v 5.043533 6.323142 -4.143387 +v 5.103928 6.323142 -4.074409 +v 5.167347 6.323142 -4.008457 +v 5.234149 6.323142 -3.945886 +v 5.304429 6.323142 -3.886795 +v 5.377825 6.323142 -3.830819 +v 5.453403 6.323142 -3.777026 +v 5.529654 6.323142 -3.723904 +v 5.605166 6.323142 -3.670045 +v 5.678996 6.323142 -3.614502 +v 5.750479 6.323142 -3.556613 +v 5.819184 6.323142 -3.495947 +v 5.884834 6.323142 -3.432226 +v 5.947245 6.323142 -3.365265 +v 6.006310 6.323142 -3.294958 +v 6.062267 6.323142 -3.221543 +v 6.116124 6.323142 -3.146028 +v 6.169235 6.323142 -3.069767 +v 6.222965 6.323142 -2.994126 +v 6.278424 6.323142 -2.920213 +v 6.336360 6.323142 -2.848778 +v 6.397200 6.323142 -2.780246 +v 6.461167 6.323142 -2.714841 +v 6.528285 6.323142 -2.652586 +v 6.598204 6.323142 -2.593134 +v 6.670565 6.323142 -2.536123 +v 6.744912 6.323142 -2.481098 +v 6.820540 6.323142 -2.427355 +v 6.896419 6.323142 -2.373862 +v 6.971258 6.323142 -2.319329 +v 7.043750 6.323142 -2.262448 +v 7.112924 6.323142 -2.202251 +v 7.178506 6.323142 -2.138462 +v 7.240678 6.323142 -2.071261 +v 7.299860 6.323142 -2.001071 +v 7.356616 6.323142 -1.928456 +v 7.411598 6.323142 -1.854066 +v 7.465530 6.323142 -1.778627 +v 7.519246 6.323142 -1.702971 +v 7.574170 6.323142 -1.628522 +v 7.631474 6.323142 -1.556455 +v 7.691581 6.323142 -1.487191 +v 7.754763 6.323142 -1.421001 +v 7.821151 6.323142 -1.358017 +v 7.890713 6.323142 -1.298207 +v 7.963195 6.323142 -1.241317 +v 8.038056 6.323142 -1.186807 +v 8.114311 6.323142 -1.133689 +v 8.190469 6.323142 -1.080475 +v 8.265121 6.323142 -1.025755 +v 8.337256 6.323142 -0.968520 +v 8.406363 6.323142 -0.908254 +v 8.472319 6.323142 -0.844838 +v 8.535213 6.323142 -0.778362 +v 4.526246 6.418943 -4.790445 +v 4.588156 6.418943 -4.722984 +v 4.647134 6.418943 -4.652590 +v 4.703578 6.418943 -4.579661 +v 4.758163 6.418943 -4.504876 +v 4.811846 6.418943 -4.429186 +v 4.865762 6.418943 -4.353731 +v 4.921067 6.418943 -4.279664 +v 4.978713 6.418944 -4.207938 +v 5.039153 6.418943 -4.139006 +v 5.102672 6.418943 -4.073153 +v 5.169502 6.418943 -4.010612 +v 5.239685 6.418943 -3.951423 +v 5.312898 6.418943 -3.895264 +v 5.388338 6.418943 -3.841332 +v 5.464742 6.418943 -3.788365 +v 5.540555 6.418943 -3.734806 +v 5.614560 6.418943 -3.679439 +v 5.686044 6.418943 -3.621552 +v 5.754618 6.418943 -3.560753 +v 5.820125 6.418943 -3.496888 +v 5.882553 6.418943 -3.429944 +v 5.941971 6.418943 -3.359991 +v 5.998528 6.418943 -3.287175 +v 6.052723 6.418943 -3.212000 +v 6.105766 6.418943 -3.135671 +v 6.159081 6.418943 -3.059614 +v 6.214011 6.418943 -2.985171 +v 6.271574 6.418943 -2.913363 +v 6.332367 6.418943 -2.844784 +v 6.396581 6.418943 -2.779626 +v 6.464111 6.418943 -2.717784 +v 6.534537 6.418943 -2.658839 +v 6.607226 6.418943 -2.602156 +v 6.681595 6.418943 -2.547153 +v 6.756951 6.418943 -2.493137 +v 6.832399 6.418943 -2.439213 +v 6.906849 6.418943 -2.384292 +v 6.979143 6.418943 -2.327214 +v 7.048294 6.418943 -2.266993 +v 7.113781 6.418943 -2.203108 +v 7.175737 6.418943 -2.135693 +v 7.234660 6.418943 -2.065243 +v 7.291214 6.418943 -1.992425 +v 7.346148 6.418943 -1.917988 +v 7.400254 6.418943 -1.842722 +v 7.454361 6.418943 -1.767458 +v 7.509367 6.418943 -1.693091 +v 7.566557 6.418943 -1.620910 +v 7.626753 6.418943 -1.551734 +v 7.690084 6.418943 -1.485693 +v 7.756539 6.418943 -1.422777 +v 7.825981 6.418943 -1.362846 +v 7.898118 6.418943 -1.305612 +v 7.972463 6.418943 -1.250584 +v 8.048273 6.418943 -1.197023 +v 8.124412 6.418943 -1.143790 +v 8.199401 6.418943 -1.089407 +v 8.272019 6.418943 -1.032655 +v 8.341517 6.418943 -0.972781 +v 8.407637 6.418943 -0.909528 +v 8.470491 6.418943 -0.843011 +v 8.530392 6.418943 -0.773540 +v 4.523036 6.514745 -4.787235 +v 4.581738 6.514745 -4.716567 +v 4.638096 6.514745 -4.643552 +v 4.692826 6.514745 -4.568910 +v 4.746805 6.514745 -4.493517 +v 4.801008 6.514745 -4.418348 +v 4.856431 6.514745 -4.344400 +v 4.913985 6.514745 -4.272582 +v 4.974397 6.514745 -4.203622 +v 5.038002 6.514745 -4.137856 +v 5.104923 6.514745 -4.075404 +v 5.175115 6.514745 -4.016224 +v 5.248234 6.514745 -3.959972 +v 5.323537 6.514745 -3.905903 +v 5.399874 6.514745 -3.852868 +v 5.475835 6.514745 -3.799458 +v 5.550052 6.514745 -3.744303 +v 5.621618 6.514745 -3.686496 +v 5.690090 6.514745 -3.625597 +v 5.755372 6.514745 -3.561507 +v 5.817597 6.514745 -3.494360 +v 5.877024 6.514745 -3.424416 +v 5.933972 6.514745 -3.351992 +v 5.988822 6.514745 -3.277471 +v 6.042287 6.514745 -3.201563 +v 6.095644 6.514745 -3.125549 +v 6.150259 6.514745 -3.050792 +v 6.207349 6.514745 -2.978510 +v 6.267771 6.514745 -2.909560 +v 6.331903 6.514745 -2.844321 +v 6.399639 6.514745 -2.782684 +v 6.470467 6.514745 -2.724141 +v 6.543599 6.514745 -2.667900 +v 6.618222 6.514745 -2.613152 +v 6.693544 6.514745 -2.559103 +v 6.768700 6.514745 -2.504886 +v 6.842733 6.514745 -2.449548 +v 6.914669 6.514745 -2.392111 +v 6.983641 6.514745 -2.331712 +v 7.049080 6.514745 -2.267779 +v 7.110917 6.514745 -2.200244 +v 7.169631 6.514745 -2.129587 +v 7.225952 6.514745 -2.056535 +v 7.280718 6.514745 -1.981930 +v 7.334808 6.514745 -1.906648 +v 7.389098 6.514745 -1.831566 +v 7.444454 6.514745 -1.757551 +v 7.501739 6.514745 -1.685464 +v 7.561931 6.514745 -1.616284 +v 7.625417 6.514745 -1.550398 +v 7.692057 6.514745 -1.487666 +v 7.761579 6.514745 -1.427817 +v 7.833601 6.514745 -1.370467 +v 7.907608 6.514745 -1.315102 +v 7.982920 6.514745 -1.261042 +v 8.058664 6.514745 -1.207415 +v 8.133669 6.514745 -1.153047 +v 8.206611 6.514745 -1.096617 +v 8.276534 6.514745 -1.037168 +v 8.342959 6.514745 -0.974223 +v 8.405880 6.514745 -0.907771 +v 8.465642 6.514745 -0.838162 +v 8.522808 6.514745 -0.765956 +v 4.516544 6.610546 -4.780743 +v 4.572577 6.610547 -4.707405 +v 4.627145 6.610547 -4.632601 +v 4.681193 6.610546 -4.557277 +v 4.735655 6.610546 -4.482367 +v 4.791396 6.610547 -4.408737 +v 4.849183 6.610546 -4.337152 +v 4.909661 6.610546 -4.268258 +v 4.973333 6.610546 -4.202558 +v 5.040349 6.610546 -4.140202 +v 5.110589 6.610547 -4.081070 +v 5.183667 6.610546 -4.024776 +v 5.258855 6.610546 -3.970592 +v 5.335078 6.610547 -3.917444 +v 5.411021 6.610546 -3.864015 +v 5.485347 6.610546 -3.808969 +v 5.557033 6.610546 -3.751283 +v 5.625506 6.610547 -3.690385 +v 5.690602 6.610546 -3.626109 +v 5.752518 6.610546 -3.558653 +v 5.811678 6.610546 -3.488441 +v 5.868602 6.610547 -3.415994 +v 5.923836 6.610547 -3.341856 +v 5.977950 6.610546 -3.266598 +v 6.031783 6.610547 -3.191059 +v 6.086544 6.610546 -3.116448 +v 6.143410 6.610547 -3.043943 +v 6.203389 6.610546 -2.974550 +v 6.267113 6.610546 -2.908902 +v 6.334701 6.610546 -2.847118 +v 6.405709 6.610547 -2.788754 +v 6.479217 6.610547 -2.732890 +v 6.554183 6.610546 -2.678485 +v 6.629710 6.610546 -2.624640 +v 6.704843 6.610546 -2.570401 +v 6.778651 6.610546 -2.514838 +v 6.850280 6.610547 -2.457094 +v 6.919018 6.610546 -2.396461 +v 6.984394 6.610546 -2.332464 +v 7.046255 6.610546 -2.264954 +v 7.104905 6.610547 -2.194233 +v 7.161079 6.610547 -2.121035 +v 7.215666 6.610547 -2.046249 +v 7.269621 6.610546 -1.970833 +v 7.323898 6.610546 -1.895738 +v 7.379394 6.610547 -1.821862 +v 7.436922 6.610547 -1.750018 +v 7.497188 6.610546 -1.680913 +v 7.560753 6.610547 -1.615106 +v 7.627594 6.610547 -1.552575 +v 7.697335 6.610547 -1.492944 +v 7.769478 6.610546 -1.435715 +v 7.843421 6.610547 -1.380286 +v 7.918457 6.610547 -1.325951 +v 7.993772 6.610547 -1.271893 +v 8.068437 6.610546 -1.217187 +v 8.141371 6.610547 -1.160749 +v 8.211531 6.610547 -1.101537 +v 8.278267 6.610547 -1.038901 +v 8.341382 6.610546 -0.972645 +v 8.401119 6.610547 -0.903009 +v 8.458069 6.610547 -0.830588 +v 8.513059 6.610547 -0.756206 +v 4.507617 6.706348 -4.771817 +v 4.561788 6.706348 -4.696615 +v 4.615577 6.706348 -4.621033 +v 4.670022 6.706348 -4.546107 +v 4.725979 6.706348 -4.472692 +v 4.784096 6.706348 -4.401437 +v 4.844862 6.706348 -4.332830 +v 4.908668 6.706348 -4.267265 +v 4.975779 6.706348 -4.205004 +v 5.046071 6.706348 -4.145925 +v 5.119121 6.706348 -4.089602 +v 5.194201 6.706348 -4.035311 +v 5.270288 6.706348 -3.982026 +v 5.346146 6.706348 -3.928512 +v 5.420501 6.706348 -3.873495 +v 5.492269 6.706348 -3.815891 +v 5.560821 6.706348 -3.755072 +v 5.625876 6.706348 -3.690755 +v 5.687542 6.706348 -3.623049 +v 5.746315 6.706348 -3.552450 +v 5.802900 6.706348 -3.479664 +v 5.858057 6.706348 -3.405448 +v 5.912504 6.706348 -3.330524 +v 5.966928 6.706348 -3.255576 +v 6.022178 6.706348 -3.181455 +v 6.079257 6.706348 -3.109161 +v 6.139062 6.706348 -3.039594 +v 6.202330 6.706348 -2.973491 +v 6.269436 6.706348 -2.911226 +v 6.340218 6.706348 -2.852635 +v 6.413907 6.706348 -2.796953 +v 6.489239 6.706348 -2.742913 +v 6.565042 6.706348 -2.689343 +v 6.640392 6.706348 -2.635322 +v 6.714264 6.706348 -2.579822 +v 6.785804 6.706348 -2.521990 +v 6.854397 6.706348 -2.461212 +v 6.919699 6.706348 -2.397142 +v 6.981642 6.706348 -2.329713 +v 7.040433 6.706348 -2.259132 +v 7.096631 6.706348 -2.185958 +v 7.151136 6.706348 -2.111092 +v 7.204947 6.706348 -2.035531 +v 7.259088 6.706348 -1.960300 +v 7.314528 6.706348 -1.886368 +v 7.372105 6.706348 -1.814573 +v 7.432474 6.706348 -1.745571 +v 7.496073 6.706348 -1.679798 +v 7.563025 6.706348 -1.617378 +v 7.632987 6.706348 -1.557968 +v 7.705382 6.706348 -1.500991 +v 7.779500 6.706348 -1.445738 +v 7.854547 6.706348 -1.391413 +v 7.929668 6.706348 -1.337162 +v 8.003984 6.706348 -1.282106 +v 8.076615 6.706348 -1.225366 +v 8.146703 6.706348 -1.166081 +v 8.213563 6.706348 -1.103570 +v 8.276878 6.706348 -1.037513 +v 8.336735 6.706348 -0.967998 +v 8.393623 6.706348 -0.895514 +v 8.448378 6.706348 -0.820897 +v 8.502064 6.706348 -0.745212 +v 4.497266 6.802150 -4.761466 +v 4.550587 6.802150 -4.685414 +v 4.604693 6.802150 -4.610149 +v 4.660574 6.802150 -4.536659 +v 4.718877 6.802150 -4.465590 +v 4.779964 6.802150 -4.397305 +v 4.844034 6.802150 -4.332002 +v 4.911242 6.802150 -4.269839 +v 4.981589 6.802150 -4.210814 +v 5.054608 6.802150 -4.154461 +v 5.129571 6.802150 -4.100053 +v 5.205497 6.802150 -4.046607 +v 5.281221 6.802150 -3.992959 +v 5.355542 6.802150 -3.937908 +v 5.427399 6.802150 -3.880393 +v 5.496058 6.802150 -3.819681 +v 5.561229 6.802150 -3.755480 +v 5.622860 6.802150 -3.687738 +v 5.681344 6.802150 -3.616850 +v 5.737477 6.802150 -3.543612 +v 5.792227 6.802150 -3.468991 +v 5.846536 6.802150 -3.393928 +v 5.901218 6.802150 -3.319238 +v 5.956963 6.802150 -3.245611 +v 6.014502 6.802150 -3.173778 +v 6.074526 6.802150 -3.104430 +v 6.137616 6.802150 -3.038149 +v 6.204222 6.802150 -2.975382 +v 6.274447 6.802150 -2.916236 +v 6.347854 6.802150 -2.860271 +v 6.423396 6.802150 -2.806441 +v 6.499576 6.802150 -2.753249 +v 6.575192 6.802150 -2.699495 +v 6.649350 6.802150 -2.644279 +v 6.721069 6.802150 -2.586628 +v 6.789716 6.802150 -2.525902 +v 6.855012 6.802150 -2.461827 +v 6.917005 6.802150 -2.394447 +v 6.975983 6.802150 -2.324054 +v 7.032415 6.802150 -2.251114 +v 7.087011 6.802150 -2.176339 +v 7.140774 6.802150 -2.100729 +v 7.194767 6.802150 -2.025352 +v 7.250034 6.802150 -1.951246 +v 7.307483 6.802150 -1.879323 +v 7.367799 6.802150 -1.810267 +v 7.431384 6.802150 -1.744480 +v 7.498322 6.802150 -1.682046 +v 7.568369 6.802150 -1.622722 +v 7.640973 6.802150 -1.565954 +v 7.715363 6.802150 -1.510972 +v 7.790633 6.802150 -1.456871 +v 7.865829 6.802150 -1.402695 +v 7.940021 6.802150 -1.347515 +v 8.012366 6.802150 -1.290488 +v 8.082161 6.802150 -1.230911 +v 8.148881 6.802150 -1.168260 +v 8.212237 6.802150 -1.102244 +v 8.272239 6.802150 -1.032874 +v 8.329246 6.802150 -0.960509 +v 8.383983 6.802150 -0.885874 +v 8.437488 6.802150 -0.810007 +v 8.490987 6.802150 -0.734134 +v 4.486490 6.897951 -4.750690 +v 4.540098 6.897951 -4.674925 +v 4.595609 6.897951 -4.601065 +v 4.653821 6.897951 -4.529905 +v 4.715086 6.897951 -4.461798 +v 4.779449 6.897951 -4.396789 +v 4.846828 6.897951 -4.334797 +v 4.917162 6.897951 -4.275759 +v 4.990158 6.897951 -4.219383 +v 5.065000 6.897951 -4.164852 +v 5.140740 6.897951 -4.111222 +v 5.216290 6.897951 -4.057399 +v 5.290524 6.897951 -4.002262 +v 5.362431 6.897951 -3.944796 +v 5.431252 6.897951 -3.884247 +v 5.496615 6.897951 -3.820237 +v 5.558468 6.897951 -3.752718 +v 5.616961 6.897951 -3.681839 +v 5.672794 6.897951 -3.608301 +v 5.727053 6.897951 -3.533188 +v 5.780911 6.897951 -3.457675 +v 5.835404 6.897951 -3.382796 +v 5.891327 6.897951 -3.309347 +v 5.949251 6.897951 -3.237899 +v 6.009669 6.897951 -3.168946 +v 6.072930 6.897951 -3.102834 +v 6.139316 6.897951 -3.039848 +v 6.209000 6.897951 -2.980161 +v 6.281818 6.897951 -2.923607 +v 6.357072 6.897951 -2.869489 +v 6.433504 6.897951 -2.816549 +v 6.509514 6.897951 -2.763188 +v 6.583959 6.897951 -2.708261 +v 6.656024 6.897951 -2.650955 +v 6.724928 6.897951 -2.590487 +v 6.790353 6.897951 -2.526540 +v 6.852398 6.897951 -2.459213 +v 6.911461 6.897951 -2.388903 +v 6.968102 6.897951 -2.316173 +v 7.022961 6.897951 -2.241660 +v 7.076830 6.897951 -2.166158 +v 7.130773 6.897951 -2.090728 +v 7.185868 6.897951 -2.016451 +v 7.243099 6.897951 -1.944310 +v 7.303223 6.897951 -1.875063 +v 7.366683 6.897951 -1.809151 +v 7.433552 6.897951 -1.746649 +v 7.503545 6.897951 -1.687270 +v 7.576160 6.897951 -1.630513 +v 7.650718 6.897951 -1.575699 +v 7.726254 6.897951 -1.521863 +v 7.801694 6.897951 -1.467931 +v 7.875994 6.897951 -1.412859 +v 7.948251 6.897951 -1.355745 +v 8.017791 6.897951 -1.295913 +v 8.084214 6.897951 -1.232964 +v 8.147394 6.897951 -1.166773 +v 8.207417 6.897951 -1.097423 +v 8.264591 6.897951 -1.025227 +v 8.319522 6.897951 -0.950785 +v 8.373117 6.897951 -0.875009 +v 8.426539 6.897951 -0.799059 +v 8.481045 6.897951 -0.724193 +vt 0.031250 0.015625 +vt 0.015625 0.031250 +vt 0.015625 0.015625 +vt 0.046875 0.015625 +vt 0.031250 0.031250 +vt 0.062500 0.015625 +vt 0.046875 0.031250 +vt 0.078125 0.015625 +vt 0.062500 0.031250 +vt 0.093750 0.015625 +vt 0.078125 0.031250 +vt 0.109375 0.015625 +vt 0.093750 0.031250 +vt 0.125000 0.015625 +vt 0.109375 0.031250 +vt 0.140625 0.015625 +vt 0.125000 0.031250 +vt 0.156250 0.015625 +vt 0.140625 0.031250 +vt 0.171875 0.015625 +vt 0.156250 0.031250 +vt 0.187500 0.015625 +vt 0.171875 0.031250 +vt 0.203125 0.015625 +vt 0.187500 0.031250 +vt 0.218750 0.015625 +vt 0.203125 0.031250 +vt 0.234375 0.015625 +vt 0.218750 0.031250 +vt 0.250000 0.015625 +vt 0.234375 0.031250 +vt 0.265625 0.015625 +vt 0.250000 0.031250 +vt 0.281250 0.015625 +vt 0.265625 0.031250 +vt 0.296875 0.015625 +vt 0.281250 0.031250 +vt 0.312500 0.015625 +vt 0.296875 0.031250 +vt 0.328125 0.015625 +vt 0.312500 0.031250 +vt 0.343750 0.015625 +vt 0.328125 0.031250 +vt 0.359375 0.015625 +vt 0.343750 0.031250 +vt 0.375000 0.015625 +vt 0.359375 0.031250 +vt 0.390625 0.015625 +vt 0.375000 0.031250 +vt 0.406250 0.015625 +vt 0.390625 0.031250 +vt 0.421875 0.015625 +vt 0.406250 0.031250 +vt 0.437500 0.015625 +vt 0.421875 0.031250 +vt 0.453125 0.015625 +vt 0.437500 0.031250 +vt 0.468750 0.015625 +vt 0.453125 0.031250 +vt 0.484375 0.015625 +vt 0.468750 0.031250 +vt 0.500000 0.015625 +vt 0.484375 0.031250 +vt 0.515625 0.015625 +vt 0.500000 0.031250 +vt 0.531250 0.015625 +vt 0.515625 0.031250 +vt 0.546875 0.015625 +vt 0.531250 0.031250 +vt 0.562500 0.015625 +vt 0.546875 0.031250 +vt 0.578125 0.015625 +vt 0.562500 0.031250 +vt 0.593750 0.015625 +vt 0.578125 0.031250 +vt 0.609375 0.015625 +vt 0.593750 0.031250 +vt 0.625000 0.015625 +vt 0.609375 0.031250 +vt 0.640625 0.015625 +vt 0.625000 0.031250 +vt 0.656250 0.015625 +vt 0.640625 0.031250 +vt 0.671875 0.015625 +vt 0.656250 0.031250 +vt 0.687500 0.015625 +vt 0.671875 0.031250 +vt 0.703125 0.015625 +vt 0.687500 0.031250 +vt 0.718750 0.015625 +vt 0.703125 0.031250 +vt 0.734375 0.015625 +vt 0.718750 0.031250 +vt 0.750000 0.015625 +vt 0.734375 0.031250 +vt 0.765625 0.015625 +vt 0.750000 0.031250 +vt 0.781250 0.015625 +vt 0.765625 0.031250 +vt 0.796875 0.015625 +vt 0.781250 0.031250 +vt 0.812500 0.015625 +vt 0.796875 0.031250 +vt 0.828125 0.015625 +vt 0.812500 0.031250 +vt 0.843750 0.015625 +vt 0.828125 0.031250 +vt 0.859375 0.015625 +vt 0.843750 0.031250 +vt 0.875000 0.015625 +vt 0.859375 0.031250 +vt 0.890625 0.015625 +vt 0.875000 0.031250 +vt 0.906250 0.015625 +vt 0.890625 0.031250 +vt 0.921875 0.015625 +vt 0.906250 0.031250 +vt 0.937500 0.015625 +vt 0.921875 0.031250 +vt 0.953125 0.015625 +vt 0.937500 0.031250 +vt 0.968750 0.015625 +vt 0.953125 0.031250 +vt 0.984375 0.015625 +vt 0.968750 0.031250 +vt 0.015625 0.046875 +vt 0.031250 0.046875 +vt 0.046875 0.046875 +vt 0.062500 0.046875 +vt 0.078125 0.046875 +vt 0.093750 0.046875 +vt 0.109375 0.046875 +vt 0.125000 0.046875 +vt 0.140625 0.046875 +vt 0.156250 0.046875 +vt 0.171875 0.046875 +vt 0.187500 0.046875 +vt 0.203125 0.046875 +vt 0.218750 0.046875 +vt 0.234375 0.046875 +vt 0.250000 0.046875 +vt 0.265625 0.046875 +vt 0.281250 0.046875 +vt 0.296875 0.046875 +vt 0.312500 0.046875 +vt 0.328125 0.046875 +vt 0.343750 0.046875 +vt 0.359375 0.046875 +vt 0.375000 0.046875 +vt 0.390625 0.046875 +vt 0.406250 0.046875 +vt 0.421875 0.046875 +vt 0.437500 0.046875 +vt 0.453125 0.046875 +vt 0.468750 0.046875 +vt 0.484375 0.046875 +vt 0.500000 0.046875 +vt 0.515625 0.046875 +vt 0.531250 0.046875 +vt 0.546875 0.046875 +vt 0.562500 0.046875 +vt 0.578125 0.046875 +vt 0.593750 0.046875 +vt 0.609375 0.046875 +vt 0.625000 0.046875 +vt 0.640625 0.046875 +vt 0.656250 0.046875 +vt 0.671875 0.046875 +vt 0.687500 0.046875 +vt 0.703125 0.046875 +vt 0.718750 0.046875 +vt 0.734375 0.046875 +vt 0.750000 0.046875 +vt 0.765625 0.046875 +vt 0.781250 0.046875 +vt 0.796875 0.046875 +vt 0.812500 0.046875 +vt 0.828125 0.046875 +vt 0.843750 0.046875 +vt 0.859375 0.046875 +vt 0.875000 0.046875 +vt 0.890625 0.046875 +vt 0.906250 0.046875 +vt 0.921875 0.046875 +vt 0.937500 0.046875 +vt 0.953125 0.046875 +vt 0.984375 0.031250 +vt 0.968750 0.046875 +vt 0.015625 0.062500 +vt 0.031250 0.062500 +vt 0.046875 0.062500 +vt 0.062500 0.062500 +vt 0.078125 0.062500 +vt 0.093750 0.062500 +vt 0.109375 0.062500 +vt 0.125000 0.062500 +vt 0.140625 0.062500 +vt 0.156250 0.062500 +vt 0.171875 0.062500 +vt 0.187500 0.062500 +vt 0.203125 0.062500 +vt 0.218750 0.062500 +vt 0.234375 0.062500 +vt 0.250000 0.062500 +vt 0.265625 0.062500 +vt 0.281250 0.062500 +vt 0.296875 0.062500 +vt 0.312500 0.062500 +vt 0.328125 0.062500 +vt 0.343750 0.062500 +vt 0.359375 0.062500 +vt 0.375000 0.062500 +vt 0.390625 0.062500 +vt 0.406250 0.062500 +vt 0.421875 0.062500 +vt 0.437500 0.062500 +vt 0.453125 0.062500 +vt 0.468750 0.062500 +vt 0.484375 0.062500 +vt 0.500000 0.062500 +vt 0.515625 0.062500 +vt 0.531250 0.062500 +vt 0.546875 0.062500 +vt 0.562500 0.062500 +vt 0.578125 0.062500 +vt 0.593750 0.062500 +vt 0.609375 0.062500 +vt 0.625000 0.062500 +vt 0.640625 0.062500 +vt 0.656250 0.062500 +vt 0.671875 0.062500 +vt 0.687500 0.062500 +vt 0.703125 0.062500 +vt 0.718750 0.062500 +vt 0.734375 0.062500 +vt 0.750000 0.062500 +vt 0.765625 0.062500 +vt 0.781250 0.062500 +vt 0.796875 0.062500 +vt 0.812500 0.062500 +vt 0.828125 0.062500 +vt 0.843750 0.062500 +vt 0.859375 0.062500 +vt 0.875000 0.062500 +vt 0.890625 0.062500 +vt 0.906250 0.062500 +vt 0.921875 0.062500 +vt 0.937500 0.062500 +vt 0.953125 0.062500 +vt 0.984375 0.046875 +vt 0.968750 0.062500 +vt 0.015625 0.078125 +vt 0.031250 0.078125 +vt 0.046875 0.078125 +vt 0.062500 0.078125 +vt 0.078125 0.078125 +vt 0.093750 0.078125 +vt 0.109375 0.078125 +vt 0.125000 0.078125 +vt 0.140625 0.078125 +vt 0.156250 0.078125 +vt 0.171875 0.078125 +vt 0.187500 0.078125 +vt 0.203125 0.078125 +vt 0.218750 0.078125 +vt 0.234375 0.078125 +vt 0.250000 0.078125 +vt 0.265625 0.078125 +vt 0.281250 0.078125 +vt 0.296875 0.078125 +vt 0.312500 0.078125 +vt 0.328125 0.078125 +vt 0.343750 0.078125 +vt 0.359375 0.078125 +vt 0.375000 0.078125 +vt 0.390625 0.078125 +vt 0.406250 0.078125 +vt 0.421875 0.078125 +vt 0.437500 0.078125 +vt 0.453125 0.078125 +vt 0.468750 0.078125 +vt 0.484375 0.078125 +vt 0.500000 0.078125 +vt 0.515625 0.078125 +vt 0.531250 0.078125 +vt 0.546875 0.078125 +vt 0.562500 0.078125 +vt 0.578125 0.078125 +vt 0.593750 0.078125 +vt 0.609375 0.078125 +vt 0.625000 0.078125 +vt 0.640625 0.078125 +vt 0.656250 0.078125 +vt 0.671875 0.078125 +vt 0.687500 0.078125 +vt 0.703125 0.078125 +vt 0.718750 0.078125 +vt 0.734375 0.078125 +vt 0.750000 0.078125 +vt 0.765625 0.078125 +vt 0.781250 0.078125 +vt 0.796875 0.078125 +vt 0.812500 0.078125 +vt 0.828125 0.078125 +vt 0.843750 0.078125 +vt 0.859375 0.078125 +vt 0.875000 0.078125 +vt 0.890625 0.078125 +vt 0.906250 0.078125 +vt 0.921875 0.078125 +vt 0.937500 0.078125 +vt 0.953125 0.078125 +vt 0.984375 0.062500 +vt 0.968750 0.078125 +vt 0.015625 0.093750 +vt 0.031250 0.093750 +vt 0.046875 0.093750 +vt 0.062500 0.093750 +vt 0.078125 0.093750 +vt 0.093750 0.093750 +vt 0.109375 0.093750 +vt 0.125000 0.093750 +vt 0.140625 0.093750 +vt 0.156250 0.093750 +vt 0.171875 0.093750 +vt 0.187500 0.093750 +vt 0.203125 0.093750 +vt 0.218750 0.093750 +vt 0.234375 0.093750 +vt 0.250000 0.093750 +vt 0.265625 0.093750 +vt 0.281250 0.093750 +vt 0.296875 0.093750 +vt 0.312500 0.093750 +vt 0.328125 0.093750 +vt 0.343750 0.093750 +vt 0.359375 0.093750 +vt 0.375000 0.093750 +vt 0.390625 0.093750 +vt 0.406250 0.093750 +vt 0.421875 0.093750 +vt 0.437500 0.093750 +vt 0.453125 0.093750 +vt 0.468750 0.093750 +vt 0.484375 0.093750 +vt 0.500000 0.093750 +vt 0.515625 0.093750 +vt 0.531250 0.093750 +vt 0.546875 0.093750 +vt 0.562500 0.093750 +vt 0.578125 0.093750 +vt 0.593750 0.093750 +vt 0.609375 0.093750 +vt 0.625000 0.093750 +vt 0.640625 0.093750 +vt 0.656250 0.093750 +vt 0.671875 0.093750 +vt 0.687500 0.093750 +vt 0.703125 0.093750 +vt 0.718750 0.093750 +vt 0.734375 0.093750 +vt 0.750000 0.093750 +vt 0.765625 0.093750 +vt 0.781250 0.093750 +vt 0.796875 0.093750 +vt 0.812500 0.093750 +vt 0.828125 0.093750 +vt 0.843750 0.093750 +vt 0.859375 0.093750 +vt 0.875000 0.093750 +vt 0.890625 0.093750 +vt 0.906250 0.093750 +vt 0.921875 0.093750 +vt 0.937500 0.093750 +vt 0.953125 0.093750 +vt 0.984375 0.078125 +vt 0.968750 0.093750 +vt 0.015625 0.109375 +vt 0.031250 0.109375 +vt 0.046875 0.109375 +vt 0.062500 0.109375 +vt 0.078125 0.109375 +vt 0.093750 0.109375 +vt 0.109375 0.109375 +vt 0.125000 0.109375 +vt 0.140625 0.109375 +vt 0.156250 0.109375 +vt 0.171875 0.109375 +vt 0.187500 0.109375 +vt 0.203125 0.109375 +vt 0.218750 0.109375 +vt 0.234375 0.109375 +vt 0.250000 0.109375 +vt 0.265625 0.109375 +vt 0.281250 0.109375 +vt 0.296875 0.109375 +vt 0.312500 0.109375 +vt 0.328125 0.109375 +vt 0.343750 0.109375 +vt 0.359375 0.109375 +vt 0.375000 0.109375 +vt 0.390625 0.109375 +vt 0.406250 0.109375 +vt 0.421875 0.109375 +vt 0.437500 0.109375 +vt 0.453125 0.109375 +vt 0.468750 0.109375 +vt 0.484375 0.109375 +vt 0.500000 0.109375 +vt 0.515625 0.109375 +vt 0.531250 0.109375 +vt 0.546875 0.109375 +vt 0.562500 0.109375 +vt 0.578125 0.109375 +vt 0.593750 0.109375 +vt 0.609375 0.109375 +vt 0.625000 0.109375 +vt 0.640625 0.109375 +vt 0.656250 0.109375 +vt 0.671875 0.109375 +vt 0.687500 0.109375 +vt 0.703125 0.109375 +vt 0.718750 0.109375 +vt 0.734375 0.109375 +vt 0.750000 0.109375 +vt 0.765625 0.109375 +vt 0.781250 0.109375 +vt 0.796875 0.109375 +vt 0.812500 0.109375 +vt 0.828125 0.109375 +vt 0.843750 0.109375 +vt 0.859375 0.109375 +vt 0.875000 0.109375 +vt 0.890625 0.109375 +vt 0.906250 0.109375 +vt 0.921875 0.109375 +vt 0.937500 0.109375 +vt 0.953125 0.109375 +vt 0.984375 0.093750 +vt 0.968750 0.109375 +vt 0.015625 0.125000 +vt 0.031250 0.125000 +vt 0.046875 0.125000 +vt 0.062500 0.125000 +vt 0.078125 0.125000 +vt 0.093750 0.125000 +vt 0.109375 0.125000 +vt 0.125000 0.125000 +vt 0.140625 0.125000 +vt 0.156250 0.125000 +vt 0.171875 0.125000 +vt 0.187500 0.125000 +vt 0.203125 0.125000 +vt 0.218750 0.125000 +vt 0.234375 0.125000 +vt 0.250000 0.125000 +vt 0.265625 0.125000 +vt 0.281250 0.125000 +vt 0.296875 0.125000 +vt 0.312500 0.125000 +vt 0.328125 0.125000 +vt 0.343750 0.125000 +vt 0.359375 0.125000 +vt 0.375000 0.125000 +vt 0.390625 0.125000 +vt 0.406250 0.125000 +vt 0.421875 0.125000 +vt 0.437500 0.125000 +vt 0.453125 0.125000 +vt 0.468750 0.125000 +vt 0.484375 0.125000 +vt 0.500000 0.125000 +vt 0.515625 0.125000 +vt 0.531250 0.125000 +vt 0.546875 0.125000 +vt 0.562500 0.125000 +vt 0.578125 0.125000 +vt 0.593750 0.125000 +vt 0.609375 0.125000 +vt 0.625000 0.125000 +vt 0.640625 0.125000 +vt 0.656250 0.125000 +vt 0.671875 0.125000 +vt 0.687500 0.125000 +vt 0.703125 0.125000 +vt 0.718750 0.125000 +vt 0.734375 0.125000 +vt 0.750000 0.125000 +vt 0.765625 0.125000 +vt 0.781250 0.125000 +vt 0.796875 0.125000 +vt 0.812500 0.125000 +vt 0.828125 0.125000 +vt 0.843750 0.125000 +vt 0.859375 0.125000 +vt 0.875000 0.125000 +vt 0.890625 0.125000 +vt 0.906250 0.125000 +vt 0.921875 0.125000 +vt 0.937500 0.125000 +vt 0.953125 0.125000 +vt 0.984375 0.109375 +vt 0.968750 0.125000 +vt 0.015625 0.140625 +vt 0.031250 0.140625 +vt 0.046875 0.140625 +vt 0.062500 0.140625 +vt 0.078125 0.140625 +vt 0.093750 0.140625 +vt 0.109375 0.140625 +vt 0.125000 0.140625 +vt 0.140625 0.140625 +vt 0.156250 0.140625 +vt 0.171875 0.140625 +vt 0.187500 0.140625 +vt 0.203125 0.140625 +vt 0.218750 0.140625 +vt 0.234375 0.140625 +vt 0.250000 0.140625 +vt 0.265625 0.140625 +vt 0.281250 0.140625 +vt 0.296875 0.140625 +vt 0.312500 0.140625 +vt 0.328125 0.140625 +vt 0.343750 0.140625 +vt 0.359375 0.140625 +vt 0.375000 0.140625 +vt 0.390625 0.140625 +vt 0.406250 0.140625 +vt 0.421875 0.140625 +vt 0.437500 0.140625 +vt 0.453125 0.140625 +vt 0.468750 0.140625 +vt 0.484375 0.140625 +vt 0.500000 0.140625 +vt 0.515625 0.140625 +vt 0.531250 0.140625 +vt 0.546875 0.140625 +vt 0.562500 0.140625 +vt 0.578125 0.140625 +vt 0.593750 0.140625 +vt 0.609375 0.140625 +vt 0.625000 0.140625 +vt 0.640625 0.140625 +vt 0.656250 0.140625 +vt 0.671875 0.140625 +vt 0.687500 0.140625 +vt 0.703125 0.140625 +vt 0.718750 0.140625 +vt 0.734375 0.140625 +vt 0.750000 0.140625 +vt 0.765625 0.140625 +vt 0.781250 0.140625 +vt 0.796875 0.140625 +vt 0.812500 0.140625 +vt 0.828125 0.140625 +vt 0.843750 0.140625 +vt 0.859375 0.140625 +vt 0.875000 0.140625 +vt 0.890625 0.140625 +vt 0.906250 0.140625 +vt 0.921875 0.140625 +vt 0.937500 0.140625 +vt 0.953125 0.140625 +vt 0.984375 0.125000 +vt 0.968750 0.140625 +vt 0.015625 0.156250 +vt 0.031250 0.156250 +vt 0.046875 0.156250 +vt 0.062500 0.156250 +vt 0.078125 0.156250 +vt 0.093750 0.156250 +vt 0.109375 0.156250 +vt 0.125000 0.156250 +vt 0.140625 0.156250 +vt 0.156250 0.156250 +vt 0.171875 0.156250 +vt 0.187500 0.156250 +vt 0.203125 0.156250 +vt 0.218750 0.156250 +vt 0.234375 0.156250 +vt 0.250000 0.156250 +vt 0.265625 0.156250 +vt 0.281250 0.156250 +vt 0.296875 0.156250 +vt 0.312500 0.156250 +vt 0.328125 0.156250 +vt 0.343750 0.156250 +vt 0.359375 0.156250 +vt 0.375000 0.156250 +vt 0.390625 0.156250 +vt 0.406250 0.156250 +vt 0.421875 0.156250 +vt 0.437500 0.156250 +vt 0.453125 0.156250 +vt 0.468750 0.156250 +vt 0.484375 0.156250 +vt 0.500000 0.156250 +vt 0.515625 0.156250 +vt 0.531250 0.156250 +vt 0.546875 0.156250 +vt 0.562500 0.156250 +vt 0.578125 0.156250 +vt 0.593750 0.156250 +vt 0.609375 0.156250 +vt 0.625000 0.156250 +vt 0.640625 0.156250 +vt 0.656250 0.156250 +vt 0.671875 0.156250 +vt 0.687500 0.156250 +vt 0.703125 0.156250 +vt 0.718750 0.156250 +vt 0.734375 0.156250 +vt 0.750000 0.156250 +vt 0.765625 0.156250 +vt 0.781250 0.156250 +vt 0.796875 0.156250 +vt 0.812500 0.156250 +vt 0.828125 0.156250 +vt 0.843750 0.156250 +vt 0.859375 0.156250 +vt 0.875000 0.156250 +vt 0.890625 0.156250 +vt 0.906250 0.156250 +vt 0.921875 0.156250 +vt 0.937500 0.156250 +vt 0.953125 0.156250 +vt 0.984375 0.140625 +vt 0.968750 0.156250 +vt 0.015625 0.171875 +vt 0.031250 0.171875 +vt 0.046875 0.171875 +vt 0.062500 0.171875 +vt 0.078125 0.171875 +vt 0.093750 0.171875 +vt 0.109375 0.171875 +vt 0.125000 0.171875 +vt 0.140625 0.171875 +vt 0.156250 0.171875 +vt 0.171875 0.171875 +vt 0.187500 0.171875 +vt 0.203125 0.171875 +vt 0.218750 0.171875 +vt 0.234375 0.171875 +vt 0.250000 0.171875 +vt 0.265625 0.171875 +vt 0.281250 0.171875 +vt 0.296875 0.171875 +vt 0.312500 0.171875 +vt 0.328125 0.171875 +vt 0.343750 0.171875 +vt 0.359375 0.171875 +vt 0.375000 0.171875 +vt 0.390625 0.171875 +vt 0.406250 0.171875 +vt 0.421875 0.171875 +vt 0.437500 0.171875 +vt 0.453125 0.171875 +vt 0.468750 0.171875 +vt 0.484375 0.171875 +vt 0.500000 0.171875 +vt 0.515625 0.171875 +vt 0.531250 0.171875 +vt 0.546875 0.171875 +vt 0.562500 0.171875 +vt 0.578125 0.171875 +vt 0.593750 0.171875 +vt 0.609375 0.171875 +vt 0.625000 0.171875 +vt 0.640625 0.171875 +vt 0.656250 0.171875 +vt 0.671875 0.171875 +vt 0.687500 0.171875 +vt 0.703125 0.171875 +vt 0.718750 0.171875 +vt 0.734375 0.171875 +vt 0.750000 0.171875 +vt 0.765625 0.171875 +vt 0.781250 0.171875 +vt 0.796875 0.171875 +vt 0.812500 0.171875 +vt 0.828125 0.171875 +vt 0.843750 0.171875 +vt 0.859375 0.171875 +vt 0.875000 0.171875 +vt 0.890625 0.171875 +vt 0.906250 0.171875 +vt 0.921875 0.171875 +vt 0.937500 0.171875 +vt 0.953125 0.171875 +vt 0.984375 0.156250 +vt 0.968750 0.171875 +vt 0.015625 0.187500 +vt 0.031250 0.187500 +vt 0.046875 0.187500 +vt 0.062500 0.187500 +vt 0.078125 0.187500 +vt 0.093750 0.187500 +vt 0.109375 0.187500 +vt 0.125000 0.187500 +vt 0.140625 0.187500 +vt 0.156250 0.187500 +vt 0.171875 0.187500 +vt 0.187500 0.187500 +vt 0.203125 0.187500 +vt 0.218750 0.187500 +vt 0.234375 0.187500 +vt 0.250000 0.187500 +vt 0.265625 0.187500 +vt 0.281250 0.187500 +vt 0.296875 0.187500 +vt 0.312500 0.187500 +vt 0.328125 0.187500 +vt 0.343750 0.187500 +vt 0.359375 0.187500 +vt 0.375000 0.187500 +vt 0.390625 0.187500 +vt 0.406250 0.187500 +vt 0.421875 0.187500 +vt 0.437500 0.187500 +vt 0.453125 0.187500 +vt 0.468750 0.187500 +vt 0.484375 0.187500 +vt 0.500000 0.187500 +vt 0.515625 0.187500 +vt 0.531250 0.187500 +vt 0.546875 0.187500 +vt 0.562500 0.187500 +vt 0.578125 0.187500 +vt 0.593750 0.187500 +vt 0.609375 0.187500 +vt 0.625000 0.187500 +vt 0.640625 0.187500 +vt 0.656250 0.187500 +vt 0.671875 0.187500 +vt 0.687500 0.187500 +vt 0.703125 0.187500 +vt 0.718750 0.187500 +vt 0.734375 0.187500 +vt 0.750000 0.187500 +vt 0.765625 0.187500 +vt 0.781250 0.187500 +vt 0.796875 0.187500 +vt 0.812500 0.187500 +vt 0.828125 0.187500 +vt 0.843750 0.187500 +vt 0.859375 0.187500 +vt 0.875000 0.187500 +vt 0.890625 0.187500 +vt 0.906250 0.187500 +vt 0.921875 0.187500 +vt 0.937500 0.187500 +vt 0.953125 0.187500 +vt 0.984375 0.171875 +vt 0.968750 0.187500 +vt 0.015625 0.203125 +vt 0.031250 0.203125 +vt 0.046875 0.203125 +vt 0.062500 0.203125 +vt 0.078125 0.203125 +vt 0.093750 0.203125 +vt 0.109375 0.203125 +vt 0.125000 0.203125 +vt 0.140625 0.203125 +vt 0.156250 0.203125 +vt 0.171875 0.203125 +vt 0.187500 0.203125 +vt 0.203125 0.203125 +vt 0.218750 0.203125 +vt 0.234375 0.203125 +vt 0.250000 0.203125 +vt 0.265625 0.203125 +vt 0.281250 0.203125 +vt 0.296875 0.203125 +vt 0.312500 0.203125 +vt 0.328125 0.203125 +vt 0.343750 0.203125 +vt 0.359375 0.203125 +vt 0.375000 0.203125 +vt 0.390625 0.203125 +vt 0.406250 0.203125 +vt 0.421875 0.203125 +vt 0.437500 0.203125 +vt 0.453125 0.203125 +vt 0.468750 0.203125 +vt 0.484375 0.203125 +vt 0.500000 0.203125 +vt 0.515625 0.203125 +vt 0.531250 0.203125 +vt 0.546875 0.203125 +vt 0.562500 0.203125 +vt 0.578125 0.203125 +vt 0.593750 0.203125 +vt 0.609375 0.203125 +vt 0.625000 0.203125 +vt 0.640625 0.203125 +vt 0.656250 0.203125 +vt 0.671875 0.203125 +vt 0.687500 0.203125 +vt 0.703125 0.203125 +vt 0.718750 0.203125 +vt 0.734375 0.203125 +vt 0.750000 0.203125 +vt 0.765625 0.203125 +vt 0.781250 0.203125 +vt 0.796875 0.203125 +vt 0.812500 0.203125 +vt 0.828125 0.203125 +vt 0.843750 0.203125 +vt 0.859375 0.203125 +vt 0.875000 0.203125 +vt 0.890625 0.203125 +vt 0.906250 0.203125 +vt 0.921875 0.203125 +vt 0.937500 0.203125 +vt 0.953125 0.203125 +vt 0.984375 0.187500 +vt 0.968750 0.203125 +vt 0.015625 0.218750 +vt 0.031250 0.218750 +vt 0.046875 0.218750 +vt 0.062500 0.218750 +vt 0.078125 0.218750 +vt 0.093750 0.218750 +vt 0.109375 0.218750 +vt 0.125000 0.218750 +vt 0.140625 0.218750 +vt 0.156250 0.218750 +vt 0.171875 0.218750 +vt 0.187500 0.218750 +vt 0.203125 0.218750 +vt 0.218750 0.218750 +vt 0.234375 0.218750 +vt 0.250000 0.218750 +vt 0.265625 0.218750 +vt 0.281250 0.218750 +vt 0.296875 0.218750 +vt 0.312500 0.218750 +vt 0.328125 0.218750 +vt 0.343750 0.218750 +vt 0.359375 0.218750 +vt 0.375000 0.218750 +vt 0.390625 0.218750 +vt 0.406250 0.218750 +vt 0.421875 0.218750 +vt 0.437500 0.218750 +vt 0.453125 0.218750 +vt 0.468750 0.218750 +vt 0.484375 0.218750 +vt 0.500000 0.218750 +vt 0.515625 0.218750 +vt 0.531250 0.218750 +vt 0.546875 0.218750 +vt 0.562500 0.218750 +vt 0.578125 0.218750 +vt 0.593750 0.218750 +vt 0.609375 0.218750 +vt 0.625000 0.218750 +vt 0.640625 0.218750 +vt 0.656250 0.218750 +vt 0.671875 0.218750 +vt 0.687500 0.218750 +vt 0.703125 0.218750 +vt 0.718750 0.218750 +vt 0.734375 0.218750 +vt 0.750000 0.218750 +vt 0.765625 0.218750 +vt 0.781250 0.218750 +vt 0.796875 0.218750 +vt 0.812500 0.218750 +vt 0.828125 0.218750 +vt 0.843750 0.218750 +vt 0.859375 0.218750 +vt 0.875000 0.218750 +vt 0.890625 0.218750 +vt 0.906250 0.218750 +vt 0.921875 0.218750 +vt 0.937500 0.218750 +vt 0.953125 0.218750 +vt 0.984375 0.203125 +vt 0.968750 0.218750 +vt 0.015625 0.234375 +vt 0.031250 0.234375 +vt 0.046875 0.234375 +vt 0.062500 0.234375 +vt 0.078125 0.234375 +vt 0.093750 0.234375 +vt 0.109375 0.234375 +vt 0.125000 0.234375 +vt 0.140625 0.234375 +vt 0.156250 0.234375 +vt 0.171875 0.234375 +vt 0.187500 0.234375 +vt 0.203125 0.234375 +vt 0.218750 0.234375 +vt 0.234375 0.234375 +vt 0.250000 0.234375 +vt 0.265625 0.234375 +vt 0.281250 0.234375 +vt 0.296875 0.234375 +vt 0.312500 0.234375 +vt 0.328125 0.234375 +vt 0.343750 0.234375 +vt 0.359375 0.234375 +vt 0.375000 0.234375 +vt 0.390625 0.234375 +vt 0.406250 0.234375 +vt 0.421875 0.234375 +vt 0.437500 0.234375 +vt 0.453125 0.234375 +vt 0.468750 0.234375 +vt 0.484375 0.234375 +vt 0.500000 0.234375 +vt 0.515625 0.234375 +vt 0.531250 0.234375 +vt 0.546875 0.234375 +vt 0.562500 0.234375 +vt 0.578125 0.234375 +vt 0.593750 0.234375 +vt 0.609375 0.234375 +vt 0.625000 0.234375 +vt 0.640625 0.234375 +vt 0.656250 0.234375 +vt 0.671875 0.234375 +vt 0.687500 0.234375 +vt 0.703125 0.234375 +vt 0.718750 0.234375 +vt 0.734375 0.234375 +vt 0.750000 0.234375 +vt 0.765625 0.234375 +vt 0.781250 0.234375 +vt 0.796875 0.234375 +vt 0.812500 0.234375 +vt 0.828125 0.234375 +vt 0.843750 0.234375 +vt 0.859375 0.234375 +vt 0.875000 0.234375 +vt 0.890625 0.234375 +vt 0.906250 0.234375 +vt 0.921875 0.234375 +vt 0.937500 0.234375 +vt 0.953125 0.234375 +vt 0.984375 0.218750 +vt 0.968750 0.234375 +vt 0.015625 0.250000 +vt 0.031250 0.250000 +vt 0.046875 0.250000 +vt 0.062500 0.250000 +vt 0.078125 0.250000 +vt 0.093750 0.250000 +vt 0.109375 0.250000 +vt 0.125000 0.250000 +vt 0.140625 0.250000 +vt 0.156250 0.250000 +vt 0.171875 0.250000 +vt 0.187500 0.250000 +vt 0.203125 0.250000 +vt 0.218750 0.250000 +vt 0.234375 0.250000 +vt 0.250000 0.250000 +vt 0.265625 0.250000 +vt 0.281250 0.250000 +vt 0.296875 0.250000 +vt 0.312500 0.250000 +vt 0.328125 0.250000 +vt 0.343750 0.250000 +vt 0.359375 0.250000 +vt 0.375000 0.250000 +vt 0.390625 0.250000 +vt 0.406250 0.250000 +vt 0.421875 0.250000 +vt 0.437500 0.250000 +vt 0.453125 0.250000 +vt 0.468750 0.250000 +vt 0.484375 0.250000 +vt 0.500000 0.250000 +vt 0.515625 0.250000 +vt 0.531250 0.250000 +vt 0.546875 0.250000 +vt 0.562500 0.250000 +vt 0.578125 0.250000 +vt 0.593750 0.250000 +vt 0.609375 0.250000 +vt 0.625000 0.250000 +vt 0.640625 0.250000 +vt 0.656250 0.250000 +vt 0.671875 0.250000 +vt 0.687500 0.250000 +vt 0.703125 0.250000 +vt 0.718750 0.250000 +vt 0.734375 0.250000 +vt 0.750000 0.250000 +vt 0.765625 0.250000 +vt 0.781250 0.250000 +vt 0.796875 0.250000 +vt 0.812500 0.250000 +vt 0.828125 0.250000 +vt 0.843750 0.250000 +vt 0.859375 0.250000 +vt 0.875000 0.250000 +vt 0.890625 0.250000 +vt 0.906250 0.250000 +vt 0.921875 0.250000 +vt 0.937500 0.250000 +vt 0.953125 0.250000 +vt 0.984375 0.234375 +vt 0.968750 0.250000 +vt 0.015625 0.265625 +vt 0.031250 0.265625 +vt 0.046875 0.265625 +vt 0.062500 0.265625 +vt 0.078125 0.265625 +vt 0.093750 0.265625 +vt 0.109375 0.265625 +vt 0.125000 0.265625 +vt 0.140625 0.265625 +vt 0.156250 0.265625 +vt 0.171875 0.265625 +vt 0.187500 0.265625 +vt 0.203125 0.265625 +vt 0.218750 0.265625 +vt 0.234375 0.265625 +vt 0.250000 0.265625 +vt 0.265625 0.265625 +vt 0.281250 0.265625 +vt 0.296875 0.265625 +vt 0.312500 0.265625 +vt 0.328125 0.265625 +vt 0.343750 0.265625 +vt 0.359375 0.265625 +vt 0.375000 0.265625 +vt 0.390625 0.265625 +vt 0.406250 0.265625 +vt 0.421875 0.265625 +vt 0.437500 0.265625 +vt 0.453125 0.265625 +vt 0.468750 0.265625 +vt 0.484375 0.265625 +vt 0.500000 0.265625 +vt 0.515625 0.265625 +vt 0.531250 0.265625 +vt 0.546875 0.265625 +vt 0.562500 0.265625 +vt 0.578125 0.265625 +vt 0.593750 0.265625 +vt 0.609375 0.265625 +vt 0.625000 0.265625 +vt 0.640625 0.265625 +vt 0.656250 0.265625 +vt 0.671875 0.265625 +vt 0.687500 0.265625 +vt 0.703125 0.265625 +vt 0.718750 0.265625 +vt 0.734375 0.265625 +vt 0.750000 0.265625 +vt 0.765625 0.265625 +vt 0.781250 0.265625 +vt 0.796875 0.265625 +vt 0.812500 0.265625 +vt 0.828125 0.265625 +vt 0.843750 0.265625 +vt 0.859375 0.265625 +vt 0.875000 0.265625 +vt 0.890625 0.265625 +vt 0.906250 0.265625 +vt 0.921875 0.265625 +vt 0.937500 0.265625 +vt 0.953125 0.265625 +vt 0.984375 0.250000 +vt 0.968750 0.265625 +vt 0.015625 0.281250 +vt 0.031250 0.281250 +vt 0.046875 0.281250 +vt 0.062500 0.281250 +vt 0.078125 0.281250 +vt 0.093750 0.281250 +vt 0.109375 0.281250 +vt 0.125000 0.281250 +vt 0.140625 0.281250 +vt 0.156250 0.281250 +vt 0.171875 0.281250 +vt 0.187500 0.281250 +vt 0.203125 0.281250 +vt 0.218750 0.281250 +vt 0.234375 0.281250 +vt 0.250000 0.281250 +vt 0.265625 0.281250 +vt 0.281250 0.281250 +vt 0.296875 0.281250 +vt 0.312500 0.281250 +vt 0.328125 0.281250 +vt 0.343750 0.281250 +vt 0.359375 0.281250 +vt 0.375000 0.281250 +vt 0.390625 0.281250 +vt 0.406250 0.281250 +vt 0.421875 0.281250 +vt 0.437500 0.281250 +vt 0.453125 0.281250 +vt 0.468750 0.281250 +vt 0.484375 0.281250 +vt 0.500000 0.281250 +vt 0.515625 0.281250 +vt 0.531250 0.281250 +vt 0.546875 0.281250 +vt 0.562500 0.281250 +vt 0.578125 0.281250 +vt 0.593750 0.281250 +vt 0.609375 0.281250 +vt 0.625000 0.281250 +vt 0.640625 0.281250 +vt 0.656250 0.281250 +vt 0.671875 0.281250 +vt 0.687500 0.281250 +vt 0.703125 0.281250 +vt 0.718750 0.281250 +vt 0.734375 0.281250 +vt 0.750000 0.281250 +vt 0.765625 0.281250 +vt 0.781250 0.281250 +vt 0.796875 0.281250 +vt 0.812500 0.281250 +vt 0.828125 0.281250 +vt 0.843750 0.281250 +vt 0.859375 0.281250 +vt 0.875000 0.281250 +vt 0.890625 0.281250 +vt 0.906250 0.281250 +vt 0.921875 0.281250 +vt 0.937500 0.281250 +vt 0.953125 0.281250 +vt 0.984375 0.265625 +vt 0.968750 0.281250 +vt 0.015625 0.296875 +vt 0.031250 0.296875 +vt 0.046875 0.296875 +vt 0.062500 0.296875 +vt 0.078125 0.296875 +vt 0.093750 0.296875 +vt 0.109375 0.296875 +vt 0.125000 0.296875 +vt 0.140625 0.296875 +vt 0.156250 0.296875 +vt 0.171875 0.296875 +vt 0.187500 0.296875 +vt 0.203125 0.296875 +vt 0.218750 0.296875 +vt 0.234375 0.296875 +vt 0.250000 0.296875 +vt 0.265625 0.296875 +vt 0.281250 0.296875 +vt 0.296875 0.296875 +vt 0.312500 0.296875 +vt 0.328125 0.296875 +vt 0.343750 0.296875 +vt 0.359375 0.296875 +vt 0.375000 0.296875 +vt 0.390625 0.296875 +vt 0.406250 0.296875 +vt 0.421875 0.296875 +vt 0.437500 0.296875 +vt 0.453125 0.296875 +vt 0.468750 0.296875 +vt 0.484375 0.296875 +vt 0.500000 0.296875 +vt 0.515625 0.296875 +vt 0.531250 0.296875 +vt 0.546875 0.296875 +vt 0.562500 0.296875 +vt 0.578125 0.296875 +vt 0.593750 0.296875 +vt 0.609375 0.296875 +vt 0.625000 0.296875 +vt 0.640625 0.296875 +vt 0.656250 0.296875 +vt 0.671875 0.296875 +vt 0.687500 0.296875 +vt 0.703125 0.296875 +vt 0.718750 0.296875 +vt 0.734375 0.296875 +vt 0.750000 0.296875 +vt 0.765625 0.296875 +vt 0.781250 0.296875 +vt 0.796875 0.296875 +vt 0.812500 0.296875 +vt 0.828125 0.296875 +vt 0.843750 0.296875 +vt 0.859375 0.296875 +vt 0.875000 0.296875 +vt 0.890625 0.296875 +vt 0.906250 0.296875 +vt 0.921875 0.296875 +vt 0.937500 0.296875 +vt 0.953125 0.296875 +vt 0.984375 0.281250 +vt 0.968750 0.296875 +vt 0.015625 0.312500 +vt 0.031250 0.312500 +vt 0.046875 0.312500 +vt 0.062500 0.312500 +vt 0.078125 0.312500 +vt 0.093750 0.312500 +vt 0.109375 0.312500 +vt 0.125000 0.312500 +vt 0.140625 0.312500 +vt 0.156250 0.312500 +vt 0.171875 0.312500 +vt 0.187500 0.312500 +vt 0.203125 0.312500 +vt 0.218750 0.312500 +vt 0.234375 0.312500 +vt 0.250000 0.312500 +vt 0.265625 0.312500 +vt 0.281250 0.312500 +vt 0.296875 0.312500 +vt 0.312500 0.312500 +vt 0.328125 0.312500 +vt 0.343750 0.312500 +vt 0.359375 0.312500 +vt 0.375000 0.312500 +vt 0.390625 0.312500 +vt 0.406250 0.312500 +vt 0.421875 0.312500 +vt 0.437500 0.312500 +vt 0.453125 0.312500 +vt 0.468750 0.312500 +vt 0.484375 0.312500 +vt 0.500000 0.312500 +vt 0.515625 0.312500 +vt 0.531250 0.312500 +vt 0.546875 0.312500 +vt 0.562500 0.312500 +vt 0.578125 0.312500 +vt 0.593750 0.312500 +vt 0.609375 0.312500 +vt 0.625000 0.312500 +vt 0.640625 0.312500 +vt 0.656250 0.312500 +vt 0.671875 0.312500 +vt 0.687500 0.312500 +vt 0.703125 0.312500 +vt 0.718750 0.312500 +vt 0.734375 0.312500 +vt 0.750000 0.312500 +vt 0.765625 0.312500 +vt 0.781250 0.312500 +vt 0.796875 0.312500 +vt 0.812500 0.312500 +vt 0.828125 0.312500 +vt 0.843750 0.312500 +vt 0.859375 0.312500 +vt 0.875000 0.312500 +vt 0.890625 0.312500 +vt 0.906250 0.312500 +vt 0.921875 0.312500 +vt 0.937500 0.312500 +vt 0.953125 0.312500 +vt 0.984375 0.296875 +vt 0.968750 0.312500 +vt 0.015625 0.328125 +vt 0.031250 0.328125 +vt 0.046875 0.328125 +vt 0.062500 0.328125 +vt 0.078125 0.328125 +vt 0.093750 0.328125 +vt 0.109375 0.328125 +vt 0.125000 0.328125 +vt 0.140625 0.328125 +vt 0.156250 0.328125 +vt 0.171875 0.328125 +vt 0.187500 0.328125 +vt 0.203125 0.328125 +vt 0.218750 0.328125 +vt 0.234375 0.328125 +vt 0.250000 0.328125 +vt 0.265625 0.328125 +vt 0.281250 0.328125 +vt 0.296875 0.328125 +vt 0.312500 0.328125 +vt 0.328125 0.328125 +vt 0.343750 0.328125 +vt 0.359375 0.328125 +vt 0.375000 0.328125 +vt 0.390625 0.328125 +vt 0.406250 0.328125 +vt 0.421875 0.328125 +vt 0.437500 0.328125 +vt 0.453125 0.328125 +vt 0.468750 0.328125 +vt 0.484375 0.328125 +vt 0.500000 0.328125 +vt 0.515625 0.328125 +vt 0.531250 0.328125 +vt 0.546875 0.328125 +vt 0.562500 0.328125 +vt 0.578125 0.328125 +vt 0.593750 0.328125 +vt 0.609375 0.328125 +vt 0.625000 0.328125 +vt 0.640625 0.328125 +vt 0.656250 0.328125 +vt 0.671875 0.328125 +vt 0.687500 0.328125 +vt 0.703125 0.328125 +vt 0.718750 0.328125 +vt 0.734375 0.328125 +vt 0.750000 0.328125 +vt 0.765625 0.328125 +vt 0.781250 0.328125 +vt 0.796875 0.328125 +vt 0.812500 0.328125 +vt 0.828125 0.328125 +vt 0.843750 0.328125 +vt 0.859375 0.328125 +vt 0.875000 0.328125 +vt 0.890625 0.328125 +vt 0.906250 0.328125 +vt 0.921875 0.328125 +vt 0.937500 0.328125 +vt 0.953125 0.328125 +vt 0.984375 0.312500 +vt 0.968750 0.328125 +vt 0.015625 0.343750 +vt 0.031250 0.343750 +vt 0.046875 0.343750 +vt 0.062500 0.343750 +vt 0.078125 0.343750 +vt 0.093750 0.343750 +vt 0.109375 0.343750 +vt 0.125000 0.343750 +vt 0.140625 0.343750 +vt 0.156250 0.343750 +vt 0.171875 0.343750 +vt 0.187500 0.343750 +vt 0.203125 0.343750 +vt 0.218750 0.343750 +vt 0.234375 0.343750 +vt 0.250000 0.343750 +vt 0.265625 0.343750 +vt 0.281250 0.343750 +vt 0.296875 0.343750 +vt 0.312500 0.343750 +vt 0.328125 0.343750 +vt 0.343750 0.343750 +vt 0.359375 0.343750 +vt 0.375000 0.343750 +vt 0.390625 0.343750 +vt 0.406250 0.343750 +vt 0.421875 0.343750 +vt 0.437500 0.343750 +vt 0.453125 0.343750 +vt 0.468750 0.343750 +vt 0.484375 0.343750 +vt 0.500000 0.343750 +vt 0.515625 0.343750 +vt 0.531250 0.343750 +vt 0.546875 0.343750 +vt 0.562500 0.343750 +vt 0.578125 0.343750 +vt 0.593750 0.343750 +vt 0.609375 0.343750 +vt 0.625000 0.343750 +vt 0.640625 0.343750 +vt 0.656250 0.343750 +vt 0.671875 0.343750 +vt 0.687500 0.343750 +vt 0.703125 0.343750 +vt 0.718750 0.343750 +vt 0.734375 0.343750 +vt 0.750000 0.343750 +vt 0.765625 0.343750 +vt 0.781250 0.343750 +vt 0.796875 0.343750 +vt 0.812500 0.343750 +vt 0.828125 0.343750 +vt 0.843750 0.343750 +vt 0.859375 0.343750 +vt 0.875000 0.343750 +vt 0.890625 0.343750 +vt 0.906250 0.343750 +vt 0.921875 0.343750 +vt 0.937500 0.343750 +vt 0.953125 0.343750 +vt 0.984375 0.328125 +vt 0.968750 0.343750 +vt 0.015625 0.359375 +vt 0.031250 0.359375 +vt 0.046875 0.359375 +vt 0.062500 0.359375 +vt 0.078125 0.359375 +vt 0.093750 0.359375 +vt 0.109375 0.359375 +vt 0.125000 0.359375 +vt 0.140625 0.359375 +vt 0.156250 0.359375 +vt 0.171875 0.359375 +vt 0.187500 0.359375 +vt 0.203125 0.359375 +vt 0.218750 0.359375 +vt 0.234375 0.359375 +vt 0.250000 0.359375 +vt 0.265625 0.359375 +vt 0.281250 0.359375 +vt 0.296875 0.359375 +vt 0.312500 0.359375 +vt 0.328125 0.359375 +vt 0.343750 0.359375 +vt 0.359375 0.359375 +vt 0.375000 0.359375 +vt 0.390625 0.359375 +vt 0.406250 0.359375 +vt 0.421875 0.359375 +vt 0.437500 0.359375 +vt 0.453125 0.359375 +vt 0.468750 0.359375 +vt 0.484375 0.359375 +vt 0.500000 0.359375 +vt 0.515625 0.359375 +vt 0.531250 0.359375 +vt 0.546875 0.359375 +vt 0.562500 0.359375 +vt 0.578125 0.359375 +vt 0.593750 0.359375 +vt 0.609375 0.359375 +vt 0.625000 0.359375 +vt 0.640625 0.359375 +vt 0.656250 0.359375 +vt 0.671875 0.359375 +vt 0.687500 0.359375 +vt 0.703125 0.359375 +vt 0.718750 0.359375 +vt 0.734375 0.359375 +vt 0.750000 0.359375 +vt 0.765625 0.359375 +vt 0.781250 0.359375 +vt 0.796875 0.359375 +vt 0.812500 0.359375 +vt 0.828125 0.359375 +vt 0.843750 0.359375 +vt 0.859375 0.359375 +vt 0.875000 0.359375 +vt 0.890625 0.359375 +vt 0.906250 0.359375 +vt 0.921875 0.359375 +vt 0.937500 0.359375 +vt 0.953125 0.359375 +vt 0.984375 0.343750 +vt 0.968750 0.359375 +vt 0.015625 0.375000 +vt 0.031250 0.375000 +vt 0.046875 0.375000 +vt 0.062500 0.375000 +vt 0.078125 0.375000 +vt 0.093750 0.375000 +vt 0.109375 0.375000 +vt 0.125000 0.375000 +vt 0.140625 0.375000 +vt 0.156250 0.375000 +vt 0.171875 0.375000 +vt 0.187500 0.375000 +vt 0.203125 0.375000 +vt 0.218750 0.375000 +vt 0.234375 0.375000 +vt 0.250000 0.375000 +vt 0.265625 0.375000 +vt 0.281250 0.375000 +vt 0.296875 0.375000 +vt 0.312500 0.375000 +vt 0.328125 0.375000 +vt 0.343750 0.375000 +vt 0.359375 0.375000 +vt 0.375000 0.375000 +vt 0.390625 0.375000 +vt 0.406250 0.375000 +vt 0.421875 0.375000 +vt 0.437500 0.375000 +vt 0.453125 0.375000 +vt 0.468750 0.375000 +vt 0.484375 0.375000 +vt 0.500000 0.375000 +vt 0.515625 0.375000 +vt 0.531250 0.375000 +vt 0.546875 0.375000 +vt 0.562500 0.375000 +vt 0.578125 0.375000 +vt 0.593750 0.375000 +vt 0.609375 0.375000 +vt 0.625000 0.375000 +vt 0.640625 0.375000 +vt 0.656250 0.375000 +vt 0.671875 0.375000 +vt 0.687500 0.375000 +vt 0.703125 0.375000 +vt 0.718750 0.375000 +vt 0.734375 0.375000 +vt 0.750000 0.375000 +vt 0.765625 0.375000 +vt 0.781250 0.375000 +vt 0.796875 0.375000 +vt 0.812500 0.375000 +vt 0.828125 0.375000 +vt 0.843750 0.375000 +vt 0.859375 0.375000 +vt 0.875000 0.375000 +vt 0.890625 0.375000 +vt 0.906250 0.375000 +vt 0.921875 0.375000 +vt 0.937500 0.375000 +vt 0.953125 0.375000 +vt 0.984375 0.359375 +vt 0.968750 0.375000 +vt 0.015625 0.390625 +vt 0.031250 0.390625 +vt 0.046875 0.390625 +vt 0.062500 0.390625 +vt 0.078125 0.390625 +vt 0.093750 0.390625 +vt 0.109375 0.390625 +vt 0.125000 0.390625 +vt 0.140625 0.390625 +vt 0.156250 0.390625 +vt 0.171875 0.390625 +vt 0.187500 0.390625 +vt 0.203125 0.390625 +vt 0.218750 0.390625 +vt 0.234375 0.390625 +vt 0.250000 0.390625 +vt 0.265625 0.390625 +vt 0.281250 0.390625 +vt 0.296875 0.390625 +vt 0.312500 0.390625 +vt 0.328125 0.390625 +vt 0.343750 0.390625 +vt 0.359375 0.390625 +vt 0.375000 0.390625 +vt 0.390625 0.390625 +vt 0.406250 0.390625 +vt 0.421875 0.390625 +vt 0.437500 0.390625 +vt 0.453125 0.390625 +vt 0.468750 0.390625 +vt 0.484375 0.390625 +vt 0.500000 0.390625 +vt 0.515625 0.390625 +vt 0.531250 0.390625 +vt 0.546875 0.390625 +vt 0.562500 0.390625 +vt 0.578125 0.390625 +vt 0.593750 0.390625 +vt 0.609375 0.390625 +vt 0.625000 0.390625 +vt 0.640625 0.390625 +vt 0.656250 0.390625 +vt 0.671875 0.390625 +vt 0.687500 0.390625 +vt 0.703125 0.390625 +vt 0.718750 0.390625 +vt 0.734375 0.390625 +vt 0.750000 0.390625 +vt 0.765625 0.390625 +vt 0.781250 0.390625 +vt 0.796875 0.390625 +vt 0.812500 0.390625 +vt 0.828125 0.390625 +vt 0.843750 0.390625 +vt 0.859375 0.390625 +vt 0.875000 0.390625 +vt 0.890625 0.390625 +vt 0.906250 0.390625 +vt 0.921875 0.390625 +vt 0.937500 0.390625 +vt 0.953125 0.390625 +vt 0.984375 0.375000 +vt 0.968750 0.390625 +vt 0.015625 0.406250 +vt 0.031250 0.406250 +vt 0.046875 0.406250 +vt 0.062500 0.406250 +vt 0.078125 0.406250 +vt 0.093750 0.406250 +vt 0.109375 0.406250 +vt 0.125000 0.406250 +vt 0.140625 0.406250 +vt 0.156250 0.406250 +vt 0.171875 0.406250 +vt 0.187500 0.406250 +vt 0.203125 0.406250 +vt 0.218750 0.406250 +vt 0.234375 0.406250 +vt 0.250000 0.406250 +vt 0.265625 0.406250 +vt 0.281250 0.406250 +vt 0.296875 0.406250 +vt 0.312500 0.406250 +vt 0.328125 0.406250 +vt 0.343750 0.406250 +vt 0.359375 0.406250 +vt 0.375000 0.406250 +vt 0.390625 0.406250 +vt 0.406250 0.406250 +vt 0.421875 0.406250 +vt 0.437500 0.406250 +vt 0.453125 0.406250 +vt 0.468750 0.406250 +vt 0.484375 0.406250 +vt 0.500000 0.406250 +vt 0.515625 0.406250 +vt 0.531250 0.406250 +vt 0.546875 0.406250 +vt 0.562500 0.406250 +vt 0.578125 0.406250 +vt 0.593750 0.406250 +vt 0.609375 0.406250 +vt 0.625000 0.406250 +vt 0.640625 0.406250 +vt 0.656250 0.406250 +vt 0.671875 0.406250 +vt 0.687500 0.406250 +vt 0.703125 0.406250 +vt 0.718750 0.406250 +vt 0.734375 0.406250 +vt 0.750000 0.406250 +vt 0.765625 0.406250 +vt 0.781250 0.406250 +vt 0.796875 0.406250 +vt 0.812500 0.406250 +vt 0.828125 0.406250 +vt 0.843750 0.406250 +vt 0.859375 0.406250 +vt 0.875000 0.406250 +vt 0.890625 0.406250 +vt 0.906250 0.406250 +vt 0.921875 0.406250 +vt 0.937500 0.406250 +vt 0.953125 0.406250 +vt 0.984375 0.390625 +vt 0.968750 0.406250 +vt 0.015625 0.421875 +vt 0.031250 0.421875 +vt 0.046875 0.421875 +vt 0.062500 0.421875 +vt 0.078125 0.421875 +vt 0.093750 0.421875 +vt 0.109375 0.421875 +vt 0.125000 0.421875 +vt 0.140625 0.421875 +vt 0.156250 0.421875 +vt 0.171875 0.421875 +vt 0.187500 0.421875 +vt 0.203125 0.421875 +vt 0.218750 0.421875 +vt 0.234375 0.421875 +vt 0.250000 0.421875 +vt 0.265625 0.421875 +vt 0.281250 0.421875 +vt 0.296875 0.421875 +vt 0.312500 0.421875 +vt 0.328125 0.421875 +vt 0.343750 0.421875 +vt 0.359375 0.421875 +vt 0.375000 0.421875 +vt 0.390625 0.421875 +vt 0.406250 0.421875 +vt 0.421875 0.421875 +vt 0.437500 0.421875 +vt 0.453125 0.421875 +vt 0.468750 0.421875 +vt 0.484375 0.421875 +vt 0.500000 0.421875 +vt 0.515625 0.421875 +vt 0.531250 0.421875 +vt 0.546875 0.421875 +vt 0.562500 0.421875 +vt 0.578125 0.421875 +vt 0.593750 0.421875 +vt 0.609375 0.421875 +vt 0.625000 0.421875 +vt 0.640625 0.421875 +vt 0.656250 0.421875 +vt 0.671875 0.421875 +vt 0.687500 0.421875 +vt 0.703125 0.421875 +vt 0.718750 0.421875 +vt 0.734375 0.421875 +vt 0.750000 0.421875 +vt 0.765625 0.421875 +vt 0.781250 0.421875 +vt 0.796875 0.421875 +vt 0.812500 0.421875 +vt 0.828125 0.421875 +vt 0.843750 0.421875 +vt 0.859375 0.421875 +vt 0.875000 0.421875 +vt 0.890625 0.421875 +vt 0.906250 0.421875 +vt 0.921875 0.421875 +vt 0.937500 0.421875 +vt 0.953125 0.421875 +vt 0.984375 0.406250 +vt 0.968750 0.421875 +vt 0.015625 0.437500 +vt 0.031250 0.437500 +vt 0.046875 0.437500 +vt 0.062500 0.437500 +vt 0.078125 0.437500 +vt 0.093750 0.437500 +vt 0.109375 0.437500 +vt 0.125000 0.437500 +vt 0.140625 0.437500 +vt 0.156250 0.437500 +vt 0.171875 0.437500 +vt 0.187500 0.437500 +vt 0.203125 0.437500 +vt 0.218750 0.437500 +vt 0.234375 0.437500 +vt 0.250000 0.437500 +vt 0.265625 0.437500 +vt 0.281250 0.437500 +vt 0.296875 0.437500 +vt 0.312500 0.437500 +vt 0.328125 0.437500 +vt 0.343750 0.437500 +vt 0.359375 0.437500 +vt 0.375000 0.437500 +vt 0.390625 0.437500 +vt 0.406250 0.437500 +vt 0.421875 0.437500 +vt 0.437500 0.437500 +vt 0.453125 0.437500 +vt 0.468750 0.437500 +vt 0.484375 0.437500 +vt 0.500000 0.437500 +vt 0.515625 0.437500 +vt 0.531250 0.437500 +vt 0.546875 0.437500 +vt 0.562500 0.437500 +vt 0.578125 0.437500 +vt 0.593750 0.437500 +vt 0.609375 0.437500 +vt 0.625000 0.437500 +vt 0.640625 0.437500 +vt 0.656250 0.437500 +vt 0.671875 0.437500 +vt 0.687500 0.437500 +vt 0.703125 0.437500 +vt 0.718750 0.437500 +vt 0.734375 0.437500 +vt 0.750000 0.437500 +vt 0.765625 0.437500 +vt 0.781250 0.437500 +vt 0.796875 0.437500 +vt 0.812500 0.437500 +vt 0.828125 0.437500 +vt 0.843750 0.437500 +vt 0.859375 0.437500 +vt 0.875000 0.437500 +vt 0.890625 0.437500 +vt 0.906250 0.437500 +vt 0.921875 0.437500 +vt 0.937500 0.437500 +vt 0.953125 0.437500 +vt 0.984375 0.421875 +vt 0.968750 0.437500 +vt 0.015625 0.453125 +vt 0.031250 0.453125 +vt 0.046875 0.453125 +vt 0.062500 0.453125 +vt 0.078125 0.453125 +vt 0.093750 0.453125 +vt 0.109375 0.453125 +vt 0.125000 0.453125 +vt 0.140625 0.453125 +vt 0.156250 0.453125 +vt 0.171875 0.453125 +vt 0.187500 0.453125 +vt 0.203125 0.453125 +vt 0.218750 0.453125 +vt 0.234375 0.453125 +vt 0.250000 0.453125 +vt 0.265625 0.453125 +vt 0.281250 0.453125 +vt 0.296875 0.453125 +vt 0.312500 0.453125 +vt 0.328125 0.453125 +vt 0.343750 0.453125 +vt 0.359375 0.453125 +vt 0.375000 0.453125 +vt 0.390625 0.453125 +vt 0.406250 0.453125 +vt 0.421875 0.453125 +vt 0.437500 0.453125 +vt 0.453125 0.453125 +vt 0.468750 0.453125 +vt 0.484375 0.453125 +vt 0.500000 0.453125 +vt 0.515625 0.453125 +vt 0.531250 0.453125 +vt 0.546875 0.453125 +vt 0.562500 0.453125 +vt 0.578125 0.453125 +vt 0.593750 0.453125 +vt 0.609375 0.453125 +vt 0.625000 0.453125 +vt 0.640625 0.453125 +vt 0.656250 0.453125 +vt 0.671875 0.453125 +vt 0.687500 0.453125 +vt 0.703125 0.453125 +vt 0.718750 0.453125 +vt 0.734375 0.453125 +vt 0.750000 0.453125 +vt 0.765625 0.453125 +vt 0.781250 0.453125 +vt 0.796875 0.453125 +vt 0.812500 0.453125 +vt 0.828125 0.453125 +vt 0.843750 0.453125 +vt 0.859375 0.453125 +vt 0.875000 0.453125 +vt 0.890625 0.453125 +vt 0.906250 0.453125 +vt 0.921875 0.453125 +vt 0.937500 0.453125 +vt 0.953125 0.453125 +vt 0.984375 0.437500 +vt 0.968750 0.453125 +vt 0.015625 0.468750 +vt 0.031250 0.468750 +vt 0.046875 0.468750 +vt 0.062500 0.468750 +vt 0.078125 0.468750 +vt 0.093750 0.468750 +vt 0.109375 0.468750 +vt 0.125000 0.468750 +vt 0.140625 0.468750 +vt 0.156250 0.468750 +vt 0.171875 0.468750 +vt 0.187500 0.468750 +vt 0.203125 0.468750 +vt 0.218750 0.468750 +vt 0.234375 0.468750 +vt 0.250000 0.468750 +vt 0.265625 0.468750 +vt 0.281250 0.468750 +vt 0.296875 0.468750 +vt 0.312500 0.468750 +vt 0.328125 0.468750 +vt 0.343750 0.468750 +vt 0.359375 0.468750 +vt 0.375000 0.468750 +vt 0.390625 0.468750 +vt 0.406250 0.468750 +vt 0.421875 0.468750 +vt 0.437500 0.468750 +vt 0.453125 0.468750 +vt 0.468750 0.468750 +vt 0.484375 0.468750 +vt 0.500000 0.468750 +vt 0.515625 0.468750 +vt 0.531250 0.468750 +vt 0.546875 0.468750 +vt 0.562500 0.468750 +vt 0.578125 0.468750 +vt 0.593750 0.468750 +vt 0.609375 0.468750 +vt 0.625000 0.468750 +vt 0.640625 0.468750 +vt 0.656250 0.468750 +vt 0.671875 0.468750 +vt 0.687500 0.468750 +vt 0.703125 0.468750 +vt 0.718750 0.468750 +vt 0.734375 0.468750 +vt 0.750000 0.468750 +vt 0.765625 0.468750 +vt 0.781250 0.468750 +vt 0.796875 0.468750 +vt 0.812500 0.468750 +vt 0.828125 0.468750 +vt 0.843750 0.468750 +vt 0.859375 0.468750 +vt 0.875000 0.468750 +vt 0.890625 0.468750 +vt 0.906250 0.468750 +vt 0.921875 0.468750 +vt 0.937500 0.468750 +vt 0.953125 0.468750 +vt 0.984375 0.453125 +vt 0.968750 0.468750 +vt 0.015625 0.484375 +vt 0.031250 0.484375 +vt 0.046875 0.484375 +vt 0.062500 0.484375 +vt 0.078125 0.484375 +vt 0.093750 0.484375 +vt 0.109375 0.484375 +vt 0.125000 0.484375 +vt 0.140625 0.484375 +vt 0.156250 0.484375 +vt 0.171875 0.484375 +vt 0.187500 0.484375 +vt 0.203125 0.484375 +vt 0.218750 0.484375 +vt 0.234375 0.484375 +vt 0.250000 0.484375 +vt 0.265625 0.484375 +vt 0.281250 0.484375 +vt 0.296875 0.484375 +vt 0.312500 0.484375 +vt 0.328125 0.484375 +vt 0.343750 0.484375 +vt 0.359375 0.484375 +vt 0.375000 0.484375 +vt 0.390625 0.484375 +vt 0.406250 0.484375 +vt 0.421875 0.484375 +vt 0.437500 0.484375 +vt 0.453125 0.484375 +vt 0.468750 0.484375 +vt 0.484375 0.484375 +vt 0.500000 0.484375 +vt 0.515625 0.484375 +vt 0.531250 0.484375 +vt 0.546875 0.484375 +vt 0.562500 0.484375 +vt 0.578125 0.484375 +vt 0.593750 0.484375 +vt 0.609375 0.484375 +vt 0.625000 0.484375 +vt 0.640625 0.484375 +vt 0.656250 0.484375 +vt 0.671875 0.484375 +vt 0.687500 0.484375 +vt 0.703125 0.484375 +vt 0.718750 0.484375 +vt 0.734375 0.484375 +vt 0.750000 0.484375 +vt 0.765625 0.484375 +vt 0.781250 0.484375 +vt 0.796875 0.484375 +vt 0.812500 0.484375 +vt 0.828125 0.484375 +vt 0.843750 0.484375 +vt 0.859375 0.484375 +vt 0.875000 0.484375 +vt 0.890625 0.484375 +vt 0.906250 0.484375 +vt 0.921875 0.484375 +vt 0.937500 0.484375 +vt 0.953125 0.484375 +vt 0.984375 0.468750 +vt 0.968750 0.484375 +vt 0.015625 0.500000 +vt 0.031250 0.500000 +vt 0.046875 0.500000 +vt 0.062500 0.500000 +vt 0.078125 0.500000 +vt 0.093750 0.500000 +vt 0.109375 0.500000 +vt 0.125000 0.500000 +vt 0.140625 0.500000 +vt 0.156250 0.500000 +vt 0.171875 0.500000 +vt 0.187500 0.500000 +vt 0.203125 0.500000 +vt 0.218750 0.500000 +vt 0.234375 0.500000 +vt 0.250000 0.500000 +vt 0.265625 0.500000 +vt 0.281250 0.500000 +vt 0.296875 0.500000 +vt 0.312500 0.500000 +vt 0.328125 0.500000 +vt 0.343750 0.500000 +vt 0.359375 0.500000 +vt 0.375000 0.500000 +vt 0.390625 0.500000 +vt 0.406250 0.500000 +vt 0.421875 0.500000 +vt 0.437500 0.500000 +vt 0.453125 0.500000 +vt 0.468750 0.500000 +vt 0.484375 0.500000 +vt 0.500000 0.500000 +vt 0.515625 0.500000 +vt 0.531250 0.500000 +vt 0.546875 0.500000 +vt 0.562500 0.500000 +vt 0.578125 0.500000 +vt 0.593750 0.500000 +vt 0.609375 0.500000 +vt 0.625000 0.500000 +vt 0.640625 0.500000 +vt 0.656250 0.500000 +vt 0.671875 0.500000 +vt 0.687500 0.500000 +vt 0.703125 0.500000 +vt 0.718750 0.500000 +vt 0.734375 0.500000 +vt 0.750000 0.500000 +vt 0.765625 0.500000 +vt 0.781250 0.500000 +vt 0.796875 0.500000 +vt 0.812500 0.500000 +vt 0.828125 0.500000 +vt 0.843750 0.500000 +vt 0.859375 0.500000 +vt 0.875000 0.500000 +vt 0.890625 0.500000 +vt 0.906250 0.500000 +vt 0.921875 0.500000 +vt 0.937500 0.500000 +vt 0.953125 0.500000 +vt 0.984375 0.484375 +vt 0.968750 0.500000 +vt 0.015625 0.515625 +vt 0.031250 0.515625 +vt 0.046875 0.515625 +vt 0.062500 0.515625 +vt 0.078125 0.515625 +vt 0.093750 0.515625 +vt 0.109375 0.515625 +vt 0.125000 0.515625 +vt 0.140625 0.515625 +vt 0.156250 0.515625 +vt 0.171875 0.515625 +vt 0.187500 0.515625 +vt 0.203125 0.515625 +vt 0.218750 0.515625 +vt 0.234375 0.515625 +vt 0.250000 0.515625 +vt 0.265625 0.515625 +vt 0.281250 0.515625 +vt 0.296875 0.515625 +vt 0.312500 0.515625 +vt 0.328125 0.515625 +vt 0.343750 0.515625 +vt 0.359375 0.515625 +vt 0.375000 0.515625 +vt 0.390625 0.515625 +vt 0.406250 0.515625 +vt 0.421875 0.515625 +vt 0.437500 0.515625 +vt 0.453125 0.515625 +vt 0.468750 0.515625 +vt 0.484375 0.515625 +vt 0.500000 0.515625 +vt 0.515625 0.515625 +vt 0.531250 0.515625 +vt 0.546875 0.515625 +vt 0.562500 0.515625 +vt 0.578125 0.515625 +vt 0.593750 0.515625 +vt 0.609375 0.515625 +vt 0.625000 0.515625 +vt 0.640625 0.515625 +vt 0.656250 0.515625 +vt 0.671875 0.515625 +vt 0.687500 0.515625 +vt 0.703125 0.515625 +vt 0.718750 0.515625 +vt 0.734375 0.515625 +vt 0.750000 0.515625 +vt 0.765625 0.515625 +vt 0.781250 0.515625 +vt 0.796875 0.515625 +vt 0.812500 0.515625 +vt 0.828125 0.515625 +vt 0.843750 0.515625 +vt 0.859375 0.515625 +vt 0.875000 0.515625 +vt 0.890625 0.515625 +vt 0.906250 0.515625 +vt 0.921875 0.515625 +vt 0.937500 0.515625 +vt 0.953125 0.515625 +vt 0.984375 0.500000 +vt 0.968750 0.515625 +vt 0.015625 0.531250 +vt 0.031250 0.531250 +vt 0.046875 0.531250 +vt 0.062500 0.531250 +vt 0.078125 0.531250 +vt 0.093750 0.531250 +vt 0.109375 0.531250 +vt 0.125000 0.531250 +vt 0.140625 0.531250 +vt 0.156250 0.531250 +vt 0.171875 0.531250 +vt 0.187500 0.531250 +vt 0.203125 0.531250 +vt 0.218750 0.531250 +vt 0.234375 0.531250 +vt 0.250000 0.531250 +vt 0.265625 0.531250 +vt 0.281250 0.531250 +vt 0.296875 0.531250 +vt 0.312500 0.531250 +vt 0.328125 0.531250 +vt 0.343750 0.531250 +vt 0.359375 0.531250 +vt 0.375000 0.531250 +vt 0.390625 0.531250 +vt 0.406250 0.531250 +vt 0.421875 0.531250 +vt 0.437500 0.531250 +vt 0.453125 0.531250 +vt 0.468750 0.531250 +vt 0.484375 0.531250 +vt 0.500000 0.531250 +vt 0.515625 0.531250 +vt 0.531250 0.531250 +vt 0.546875 0.531250 +vt 0.562500 0.531250 +vt 0.578125 0.531250 +vt 0.593750 0.531250 +vt 0.609375 0.531250 +vt 0.625000 0.531250 +vt 0.640625 0.531250 +vt 0.656250 0.531250 +vt 0.671875 0.531250 +vt 0.687500 0.531250 +vt 0.703125 0.531250 +vt 0.718750 0.531250 +vt 0.734375 0.531250 +vt 0.750000 0.531250 +vt 0.765625 0.531250 +vt 0.781250 0.531250 +vt 0.796875 0.531250 +vt 0.812500 0.531250 +vt 0.828125 0.531250 +vt 0.843750 0.531250 +vt 0.859375 0.531250 +vt 0.875000 0.531250 +vt 0.890625 0.531250 +vt 0.906250 0.531250 +vt 0.921875 0.531250 +vt 0.937500 0.531250 +vt 0.953125 0.531250 +vt 0.984375 0.515625 +vt 0.968750 0.531250 +vt 0.015625 0.546875 +vt 0.031250 0.546875 +vt 0.046875 0.546875 +vt 0.062500 0.546875 +vt 0.078125 0.546875 +vt 0.093750 0.546875 +vt 0.109375 0.546875 +vt 0.125000 0.546875 +vt 0.140625 0.546875 +vt 0.156250 0.546875 +vt 0.171875 0.546875 +vt 0.187500 0.546875 +vt 0.203125 0.546875 +vt 0.218750 0.546875 +vt 0.234375 0.546875 +vt 0.250000 0.546875 +vt 0.265625 0.546875 +vt 0.281250 0.546875 +vt 0.296875 0.546875 +vt 0.312500 0.546875 +vt 0.328125 0.546875 +vt 0.343750 0.546875 +vt 0.359375 0.546875 +vt 0.375000 0.546875 +vt 0.390625 0.546875 +vt 0.406250 0.546875 +vt 0.421875 0.546875 +vt 0.437500 0.546875 +vt 0.453125 0.546875 +vt 0.468750 0.546875 +vt 0.484375 0.546875 +vt 0.500000 0.546875 +vt 0.515625 0.546875 +vt 0.531250 0.546875 +vt 0.546875 0.546875 +vt 0.562500 0.546875 +vt 0.578125 0.546875 +vt 0.593750 0.546875 +vt 0.609375 0.546875 +vt 0.625000 0.546875 +vt 0.640625 0.546875 +vt 0.656250 0.546875 +vt 0.671875 0.546875 +vt 0.687500 0.546875 +vt 0.703125 0.546875 +vt 0.718750 0.546875 +vt 0.734375 0.546875 +vt 0.750000 0.546875 +vt 0.765625 0.546875 +vt 0.781250 0.546875 +vt 0.796875 0.546875 +vt 0.812500 0.546875 +vt 0.828125 0.546875 +vt 0.843750 0.546875 +vt 0.859375 0.546875 +vt 0.875000 0.546875 +vt 0.890625 0.546875 +vt 0.906250 0.546875 +vt 0.921875 0.546875 +vt 0.937500 0.546875 +vt 0.953125 0.546875 +vt 0.984375 0.531250 +vt 0.968750 0.546875 +vt 0.015625 0.562500 +vt 0.031250 0.562500 +vt 0.046875 0.562500 +vt 0.062500 0.562500 +vt 0.078125 0.562500 +vt 0.093750 0.562500 +vt 0.109375 0.562500 +vt 0.125000 0.562500 +vt 0.140625 0.562500 +vt 0.156250 0.562500 +vt 0.171875 0.562500 +vt 0.187500 0.562500 +vt 0.203125 0.562500 +vt 0.218750 0.562500 +vt 0.234375 0.562500 +vt 0.250000 0.562500 +vt 0.265625 0.562500 +vt 0.281250 0.562500 +vt 0.296875 0.562500 +vt 0.312500 0.562500 +vt 0.328125 0.562500 +vt 0.343750 0.562500 +vt 0.359375 0.562500 +vt 0.375000 0.562500 +vt 0.390625 0.562500 +vt 0.406250 0.562500 +vt 0.421875 0.562500 +vt 0.437500 0.562500 +vt 0.453125 0.562500 +vt 0.468750 0.562500 +vt 0.484375 0.562500 +vt 0.500000 0.562500 +vt 0.515625 0.562500 +vt 0.531250 0.562500 +vt 0.546875 0.562500 +vt 0.562500 0.562500 +vt 0.578125 0.562500 +vt 0.593750 0.562500 +vt 0.609375 0.562500 +vt 0.625000 0.562500 +vt 0.640625 0.562500 +vt 0.656250 0.562500 +vt 0.671875 0.562500 +vt 0.687500 0.562500 +vt 0.703125 0.562500 +vt 0.718750 0.562500 +vt 0.734375 0.562500 +vt 0.750000 0.562500 +vt 0.765625 0.562500 +vt 0.781250 0.562500 +vt 0.796875 0.562500 +vt 0.812500 0.562500 +vt 0.828125 0.562500 +vt 0.843750 0.562500 +vt 0.859375 0.562500 +vt 0.875000 0.562500 +vt 0.890625 0.562500 +vt 0.906250 0.562500 +vt 0.921875 0.562500 +vt 0.937500 0.562500 +vt 0.953125 0.562500 +vt 0.984375 0.546875 +vt 0.968750 0.562500 +vt 0.015625 0.578125 +vt 0.031250 0.578125 +vt 0.046875 0.578125 +vt 0.062500 0.578125 +vt 0.078125 0.578125 +vt 0.093750 0.578125 +vt 0.109375 0.578125 +vt 0.125000 0.578125 +vt 0.140625 0.578125 +vt 0.156250 0.578125 +vt 0.171875 0.578125 +vt 0.187500 0.578125 +vt 0.203125 0.578125 +vt 0.218750 0.578125 +vt 0.234375 0.578125 +vt 0.250000 0.578125 +vt 0.265625 0.578125 +vt 0.281250 0.578125 +vt 0.296875 0.578125 +vt 0.312500 0.578125 +vt 0.328125 0.578125 +vt 0.343750 0.578125 +vt 0.359375 0.578125 +vt 0.375000 0.578125 +vt 0.390625 0.578125 +vt 0.406250 0.578125 +vt 0.421875 0.578125 +vt 0.437500 0.578125 +vt 0.453125 0.578125 +vt 0.468750 0.578125 +vt 0.484375 0.578125 +vt 0.500000 0.578125 +vt 0.515625 0.578125 +vt 0.531250 0.578125 +vt 0.546875 0.578125 +vt 0.562500 0.578125 +vt 0.578125 0.578125 +vt 0.593750 0.578125 +vt 0.609375 0.578125 +vt 0.625000 0.578125 +vt 0.640625 0.578125 +vt 0.656250 0.578125 +vt 0.671875 0.578125 +vt 0.687500 0.578125 +vt 0.703125 0.578125 +vt 0.718750 0.578125 +vt 0.734375 0.578125 +vt 0.750000 0.578125 +vt 0.765625 0.578125 +vt 0.781250 0.578125 +vt 0.796875 0.578125 +vt 0.812500 0.578125 +vt 0.828125 0.578125 +vt 0.843750 0.578125 +vt 0.859375 0.578125 +vt 0.875000 0.578125 +vt 0.890625 0.578125 +vt 0.906250 0.578125 +vt 0.921875 0.578125 +vt 0.937500 0.578125 +vt 0.953125 0.578125 +vt 0.984375 0.562500 +vt 0.968750 0.578125 +vt 0.015625 0.593750 +vt 0.031250 0.593750 +vt 0.046875 0.593750 +vt 0.062500 0.593750 +vt 0.078125 0.593750 +vt 0.093750 0.593750 +vt 0.109375 0.593750 +vt 0.125000 0.593750 +vt 0.140625 0.593750 +vt 0.156250 0.593750 +vt 0.171875 0.593750 +vt 0.187500 0.593750 +vt 0.203125 0.593750 +vt 0.218750 0.593750 +vt 0.234375 0.593750 +vt 0.250000 0.593750 +vt 0.265625 0.593750 +vt 0.281250 0.593750 +vt 0.296875 0.593750 +vt 0.312500 0.593750 +vt 0.328125 0.593750 +vt 0.343750 0.593750 +vt 0.359375 0.593750 +vt 0.375000 0.593750 +vt 0.390625 0.593750 +vt 0.406250 0.593750 +vt 0.421875 0.593750 +vt 0.437500 0.593750 +vt 0.453125 0.593750 +vt 0.468750 0.593750 +vt 0.484375 0.593750 +vt 0.500000 0.593750 +vt 0.515625 0.593750 +vt 0.531250 0.593750 +vt 0.546875 0.593750 +vt 0.562500 0.593750 +vt 0.578125 0.593750 +vt 0.593750 0.593750 +vt 0.609375 0.593750 +vt 0.625000 0.593750 +vt 0.640625 0.593750 +vt 0.656250 0.593750 +vt 0.671875 0.593750 +vt 0.687500 0.593750 +vt 0.703125 0.593750 +vt 0.718750 0.593750 +vt 0.734375 0.593750 +vt 0.750000 0.593750 +vt 0.765625 0.593750 +vt 0.781250 0.593750 +vt 0.796875 0.593750 +vt 0.812500 0.593750 +vt 0.828125 0.593750 +vt 0.843750 0.593750 +vt 0.859375 0.593750 +vt 0.875000 0.593750 +vt 0.890625 0.593750 +vt 0.906250 0.593750 +vt 0.921875 0.593750 +vt 0.937500 0.593750 +vt 0.953125 0.593750 +vt 0.984375 0.578125 +vt 0.968750 0.593750 +vt 0.015625 0.609375 +vt 0.031250 0.609375 +vt 0.046875 0.609375 +vt 0.062500 0.609375 +vt 0.078125 0.609375 +vt 0.093750 0.609375 +vt 0.109375 0.609375 +vt 0.125000 0.609375 +vt 0.140625 0.609375 +vt 0.156250 0.609375 +vt 0.171875 0.609375 +vt 0.187500 0.609375 +vt 0.203125 0.609375 +vt 0.218750 0.609375 +vt 0.234375 0.609375 +vt 0.250000 0.609375 +vt 0.265625 0.609375 +vt 0.281250 0.609375 +vt 0.296875 0.609375 +vt 0.312500 0.609375 +vt 0.328125 0.609375 +vt 0.343750 0.609375 +vt 0.359375 0.609375 +vt 0.375000 0.609375 +vt 0.390625 0.609375 +vt 0.406250 0.609375 +vt 0.421875 0.609375 +vt 0.437500 0.609375 +vt 0.453125 0.609375 +vt 0.468750 0.609375 +vt 0.484375 0.609375 +vt 0.500000 0.609375 +vt 0.515625 0.609375 +vt 0.531250 0.609375 +vt 0.546875 0.609375 +vt 0.562500 0.609375 +vt 0.578125 0.609375 +vt 0.593750 0.609375 +vt 0.609375 0.609375 +vt 0.625000 0.609375 +vt 0.640625 0.609375 +vt 0.656250 0.609375 +vt 0.671875 0.609375 +vt 0.687500 0.609375 +vt 0.703125 0.609375 +vt 0.718750 0.609375 +vt 0.734375 0.609375 +vt 0.750000 0.609375 +vt 0.765625 0.609375 +vt 0.781250 0.609375 +vt 0.796875 0.609375 +vt 0.812500 0.609375 +vt 0.828125 0.609375 +vt 0.843750 0.609375 +vt 0.859375 0.609375 +vt 0.875000 0.609375 +vt 0.890625 0.609375 +vt 0.906250 0.609375 +vt 0.921875 0.609375 +vt 0.937500 0.609375 +vt 0.953125 0.609375 +vt 0.984375 0.593750 +vt 0.968750 0.609375 +vt 0.015625 0.625000 +vt 0.031250 0.625000 +vt 0.046875 0.625000 +vt 0.062500 0.625000 +vt 0.078125 0.625000 +vt 0.093750 0.625000 +vt 0.109375 0.625000 +vt 0.125000 0.625000 +vt 0.140625 0.625000 +vt 0.156250 0.625000 +vt 0.171875 0.625000 +vt 0.187500 0.625000 +vt 0.203125 0.625000 +vt 0.218750 0.625000 +vt 0.234375 0.625000 +vt 0.250000 0.625000 +vt 0.265625 0.625000 +vt 0.281250 0.625000 +vt 0.296875 0.625000 +vt 0.312500 0.625000 +vt 0.328125 0.625000 +vt 0.343750 0.625000 +vt 0.359375 0.625000 +vt 0.375000 0.625000 +vt 0.390625 0.625000 +vt 0.406250 0.625000 +vt 0.421875 0.625000 +vt 0.437500 0.625000 +vt 0.453125 0.625000 +vt 0.468750 0.625000 +vt 0.484375 0.625000 +vt 0.500000 0.625000 +vt 0.515625 0.625000 +vt 0.531250 0.625000 +vt 0.546875 0.625000 +vt 0.562500 0.625000 +vt 0.578125 0.625000 +vt 0.593750 0.625000 +vt 0.609375 0.625000 +vt 0.625000 0.625000 +vt 0.640625 0.625000 +vt 0.656250 0.625000 +vt 0.671875 0.625000 +vt 0.687500 0.625000 +vt 0.703125 0.625000 +vt 0.718750 0.625000 +vt 0.734375 0.625000 +vt 0.750000 0.625000 +vt 0.765625 0.625000 +vt 0.781250 0.625000 +vt 0.796875 0.625000 +vt 0.812500 0.625000 +vt 0.828125 0.625000 +vt 0.843750 0.625000 +vt 0.859375 0.625000 +vt 0.875000 0.625000 +vt 0.890625 0.625000 +vt 0.906250 0.625000 +vt 0.921875 0.625000 +vt 0.937500 0.625000 +vt 0.953125 0.625000 +vt 0.984375 0.609375 +vt 0.968750 0.625000 +vt 0.015625 0.640625 +vt 0.031250 0.640625 +vt 0.046875 0.640625 +vt 0.062500 0.640625 +vt 0.078125 0.640625 +vt 0.093750 0.640625 +vt 0.109375 0.640625 +vt 0.125000 0.640625 +vt 0.140625 0.640625 +vt 0.156250 0.640625 +vt 0.171875 0.640625 +vt 0.187500 0.640625 +vt 0.203125 0.640625 +vt 0.218750 0.640625 +vt 0.234375 0.640625 +vt 0.250000 0.640625 +vt 0.265625 0.640625 +vt 0.281250 0.640625 +vt 0.296875 0.640625 +vt 0.312500 0.640625 +vt 0.328125 0.640625 +vt 0.343750 0.640625 +vt 0.359375 0.640625 +vt 0.375000 0.640625 +vt 0.390625 0.640625 +vt 0.406250 0.640625 +vt 0.421875 0.640625 +vt 0.437500 0.640625 +vt 0.453125 0.640625 +vt 0.468750 0.640625 +vt 0.484375 0.640625 +vt 0.500000 0.640625 +vt 0.515625 0.640625 +vt 0.531250 0.640625 +vt 0.546875 0.640625 +vt 0.562500 0.640625 +vt 0.578125 0.640625 +vt 0.593750 0.640625 +vt 0.609375 0.640625 +vt 0.625000 0.640625 +vt 0.640625 0.640625 +vt 0.656250 0.640625 +vt 0.671875 0.640625 +vt 0.687500 0.640625 +vt 0.703125 0.640625 +vt 0.718750 0.640625 +vt 0.734375 0.640625 +vt 0.750000 0.640625 +vt 0.765625 0.640625 +vt 0.781250 0.640625 +vt 0.796875 0.640625 +vt 0.812500 0.640625 +vt 0.828125 0.640625 +vt 0.843750 0.640625 +vt 0.859375 0.640625 +vt 0.875000 0.640625 +vt 0.890625 0.640625 +vt 0.906250 0.640625 +vt 0.921875 0.640625 +vt 0.937500 0.640625 +vt 0.953125 0.640625 +vt 0.984375 0.625000 +vt 0.968750 0.640625 +vt 0.015625 0.656250 +vt 0.031250 0.656250 +vt 0.046875 0.656250 +vt 0.062500 0.656250 +vt 0.078125 0.656250 +vt 0.093750 0.656250 +vt 0.109375 0.656250 +vt 0.125000 0.656250 +vt 0.140625 0.656250 +vt 0.156250 0.656250 +vt 0.171875 0.656250 +vt 0.187500 0.656250 +vt 0.203125 0.656250 +vt 0.218750 0.656250 +vt 0.234375 0.656250 +vt 0.250000 0.656250 +vt 0.265625 0.656250 +vt 0.281250 0.656250 +vt 0.296875 0.656250 +vt 0.312500 0.656250 +vt 0.328125 0.656250 +vt 0.343750 0.656250 +vt 0.359375 0.656250 +vt 0.375000 0.656250 +vt 0.390625 0.656250 +vt 0.406250 0.656250 +vt 0.421875 0.656250 +vt 0.437500 0.656250 +vt 0.453125 0.656250 +vt 0.468750 0.656250 +vt 0.484375 0.656250 +vt 0.500000 0.656250 +vt 0.515625 0.656250 +vt 0.531250 0.656250 +vt 0.546875 0.656250 +vt 0.562500 0.656250 +vt 0.578125 0.656250 +vt 0.593750 0.656250 +vt 0.609375 0.656250 +vt 0.625000 0.656250 +vt 0.640625 0.656250 +vt 0.656250 0.656250 +vt 0.671875 0.656250 +vt 0.687500 0.656250 +vt 0.703125 0.656250 +vt 0.718750 0.656250 +vt 0.734375 0.656250 +vt 0.750000 0.656250 +vt 0.765625 0.656250 +vt 0.781250 0.656250 +vt 0.796875 0.656250 +vt 0.812500 0.656250 +vt 0.828125 0.656250 +vt 0.843750 0.656250 +vt 0.859375 0.656250 +vt 0.875000 0.656250 +vt 0.906250 0.656250 +vt 0.890625 0.656250 +vt 0.921875 0.656250 +vt 0.937500 0.656250 +vt 0.953125 0.656250 +vt 0.984375 0.640625 +vt 0.968750 0.656250 +vt 0.015625 0.671875 +vt 0.031250 0.671875 +vt 0.046875 0.671875 +vt 0.062500 0.671875 +vt 0.078125 0.671875 +vt 0.093750 0.671875 +vt 0.109375 0.671875 +vt 0.125000 0.671875 +vt 0.140625 0.671875 +vt 0.156250 0.671875 +vt 0.171875 0.671875 +vt 0.187500 0.671875 +vt 0.203125 0.671875 +vt 0.218750 0.671875 +vt 0.234375 0.671875 +vt 0.250000 0.671875 +vt 0.265625 0.671875 +vt 0.281250 0.671875 +vt 0.296875 0.671875 +vt 0.312500 0.671875 +vt 0.328125 0.671875 +vt 0.343750 0.671875 +vt 0.359375 0.671875 +vt 0.375000 0.671875 +vt 0.390625 0.671875 +vt 0.406250 0.671875 +vt 0.421875 0.671875 +vt 0.437500 0.671875 +vt 0.453125 0.671875 +vt 0.468750 0.671875 +vt 0.484375 0.671875 +vt 0.500000 0.671875 +vt 0.515625 0.671875 +vt 0.531250 0.671875 +vt 0.546875 0.671875 +vt 0.562500 0.671875 +vt 0.578125 0.671875 +vt 0.593750 0.671875 +vt 0.609375 0.671875 +vt 0.625000 0.671875 +vt 0.640625 0.671875 +vt 0.656250 0.671875 +vt 0.671875 0.671875 +vt 0.687500 0.671875 +vt 0.703125 0.671875 +vt 0.718750 0.671875 +vt 0.734375 0.671875 +vt 0.750000 0.671875 +vt 0.765625 0.671875 +vt 0.781250 0.671875 +vt 0.796875 0.671875 +vt 0.812500 0.671875 +vt 0.828125 0.671875 +vt 0.843750 0.671875 +vt 0.859375 0.671875 +vt 0.875000 0.671875 +vt 0.890625 0.671875 +vt 0.906250 0.671875 +vt 0.921875 0.671875 +vt 0.937500 0.671875 +vt 0.953125 0.671875 +vt 0.984375 0.656250 +vt 0.968750 0.671875 +vt 0.015625 0.687500 +vt 0.031250 0.687500 +vt 0.046875 0.687500 +vt 0.062500 0.687500 +vt 0.078125 0.687500 +vt 0.093750 0.687500 +vt 0.109375 0.687500 +vt 0.125000 0.687500 +vt 0.140625 0.687500 +vt 0.156250 0.687500 +vt 0.171875 0.687500 +vt 0.187500 0.687500 +vt 0.203125 0.687500 +vt 0.218750 0.687500 +vt 0.234375 0.687500 +vt 0.250000 0.687500 +vt 0.265625 0.687500 +vt 0.281250 0.687500 +vt 0.296875 0.687500 +vt 0.312500 0.687500 +vt 0.328125 0.687500 +vt 0.343750 0.687500 +vt 0.359375 0.687500 +vt 0.375000 0.687500 +vt 0.390625 0.687500 +vt 0.406250 0.687500 +vt 0.421875 0.687500 +vt 0.437500 0.687500 +vt 0.453125 0.687500 +vt 0.468750 0.687500 +vt 0.484375 0.687500 +vt 0.500000 0.687500 +vt 0.515625 0.687500 +vt 0.531250 0.687500 +vt 0.546875 0.687500 +vt 0.562500 0.687500 +vt 0.578125 0.687500 +vt 0.593750 0.687500 +vt 0.609375 0.687500 +vt 0.625000 0.687500 +vt 0.640625 0.687500 +vt 0.656250 0.687500 +vt 0.671875 0.687500 +vt 0.687500 0.687500 +vt 0.703125 0.687500 +vt 0.718750 0.687500 +vt 0.734375 0.687500 +vt 0.750000 0.687500 +vt 0.765625 0.687500 +vt 0.781250 0.687500 +vt 0.796875 0.687500 +vt 0.812500 0.687500 +vt 0.828125 0.687500 +vt 0.843750 0.687500 +vt 0.859375 0.687500 +vt 0.875000 0.687500 +vt 0.890625 0.687500 +vt 0.906250 0.687500 +vt 0.921875 0.687500 +vt 0.937500 0.687500 +vt 0.953125 0.687500 +vt 0.984375 0.671875 +vt 0.968750 0.687500 +vt 0.015625 0.703125 +vt 0.031250 0.703125 +vt 0.046875 0.703125 +vt 0.062500 0.703125 +vt 0.078125 0.703125 +vt 0.093750 0.703125 +vt 0.109375 0.703125 +vt 0.125000 0.703125 +vt 0.140625 0.703125 +vt 0.156250 0.703125 +vt 0.171875 0.703125 +vt 0.187500 0.703125 +vt 0.203125 0.703125 +vt 0.218750 0.703125 +vt 0.234375 0.703125 +vt 0.250000 0.703125 +vt 0.265625 0.703125 +vt 0.281250 0.703125 +vt 0.296875 0.703125 +vt 0.312500 0.703125 +vt 0.328125 0.703125 +vt 0.343750 0.703125 +vt 0.359375 0.703125 +vt 0.375000 0.703125 +vt 0.390625 0.703125 +vt 0.406250 0.703125 +vt 0.421875 0.703125 +vt 0.437500 0.703125 +vt 0.453125 0.703125 +vt 0.468750 0.703125 +vt 0.484375 0.703125 +vt 0.500000 0.703125 +vt 0.515625 0.703125 +vt 0.531250 0.703125 +vt 0.546875 0.703125 +vt 0.562500 0.703125 +vt 0.578125 0.703125 +vt 0.593750 0.703125 +vt 0.609375 0.703125 +vt 0.625000 0.703125 +vt 0.640625 0.703125 +vt 0.656250 0.703125 +vt 0.671875 0.703125 +vt 0.687500 0.703125 +vt 0.703125 0.703125 +vt 0.718750 0.703125 +vt 0.734375 0.703125 +vt 0.750000 0.703125 +vt 0.765625 0.703125 +vt 0.781250 0.703125 +vt 0.796875 0.703125 +vt 0.812500 0.703125 +vt 0.828125 0.703125 +vt 0.843750 0.703125 +vt 0.859375 0.703125 +vt 0.875000 0.703125 +vt 0.890625 0.703125 +vt 0.906250 0.703125 +vt 0.921875 0.703125 +vt 0.937500 0.703125 +vt 0.953125 0.703125 +vt 0.984375 0.687500 +vt 0.968750 0.703125 +vt 0.015625 0.718750 +vt 0.031250 0.718750 +vt 0.046875 0.718750 +vt 0.062500 0.718750 +vt 0.078125 0.718750 +vt 0.093750 0.718750 +vt 0.109375 0.718750 +vt 0.125000 0.718750 +vt 0.140625 0.718750 +vt 0.156250 0.718750 +vt 0.171875 0.718750 +vt 0.187500 0.718750 +vt 0.203125 0.718750 +vt 0.218750 0.718750 +vt 0.234375 0.718750 +vt 0.250000 0.718750 +vt 0.265625 0.718750 +vt 0.281250 0.718750 +vt 0.296875 0.718750 +vt 0.312500 0.718750 +vt 0.328125 0.718750 +vt 0.343750 0.718750 +vt 0.359375 0.718750 +vt 0.375000 0.718750 +vt 0.390625 0.718750 +vt 0.406250 0.718750 +vt 0.421875 0.718750 +vt 0.437500 0.718750 +vt 0.453125 0.718750 +vt 0.468750 0.718750 +vt 0.484375 0.718750 +vt 0.500000 0.718750 +vt 0.515625 0.718750 +vt 0.531250 0.718750 +vt 0.546875 0.718750 +vt 0.562500 0.718750 +vt 0.578125 0.718750 +vt 0.593750 0.718750 +vt 0.609375 0.718750 +vt 0.625000 0.718750 +vt 0.640625 0.718750 +vt 0.656250 0.718750 +vt 0.671875 0.718750 +vt 0.687500 0.718750 +vt 0.703125 0.718750 +vt 0.718750 0.718750 +vt 0.734375 0.718750 +vt 0.750000 0.718750 +vt 0.765625 0.718750 +vt 0.781250 0.718750 +vt 0.796875 0.718750 +vt 0.812500 0.718750 +vt 0.843750 0.718750 +vt 0.828125 0.718750 +vt 0.859375 0.718750 +vt 0.875000 0.718750 +vt 0.890625 0.718750 +vt 0.906250 0.718750 +vt 0.921875 0.718750 +vt 0.937500 0.718750 +vt 0.953125 0.718750 +vt 0.984375 0.703125 +vt 0.968750 0.718750 +vt 0.015625 0.734375 +vt 0.031250 0.734375 +vt 0.046875 0.734375 +vt 0.062500 0.734375 +vt 0.078125 0.734375 +vt 0.093750 0.734375 +vt 0.109375 0.734375 +vt 0.125000 0.734375 +vt 0.140625 0.734375 +vt 0.156250 0.734375 +vt 0.171875 0.734375 +vt 0.187500 0.734375 +vt 0.203125 0.734375 +vt 0.218750 0.734375 +vt 0.234375 0.734375 +vt 0.250000 0.734375 +vt 0.265625 0.734375 +vt 0.281250 0.734375 +vt 0.296875 0.734375 +vt 0.312500 0.734375 +vt 0.328125 0.734375 +vt 0.343750 0.734375 +vt 0.359375 0.734375 +vt 0.375000 0.734375 +vt 0.390625 0.734375 +vt 0.406250 0.734375 +vt 0.421875 0.734375 +vt 0.437500 0.734375 +vt 0.453125 0.734375 +vt 0.468750 0.734375 +vt 0.484375 0.734375 +vt 0.500000 0.734375 +vt 0.515625 0.734375 +vt 0.531250 0.734375 +vt 0.546875 0.734375 +vt 0.562500 0.734375 +vt 0.578125 0.734375 +vt 0.593750 0.734375 +vt 0.609375 0.734375 +vt 0.625000 0.734375 +vt 0.640625 0.734375 +vt 0.656250 0.734375 +vt 0.671875 0.734375 +vt 0.687500 0.734375 +vt 0.703125 0.734375 +vt 0.718750 0.734375 +vt 0.734375 0.734375 +vt 0.750000 0.734375 +vt 0.765625 0.734375 +vt 0.781250 0.734375 +vt 0.796875 0.734375 +vt 0.812500 0.734375 +vt 0.828125 0.734375 +vt 0.843750 0.734375 +vt 0.859375 0.734375 +vt 0.875000 0.734375 +vt 0.890625 0.734375 +vt 0.906250 0.734375 +vt 0.921875 0.734375 +vt 0.937500 0.734375 +vt 0.953125 0.734375 +vt 0.984375 0.718750 +vt 0.968750 0.734375 +vt 0.015625 0.750000 +vt 0.031250 0.750000 +vt 0.046875 0.750000 +vt 0.062500 0.750000 +vt 0.078125 0.750000 +vt 0.093750 0.750000 +vt 0.109375 0.750000 +vt 0.125000 0.750000 +vt 0.140625 0.750000 +vt 0.156250 0.750000 +vt 0.171875 0.750000 +vt 0.187500 0.750000 +vt 0.203125 0.750000 +vt 0.218750 0.750000 +vt 0.234375 0.750000 +vt 0.250000 0.750000 +vt 0.265625 0.750000 +vt 0.281250 0.750000 +vt 0.296875 0.750000 +vt 0.312500 0.750000 +vt 0.328125 0.750000 +vt 0.343750 0.750000 +vt 0.359375 0.750000 +vt 0.375000 0.750000 +vt 0.390625 0.750000 +vt 0.406250 0.750000 +vt 0.421875 0.750000 +vt 0.437500 0.750000 +vt 0.453125 0.750000 +vt 0.468750 0.750000 +vt 0.484375 0.750000 +vt 0.500000 0.750000 +vt 0.515625 0.750000 +vt 0.531250 0.750000 +vt 0.546875 0.750000 +vt 0.562500 0.750000 +vt 0.578125 0.750000 +vt 0.593750 0.750000 +vt 0.609375 0.750000 +vt 0.625000 0.750000 +vt 0.640625 0.750000 +vt 0.656250 0.750000 +vt 0.671875 0.750000 +vt 0.687500 0.750000 +vt 0.703125 0.750000 +vt 0.718750 0.750000 +vt 0.734375 0.750000 +vt 0.750000 0.750000 +vt 0.765625 0.750000 +vt 0.781250 0.750000 +vt 0.796875 0.750000 +vt 0.812500 0.750000 +vt 0.828125 0.750000 +vt 0.843750 0.750000 +vt 0.859375 0.750000 +vt 0.875000 0.750000 +vt 0.890625 0.750000 +vt 0.906250 0.750000 +vt 0.921875 0.750000 +vt 0.937500 0.750000 +vt 0.953125 0.750000 +vt 0.984375 0.734375 +vt 0.968750 0.750000 +vt 0.015625 0.765625 +vt 0.031250 0.765625 +vt 0.046875 0.765625 +vt 0.062500 0.765625 +vt 0.078125 0.765625 +vt 0.093750 0.765625 +vt 0.109375 0.765625 +vt 0.125000 0.765625 +vt 0.140625 0.765625 +vt 0.156250 0.765625 +vt 0.171875 0.765625 +vt 0.187500 0.765625 +vt 0.203125 0.765625 +vt 0.218750 0.765625 +vt 0.234375 0.765625 +vt 0.250000 0.765625 +vt 0.265625 0.765625 +vt 0.281250 0.765625 +vt 0.296875 0.765625 +vt 0.312500 0.765625 +vt 0.328125 0.765625 +vt 0.343750 0.765625 +vt 0.359375 0.765625 +vt 0.375000 0.765625 +vt 0.390625 0.765625 +vt 0.406250 0.765625 +vt 0.421875 0.765625 +vt 0.437500 0.765625 +vt 0.453125 0.765625 +vt 0.468750 0.765625 +vt 0.484375 0.765625 +vt 0.500000 0.765625 +vt 0.515625 0.765625 +vt 0.531250 0.765625 +vt 0.546875 0.765625 +vt 0.562500 0.765625 +vt 0.578125 0.765625 +vt 0.593750 0.765625 +vt 0.609375 0.765625 +vt 0.625000 0.765625 +vt 0.640625 0.765625 +vt 0.656250 0.765625 +vt 0.671875 0.765625 +vt 0.687500 0.765625 +vt 0.703125 0.765625 +vt 0.718750 0.765625 +vt 0.734375 0.765625 +vt 0.750000 0.765625 +vt 0.765625 0.765625 +vt 0.781250 0.765625 +vt 0.796875 0.765625 +vt 0.812500 0.765625 +vt 0.828125 0.765625 +vt 0.843750 0.765625 +vt 0.859375 0.765625 +vt 0.875000 0.765625 +vt 0.890625 0.765625 +vt 0.906250 0.765625 +vt 0.921875 0.765625 +vt 0.937500 0.765625 +vt 0.953125 0.765625 +vt 0.984375 0.750000 +vt 0.968750 0.765625 +vt 0.015625 0.781250 +vt 0.031250 0.781250 +vt 0.046875 0.781250 +vt 0.062500 0.781250 +vt 0.078125 0.781250 +vt 0.093750 0.781250 +vt 0.109375 0.781250 +vt 0.125000 0.781250 +vt 0.140625 0.781250 +vt 0.156250 0.781250 +vt 0.171875 0.781250 +vt 0.187500 0.781250 +vt 0.203125 0.781250 +vt 0.218750 0.781250 +vt 0.234375 0.781250 +vt 0.250000 0.781250 +vt 0.265625 0.781250 +vt 0.281250 0.781250 +vt 0.296875 0.781250 +vt 0.312500 0.781250 +vt 0.328125 0.781250 +vt 0.343750 0.781250 +vt 0.359375 0.781250 +vt 0.375000 0.781250 +vt 0.390625 0.781250 +vt 0.406250 0.781250 +vt 0.421875 0.781250 +vt 0.437500 0.781250 +vt 0.453125 0.781250 +vt 0.468750 0.781250 +vt 0.484375 0.781250 +vt 0.500000 0.781250 +vt 0.515625 0.781250 +vt 0.531250 0.781250 +vt 0.546875 0.781250 +vt 0.562500 0.781250 +vt 0.578125 0.781250 +vt 0.593750 0.781250 +vt 0.609375 0.781250 +vt 0.625000 0.781250 +vt 0.640625 0.781250 +vt 0.656250 0.781250 +vt 0.671875 0.781250 +vt 0.687500 0.781250 +vt 0.703125 0.781250 +vt 0.718750 0.781250 +vt 0.734375 0.781250 +vt 0.750000 0.781250 +vt 0.765625 0.781250 +vt 0.781250 0.781250 +vt 0.796875 0.781250 +vt 0.812500 0.781250 +vt 0.828125 0.781250 +vt 0.843750 0.781250 +vt 0.859375 0.781250 +vt 0.875000 0.781250 +vt 0.890625 0.781250 +vt 0.906250 0.781250 +vt 0.921875 0.781250 +vt 0.937500 0.781250 +vt 0.953125 0.781250 +vt 0.984375 0.765625 +vt 0.968750 0.781250 +vt 0.015625 0.796875 +vt 0.031250 0.796875 +vt 0.046875 0.796875 +vt 0.062500 0.796875 +vt 0.078125 0.796875 +vt 0.093750 0.796875 +vt 0.109375 0.796875 +vt 0.125000 0.796875 +vt 0.140625 0.796875 +vt 0.156250 0.796875 +vt 0.171875 0.796875 +vt 0.187500 0.796875 +vt 0.203125 0.796875 +vt 0.218750 0.796875 +vt 0.234375 0.796875 +vt 0.250000 0.796875 +vt 0.265625 0.796875 +vt 0.281250 0.796875 +vt 0.296875 0.796875 +vt 0.312500 0.796875 +vt 0.328125 0.796875 +vt 0.343750 0.796875 +vt 0.359375 0.796875 +vt 0.375000 0.796875 +vt 0.390625 0.796875 +vt 0.406250 0.796875 +vt 0.421875 0.796875 +vt 0.437500 0.796875 +vt 0.453125 0.796875 +vt 0.468750 0.796875 +vt 0.484375 0.796875 +vt 0.500000 0.796875 +vt 0.515625 0.796875 +vt 0.531250 0.796875 +vt 0.546875 0.796875 +vt 0.562500 0.796875 +vt 0.578125 0.796875 +vt 0.593750 0.796875 +vt 0.609375 0.796875 +vt 0.625000 0.796875 +vt 0.640625 0.796875 +vt 0.656250 0.796875 +vt 0.671875 0.796875 +vt 0.687500 0.796875 +vt 0.703125 0.796875 +vt 0.718750 0.796875 +vt 0.734375 0.796875 +vt 0.750000 0.796875 +vt 0.765625 0.796875 +vt 0.781250 0.796875 +vt 0.796875 0.796875 +vt 0.812500 0.796875 +vt 0.828125 0.796875 +vt 0.843750 0.796875 +vt 0.859375 0.796875 +vt 0.875000 0.796875 +vt 0.890625 0.796875 +vt 0.906250 0.796875 +vt 0.921875 0.796875 +vt 0.937500 0.796875 +vt 0.953125 0.796875 +vt 0.984375 0.781250 +vt 0.968750 0.796875 +vt 0.015625 0.812500 +vt 0.031250 0.812500 +vt 0.046875 0.812500 +vt 0.062500 0.812500 +vt 0.078125 0.812500 +vt 0.093750 0.812500 +vt 0.109375 0.812500 +vt 0.125000 0.812500 +vt 0.140625 0.812500 +vt 0.156250 0.812500 +vt 0.171875 0.812500 +vt 0.187500 0.812500 +vt 0.203125 0.812500 +vt 0.218750 0.812500 +vt 0.234375 0.812500 +vt 0.250000 0.812500 +vt 0.265625 0.812500 +vt 0.281250 0.812500 +vt 0.296875 0.812500 +vt 0.312500 0.812500 +vt 0.328125 0.812500 +vt 0.343750 0.812500 +vt 0.359375 0.812500 +vt 0.375000 0.812500 +vt 0.390625 0.812500 +vt 0.406250 0.812500 +vt 0.421875 0.812500 +vt 0.437500 0.812500 +vt 0.453125 0.812500 +vt 0.468750 0.812500 +vt 0.484375 0.812500 +vt 0.500000 0.812500 +vt 0.515625 0.812500 +vt 0.531250 0.812500 +vt 0.546875 0.812500 +vt 0.562500 0.812500 +vt 0.578125 0.812500 +vt 0.593750 0.812500 +vt 0.609375 0.812500 +vt 0.625000 0.812500 +vt 0.640625 0.812500 +vt 0.656250 0.812500 +vt 0.671875 0.812500 +vt 0.687500 0.812500 +vt 0.703125 0.812500 +vt 0.718750 0.812500 +vt 0.734375 0.812500 +vt 0.750000 0.812500 +vt 0.765625 0.812500 +vt 0.781250 0.812500 +vt 0.796875 0.812500 +vt 0.812500 0.812500 +vt 0.828125 0.812500 +vt 0.843750 0.812500 +vt 0.859375 0.812500 +vt 0.875000 0.812500 +vt 0.890625 0.812500 +vt 0.906250 0.812500 +vt 0.921875 0.812500 +vt 0.937500 0.812500 +vt 0.953125 0.812500 +vt 0.984375 0.796875 +vt 0.968750 0.812500 +vt 0.015625 0.828125 +vt 0.031250 0.828125 +vt 0.046875 0.828125 +vt 0.062500 0.828125 +vt 0.078125 0.828125 +vt 0.093750 0.828125 +vt 0.109375 0.828125 +vt 0.125000 0.828125 +vt 0.140625 0.828125 +vt 0.156250 0.828125 +vt 0.171875 0.828125 +vt 0.187500 0.828125 +vt 0.203125 0.828125 +vt 0.218750 0.828125 +vt 0.234375 0.828125 +vt 0.250000 0.828125 +vt 0.265625 0.828125 +vt 0.281250 0.828125 +vt 0.296875 0.828125 +vt 0.312500 0.828125 +vt 0.328125 0.828125 +vt 0.343750 0.828125 +vt 0.359375 0.828125 +vt 0.375000 0.828125 +vt 0.390625 0.828125 +vt 0.406250 0.828125 +vt 0.421875 0.828125 +vt 0.437500 0.828125 +vt 0.453125 0.828125 +vt 0.468750 0.828125 +vt 0.484375 0.828125 +vt 0.500000 0.828125 +vt 0.515625 0.828125 +vt 0.531250 0.828125 +vt 0.546875 0.828125 +vt 0.562500 0.828125 +vt 0.578125 0.828125 +vt 0.593750 0.828125 +vt 0.609375 0.828125 +vt 0.625000 0.828125 +vt 0.640625 0.828125 +vt 0.656250 0.828125 +vt 0.671875 0.828125 +vt 0.687500 0.828125 +vt 0.703125 0.828125 +vt 0.718750 0.828125 +vt 0.734375 0.828125 +vt 0.750000 0.828125 +vt 0.765625 0.828125 +vt 0.781250 0.828125 +vt 0.796875 0.828125 +vt 0.812500 0.828125 +vt 0.828125 0.828125 +vt 0.843750 0.828125 +vt 0.859375 0.828125 +vt 0.875000 0.828125 +vt 0.890625 0.828125 +vt 0.906250 0.828125 +vt 0.921875 0.828125 +vt 0.937500 0.828125 +vt 0.953125 0.828125 +vt 0.984375 0.812500 +vt 0.968750 0.828125 +vt 0.015625 0.843750 +vt 0.031250 0.843750 +vt 0.046875 0.843750 +vt 0.062500 0.843750 +vt 0.078125 0.843750 +vt 0.093750 0.843750 +vt 0.109375 0.843750 +vt 0.125000 0.843750 +vt 0.140625 0.843750 +vt 0.156250 0.843750 +vt 0.171875 0.843750 +vt 0.187500 0.843750 +vt 0.203125 0.843750 +vt 0.218750 0.843750 +vt 0.234375 0.843750 +vt 0.250000 0.843750 +vt 0.265625 0.843750 +vt 0.281250 0.843750 +vt 0.296875 0.843750 +vt 0.312500 0.843750 +vt 0.328125 0.843750 +vt 0.343750 0.843750 +vt 0.359375 0.843750 +vt 0.375000 0.843750 +vt 0.390625 0.843750 +vt 0.406250 0.843750 +vt 0.421875 0.843750 +vt 0.437500 0.843750 +vt 0.453125 0.843750 +vt 0.468750 0.843750 +vt 0.484375 0.843750 +vt 0.500000 0.843750 +vt 0.515625 0.843750 +vt 0.531250 0.843750 +vt 0.546875 0.843750 +vt 0.562500 0.843750 +vt 0.578125 0.843750 +vt 0.593750 0.843750 +vt 0.609375 0.843750 +vt 0.625000 0.843750 +vt 0.640625 0.843750 +vt 0.656250 0.843750 +vt 0.671875 0.843750 +vt 0.687500 0.843750 +vt 0.703125 0.843750 +vt 0.718750 0.843750 +vt 0.734375 0.843750 +vt 0.750000 0.843750 +vt 0.765625 0.843750 +vt 0.781250 0.843750 +vt 0.796875 0.843750 +vt 0.812500 0.843750 +vt 0.828125 0.843750 +vt 0.843750 0.843750 +vt 0.859375 0.843750 +vt 0.875000 0.843750 +vt 0.890625 0.843750 +vt 0.906250 0.843750 +vt 0.921875 0.843750 +vt 0.937500 0.843750 +vt 0.953125 0.843750 +vt 0.984375 0.828125 +vt 0.968750 0.843750 +vt 0.015625 0.859375 +vt 0.031250 0.859375 +vt 0.046875 0.859375 +vt 0.062500 0.859375 +vt 0.078125 0.859375 +vt 0.093750 0.859375 +vt 0.109375 0.859375 +vt 0.125000 0.859375 +vt 0.140625 0.859375 +vt 0.156250 0.859375 +vt 0.171875 0.859375 +vt 0.187500 0.859375 +vt 0.203125 0.859375 +vt 0.218750 0.859375 +vt 0.234375 0.859375 +vt 0.250000 0.859375 +vt 0.265625 0.859375 +vt 0.281250 0.859375 +vt 0.296875 0.859375 +vt 0.312500 0.859375 +vt 0.328125 0.859375 +vt 0.343750 0.859375 +vt 0.359375 0.859375 +vt 0.375000 0.859375 +vt 0.390625 0.859375 +vt 0.406250 0.859375 +vt 0.421875 0.859375 +vt 0.437500 0.859375 +vt 0.453125 0.859375 +vt 0.468750 0.859375 +vt 0.484375 0.859375 +vt 0.500000 0.859375 +vt 0.515625 0.859375 +vt 0.531250 0.859375 +vt 0.546875 0.859375 +vt 0.562500 0.859375 +vt 0.578125 0.859375 +vt 0.593750 0.859375 +vt 0.609375 0.859375 +vt 0.625000 0.859375 +vt 0.640625 0.859375 +vt 0.656250 0.859375 +vt 0.671875 0.859375 +vt 0.687500 0.859375 +vt 0.703125 0.859375 +vt 0.718750 0.859375 +vt 0.734375 0.859375 +vt 0.750000 0.859375 +vt 0.765625 0.859375 +vt 0.781250 0.859375 +vt 0.796875 0.859375 +vt 0.812500 0.859375 +vt 0.828125 0.859375 +vt 0.843750 0.859375 +vt 0.859375 0.859375 +vt 0.875000 0.859375 +vt 0.890625 0.859375 +vt 0.906250 0.859375 +vt 0.921875 0.859375 +vt 0.937500 0.859375 +vt 0.953125 0.859375 +vt 0.984375 0.843750 +vt 0.968750 0.859375 +vt 0.015625 0.875000 +vt 0.031250 0.875000 +vt 0.046875 0.875000 +vt 0.062500 0.875000 +vt 0.078125 0.875000 +vt 0.093750 0.875000 +vt 0.109375 0.875000 +vt 0.125000 0.875000 +vt 0.140625 0.875000 +vt 0.156250 0.875000 +vt 0.171875 0.875000 +vt 0.187500 0.875000 +vt 0.203125 0.875000 +vt 0.218750 0.875000 +vt 0.234375 0.875000 +vt 0.250000 0.875000 +vt 0.265625 0.875000 +vt 0.281250 0.875000 +vt 0.296875 0.875000 +vt 0.312500 0.875000 +vt 0.328125 0.875000 +vt 0.343750 0.875000 +vt 0.359375 0.875000 +vt 0.375000 0.875000 +vt 0.390625 0.875000 +vt 0.406250 0.875000 +vt 0.421875 0.875000 +vt 0.437500 0.875000 +vt 0.453125 0.875000 +vt 0.468750 0.875000 +vt 0.484375 0.875000 +vt 0.500000 0.875000 +vt 0.515625 0.875000 +vt 0.531250 0.875000 +vt 0.546875 0.875000 +vt 0.562500 0.875000 +vt 0.578125 0.875000 +vt 0.593750 0.875000 +vt 0.609375 0.875000 +vt 0.625000 0.875000 +vt 0.640625 0.875000 +vt 0.656250 0.875000 +vt 0.671875 0.875000 +vt 0.687500 0.875000 +vt 0.703125 0.875000 +vt 0.718750 0.875000 +vt 0.734375 0.875000 +vt 0.750000 0.875000 +vt 0.765625 0.875000 +vt 0.781250 0.875000 +vt 0.796875 0.875000 +vt 0.812500 0.875000 +vt 0.828125 0.875000 +vt 0.843750 0.875000 +vt 0.859375 0.875000 +vt 0.875000 0.875000 +vt 0.890625 0.875000 +vt 0.906250 0.875000 +vt 0.921875 0.875000 +vt 0.937500 0.875000 +vt 0.953125 0.875000 +vt 0.984375 0.859375 +vt 0.968750 0.875000 +vt 0.015625 0.890625 +vt 0.031250 0.890625 +vt 0.046875 0.890625 +vt 0.062500 0.890625 +vt 0.078125 0.890625 +vt 0.093750 0.890625 +vt 0.109375 0.890625 +vt 0.125000 0.890625 +vt 0.140625 0.890625 +vt 0.156250 0.890625 +vt 0.171875 0.890625 +vt 0.187500 0.890625 +vt 0.203125 0.890625 +vt 0.218750 0.890625 +vt 0.234375 0.890625 +vt 0.250000 0.890625 +vt 0.265625 0.890625 +vt 0.281250 0.890625 +vt 0.296875 0.890625 +vt 0.312500 0.890625 +vt 0.328125 0.890625 +vt 0.343750 0.890625 +vt 0.359375 0.890625 +vt 0.375000 0.890625 +vt 0.390625 0.890625 +vt 0.406250 0.890625 +vt 0.421875 0.890625 +vt 0.437500 0.890625 +vt 0.453125 0.890625 +vt 0.468750 0.890625 +vt 0.484375 0.890625 +vt 0.500000 0.890625 +vt 0.515625 0.890625 +vt 0.531250 0.890625 +vt 0.546875 0.890625 +vt 0.562500 0.890625 +vt 0.578125 0.890625 +vt 0.593750 0.890625 +vt 0.609375 0.890625 +vt 0.625000 0.890625 +vt 0.640625 0.890625 +vt 0.656250 0.890625 +vt 0.671875 0.890625 +vt 0.687500 0.890625 +vt 0.703125 0.890625 +vt 0.718750 0.890625 +vt 0.734375 0.890625 +vt 0.750000 0.890625 +vt 0.765625 0.890625 +vt 0.781250 0.890625 +vt 0.796875 0.890625 +vt 0.828125 0.890625 +vt 0.812500 0.890625 +vt 0.843750 0.890625 +vt 0.859375 0.890625 +vt 0.875000 0.890625 +vt 0.890625 0.890625 +vt 0.906250 0.890625 +vt 0.921875 0.890625 +vt 0.937500 0.890625 +vt 0.953125 0.890625 +vt 0.984375 0.875000 +vt 0.968750 0.890625 +vt 0.015625 0.906250 +vt 0.031250 0.906250 +vt 0.046875 0.906250 +vt 0.062500 0.906250 +vt 0.078125 0.906250 +vt 0.093750 0.906250 +vt 0.109375 0.906250 +vt 0.125000 0.906250 +vt 0.140625 0.906250 +vt 0.156250 0.906250 +vt 0.171875 0.906250 +vt 0.187500 0.906250 +vt 0.203125 0.906250 +vt 0.218750 0.906250 +vt 0.234375 0.906250 +vt 0.250000 0.906250 +vt 0.265625 0.906250 +vt 0.281250 0.906250 +vt 0.296875 0.906250 +vt 0.312500 0.906250 +vt 0.328125 0.906250 +vt 0.343750 0.906250 +vt 0.359375 0.906250 +vt 0.375000 0.906250 +vt 0.390625 0.906250 +vt 0.406250 0.906250 +vt 0.421875 0.906250 +vt 0.437500 0.906250 +vt 0.453125 0.906250 +vt 0.468750 0.906250 +vt 0.484375 0.906250 +vt 0.500000 0.906250 +vt 0.515625 0.906250 +vt 0.531250 0.906250 +vt 0.546875 0.906250 +vt 0.562500 0.906250 +vt 0.578125 0.906250 +vt 0.593750 0.906250 +vt 0.609375 0.906250 +vt 0.625000 0.906250 +vt 0.640625 0.906250 +vt 0.656250 0.906250 +vt 0.671875 0.906250 +vt 0.687500 0.906250 +vt 0.703125 0.906250 +vt 0.718750 0.906250 +vt 0.734375 0.906250 +vt 0.750000 0.906250 +vt 0.765625 0.906250 +vt 0.781250 0.906250 +vt 0.796875 0.906250 +vt 0.812500 0.906250 +vt 0.828125 0.906250 +vt 0.843750 0.906250 +vt 0.859375 0.906250 +vt 0.875000 0.906250 +vt 0.890625 0.906250 +vt 0.906250 0.906250 +vt 0.921875 0.906250 +vt 0.937500 0.906250 +vt 0.953125 0.906250 +vt 0.984375 0.890625 +vt 0.968750 0.906250 +vt 0.015625 0.921875 +vt 0.031250 0.921875 +vt 0.046875 0.921875 +vt 0.062500 0.921875 +vt 0.078125 0.921875 +vt 0.093750 0.921875 +vt 0.109375 0.921875 +vt 0.125000 0.921875 +vt 0.140625 0.921875 +vt 0.156250 0.921875 +vt 0.171875 0.921875 +vt 0.187500 0.921875 +vt 0.203125 0.921875 +vt 0.218750 0.921875 +vt 0.234375 0.921875 +vt 0.250000 0.921875 +vt 0.265625 0.921875 +vt 0.281250 0.921875 +vt 0.296875 0.921875 +vt 0.312500 0.921875 +vt 0.328125 0.921875 +vt 0.343750 0.921875 +vt 0.359375 0.921875 +vt 0.375000 0.921875 +vt 0.390625 0.921875 +vt 0.406250 0.921875 +vt 0.421875 0.921875 +vt 0.437500 0.921875 +vt 0.453125 0.921875 +vt 0.468750 0.921875 +vt 0.484375 0.921875 +vt 0.500000 0.921875 +vt 0.515625 0.921875 +vt 0.531250 0.921875 +vt 0.546875 0.921875 +vt 0.562500 0.921875 +vt 0.578125 0.921875 +vt 0.593750 0.921875 +vt 0.609375 0.921875 +vt 0.625000 0.921875 +vt 0.640625 0.921875 +vt 0.656250 0.921875 +vt 0.671875 0.921875 +vt 0.687500 0.921875 +vt 0.703125 0.921875 +vt 0.718750 0.921875 +vt 0.734375 0.921875 +vt 0.750000 0.921875 +vt 0.765625 0.921875 +vt 0.781250 0.921875 +vt 0.796875 0.921875 +vt 0.812500 0.921875 +vt 0.828125 0.921875 +vt 0.843750 0.921875 +vt 0.859375 0.921875 +vt 0.875000 0.921875 +vt 0.890625 0.921875 +vt 0.906250 0.921875 +vt 0.921875 0.921875 +vt 0.937500 0.921875 +vt 0.953125 0.921875 +vt 0.984375 0.906250 +vt 0.968750 0.921875 +vt 0.015625 0.937500 +vt 0.031250 0.937500 +vt 0.046875 0.937500 +vt 0.062500 0.937500 +vt 0.078125 0.937500 +vt 0.093750 0.937500 +vt 0.109375 0.937500 +vt 0.125000 0.937500 +vt 0.140625 0.937500 +vt 0.156250 0.937500 +vt 0.171875 0.937500 +vt 0.187500 0.937500 +vt 0.203125 0.937500 +vt 0.218750 0.937500 +vt 0.234375 0.937500 +vt 0.250000 0.937500 +vt 0.265625 0.937500 +vt 0.281250 0.937500 +vt 0.296875 0.937500 +vt 0.312500 0.937500 +vt 0.328125 0.937500 +vt 0.343750 0.937500 +vt 0.359375 0.937500 +vt 0.375000 0.937500 +vt 0.390625 0.937500 +vt 0.406250 0.937500 +vt 0.421875 0.937500 +vt 0.437500 0.937500 +vt 0.453125 0.937500 +vt 0.468750 0.937500 +vt 0.484375 0.937500 +vt 0.500000 0.937500 +vt 0.515625 0.937500 +vt 0.531250 0.937500 +vt 0.546875 0.937500 +vt 0.562500 0.937500 +vt 0.578125 0.937500 +vt 0.593750 0.937500 +vt 0.609375 0.937500 +vt 0.625000 0.937500 +vt 0.640625 0.937500 +vt 0.656250 0.937500 +vt 0.671875 0.937500 +vt 0.687500 0.937500 +vt 0.703125 0.937500 +vt 0.718750 0.937500 +vt 0.734375 0.937500 +vt 0.750000 0.937500 +vt 0.765625 0.937500 +vt 0.781250 0.937500 +vt 0.796875 0.937500 +vt 0.812500 0.937500 +vt 0.828125 0.937500 +vt 0.843750 0.937500 +vt 0.859375 0.937500 +vt 0.875000 0.937500 +vt 0.890625 0.937500 +vt 0.906250 0.937500 +vt 0.921875 0.937500 +vt 0.937500 0.937500 +vt 0.953125 0.937500 +vt 0.984375 0.921875 +vt 0.968750 0.937500 +vt 0.015625 0.953125 +vt 0.031250 0.953125 +vt 0.046875 0.953125 +vt 0.062500 0.953125 +vt 0.078125 0.953125 +vt 0.093750 0.953125 +vt 0.109375 0.953125 +vt 0.125000 0.953125 +vt 0.140625 0.953125 +vt 0.156250 0.953125 +vt 0.171875 0.953125 +vt 0.187500 0.953125 +vt 0.203125 0.953125 +vt 0.218750 0.953125 +vt 0.234375 0.953125 +vt 0.250000 0.953125 +vt 0.265625 0.953125 +vt 0.281250 0.953125 +vt 0.296875 0.953125 +vt 0.312500 0.953125 +vt 0.328125 0.953125 +vt 0.343750 0.953125 +vt 0.359375 0.953125 +vt 0.375000 0.953125 +vt 0.390625 0.953125 +vt 0.406250 0.953125 +vt 0.421875 0.953125 +vt 0.437500 0.953125 +vt 0.453125 0.953125 +vt 0.468750 0.953125 +vt 0.484375 0.953125 +vt 0.500000 0.953125 +vt 0.515625 0.953125 +vt 0.531250 0.953125 +vt 0.546875 0.953125 +vt 0.562500 0.953125 +vt 0.578125 0.953125 +vt 0.593750 0.953125 +vt 0.609375 0.953125 +vt 0.625000 0.953125 +vt 0.640625 0.953125 +vt 0.656250 0.953125 +vt 0.671875 0.953125 +vt 0.687500 0.953125 +vt 0.703125 0.953125 +vt 0.718750 0.953125 +vt 0.734375 0.953125 +vt 0.750000 0.953125 +vt 0.765625 0.953125 +vt 0.781250 0.953125 +vt 0.796875 0.953125 +vt 0.812500 0.953125 +vt 0.828125 0.953125 +vt 0.843750 0.953125 +vt 0.859375 0.953125 +vt 0.875000 0.953125 +vt 0.890625 0.953125 +vt 0.906250 0.953125 +vt 0.921875 0.953125 +vt 0.937500 0.953125 +vt 0.953125 0.953125 +vt 0.984375 0.937500 +vt 0.968750 0.953125 +vt 0.015625 0.968750 +vt 0.031250 0.968750 +vt 0.046875 0.968750 +vt 0.062500 0.968750 +vt 0.078125 0.968750 +vt 0.093750 0.968750 +vt 0.109375 0.968750 +vt 0.125000 0.968750 +vt 0.140625 0.968750 +vt 0.156250 0.968750 +vt 0.171875 0.968750 +vt 0.187500 0.968750 +vt 0.203125 0.968750 +vt 0.218750 0.968750 +vt 0.234375 0.968750 +vt 0.250000 0.968750 +vt 0.265625 0.968750 +vt 0.281250 0.968750 +vt 0.296875 0.968750 +vt 0.312500 0.968750 +vt 0.328125 0.968750 +vt 0.343750 0.968750 +vt 0.359375 0.968750 +vt 0.375000 0.968750 +vt 0.390625 0.968750 +vt 0.406250 0.968750 +vt 0.421875 0.968750 +vt 0.437500 0.968750 +vt 0.453125 0.968750 +vt 0.468750 0.968750 +vt 0.484375 0.968750 +vt 0.500000 0.968750 +vt 0.515625 0.968750 +vt 0.531250 0.968750 +vt 0.546875 0.968750 +vt 0.562500 0.968750 +vt 0.578125 0.968750 +vt 0.593750 0.968750 +vt 0.609375 0.968750 +vt 0.625000 0.968750 +vt 0.640625 0.968750 +vt 0.656250 0.968750 +vt 0.671875 0.968750 +vt 0.687500 0.968750 +vt 0.703125 0.968750 +vt 0.718750 0.968750 +vt 0.734375 0.968750 +vt 0.750000 0.968750 +vt 0.765625 0.968750 +vt 0.781250 0.968750 +vt 0.796875 0.968750 +vt 0.812500 0.968750 +vt 0.828125 0.968750 +vt 0.843750 0.968750 +vt 0.859375 0.968750 +vt 0.875000 0.968750 +vt 0.890625 0.968750 +vt 0.906250 0.968750 +vt 0.921875 0.968750 +vt 0.937500 0.968750 +vt 0.953125 0.968750 +vt 0.984375 0.953125 +vt 0.968750 0.968750 +vt 0.015625 0.984375 +vt 0.031250 0.984375 +vt 0.046875 0.984375 +vt 0.062500 0.984375 +vt 0.078125 0.984375 +vt 0.093750 0.984375 +vt 0.109375 0.984375 +vt 0.125000 0.984375 +vt 0.140625 0.984375 +vt 0.156250 0.984375 +vt 0.171875 0.984375 +vt 0.187500 0.984375 +vt 0.203125 0.984375 +vt 0.218750 0.984375 +vt 0.234375 0.984375 +vt 0.250000 0.984375 +vt 0.265625 0.984375 +vt 0.281250 0.984375 +vt 0.296875 0.984375 +vt 0.312500 0.984375 +vt 0.328125 0.984375 +vt 0.343750 0.984375 +vt 0.359375 0.984375 +vt 0.375000 0.984375 +vt 0.390625 0.984375 +vt 0.406250 0.984375 +vt 0.421875 0.984375 +vt 0.437500 0.984375 +vt 0.453125 0.984375 +vt 0.468750 0.984375 +vt 0.484375 0.984375 +vt 0.500000 0.984375 +vt 0.515625 0.984375 +vt 0.531250 0.984375 +vt 0.546875 0.984375 +vt 0.562500 0.984375 +vt 0.578125 0.984375 +vt 0.593750 0.984375 +vt 0.609375 0.984375 +vt 0.625000 0.984375 +vt 0.640625 0.984375 +vt 0.656250 0.984375 +vt 0.671875 0.984375 +vt 0.687500 0.984375 +vt 0.703125 0.984375 +vt 0.718750 0.984375 +vt 0.734375 0.984375 +vt 0.750000 0.984375 +vt 0.765625 0.984375 +vt 0.781250 0.984375 +vt 0.796875 0.984375 +vt 0.812500 0.984375 +vt 0.828125 0.984375 +vt 0.843750 0.984375 +vt 0.859375 0.984375 +vt 0.875000 0.984375 +vt 0.890625 0.984375 +vt 0.906250 0.984375 +vt 0.921875 0.984375 +vt 0.937500 0.984375 +vt 0.953125 0.984375 +vt 0.984375 0.968750 +vt 0.968750 0.984375 +vt 0.015625 0.000000 +vt 0.000000 0.015625 +vt 0.000000 0.000000 +vt 0.031250 0.000000 +vt 0.046875 0.000000 +vt 0.062500 0.000000 +vt 0.078125 0.000000 +vt 0.093750 0.000000 +vt 0.109375 0.000000 +vt 0.125000 0.000000 +vt 0.140625 0.000000 +vt 0.156250 0.000000 +vt 0.171875 0.000000 +vt 0.187500 0.000000 +vt 0.203125 0.000000 +vt 0.218750 0.000000 +vt 0.234375 0.000000 +vt 0.250000 0.000000 +vt 0.265625 0.000000 +vt 0.281250 0.000000 +vt 0.296875 0.000000 +vt 0.312500 0.000000 +vt 0.328125 0.000000 +vt 0.343750 0.000000 +vt 0.359375 0.000000 +vt 0.375000 0.000000 +vt 0.390625 0.000000 +vt 0.406250 0.000000 +vt 0.421875 0.000000 +vt 0.437500 0.000000 +vt 0.453125 0.000000 +vt 0.468750 0.000000 +vt 0.484375 0.000000 +vt 0.500000 0.000000 +vt 0.515625 0.000000 +vt 0.531250 0.000000 +vt 0.546875 0.000000 +vt 0.562500 0.000000 +vt 0.578125 0.000000 +vt 0.593750 0.000000 +vt 0.609375 0.000000 +vt 0.625000 0.000000 +vt 0.640625 0.000000 +vt 0.656250 0.000000 +vt 0.671875 0.000000 +vt 0.687500 0.000000 +vt 0.703125 0.000000 +vt 0.718750 0.000000 +vt 0.734375 0.000000 +vt 0.750000 0.000000 +vt 0.765625 0.000000 +vt 0.781250 0.000000 +vt 0.796875 0.000000 +vt 0.812500 0.000000 +vt 0.828125 0.000000 +vt 0.843750 0.000000 +vt 0.859375 0.000000 +vt 0.875000 0.000000 +vt 0.890625 0.000000 +vt 0.906250 0.000000 +vt 0.921875 0.000000 +vt 0.937500 0.000000 +vt 0.953125 0.000000 +vt 0.968750 0.000000 +vt 0.984375 0.000000 +vt 1.000000 0.000000 +vt 1.000000 0.015625 +vt 1.000000 0.031250 +vt 1.000000 0.046875 +vt 1.000000 0.062500 +vt 1.000000 0.078125 +vt 1.000000 0.093750 +vt 1.000000 0.109375 +vt 1.000000 0.125000 +vt 1.000000 0.140625 +vt 1.000000 0.156250 +vt 1.000000 0.171875 +vt 1.000000 0.187500 +vt 1.000000 0.203125 +vt 1.000000 0.218750 +vt 1.000000 0.234375 +vt 1.000000 0.250000 +vt 1.000000 0.265625 +vt 1.000000 0.281250 +vt 1.000000 0.296875 +vt 1.000000 0.312500 +vt 1.000000 0.328125 +vt 1.000000 0.343750 +vt 1.000000 0.359375 +vt 1.000000 0.375000 +vt 1.000000 0.390625 +vt 1.000000 0.406250 +vt 1.000000 0.421875 +vt 1.000000 0.437500 +vt 1.000000 0.453125 +vt 1.000000 0.468750 +vt 1.000000 0.484375 +vt 1.000000 0.500000 +vt 1.000000 0.515625 +vt 1.000000 0.531250 +vt 1.000000 0.546875 +vt 1.000000 0.562500 +vt 1.000000 0.578125 +vt 1.000000 0.593750 +vt 1.000000 0.609375 +vt 1.000000 0.625000 +vt 1.000000 0.640625 +vt 1.000000 0.656250 +vt 1.000000 0.671875 +vt 1.000000 0.687500 +vt 1.000000 0.703125 +vt 1.000000 0.718750 +vt 1.000000 0.734375 +vt 1.000000 0.750000 +vt 1.000000 0.765625 +vt 1.000000 0.781250 +vt 1.000000 0.796875 +vt 1.000000 0.812500 +vt 1.000000 0.828125 +vt 1.000000 0.843750 +vt 1.000000 0.859375 +vt 1.000000 0.875000 +vt 1.000000 0.890625 +vt 1.000000 0.906250 +vt 1.000000 0.921875 +vt 1.000000 0.937500 +vt 1.000000 0.953125 +vt 1.000000 0.968750 +vt 0.984375 0.984375 +vt 1.000000 0.984375 +vt 0.984375 1.000000 +vt 0.968750 1.000000 +vt 0.953125 1.000000 +vt 0.937500 1.000000 +vt 0.921875 1.000000 +vt 0.906250 1.000000 +vt 0.890625 1.000000 +vt 0.875000 1.000000 +vt 0.859375 1.000000 +vt 0.843750 1.000000 +vt 0.828125 1.000000 +vt 0.812500 1.000000 +vt 0.796875 1.000000 +vt 0.781250 1.000000 +vt 0.765625 1.000000 +vt 0.750000 1.000000 +vt 0.734375 1.000000 +vt 0.718750 1.000000 +vt 0.703125 1.000000 +vt 0.687500 1.000000 +vt 0.671875 1.000000 +vt 0.656250 1.000000 +vt 0.640625 1.000000 +vt 0.625000 1.000000 +vt 0.609375 1.000000 +vt 0.593750 1.000000 +vt 0.578125 1.000000 +vt 0.562500 1.000000 +vt 0.546875 1.000000 +vt 0.531250 1.000000 +vt 0.515625 1.000000 +vt 0.500000 1.000000 +vt 0.484375 1.000000 +vt 0.468750 1.000000 +vt 0.453125 1.000000 +vt 0.437500 1.000000 +vt 0.421875 1.000000 +vt 0.406250 1.000000 +vt 0.390625 1.000000 +vt 0.375000 1.000000 +vt 0.359375 1.000000 +vt 0.343750 1.000000 +vt 0.328125 1.000000 +vt 0.312500 1.000000 +vt 0.296875 1.000000 +vt 0.281250 1.000000 +vt 0.265625 1.000000 +vt 0.250000 1.000000 +vt 0.234375 1.000000 +vt 0.218750 1.000000 +vt 0.203125 1.000000 +vt 0.187500 1.000000 +vt 0.171875 1.000000 +vt 0.156250 1.000000 +vt 0.140625 1.000000 +vt 0.125000 1.000000 +vt 0.109375 1.000000 +vt 0.093750 1.000000 +vt 0.078125 1.000000 +vt 0.062500 1.000000 +vt 0.046875 1.000000 +vt 0.031250 1.000000 +vt 0.015625 1.000000 +vt 0.000000 1.000000 +vt 0.000000 0.984375 +vt 0.000000 0.968750 +vt 0.000000 0.953125 +vt 0.000000 0.937500 +vt 0.000000 0.921875 +vt 0.000000 0.906250 +vt 0.000000 0.890625 +vt 0.000000 0.875000 +vt 0.000000 0.859375 +vt 0.000000 0.843750 +vt 0.000000 0.828125 +vt 0.000000 0.812500 +vt 0.000000 0.796875 +vt 0.000000 0.781250 +vt 0.000000 0.765625 +vt 0.000000 0.750000 +vt 0.000000 0.734375 +vt 0.000000 0.718750 +vt 0.000000 0.703125 +vt 0.000000 0.687500 +vt 0.000000 0.671875 +vt 0.000000 0.656250 +vt 0.000000 0.640625 +vt 0.000000 0.625000 +vt 0.000000 0.609375 +vt 0.000000 0.593750 +vt 0.000000 0.578125 +vt 0.000000 0.562500 +vt 0.000000 0.546875 +vt 0.000000 0.531250 +vt 0.000000 0.515625 +vt 0.000000 0.500000 +vt 0.000000 0.484375 +vt 0.000000 0.468750 +vt 0.000000 0.453125 +vt 0.000000 0.437500 +vt 0.000000 0.421875 +vt 0.000000 0.406250 +vt 0.000000 0.390625 +vt 0.000000 0.375000 +vt 0.000000 0.359375 +vt 0.000000 0.343750 +vt 0.000000 0.328125 +vt 0.000000 0.312500 +vt 0.000000 0.296875 +vt 0.000000 0.281250 +vt 0.000000 0.265625 +vt 0.000000 0.250000 +vt 0.000000 0.234375 +vt 0.000000 0.218750 +vt 0.000000 0.203125 +vt 0.000000 0.187500 +vt 0.000000 0.171875 +vt 0.000000 0.156250 +vt 0.000000 0.140625 +vt 0.000000 0.125000 +vt 0.000000 0.109375 +vt 0.000000 0.093750 +vt 0.000000 0.078125 +vt 0.000000 0.062500 +vt 0.000000 0.046875 +vt 0.000000 0.031250 +vt 1.000000 1.000000 +vn -0.7992 -0.1581 0.5799 +vn -0.8003 -0.1565 0.5788 +vn -0.7935 -0.1455 0.5909 +vn -0.7998 -0.1570 0.5793 +vn -0.7990 -0.1560 0.5806 +vn -0.7945 -0.1417 0.5905 +vn -0.7923 -0.1419 0.5934 +vn -0.7811 -0.1125 0.6142 +vn -0.7786 -0.1141 0.6170 +vn -0.7578 -0.0714 0.6485 +vn -0.7564 -0.0737 0.6499 +vn -0.7244 -0.0224 0.6890 +vn -0.7248 -0.0245 0.6885 +vn -0.6837 0.0285 0.7291 +vn -0.6861 0.0273 0.7270 +vn -0.6406 0.0757 0.7641 +vn -0.6450 0.0749 0.7605 +vn -0.6032 0.1135 0.7895 +vn -0.6070 0.1130 0.7866 +vn -0.5797 0.1383 0.8030 +vn -0.5798 0.1379 0.8030 +vn -0.5730 0.1491 0.8058 +vn -0.5693 0.1486 0.8085 +vn -0.5812 0.1465 0.8005 +vn -0.5758 0.1457 0.8045 +vn -0.5999 0.1317 0.7891 +vn -0.5956 0.1303 0.7926 +vn -0.6252 0.1055 0.7732 +vn -0.6241 0.1037 0.7744 +vn -0.6552 0.0693 0.7523 +vn -0.6568 0.0671 0.7510 +vn -0.6887 0.0251 0.7246 +vn -0.6910 0.0227 0.7225 +vn -0.7229 -0.0224 0.6905 +vn -0.7241 -0.0253 0.6892 +vn -0.7544 -0.0683 0.6528 +vn -0.7537 -0.0713 0.6534 +vn -0.7803 -0.1070 0.6162 +vn -0.7777 -0.1098 0.6189 +vn -0.7982 -0.1345 0.5872 +vn -0.7951 -0.1368 0.5907 +vn -0.8069 -0.1483 0.5718 +vn -0.8050 -0.1502 0.5740 +vn -0.8059 -0.1479 0.5732 +vn -0.8063 -0.1493 0.5723 +vn -0.7967 -0.1343 0.5893 +vn -0.7986 -0.1350 0.5865 +vn -0.7810 -0.1090 0.6150 +vn -0.7825 -0.1090 0.6130 +vn -0.7580 -0.0725 0.6482 +vn -0.7592 -0.0728 0.6468 +vn -0.7267 -0.0270 0.6864 +vn -0.7280 -0.0279 0.6850 +vn -0.6887 0.0237 0.7246 +vn -0.6897 0.0219 0.7237 +vn -0.6482 0.0739 0.7578 +vn -0.6484 0.0711 0.7579 +vn -0.6113 0.1173 0.7826 +vn -0.6105 0.1137 0.7838 +vn -0.5846 0.1485 0.7976 +vn -0.5825 0.1445 0.7999 +vn -0.5714 0.1644 0.8040 +vn -0.5695 0.1604 0.8061 +vn -0.5720 0.1640 0.8037 +vn -0.5721 0.1601 0.8043 +vn -0.5873 0.1476 0.7957 +vn -0.5882 0.1439 0.7958 +vn -0.6160 0.1165 0.7790 +vn -0.6168 0.1127 0.7790 +vn -0.6529 0.0731 0.7539 +vn -0.6544 0.0692 0.7529 +vn -0.6919 0.0218 0.7217 +vn -0.6945 0.0178 0.7193 +vn -0.7276 -0.0317 0.6852 +vn -0.7310 -0.0355 0.6814 +vn -0.7569 -0.0818 0.6483 +vn -0.7603 -0.0850 0.6439 +vn -0.7776 -0.1235 0.6165 +vn -0.7813 -0.1258 0.6113 +vn -0.7891 -0.1529 0.5948 +vn -0.7933 -0.1545 0.5889 +vn -0.7948 -0.1680 0.5831 +vn -0.7967 -0.1693 0.5801 +vn -0.7970 -0.1686 0.5800 +vn -0.7949 -0.1697 0.5824 +vn -0.7944 -0.1543 0.5875 +vn -0.7895 -0.1555 0.5937 +vn -0.7845 -0.1256 0.6073 +vn -0.7787 -0.1269 0.6144 +vn -0.7642 -0.0840 0.6394 +vn -0.7599 -0.0857 0.6443 +vn -0.7323 -0.0336 0.6801 +vn -0.7312 -0.0353 0.6813 +vn -0.6915 0.0198 0.7221 +vn -0.6931 0.0184 0.7206 +vn -0.6492 0.0696 0.7574 +vn -0.6510 0.0687 0.7560 +vn -0.6131 0.1103 0.7822 +vn -0.6132 0.1098 0.7822 +vn -0.5884 0.1390 0.7965 +vn -0.5865 0.1383 0.7980 +vn -0.5768 0.1545 0.8021 +vn -0.5738 0.1533 0.8045 +vn -0.5778 0.1565 0.8010 +vn -0.5753 0.1546 0.8032 +vn -0.5902 0.1447 0.7942 +vn -0.5895 0.1424 0.7951 +vn -0.6126 0.1190 0.7813 +vn -0.6143 0.1168 0.7804 +vn -0.6448 0.0797 0.7602 +vn -0.6471 0.0785 0.7584 +vn -0.6838 0.0306 0.7290 +vn -0.6851 0.0299 0.7278 +vn -0.7222 -0.0214 0.6913 +vn -0.7230 -0.0228 0.6904 +vn -0.7541 -0.0692 0.6530 +vn -0.7547 -0.0717 0.6521 +vn -0.7774 -0.1073 0.6197 +vn -0.7774 -0.1109 0.6191 +vn -0.7923 -0.1332 0.5954 +vn -0.7915 -0.1372 0.5955 +vn -0.8002 -0.1462 0.5817 +vn -0.7986 -0.1500 0.5828 +vn -0.8020 -0.1469 0.5789 +vn -0.7999 -0.1499 0.5811 +vn -0.8002 -0.1530 0.5798 +vn -0.7922 -0.1391 0.5942 +vn -0.7774 -0.1121 0.6189 +vn -0.7547 -0.0726 0.6521 +vn -0.7237 -0.0238 0.6897 +vn -0.6861 0.0283 0.7269 +vn -0.6468 0.0767 0.7588 +vn -0.6110 0.1152 0.7832 +vn -0.5834 0.1401 0.8000 +vn -0.5695 0.1504 0.8081 +vn -0.5726 0.1465 0.8066 +vn -0.5911 0.1299 0.7961 +vn -0.6207 0.1021 0.7773 +vn -0.6563 0.0646 0.7517 +vn -0.6928 0.0196 0.7208 +vn -0.7265 -0.0289 0.6865 +vn -0.7548 -0.0753 0.6516 +vn -0.7768 -0.1140 0.6193 +vn -0.7924 -0.1412 0.5934 +vn -0.8016 -0.1548 0.5774 +vn -0.8039 -0.1538 0.5744 +vn -0.7983 -0.1391 0.5859 +vn -0.7837 -0.1120 0.6109 +vn -0.7604 -0.0749 0.6451 +vn -0.7294 -0.0298 0.6834 +vn -0.6915 0.0197 0.7221 +vn -0.6503 0.0683 0.7566 +vn -0.6116 0.1100 0.7834 +vn -0.5823 0.1400 0.8008 +vn -0.5677 0.1553 0.8084 +vn -0.5704 0.1549 0.8066 +vn -0.5881 0.1391 0.7967 +vn -0.6172 0.1089 0.7792 +vn -0.6547 0.0663 0.7529 +vn -0.6954 0.0159 0.7184 +vn -0.7329 -0.0363 0.6793 +vn -0.7629 -0.0842 0.6410 +vn -0.7840 -0.1232 0.6084 +vn -0.7967 -0.1501 0.5853 +vn -0.8011 -0.1634 0.5757 +vn -0.7976 -0.1628 0.5808 +vn -0.7884 -0.1487 0.5968 +vn -0.7747 -0.1209 0.6206 +vn -0.7549 -0.0809 0.6508 +vn -0.7274 -0.0319 0.6855 +vn -0.6923 0.0206 0.7213 +vn -0.6527 0.0701 0.7543 +vn -0.6150 0.1107 0.7807 +vn -0.5869 0.1386 0.7977 +vn -0.5727 0.1524 0.8054 +vn -0.5734 0.1524 0.8050 +vn -0.5878 0.1391 0.7969 +vn -0.6138 0.1132 0.7813 +vn -0.6480 0.0754 0.7578 +vn -0.6864 0.0281 0.7267 +vn -0.7242 -0.0239 0.6891 +vn -0.7560 -0.0733 0.6504 +vn -0.7786 -0.1134 0.6172 +vn -0.7920 -0.1409 0.5940 +vn -0.7979 -0.1545 0.5826 +vn -0.7980 -0.1546 0.5824 +vn -0.7957 -0.1380 0.5897 +vn -0.7930 -0.1424 0.5923 +vn -0.7931 -0.1361 0.5937 +vn -0.7775 -0.1090 0.6193 +vn -0.7538 -0.0699 0.6534 +vn -0.7221 -0.0216 0.6914 +vn -0.6848 0.0305 0.7281 +vn -0.6462 0.0794 0.7590 +vn -0.6123 0.1186 0.7817 +vn -0.5872 0.1440 0.7965 +vn -0.5732 0.1542 0.8048 +vn -0.5733 0.1496 0.8056 +vn -0.5888 0.1319 0.7974 +vn -0.6172 0.1028 0.7800 +vn -0.6537 0.0643 0.7540 +vn -0.6927 0.0186 0.7210 +vn -0.7285 -0.0304 0.6843 +vn -0.7574 -0.0775 0.6482 +vn -0.7781 -0.1169 0.6171 +vn -0.7917 -0.1445 0.5936 +vn -0.7991 -0.1585 0.5798 +vn -0.8008 -0.1581 0.5776 +vn -0.7959 -0.1436 0.5882 +vn -0.7829 -0.1161 0.6112 +vn -0.7609 -0.0777 0.6441 +vn -0.7303 -0.0316 0.6824 +vn -0.6930 0.0185 0.7207 +vn -0.6524 0.0672 0.7548 +vn -0.6141 0.1085 0.7817 +vn -0.5842 0.1377 0.7998 +vn -0.5681 0.1523 0.8087 +vn -0.5687 0.1513 0.8085 +vn -0.5860 0.1354 0.7989 +vn -0.6160 0.1061 0.7806 +vn -0.6537 0.0651 0.7539 +vn -0.6945 0.0163 0.7192 +vn -0.7328 -0.0343 0.6796 +vn -0.7638 -0.0807 0.6404 +vn -0.7856 -0.1178 0.6074 +vn -0.7987 -0.1430 0.5845 +vn -0.8041 -0.1549 0.5740 +vn -0.8017 -0.1530 0.5778 +vn -0.7912 -0.1382 0.5957 +vn -0.7742 -0.1111 0.6231 +vn -0.7516 -0.0725 0.6556 +vn -0.7231 -0.0253 0.6903 +vn -0.6894 0.0255 0.7240 +vn -0.6528 0.0735 0.7540 +vn -0.6174 0.1131 0.7784 +vn -0.5892 0.1403 0.7957 +vn -0.5739 0.1532 0.8045 +vn -0.5734 0.1520 0.8050 +vn -0.5868 0.1375 0.7979 +vn -0.6124 0.1109 0.7827 +vn -0.6471 0.0733 0.7588 +vn -0.6862 0.0272 0.7269 +vn -0.7245 -0.0234 0.6888 +vn -0.7571 -0.0723 0.6492 +vn -0.7805 -0.1129 0.6149 +vn -0.7940 -0.1413 0.5912 +vn -0.7992 -0.1561 0.5804 +vn -0.7979 -0.1571 0.5819 +vn -0.7913 -0.1451 0.5939 +vn -0.7826 -0.1188 0.6110 +vn -0.7797 -0.1213 0.6142 +vn -0.7779 -0.1071 0.6192 +vn -0.7539 -0.0680 0.6535 +vn -0.7213 -0.0199 0.6923 +vn -0.6832 0.0321 0.7295 +vn -0.6444 0.0812 0.7604 +vn -0.6110 0.1210 0.7823 +vn -0.5878 0.1471 0.7955 +vn -0.5767 0.1579 0.8015 +vn -0.5772 0.1535 0.8020 +vn -0.5902 0.1354 0.7958 +vn -0.6158 0.1056 0.7808 +vn -0.6510 0.0664 0.7562 +vn -0.6907 0.0204 0.7229 +vn -0.7287 -0.0288 0.6842 +vn -0.7599 -0.0762 0.6455 +vn -0.7813 -0.1163 0.6132 +vn -0.7935 -0.1445 0.5911 +vn -0.7990 -0.1591 0.5798 +vn -0.7990 -0.1593 0.5798 +vn -0.7933 -0.1455 0.5912 +vn -0.7807 -0.1182 0.6136 +vn -0.7598 -0.0795 0.6453 +vn -0.7301 -0.0324 0.6825 +vn -0.6933 0.0187 0.7204 +vn -0.6534 0.0683 0.7539 +vn -0.6162 0.1099 0.7798 +vn -0.5870 0.1389 0.7976 +vn -0.5703 0.1529 0.8070 +vn -0.5692 0.1513 0.8081 +vn -0.5842 0.1350 0.8003 +vn -0.6132 0.1057 0.7828 +vn -0.6511 0.0658 0.7561 +vn -0.6922 0.0186 0.7214 +vn -0.7310 -0.0309 0.6816 +vn -0.7629 -0.0761 0.6420 +vn -0.7857 -0.1122 0.6083 +vn -0.7995 -0.1363 0.5849 +vn -0.8054 -0.1472 0.5742 +vn -0.8039 -0.1448 0.5768 +vn -0.7946 -0.1296 0.5930 +vn -0.7768 -0.1027 0.6213 +vn -0.7515 -0.0653 0.6565 +vn -0.7205 -0.0198 0.6932 +vn -0.6859 0.0294 0.7271 +vn -0.6506 0.0763 0.7555 +vn -0.6182 0.1153 0.7775 +vn -0.5922 0.1420 0.7931 +vn -0.5767 0.1547 0.8021 +vn -0.5753 0.1530 0.8035 +vn -0.5876 0.1379 0.7973 +vn -0.6118 0.1108 0.7832 +vn -0.6454 0.0735 0.7602 +vn -0.6844 0.0283 0.7285 +vn -0.7234 -0.0209 0.6901 +vn -0.7571 -0.0688 0.6497 +vn -0.7818 -0.1092 0.6138 +vn -0.7966 -0.1380 0.5885 +vn -0.8023 -0.1536 0.5768 +vn -0.8002 -0.1556 0.5791 +vn -0.7919 -0.1443 0.5933 +vn -0.7783 -0.1205 0.6162 +vn -0.7624 -0.0871 0.6412 +vn -0.7594 -0.0858 0.6450 +vn -0.7539 -0.0676 0.6534 +vn -0.7215 -0.0197 0.6921 +vn -0.6824 0.0321 0.7302 +vn -0.6426 0.0811 0.7618 +vn -0.6088 0.1211 0.7840 +vn -0.5861 0.1476 0.7966 +vn -0.5770 0.1590 0.8010 +vn -0.5804 0.1554 0.7993 +vn -0.5941 0.1379 0.7925 +vn -0.6175 0.1084 0.7790 +vn -0.6500 0.0693 0.7568 +vn -0.6881 0.0236 0.7252 +vn -0.7268 -0.0251 0.6864 +vn -0.7602 -0.0722 0.6456 +vn -0.7842 -0.1123 0.6102 +vn -0.7972 -0.1410 0.5870 +vn -0.8015 -0.1558 0.5773 +vn -0.7997 -0.1565 0.5796 +vn -0.7923 -0.1433 0.5930 +vn -0.7787 -0.1169 0.6164 +vn -0.7577 -0.0786 0.6478 +vn -0.7287 -0.0315 0.6841 +vn -0.6925 0.0200 0.7212 +vn -0.6529 0.0704 0.7541 +vn -0.6164 0.1131 0.7792 +vn -0.5888 0.1426 0.7956 +vn -0.5732 0.1566 0.8043 +vn -0.5716 0.1547 0.8057 +vn -0.5848 0.1381 0.7993 +vn -0.6114 0.1085 0.7838 +vn -0.6478 0.0687 0.7586 +vn -0.6888 0.0221 0.7246 +vn -0.7282 -0.0269 0.6848 +vn -0.7609 -0.0723 0.6447 +vn -0.7846 -0.1084 0.6104 +vn -0.7991 -0.1324 0.5864 +vn -0.8055 -0.1431 0.5750 +vn -0.8046 -0.1406 0.5769 +vn -0.7964 -0.1257 0.5915 +vn -0.7800 -0.0992 0.6179 +vn -0.7544 -0.0627 0.6534 +vn -0.7212 -0.0185 0.6925 +vn -0.6841 0.0294 0.7287 +vn -0.6479 0.0755 0.7580 +vn -0.6165 0.1143 0.7790 +vn -0.5932 0.1415 0.7924 +vn -0.5797 0.1549 0.7999 +vn -0.5781 0.1537 0.8014 +vn -0.5897 0.1389 0.7956 +vn -0.6127 0.1120 0.7823 +vn -0.6445 0.0751 0.7609 +vn -0.6820 0.0309 0.7307 +vn -0.7208 -0.0170 0.6929 +vn -0.7555 -0.0638 0.6520 +vn -0.7819 -0.1040 0.6147 +vn -0.7982 -0.1329 0.5875 +vn -0.8053 -0.1487 0.5739 +vn -0.8040 -0.1512 0.5751 +vn -0.7949 -0.1404 0.5903 +vn -0.7792 -0.1166 0.6158 +vn -0.7577 -0.0815 0.6475 +vn -0.7345 -0.0424 0.6773 +vn -0.7310 -0.0375 0.6813 +vn -0.7216 -0.0201 0.6920 +vn -0.6828 0.0313 0.7299 +vn -0.6422 0.0799 0.7624 +vn -0.6073 0.1194 0.7855 +vn -0.5841 0.1456 0.7985 +vn -0.5753 0.1569 0.8027 +vn -0.5806 0.1536 0.7996 +vn -0.5968 0.1371 0.7906 +vn -0.6207 0.1089 0.7764 +vn -0.6512 0.0710 0.7555 +vn -0.6867 0.0262 0.7264 +vn -0.7240 -0.0215 0.6895 +vn -0.7581 -0.0677 0.6486 +vn -0.7845 -0.1073 0.6107 +vn -0.8003 -0.1358 0.5839 +vn -0.8054 -0.1505 0.5733 +vn -0.8025 -0.1511 0.5772 +vn -0.7935 -0.1382 0.5926 +vn -0.7783 -0.1126 0.6176 +vn -0.7562 -0.0753 0.6499 +vn -0.7268 -0.0290 0.6862 +vn -0.6909 0.0221 0.7226 +vn -0.6517 0.0723 0.7550 +vn -0.6150 0.1155 0.7800 +vn -0.5882 0.1459 0.7954 +vn -0.5747 0.1605 0.8025 +vn -0.5744 0.1591 0.8030 +vn -0.5872 0.1426 0.7967 +vn -0.6120 0.1131 0.7827 +vn -0.6462 0.0731 0.7596 +vn -0.6858 0.0261 0.7273 +vn -0.7252 -0.0235 0.6881 +vn -0.7588 -0.0701 0.6475 +vn -0.7831 -0.1078 0.6125 +vn -0.7980 -0.1328 0.5878 +vn -0.8047 -0.1442 0.5759 +vn -0.8042 -0.1420 0.5771 +vn -0.7967 -0.1273 0.5908 +vn -0.7816 -0.1012 0.6155 +vn -0.7578 -0.0652 0.6492 +vn -0.7248 -0.0217 0.6886 +vn -0.6857 0.0255 0.7274 +vn -0.6468 0.0712 0.7593 +vn -0.6141 0.1098 0.7815 +vn -0.5914 0.1374 0.7945 +vn -0.5802 0.1517 0.8001 +vn -0.5803 0.1520 0.8000 +vn -0.5918 0.1386 0.7941 +vn -0.6143 0.1128 0.7810 +vn -0.6448 0.0768 0.7604 +vn -0.6804 0.0336 0.7320 +vn -0.7177 -0.0132 0.6962 +vn -0.7524 -0.0591 0.6560 +vn -0.7803 -0.0990 0.6175 +vn -0.7985 -0.1284 0.5882 +vn -0.8069 -0.1445 0.5727 +vn -0.8071 -0.1470 0.5719 +vn -0.7989 -0.1363 0.5858 +vn -0.7822 -0.1125 0.6128 +vn -0.7583 -0.0768 0.6474 +vn -0.7287 -0.0323 0.6840 +vn -0.6995 0.0113 0.7145 +vn -0.6955 0.0169 0.7183 +vn -0.6833 0.0309 0.7294 +vn -0.6431 0.0786 0.7617 +vn -0.6075 0.1173 0.7856 +vn -0.5832 0.1427 0.7997 +vn -0.5737 0.1534 0.8045 +vn -0.5790 0.1499 0.8014 +vn -0.5965 0.1335 0.7913 +vn -0.6224 0.1063 0.7754 +vn -0.6531 0.0700 0.7540 +vn -0.6869 0.0270 0.7262 +vn -0.7219 -0.0193 0.6917 +vn -0.7548 -0.0643 0.6527 +vn -0.7821 -0.1031 0.6145 +vn -0.8005 -0.1313 0.5847 +vn -0.8083 -0.1460 0.5703 +vn -0.8061 -0.1462 0.5734 +vn -0.7962 -0.1332 0.5901 +vn -0.7799 -0.1081 0.6164 +vn -0.7564 -0.0718 0.6501 +vn -0.7259 -0.0266 0.6873 +vn -0.6895 0.0233 0.7239 +vn -0.6505 0.0727 0.7560 +vn -0.6138 0.1153 0.7809 +vn -0.5864 0.1458 0.7968 +vn -0.5738 0.1609 0.8030 +vn -0.5756 0.1602 0.8018 +vn -0.5897 0.1447 0.7945 +vn -0.6143 0.1160 0.7804 +vn -0.6471 0.0763 0.7585 +vn -0.6847 0.0289 0.7282 +vn -0.7230 -0.0216 0.6904 +vn -0.7571 -0.0700 0.6495 +vn -0.7821 -0.1099 0.6133 +vn -0.7971 -0.1369 0.5881 +vn -0.8037 -0.1493 0.5760 +vn -0.8031 -0.1476 0.5772 +vn -0.7959 -0.1329 0.5907 +vn -0.7816 -0.1066 0.6145 +vn -0.7595 -0.0705 0.6466 +vn -0.7285 -0.0269 0.6844 +vn -0.6898 0.0208 0.7237 +vn -0.6487 0.0670 0.7580 +vn -0.6131 0.1060 0.7828 +vn -0.5887 0.1339 0.7971 +vn -0.5778 0.1486 0.8025 +vn -0.5798 0.1496 0.8009 +vn -0.5926 0.1374 0.7936 +vn -0.6152 0.1127 0.7803 +vn -0.6455 0.0776 0.7598 +vn -0.6800 0.0351 0.7323 +vn -0.7156 -0.0112 0.6984 +vn -0.7491 -0.0569 0.6600 +vn -0.7772 -0.0968 0.6218 +vn -0.7971 -0.1267 0.5904 +vn -0.8072 -0.1434 0.5726 +vn -0.8083 -0.1460 0.5704 +vn -0.8015 -0.1350 0.5825 +vn -0.7859 -0.1108 0.6083 +vn -0.7609 -0.0748 0.6446 +vn -0.7287 -0.0297 0.6842 +vn -0.6926 0.0199 0.7210 +vn -0.6605 0.0655 0.7479 +vn -0.6565 0.0685 0.7512 +vn -0.6448 0.0778 0.7604 +vn -0.6094 0.1155 0.7844 +vn -0.5841 0.1404 0.7994 +vn -0.5732 0.1510 0.8054 +vn -0.5775 0.1475 0.8029 +vn -0.5949 0.1312 0.7930 +vn -0.6217 0.1040 0.7763 +vn -0.6537 0.0682 0.7536 +vn -0.6875 0.0263 0.7257 +vn -0.7208 -0.0186 0.6928 +vn -0.7520 -0.0625 0.6561 +vn -0.7786 -0.1007 0.6194 +vn -0.7980 -0.1290 0.5887 +vn -0.8084 -0.1442 0.5706 +vn -0.8087 -0.1450 0.5701 +vn -0.7993 -0.1319 0.5862 +vn -0.7824 -0.1067 0.6135 +vn -0.7583 -0.0708 0.6481 +vn -0.7266 -0.0262 0.6865 +vn -0.6893 0.0230 0.7241 +vn -0.6499 0.0714 0.7566 +vn -0.6136 0.1131 0.7814 +vn -0.5859 0.1429 0.7977 +vn -0.5721 0.1577 0.8048 +vn -0.5746 0.1570 0.8032 +vn -0.5904 0.1423 0.7945 +vn -0.6161 0.1147 0.7793 +vn -0.6490 0.0760 0.7570 +vn -0.6858 0.0289 0.7271 +vn -0.7227 -0.0221 0.6908 +vn -0.7559 -0.0714 0.6507 +vn -0.7816 -0.1129 0.6135 +vn -0.7970 -0.1413 0.5872 +vn -0.8032 -0.1544 0.5754 +vn -0.8022 -0.1527 0.5771 +vn -0.7948 -0.1379 0.5909 +vn -0.7808 -0.1113 0.6147 +vn -0.7595 -0.0750 0.6461 +vn -0.7303 -0.0310 0.6824 +vn -0.6933 0.0172 0.7204 +vn -0.6520 0.0648 0.7554 +vn -0.6140 0.1055 0.7822 +vn -0.5869 0.1346 0.7984 +vn -0.5745 0.1498 0.8047 +vn -0.5768 0.1507 0.8028 +vn -0.5915 0.1381 0.7944 +vn -0.6154 0.1133 0.7800 +vn -0.6460 0.0780 0.7593 +vn -0.6806 0.0352 0.7318 +vn -0.7152 -0.0114 0.6988 +vn -0.7471 -0.0574 0.6622 +vn -0.7741 -0.0980 0.6254 +vn -0.7941 -0.1286 0.5940 +vn -0.8058 -0.1462 0.5739 +vn -0.8082 -0.1491 0.5697 +vn -0.8021 -0.1378 0.5810 +vn -0.7880 -0.1130 0.6051 +vn -0.7642 -0.0764 0.6404 +vn -0.7309 -0.0308 0.6817 +vn -0.6922 0.0191 0.7214 +vn -0.6533 0.0680 0.7540 +vn -0.6235 0.1110 0.7739 +vn -0.6194 0.1107 0.7772 +vn -0.6119 0.1144 0.7826 +vn -0.5861 0.1393 0.7981 +vn -0.5737 0.1503 0.8051 +vn -0.5764 0.1473 0.8037 +vn -0.5929 0.1314 0.7944 +vn -0.6199 0.1041 0.7777 +vn -0.6530 0.0679 0.7543 +vn -0.6877 0.0255 0.7255 +vn -0.7208 -0.0193 0.6928 +vn -0.7505 -0.0629 0.6579 +vn -0.7755 -0.1009 0.6232 +vn -0.7945 -0.1296 0.5932 +vn -0.8061 -0.1458 0.5735 +vn -0.8089 -0.1476 0.5691 +vn -0.8017 -0.1350 0.5823 +vn -0.7851 -0.1093 0.6097 +vn -0.7606 -0.0729 0.6451 +vn -0.7286 -0.0280 0.6844 +vn -0.6904 0.0214 0.7231 +vn -0.6502 0.0699 0.7565 +vn -0.6136 0.1112 0.7817 +vn -0.5862 0.1407 0.7978 +vn -0.5720 0.1552 0.8054 +vn -0.5733 0.1540 0.8047 +vn -0.5893 0.1387 0.7959 +vn -0.6161 0.1114 0.7797 +vn -0.6499 0.0734 0.7564 +vn -0.6872 0.0271 0.7259 +vn -0.7237 -0.0236 0.6897 +vn -0.7558 -0.0729 0.6507 +vn -0.7810 -0.1149 0.6139 +vn -0.7971 -0.1442 0.5863 +vn -0.8034 -0.1576 0.5741 +vn -0.8018 -0.1556 0.5769 +vn -0.7941 -0.1401 0.5914 +vn -0.7799 -0.1131 0.6156 +vn -0.7588 -0.0766 0.6467 +vn -0.7304 -0.0326 0.6821 +vn -0.6951 0.0157 0.7187 +vn -0.6548 0.0640 0.7530 +vn -0.6157 0.1063 0.7808 +vn -0.5860 0.1372 0.7985 +vn -0.5716 0.1534 0.8061 +vn -0.5734 0.1542 0.8046 +vn -0.5892 0.1407 0.7956 +vn -0.6150 0.1145 0.7801 +vn -0.6469 0.0781 0.7586 +vn -0.6817 0.0342 0.7308 +vn -0.7162 -0.0133 0.6977 +vn -0.7471 -0.0599 0.6620 +vn -0.7725 -0.1012 0.6269 +vn -0.7914 -0.1327 0.5967 +vn -0.8031 -0.1511 0.5764 +vn -0.8068 -0.1546 0.5702 +vn -0.8017 -0.1431 0.5803 +vn -0.7881 -0.1179 0.6041 +vn -0.7660 -0.0807 0.6377 +vn -0.7341 -0.0346 0.6782 +vn -0.6944 0.0156 0.7194 +vn -0.6530 0.0643 0.7546 +vn -0.6164 0.1068 0.7802 +vn -0.5940 0.1429 0.7917 +vn -0.5897 0.1390 0.7955 +vn -0.5886 0.1393 0.7963 +vn -0.5752 0.1509 0.8039 +vn -0.5763 0.1485 0.8036 +vn -0.5914 0.1330 0.7953 +vn -0.6180 0.1057 0.7790 +vn -0.6517 0.0688 0.7553 +vn -0.6877 0.0253 0.7255 +vn -0.7215 -0.0208 0.6921 +vn -0.7505 -0.0651 0.6576 +vn -0.7739 -0.1035 0.6247 +vn -0.7916 -0.1327 0.5965 +vn -0.8029 -0.1497 0.5770 +vn -0.8068 -0.1526 0.5707 +vn -0.8020 -0.1406 0.5806 +vn -0.7870 -0.1145 0.6062 +vn -0.7627 -0.0768 0.6421 +vn -0.7306 -0.0309 0.6821 +vn -0.6920 0.0195 0.7216 +vn -0.6509 0.0688 0.7560 +vn -0.6138 0.1107 0.7817 +vn -0.5862 0.1404 0.7978 +vn -0.5723 0.1549 0.8053 +vn -0.5732 0.1536 0.8048 +vn -0.5885 0.1376 0.7967 +vn -0.6151 0.1095 0.7808 +vn -0.6494 0.0716 0.7570 +vn -0.6874 0.0259 0.7258 +vn -0.7245 -0.0240 0.6888 +vn -0.7566 -0.0729 0.6497 +vn -0.7812 -0.1150 0.6136 +vn -0.7971 -0.1449 0.5861 +vn -0.8040 -0.1590 0.5729 +vn -0.8021 -0.1569 0.5762 +vn -0.7935 -0.1407 0.5921 +vn -0.7790 -0.1131 0.6168 +vn -0.7579 -0.0763 0.6479 +vn -0.7298 -0.0324 0.6828 +vn -0.6953 0.0157 0.7185 +vn -0.6564 0.0640 0.7517 +vn -0.6175 0.1071 0.7792 +vn -0.5863 0.1392 0.7980 +vn -0.5697 0.1564 0.8068 +vn -0.5705 0.1575 0.8061 +vn -0.5868 0.1432 0.7970 +vn -0.6142 0.1155 0.7806 +vn -0.6478 0.0774 0.7578 +vn -0.6834 0.0325 0.7293 +vn -0.7179 -0.0156 0.6959 +vn -0.7484 -0.0628 0.6602 +vn -0.7726 -0.1045 0.6262 +vn -0.7901 -0.1365 0.5975 +vn -0.8008 -0.1556 0.5783 +vn -0.8045 -0.1599 0.5720 +vn -0.8003 -0.1486 0.5808 +vn -0.7875 -0.1228 0.6040 +vn -0.7659 -0.0851 0.6373 +vn -0.7358 -0.0386 0.6761 +vn -0.6976 0.0117 0.7163 +vn -0.6556 0.0603 0.7526 +vn -0.6167 0.1018 0.7805 +vn -0.5874 0.1329 0.7983 +vn -0.5759 0.1582 0.8020 +vn -0.5720 0.1515 0.8061 +vn -0.5773 0.1519 0.8023 +vn -0.5770 0.1501 0.8028 +vn -0.5907 0.1350 0.7955 +vn -0.6165 0.1078 0.7799 +vn -0.6504 0.0702 0.7563 +vn -0.6875 0.0255 0.7257 +vn -0.7226 -0.0223 0.6909 +vn -0.7519 -0.0681 0.6558 +vn -0.7742 -0.1075 0.6238 +vn -0.7901 -0.1371 0.5974 +vn -0.8002 -0.1545 0.5795 +vn -0.8040 -0.1578 0.5733 +vn -0.8002 -0.1463 0.5815 +vn -0.7873 -0.1200 0.6048 +vn -0.7641 -0.0811 0.6400 +vn -0.7319 -0.0335 0.6805 +vn -0.6934 0.0181 0.7204 +vn -0.6518 0.0685 0.7553 +vn -0.6137 0.1115 0.7816 +vn -0.5857 0.1419 0.7979 +vn -0.5719 0.1567 0.8051 +vn -0.5734 0.1554 0.8044 +vn -0.5886 0.1391 0.7963 +vn -0.6149 0.1103 0.7809 +vn -0.6485 0.0718 0.7577 +vn -0.6865 0.0264 0.7266 +vn -0.7242 -0.0227 0.6892 +vn -0.7571 -0.0709 0.6494 +vn -0.7820 -0.1126 0.6130 +vn -0.7978 -0.1428 0.5857 +vn -0.8048 -0.1579 0.5721 +vn -0.8031 -0.1565 0.5748 +vn -0.7936 -0.1400 0.5921 +vn -0.7781 -0.1119 0.6180 +vn -0.7568 -0.0749 0.6493 +vn -0.7290 -0.0314 0.6838 +vn -0.6949 0.0161 0.7189 +vn -0.6568 0.0638 0.7513 +vn -0.6189 0.1070 0.7782 +vn -0.5873 0.1399 0.7972 +vn -0.5690 0.1581 0.8070 +vn -0.5683 0.1598 0.8072 +vn -0.5845 0.1451 0.7983 +vn -0.6133 0.1161 0.7813 +vn -0.6486 0.0764 0.7573 +vn -0.6852 0.0302 0.7277 +vn -0.7197 -0.0183 0.6940 +vn -0.7500 -0.0653 0.6582 +vn -0.7740 -0.1067 0.6241 +vn -0.7905 -0.1387 0.5965 +vn -0.8000 -0.1581 0.5787 +vn -0.8028 -0.1629 0.5735 +vn -0.7985 -0.1520 0.5825 +vn -0.7861 -0.1261 0.6050 +vn -0.7650 -0.0876 0.6381 +vn -0.7356 -0.0405 0.6762 +vn -0.6995 0.0101 0.7146 +vn -0.6592 0.0585 0.7496 +vn -0.6202 0.0992 0.7781 +vn -0.5889 0.1289 0.7978 +vn -0.5707 0.1460 0.8081 +vn -0.5723 0.1559 0.8050 +vn -0.5687 0.1496 0.8088 +vn -0.5786 0.1518 0.8013 +vn -0.5911 0.1370 0.7948 +vn -0.6158 0.1097 0.7802 +vn -0.6495 0.0717 0.7570 +vn -0.6872 0.0258 0.7260 +vn -0.7235 -0.0235 0.6898 +vn -0.7539 -0.0710 0.6531 +vn -0.7760 -0.1116 0.6207 +vn -0.7904 -0.1414 0.5960 +vn -0.7987 -0.1587 0.5803 +vn -0.8014 -0.1619 0.5757 +vn -0.7977 -0.1504 0.5840 +vn -0.7857 -0.1239 0.6060 +vn -0.7639 -0.0842 0.6398 +vn -0.7323 -0.0350 0.6801 +vn -0.6938 0.0180 0.7199 +vn -0.6523 0.0693 0.7548 +vn -0.6135 0.1133 0.7815 +vn -0.5848 0.1445 0.7982 +vn -0.5709 0.1598 0.8053 +vn -0.5730 0.1585 0.8041 +vn -0.5890 0.1419 0.7956 +vn -0.6156 0.1124 0.7800 +vn -0.6488 0.0733 0.7574 +vn -0.6855 0.0278 0.7275 +vn -0.7228 -0.0208 0.6907 +vn -0.7563 -0.0681 0.6506 +vn -0.7823 -0.1091 0.6133 +vn -0.7989 -0.1391 0.5851 +vn -0.8062 -0.1547 0.5710 +vn -0.8047 -0.1544 0.5732 +vn -0.7949 -0.1386 0.5907 +vn -0.7780 -0.1102 0.6185 +vn -0.7559 -0.0731 0.6506 +vn -0.7281 -0.0301 0.6847 +vn -0.6947 0.0162 0.7191 +vn -0.6572 0.0627 0.7511 +vn -0.6197 0.1051 0.7778 +vn -0.5882 0.1384 0.7967 +vn -0.5692 0.1576 0.8069 +vn -0.5671 0.1600 0.8079 +vn -0.5825 0.1456 0.7996 +vn -0.6120 0.1161 0.7823 +vn -0.6490 0.0751 0.7571 +vn -0.6870 0.0276 0.7261 +vn -0.7216 -0.0214 0.6919 +vn -0.7512 -0.0677 0.6565 +vn -0.7750 -0.1079 0.6226 +vn -0.7917 -0.1390 0.5949 +vn -0.8006 -0.1580 0.5780 +vn -0.8025 -0.1627 0.5740 +vn -0.7974 -0.1521 0.5840 +vn -0.7846 -0.1264 0.6070 +vn -0.7635 -0.0876 0.6398 +vn -0.7342 -0.0398 0.6777 +vn -0.6991 0.0113 0.7150 +vn -0.6611 0.0599 0.7479 +vn -0.6243 0.1003 0.7747 +vn -0.5934 0.1290 0.7945 +vn -0.5733 0.1447 0.8064 +vn -0.5680 0.1470 0.8098 +vn -0.5831 0.1390 0.8003 +vn -0.5795 0.1357 0.8036 +vn -0.5927 0.1386 0.7934 +vn -0.6164 0.1112 0.7796 +vn -0.6493 0.0728 0.7570 +vn -0.6871 0.0262 0.7261 +vn -0.7243 -0.0242 0.6891 +vn -0.7558 -0.0730 0.6507 +vn -0.7786 -0.1146 0.6169 +vn -0.7923 -0.1448 0.5927 +vn -0.7988 -0.1614 0.5795 +vn -0.7999 -0.1638 0.5773 +vn -0.7953 -0.1516 0.5870 +vn -0.7833 -0.1249 0.6090 +vn -0.7622 -0.0849 0.6417 +vn -0.7314 -0.0350 0.6810 +vn -0.6931 0.0192 0.7205 +vn -0.6522 0.0710 0.7547 +vn -0.6135 0.1151 0.7812 +vn -0.5838 0.1467 0.7985 +vn -0.5694 0.1625 0.8058 +vn -0.5719 0.1614 0.8043 +vn -0.5890 0.1445 0.7951 +vn -0.6166 0.1142 0.7789 +vn -0.6502 0.0743 0.7561 +vn -0.6860 0.0284 0.7270 +vn -0.7217 -0.0200 0.6919 +vn -0.7546 -0.0667 0.6528 +vn -0.7810 -0.1069 0.6152 +vn -0.7988 -0.1363 0.5859 +vn -0.8072 -0.1516 0.5704 +vn -0.8065 -0.1517 0.5713 +vn -0.7970 -0.1367 0.5882 +vn -0.7794 -0.1086 0.6171 +vn -0.7556 -0.0715 0.6511 +vn -0.7275 -0.0290 0.6855 +vn -0.6947 0.0161 0.7190 +vn -0.6583 0.0609 0.7503 +vn -0.6212 0.1017 0.7769 +vn -0.5894 0.1343 0.7965 +vn -0.5696 0.1541 0.8073 +vn -0.5665 0.1578 0.8088 +vn -0.5810 0.1443 0.8010 +vn -0.6103 0.1151 0.7837 +vn -0.6485 0.0738 0.7576 +vn -0.6881 0.0255 0.7251 +vn -0.7236 -0.0240 0.6897 +vn -0.7526 -0.0699 0.6547 +vn -0.7753 -0.1087 0.6222 +vn -0.7920 -0.1380 0.5947 +vn -0.8015 -0.1557 0.5773 +vn -0.8032 -0.1598 0.5738 +vn -0.7975 -0.1492 0.5846 +vn -0.7839 -0.1238 0.6084 +vn -0.7621 -0.0853 0.6418 +vn -0.7325 -0.0375 0.6797 +vn -0.6972 0.0139 0.7167 +vn -0.6602 0.0629 0.7484 +vn -0.6261 0.1036 0.7728 +vn -0.5979 0.1322 0.7906 +vn -0.5785 0.1473 0.8022 +vn -0.5712 0.1489 0.8071 +vn -0.5790 0.1372 0.8037 +vn -0.6064 0.1112 0.7873 +vn -0.6024 0.1125 0.7902 +vn -0.6182 0.1122 0.7780 +vn -0.6502 0.0733 0.7562 +vn -0.6875 0.0261 0.7257 +vn -0.7248 -0.0248 0.6885 +vn -0.7570 -0.0741 0.6491 +vn -0.7809 -0.1160 0.6138 +vn -0.7951 -0.1462 0.5886 +vn -0.8006 -0.1621 0.5769 +vn -0.7997 -0.1632 0.5777 +vn -0.7936 -0.1498 0.5897 +vn -0.7808 -0.1226 0.6125 +vn -0.7599 -0.0827 0.6447 +vn -0.7297 -0.0333 0.6829 +vn -0.6919 0.0205 0.7217 +vn -0.6511 0.0723 0.7555 +vn -0.6135 0.1158 0.7811 +vn -0.5839 0.1469 0.7984 +vn -0.5683 0.1629 0.8065 +vn -0.5704 0.1622 0.8052 +vn -0.5883 0.1453 0.7954 +vn -0.6175 0.1146 0.7782 +vn -0.6522 0.0736 0.7544 +vn -0.6880 0.0266 0.7252 +vn -0.7221 -0.0220 0.6915 +vn -0.7531 -0.0685 0.6543 +vn -0.7788 -0.1083 0.6178 +vn -0.7970 -0.1369 0.5883 +vn -0.8066 -0.1515 0.5713 +vn -0.8073 -0.1511 0.5705 +vn -0.7989 -0.1360 0.5858 +vn -0.7816 -0.1081 0.6142 +vn -0.7568 -0.0707 0.6497 +vn -0.7273 -0.0282 0.6857 +vn -0.6597 0.0593 0.7491 +vn -0.6240 0.0982 0.7752 +vn -0.5923 0.1292 0.7953 +vn -0.5710 0.1485 0.8074 +vn -0.5660 0.1530 0.8101 +vn -0.5793 0.1410 0.8028 +vn -0.6080 0.1133 0.7858 +vn -0.6466 0.0729 0.7593 +vn -0.6879 0.0248 0.7254 +vn -0.7250 -0.0248 0.6883 +vn -0.7544 -0.0706 0.6526 +vn -0.7760 -0.1086 0.6213 +vn -0.7913 -0.1364 0.5960 +vn -0.8011 -0.1525 0.5787 +vn -0.8038 -0.1555 0.5741 +vn -0.7983 -0.1446 0.5846 +vn -0.7843 -0.1195 0.6087 +vn -0.7617 -0.0818 0.6427 +vn -0.7313 -0.0349 0.6812 +vn -0.6954 0.0157 0.7185 +vn -0.6581 0.0643 0.7501 +vn -0.6248 0.1053 0.7736 +vn -0.5994 0.1346 0.7890 +vn -0.5830 0.1505 0.7984 +vn -0.5764 0.1526 0.8028 +vn -0.5820 0.1414 0.8007 +vn -0.6016 0.1172 0.7901 +vn -0.6386 0.0762 0.7657 +vn -0.6344 0.0812 0.7687 +vn -0.6525 0.0724 0.7543 +vn -0.6887 0.0252 0.7246 +vn -0.7253 -0.0255 0.6879 +vn -0.7576 -0.0743 0.6485 +vn -0.7821 -0.1157 0.6123 +vn -0.7973 -0.1452 0.5859 +vn -0.8032 -0.1603 0.5737 +vn -0.8010 -0.1603 0.5767 +vn -0.7929 -0.1459 0.5916 +vn -0.7790 -0.1181 0.6158 +vn -0.7576 -0.0788 0.6480 +vn -0.7278 -0.0307 0.6850 +vn -0.6908 0.0215 0.7227 +vn -0.6505 0.0716 0.7561 +vn -0.6134 0.1139 0.7815 +vn -0.5850 0.1438 0.7981 +vn -0.5689 0.1592 0.8068 +vn -0.5691 0.1588 0.8067 +vn -0.5868 0.1427 0.7971 +vn -0.6171 0.1124 0.7788 +vn -0.6538 0.0710 0.7533 +vn -0.6908 0.0229 0.7226 +vn -0.7244 -0.0270 0.6888 +vn -0.7533 -0.0742 0.6535 +vn -0.7768 -0.1141 0.6193 +vn -0.7939 -0.1426 0.5910 +vn -0.8037 -0.1565 0.5740 +vn -0.8056 -0.1552 0.5717 +vn -0.7832 -0.1103 0.6119 +vn -0.7588 -0.0721 0.6472 +vn -0.7282 -0.0284 0.6847 +vn -0.6949 0.0165 0.7189 +vn -0.6608 0.0594 0.7482 +vn -0.6270 0.0971 0.7729 +vn -0.5965 0.1267 0.7925 +vn -0.5746 0.1450 0.8055 +vn -0.5669 0.1494 0.8101 +vn -0.5773 0.1383 0.8047 +vn -0.6047 0.1122 0.7885 +vn -0.6430 0.0735 0.7623 +vn -0.6854 0.0264 0.7277 +vn -0.7246 -0.0228 0.6887 +vn -0.7557 -0.0685 0.6513 +vn -0.7775 -0.1062 0.6198 +vn -0.7916 -0.1335 0.5963 +vn -0.7999 -0.1490 0.5813 +vn -0.8030 -0.1517 0.5763 +vn -0.7986 -0.1408 0.5851 +vn -0.7851 -0.1164 0.6082 +vn -0.7625 -0.0796 0.6420 +vn -0.7315 -0.0337 0.6810 +vn -0.6948 0.0162 0.7190 +vn -0.6569 0.0641 0.7512 +vn -0.6228 0.1047 0.7753 +vn -0.5976 0.1345 0.7904 +vn -0.5838 0.1512 0.7977 +vn -0.5801 0.1545 0.7997 +vn -0.5863 0.1445 0.7971 +vn -0.6038 0.1216 0.7877 +vn -0.6333 0.0865 0.7690 +vn -0.6759 0.0360 0.7361 +vn -0.6720 0.0416 0.7393 +vn -0.6905 0.0233 0.7230 +vn -0.7259 -0.0262 0.6873 +vn -0.7575 -0.0737 0.6486 +vn -0.7822 -0.1140 0.6125 +vn -0.7982 -0.1427 0.5853 +vn -0.8051 -0.1574 0.5718 +vn -0.8033 -0.1568 0.5745 +vn -0.7938 -0.1417 0.5914 +vn -0.7780 -0.1137 0.6179 +vn -0.7558 -0.0748 0.6505 +vn -0.7263 -0.0280 0.6868 +vn -0.6903 0.0222 0.7232 +vn -0.6511 0.0705 0.7557 +vn -0.6142 0.1111 0.7812 +vn -0.5864 0.1398 0.7979 +vn -0.5710 0.1541 0.8063 +vn -0.5697 0.1536 0.8074 +vn -0.6149 0.1087 0.7810 +vn -0.6534 0.0679 0.7540 +vn -0.6929 0.0194 0.7207 +vn -0.7280 -0.0315 0.6848 +vn -0.7561 -0.0799 0.6496 +vn -0.7772 -0.1206 0.6176 +vn -0.7919 -0.1496 0.5920 +vn -0.8003 -0.1637 0.5768 +vn -0.8020 -0.1620 0.5749 +vn -0.7964 -0.1451 0.5871 +vn -0.7823 -0.1151 0.6121 +vn -0.7595 -0.0754 0.6460 +vn -0.7292 -0.0298 0.6836 +vn -0.6947 0.0171 0.7191 +vn -0.6603 0.0613 0.7485 +vn -0.6283 0.0995 0.7716 +vn -0.6001 0.1289 0.7895 +vn -0.5792 0.1468 0.8018 +vn -0.5701 0.1511 0.8075 +vn -0.5771 0.1405 0.8044 +vn -0.6013 0.1150 0.7907 +vn -0.6385 0.0770 0.7657 +vn -0.6812 0.0304 0.7315 +vn -0.7221 -0.0189 0.6915 +vn -0.7554 -0.0648 0.6520 +vn -0.7789 -0.1026 0.6187 +vn -0.7931 -0.1299 0.5950 +vn -0.8002 -0.1456 0.5817 +vn -0.8019 -0.1491 0.5786 +vn -0.7979 -0.1393 0.5865 +vn -0.7857 -0.1160 0.6076 +vn -0.7637 -0.0801 0.6406 +vn -0.7326 -0.0344 0.6798 +vn -0.6952 0.0158 0.7186 +vn -0.6564 0.0644 0.7516 +vn -0.6216 0.1054 0.7762 +vn -0.5954 0.1352 0.7919 +vn -0.5815 0.1519 0.7992 +vn -0.5803 0.1553 0.7994 +vn -0.5893 0.1457 0.7947 +vn -0.6072 0.1234 0.7848 +vn -0.6347 0.0894 0.7675 +vn -0.6705 0.0456 0.7405 +vn -0.7140 -0.0085 0.7001 +vn -0.7104 -0.0038 0.7038 +vn -0.7263 -0.0270 0.6868 +vn -0.7570 -0.0729 0.6493 +vn -0.7815 -0.1119 0.6138 +vn -0.7980 -0.1400 0.5862 +vn -0.8059 -0.1545 0.5715 +vn -0.8052 -0.1540 0.5726 +vn -0.7957 -0.1388 0.5895 +vn -0.7785 -0.1104 0.6179 +vn -0.7548 -0.0717 0.6520 +vn -0.7250 -0.0258 0.6883 +vn -0.6897 0.0232 0.7237 +vn -0.6518 0.0702 0.7551 +vn -0.6160 0.1098 0.7800 +vn -0.5881 0.1379 0.7969 +vn -0.5730 0.1519 0.8054 +vn -0.5719 0.1510 0.8063 +vn -0.5846 0.1358 0.7998 +vn -0.6120 0.1070 0.7836 +vn -0.6504 0.0668 0.7566 +vn -0.6923 0.0189 0.7214 +vn -0.7303 -0.0320 0.6824 +vn -0.7600 -0.0807 0.6448 +vn -0.7805 -0.1220 0.6131 +vn -0.7930 -0.1515 0.5900 +vn -0.7991 -0.1663 0.5778 +vn -0.7992 -0.1651 0.5779 +vn -0.7930 -0.1484 0.5909 +vn -0.7795 -0.1182 0.6151 +vn -0.7580 -0.0776 0.6476 +vn -0.7288 -0.0308 0.6840 +vn -0.6942 0.0176 0.7195 +vn -0.6585 0.0636 0.7499 +vn -0.6266 0.1032 0.7724 +vn -0.6009 0.1332 0.7881 +vn -0.5824 0.1515 0.7986 +vn -0.5743 0.1561 0.8036 +vn -0.5797 0.1459 0.8016 +vn -0.6005 0.1208 0.7904 +vn -0.6351 0.0827 0.7680 +vn -0.6771 0.0356 0.7350 +vn -0.7186 -0.0147 0.6952 +vn -0.7536 -0.0618 0.6544 +vn -0.7789 -0.1003 0.6191 +vn -0.7944 -0.1279 0.5937 +vn -0.8017 -0.1436 0.5802 +vn -0.8023 -0.1473 0.5784 +vn -0.7973 -0.1386 0.5875 +vn -0.7856 -0.1167 0.6076 +vn -0.7647 -0.0817 0.6391 +vn -0.7338 -0.0361 0.6783 +vn -0.6957 0.0152 0.7181 +vn -0.6558 0.0652 0.7521 +vn -0.6201 0.1076 0.7771 +vn -0.5938 0.1378 0.7927 +vn -0.5795 0.1541 0.8003 +vn -0.5785 0.1566 0.8005 +vn -0.5899 0.1462 0.7941 +vn -0.6101 0.1237 0.7826 +vn -0.6375 0.0900 0.7651 +vn -0.6711 0.0471 0.7398 +vn -0.7083 -0.0015 0.7059 +vn -0.7481 -0.0528 0.6615 +vn -0.7445 -0.0501 0.6657 +vn -0.7564 -0.0728 0.6500 +vn -0.7802 -0.1106 0.6156 +vn -0.7969 -0.1381 0.5881 +vn -0.8057 -0.1524 0.5724 +vn -0.8060 -0.1523 0.5719 +vn -0.7975 -0.1374 0.5874 +vn -0.7801 -0.1089 0.6160 +vn -0.7550 -0.0698 0.6520 +vn -0.7242 -0.0242 0.6891 +vn -0.6890 0.0241 0.7243 +vn -0.6520 0.0704 0.7549 +vn -0.6173 0.1098 0.7790 +vn -0.5900 0.1380 0.7955 +vn -0.5744 0.1523 0.8042 +vn -0.5735 0.1519 0.8050 +vn -0.5863 0.1370 0.7984 +vn -0.6110 0.1087 0.7841 +vn -0.6468 0.0692 0.7595 +vn -0.6888 0.0219 0.7245 +vn -0.7293 -0.0282 0.6836 +vn -0.7623 -0.0760 0.6428 +vn -0.7848 -0.1168 0.6086 +vn -0.7972 -0.1465 0.5857 +vn -0.8013 -0.1620 0.5759 +vn -0.7992 -0.1617 0.5789 +vn -0.7912 -0.1460 0.5939 +vn -0.7767 -0.1166 0.6189 +vn -0.7553 -0.0763 0.6509 +vn -0.7269 -0.0294 0.6861 +vn -0.6931 0.0195 0.7205 +vn -0.6570 0.0659 0.7510 +vn -0.6237 0.1061 0.7744 +vn -0.5985 0.1369 0.7893 +vn -0.5830 0.1555 0.7974 +vn -0.5773 0.1603 0.8006 +vn -0.5835 0.1505 0.7980 +vn -0.6028 0.1259 0.7879 +vn -0.6345 0.0879 0.7679 +vn -0.6745 0.0401 0.7371 +vn -0.7158 -0.0116 0.6982 +vn -0.7514 -0.0605 0.6570 +vn -0.7777 -0.1005 0.6205 +vn -0.7944 -0.1286 0.5936 +vn -0.8026 -0.1441 0.5788 +vn -0.8035 -0.1474 0.5768 +vn -0.7978 -0.1386 0.5867 +vn -0.7855 -0.1172 0.6076 +vn -0.7653 -0.0832 0.6383 +vn -0.7351 -0.0379 0.6769 +vn -0.6964 0.0141 0.7175 +vn -0.6550 0.0657 0.7527 +vn -0.6182 0.1097 0.7783 +vn -0.5917 0.1407 0.7938 +vn -0.5781 0.1568 0.8007 +vn -0.5775 0.1581 0.8009 +vn -0.5892 0.1461 0.7946 +vn -0.6115 0.1225 0.7817 +vn -0.6403 0.0886 0.7629 +vn -0.6734 0.0461 0.7378 +vn -0.7085 -0.0018 0.7057 +vn -0.7425 -0.0504 0.6680 +vn -0.7747 -0.0926 0.6255 +vn -0.7715 -0.0937 0.6292 +vn -0.7789 -0.1106 0.6173 +vn -0.7953 -0.1374 0.5904 +vn -0.8044 -0.1516 0.5743 +vn -0.8058 -0.1517 0.5724 +vn -0.7985 -0.1373 0.5861 +vn -0.7819 -0.1091 0.6138 +vn -0.7563 -0.0697 0.6504 +vn -0.7243 -0.0235 0.6891 +vn -0.6886 0.0246 0.7248 +vn -0.6516 0.0706 0.7552 +vn -0.6175 0.1099 0.7788 +vn -0.5909 0.1386 0.7947 +vn -0.5757 0.1538 0.8031 +vn -0.5744 0.1542 0.8039 +vn -0.5874 0.1398 0.7971 +vn -0.6120 0.1122 0.7828 +vn -0.6453 0.0733 0.7603 +vn -0.6850 0.0267 0.7280 +vn -0.7256 -0.0226 0.6877 +vn -0.7609 -0.0693 0.6451 +vn -0.7867 -0.1088 0.6077 +vn -0.8016 -0.1376 0.5818 +vn -0.8062 -0.1532 0.5714 +vn -0.8024 -0.1538 0.5766 +vn -0.7921 -0.1393 0.5942 +vn -0.7758 -0.1111 0.6211 +vn -0.7530 -0.0721 0.6540 +vn -0.7243 -0.0258 0.6890 +vn -0.6558 0.0688 0.7518 +vn -0.6221 0.1086 0.7754 +vn -0.5952 0.1390 0.7914 +vn -0.5805 0.1574 0.7989 +vn -0.5781 0.1622 0.7997 +vn -0.5866 0.1524 0.7954 +vn -0.6064 0.1281 0.7848 +vn -0.6367 0.0904 0.7657 +vn -0.6745 0.0425 0.7370 +vn -0.7144 -0.0099 0.6996 +vn -0.7500 -0.0605 0.6586 +vn -0.7766 -0.1026 0.6215 +vn -0.7935 -0.1319 0.5940 +vn -0.8022 -0.1474 0.5785 +vn -0.8037 -0.1499 0.5758 +vn -0.7984 -0.1401 0.5855 +vn -0.7860 -0.1182 0.6067 +vn -0.7656 -0.0844 0.6377 +vn -0.7360 -0.0396 0.6757 +vn -0.6974 0.0125 0.7165 +vn -0.6546 0.0653 0.7531 +vn -0.6160 0.1108 0.7799 +vn -0.5887 0.1431 0.7956 +vn -0.5759 0.1595 0.8018 +vn -0.5771 0.1600 0.8008 +vn -0.5898 0.1464 0.7941 +vn -0.6123 0.1210 0.7813 +vn -0.6423 0.0859 0.7616 +vn -0.6760 0.0432 0.7356 +vn -0.7102 -0.0044 0.7039 +vn -0.7425 -0.0529 0.6678 +vn -0.7699 -0.0967 0.6308 +vn -0.7927 -0.1263 0.5964 +vn -0.7902 -0.1306 0.5987 +vn -0.7935 -0.1381 0.5927 +vn -0.8026 -0.1520 0.5768 +vn -0.8046 -0.1523 0.5740 +vn -0.7984 -0.1384 0.5860 +vn -0.7830 -0.1106 0.6121 +vn -0.7580 -0.0710 0.6484 +vn -0.7251 -0.0240 0.6882 +vn -0.6884 0.0247 0.7249 +vn -0.6514 0.0706 0.7555 +vn -0.6172 0.1099 0.7791 +vn -0.5907 0.1390 0.7948 +vn -0.5758 0.1550 0.8028 +vn -0.5747 0.1563 0.8033 +vn -0.5877 0.1426 0.7964 +vn -0.6128 0.1152 0.7817 +vn -0.6459 0.0766 0.7595 +vn -0.6832 0.0304 0.7295 +vn -0.7216 -0.0185 0.6920 +vn -0.7568 -0.0645 0.6504 +vn -0.7846 -0.1028 0.6113 +vn -0.8027 -0.1302 0.5820 +vn -0.8102 -0.1448 0.5679 +vn -0.8076 -0.1455 0.5715 +vn -0.7960 -0.1319 0.5907 +vn -0.7774 -0.1051 0.6201 +vn -0.7527 -0.0674 0.6549 +vn -0.7224 -0.0223 0.6910 +vn -0.6886 0.0255 0.7247 +vn -0.6538 0.0712 0.7533 +vn -0.6213 0.1104 0.7757 +vn -0.5943 0.1400 0.7920 +vn -0.5779 0.1574 0.8007 +vn -0.5763 0.1614 0.8011 +vn -0.5878 0.1511 0.7947 +vn -0.6097 0.1267 0.7824 +vn -0.6402 0.0892 0.7630 +vn -0.6767 0.0418 0.7351 +vn -0.7147 -0.0107 0.6993 +vn -0.7494 -0.0617 0.6591 +vn -0.7764 -0.1053 0.6214 +vn -0.7931 -0.1363 0.5936 +vn -0.8012 -0.1523 0.5786 +vn -0.8027 -0.1542 0.5760 +vn -0.7979 -0.1432 0.5855 +vn -0.7860 -0.1201 0.6064 +vn -0.7659 -0.0856 0.6372 +vn -0.7367 -0.0409 0.6749 +vn -0.6987 0.0107 0.7153 +vn -0.6551 0.0638 0.7528 +vn -0.6143 0.1106 0.7813 +vn -0.5852 0.1442 0.7979 +vn -0.5725 0.1612 0.8039 +vn -0.5755 0.1615 0.8017 +vn -0.5908 0.1467 0.7934 +vn -0.6144 0.1198 0.7798 +vn -0.6443 0.0833 0.7602 +vn -0.6782 0.0399 0.7338 +vn -0.7125 -0.0077 0.7016 +vn -0.7439 -0.0558 0.6660 +vn -0.7700 -0.0997 0.6302 +vn -0.7892 -0.1345 0.5992 +vn -0.8023 -0.1507 0.5775 +vn -0.8007 -0.1560 0.5784 +vn -0.8005 -0.1537 0.5793 +vn -0.8026 -0.1539 0.5763 +vn -0.7973 -0.1402 0.5871 +vn -0.7831 -0.1127 0.6116 +vn -0.7591 -0.0732 0.6467 +vn -0.7263 -0.0256 0.6868 +vn -0.6885 0.0246 0.7248 +vn -0.6510 0.0711 0.7557 +vn -0.6170 0.1102 0.7791 +vn -0.5901 0.1393 0.7952 +vn -0.5749 0.1557 0.8032 +vn -0.5741 0.1576 0.8035 +vn -0.5875 0.1444 0.7962 +vn -0.6132 0.1169 0.7812 +vn -0.6470 0.0778 0.7585 +vn -0.6839 0.0312 0.7289 +vn -0.7199 -0.0179 0.6938 +vn -0.7527 -0.0639 0.6552 +vn -0.7800 -0.1019 0.6174 +vn -0.7996 -0.1284 0.5865 +vn -0.8102 -0.1419 0.5687 +vn -0.8108 -0.1418 0.5679 +vn -0.8009 -0.1281 0.5849 +vn -0.7815 -0.1018 0.6154 +vn -0.7549 -0.0651 0.6526 +vn -0.7227 -0.0210 0.6908 +vn -0.6872 0.0259 0.7260 +vn -0.6517 0.0711 0.7551 +vn -0.6197 0.1100 0.7771 +vn -0.5942 0.1391 0.7921 +vn -0.5780 0.1559 0.8010 +vn -0.5748 0.1588 0.8027 +vn -0.5871 0.1475 0.7959 +vn -0.6114 0.1226 0.7817 +vn -0.6433 0.0853 0.7608 +vn -0.6796 0.0385 0.7325 +vn -0.7164 -0.0132 0.6976 +vn -0.7496 -0.0638 0.6588 +vn -0.7763 -0.1073 0.6212 +vn -0.7938 -0.1393 0.5920 +vn -0.8014 -0.1564 0.5773 +vn -0.8016 -0.1583 0.5765 +vn -0.7964 -0.1464 0.5868 +vn -0.7848 -0.1222 0.6076 +vn -0.7654 -0.0868 0.6377 +vn -0.7370 -0.0419 0.6746 +vn -0.6998 0.0094 0.7142 +vn -0.6567 0.0619 0.7516 +vn -0.6143 0.1088 0.7815 +vn -0.5825 0.1433 0.8001 +vn -0.5684 0.1612 0.8068 +vn -0.5723 0.1616 0.8039 +vn -0.5902 0.1462 0.7938 +vn -0.6166 0.1181 0.7783 +vn -0.6473 0.0807 0.7579 +vn -0.6805 0.0370 0.7318 +vn -0.7144 -0.0103 0.6996 +vn -0.7456 -0.0577 0.6639 +vn -0.7712 -0.1011 0.6285 +vn -0.7897 -0.1359 0.5982 +vn -0.8005 -0.1581 0.5780 +vn -0.8043 -0.1618 0.5718 +vn -0.8036 -0.1651 0.5717 +vn -0.8002 -0.1562 0.5789 +vn -0.7953 -0.1424 0.5893 +vn -0.7821 -0.1150 0.6124 +vn -0.7593 -0.0754 0.6463 +vn -0.7272 -0.0272 0.6858 +vn -0.6887 0.0242 0.7246 +vn -0.6500 0.0725 0.7564 +vn -0.6165 0.1122 0.7793 +vn -0.5901 0.1408 0.7949 +vn -0.5743 0.1567 0.8035 +vn -0.5730 0.1585 0.8040 +vn -0.5868 0.1452 0.7966 +vn -0.6133 0.1174 0.7811 +vn -0.6482 0.0774 0.7576 +vn -0.6858 0.0293 0.7272 +vn -0.7210 -0.0211 0.6926 +vn -0.7512 -0.0682 0.6565 +vn -0.7758 -0.1067 0.6218 +vn -0.7944 -0.1334 0.5926 +vn -0.8060 -0.1465 0.5734 +vn -0.8095 -0.1455 0.5688 +vn -0.8032 -0.1310 0.5811 +vn -0.7861 -0.1039 0.6093 +vn -0.7591 -0.0669 0.6474 +vn -0.7254 -0.0230 0.6879 +vn -0.6880 0.0237 0.7253 +vn -0.6508 0.0685 0.7561 +vn -0.6181 0.1070 0.7788 +vn -0.5932 0.1357 0.7935 +vn -0.5786 0.1522 0.8013 +vn -0.5756 0.1549 0.8029 +vn -0.5865 0.1431 0.7972 +vn -0.6113 0.1176 0.7826 +vn -0.6448 0.0805 0.7600 +vn -0.6818 0.0347 0.7306 +vn -0.7183 -0.0155 0.6955 +vn -0.7505 -0.0647 0.6576 +vn -0.7761 -0.1075 0.6213 +vn -0.7941 -0.1392 0.5917 +vn -0.8029 -0.1570 0.5751 +vn -0.8023 -0.1595 0.5752 +vn -0.7953 -0.1476 0.5880 +vn -0.7829 -0.1228 0.6098 +vn -0.7638 -0.0870 0.6395 +vn -0.7364 -0.0421 0.6753 +vn -0.7004 0.0086 0.7136 +vn -0.6586 0.0601 0.7501 +vn -0.6164 0.1061 0.7802 +vn -0.5822 0.1407 0.8008 +vn -0.5651 0.1591 0.8095 +vn -0.5682 0.1599 0.8072 +vn -0.5877 0.1442 0.7961 +vn -0.6171 0.1154 0.7784 +vn -0.6501 0.0773 0.7559 +vn -0.6833 0.0337 0.7293 +vn -0.7161 -0.0125 0.6979 +vn -0.7467 -0.0586 0.6625 +vn -0.7723 -0.1005 0.6272 +vn -0.7908 -0.1343 0.5971 +vn -0.8016 -0.1563 0.5771 +vn -0.8044 -0.1636 0.5710 +vn -0.7989 -0.1558 0.5810 +vn -0.7992 -0.1550 0.5806 +vn -0.7927 -0.1445 0.5923 +vn -0.7800 -0.1166 0.6148 +vn -0.7583 -0.0767 0.6474 +vn -0.7272 -0.0280 0.6859 +vn -0.6889 0.0241 0.7244 +vn -0.6489 0.0734 0.7573 +vn -0.6146 0.1141 0.7805 +vn -0.5899 0.1425 0.7948 +vn -0.5750 0.1575 0.8028 +vn -0.5728 0.1585 0.8042 +vn -0.5862 0.1446 0.7971 +vn -0.6131 0.1162 0.7813 +vn -0.6491 0.0756 0.7569 +vn -0.6879 0.0265 0.7252 +vn -0.7239 -0.0254 0.6894 +vn -0.7531 -0.0739 0.6537 +vn -0.7747 -0.1138 0.6219 +vn -0.7903 -0.1414 0.5962 +vn -0.8004 -0.1551 0.5790 +vn -0.8045 -0.1543 0.5735 +vn -0.8009 -0.1392 0.5824 +vn -0.7874 -0.1111 0.6063 +vn -0.7630 -0.0726 0.6422 +vn -0.7295 -0.0275 0.6835 +vn -0.6908 0.0198 0.7227 +vn -0.6519 0.0647 0.7555 +vn -0.6176 0.1031 0.7797 +vn -0.5921 0.1316 0.7950 +vn -0.5779 0.1481 0.8025 +vn -0.5762 0.1512 0.8032 +vn -0.5870 0.1402 0.7974 +vn -0.6105 0.1151 0.7836 +vn -0.6443 0.0779 0.7607 +vn -0.6823 0.0325 0.7303 +vn -0.7192 -0.0168 0.6946 +vn -0.7513 -0.0650 0.6567 +vn -0.7765 -0.1069 0.6210 +vn -0.7938 -0.1384 0.5922 +vn -0.8034 -0.1563 0.5745 +vn -0.8043 -0.1592 0.5725 +vn -0.7962 -0.1473 0.5868 +vn -0.7818 -0.1223 0.6113 +vn -0.7618 -0.0860 0.6420 +vn -0.7348 -0.0410 0.6770 +vn -0.7003 0.0093 0.7138 +vn -0.6601 0.0598 0.7487 +vn -0.6193 0.1045 0.7781 +vn -0.5645 0.1562 0.8105 +vn -0.5646 0.1569 0.8103 +vn -0.5838 0.1410 0.7996 +vn -0.6152 0.1118 0.7804 +vn -0.6510 0.0733 0.7555 +vn -0.6858 0.0299 0.7271 +vn -0.7177 -0.0150 0.6961 +vn -0.7471 -0.0591 0.6621 +vn -0.7723 -0.0991 0.6274 +vn -0.7912 -0.1311 0.5973 +vn -0.8025 -0.1519 0.5769 +vn -0.8058 -0.1588 0.5704 +vn -0.8007 -0.1504 0.5798 +vn -0.7859 -0.1307 0.6044 +vn -0.7869 -0.1266 0.6039 +vn -0.7770 -0.1163 0.6186 +vn -0.7559 -0.0760 0.6502 +vn -0.7259 -0.0273 0.6872 +vn -0.6886 0.0246 0.7247 +vn -0.6487 0.0738 0.7574 +vn -0.6130 0.1143 0.7817 +vn -0.5882 0.1424 0.7961 +vn -0.5759 0.1565 0.8024 +vn -0.5747 0.1564 0.8032 +vn -0.5867 0.1420 0.7972 +vn -0.6130 0.1136 0.7819 +vn -0.6492 0.0731 0.7571 +vn -0.6892 0.0242 0.7241 +vn -0.7265 -0.0278 0.6866 +vn -0.7565 -0.0767 0.6495 +vn -0.7773 -0.1173 0.6181 +vn -0.7900 -0.1459 0.5954 +vn -0.7972 -0.1607 0.5819 +vn -0.7995 -0.1610 0.5786 +vn -0.7961 -0.1466 0.5871 +vn -0.7849 -0.1186 0.6082 +vn -0.7638 -0.0793 0.6405 +vn -0.7326 -0.0329 0.6798 +vn -0.6546 0.0611 0.7535 +vn -0.6187 0.0996 0.7792 +vn -0.5916 0.1281 0.7960 +vn -0.5765 0.1450 0.8041 +vn -0.5747 0.1491 0.8047 +vn -0.5863 0.1394 0.7980 +vn -0.6099 0.1156 0.7840 +vn -0.6434 0.0786 0.7615 +vn -0.6820 0.0324 0.7306 +vn -0.7196 -0.0177 0.6941 +vn -0.7519 -0.0665 0.6558 +vn -0.7769 -0.1087 0.6202 +vn -0.7938 -0.1402 0.5918 +vn -0.8029 -0.1581 0.5747 +vn -0.8047 -0.1609 0.5715 +vn -0.7979 -0.1484 0.5842 +vn -0.7823 -0.1220 0.6108 +vn -0.7602 -0.0844 0.6442 +vn -0.7324 -0.0383 0.6798 +vn -0.6986 0.0124 0.7154 +vn -0.6604 0.0626 0.7483 +vn -0.6218 0.1064 0.7759 +vn -0.5888 0.1386 0.7963 +vn -0.5676 0.1558 0.8084 +vn -0.5641 0.1560 0.8108 +vn -0.5804 0.1395 0.8022 +vn -0.6116 0.1095 0.7836 +vn -0.6492 0.0706 0.7573 +vn -0.6863 0.0274 0.7268 +vn -0.7191 -0.0167 0.6947 +vn -0.7473 -0.0592 0.6618 +vn -0.7715 -0.0976 0.6287 +vn -0.7904 -0.1285 0.5989 +vn -0.8022 -0.1484 0.5783 +vn -0.8063 -0.1547 0.5708 +vn -0.8020 -0.1461 0.5791 +vn -0.7886 -0.1224 0.6026 +vn -0.7645 -0.0892 0.6384 +vn -0.7656 -0.0855 0.6376 +vn -0.7528 -0.0728 0.6542 +vn -0.7237 -0.0248 0.6897 +vn -0.6877 0.0262 0.7255 +vn -0.6490 0.0744 0.7571 +vn -0.6134 0.1141 0.7815 +vn -0.5872 0.1416 0.7970 +vn -0.5751 0.1551 0.8032 +vn -0.5765 0.1543 0.8024 +vn -0.5889 0.1397 0.7960 +vn -0.6132 0.1116 0.7819 +vn -0.6484 0.0718 0.7579 +vn -0.6886 0.0239 0.7247 +vn -0.7273 -0.0272 0.6858 +vn -0.7589 -0.0756 0.6468 +vn -0.7809 -0.1161 0.6138 +vn -0.7932 -0.1447 0.5915 +vn -0.7980 -0.1600 0.5810 +vn -0.7977 -0.1615 0.5810 +vn -0.7924 -0.1487 0.5916 +vn -0.7809 -0.1220 0.6126 +vn -0.7615 -0.0832 0.6428 +vn -0.7331 -0.0363 0.6791 +vn -0.6970 0.0132 0.7169 +vn -0.6578 0.0596 0.7508 +vn -0.6213 0.0985 0.7773 +vn -0.5927 0.1268 0.7953 +vn -0.5757 0.1433 0.8050 +vn -0.5725 0.1475 0.8065 +vn -0.5837 0.1385 0.8001 +vn -0.6080 0.1157 0.7854 +vn -0.6423 0.0796 0.7623 +vn -0.6818 0.0329 0.7308 +vn -0.7202 -0.0185 0.6935 +vn -0.7530 -0.0683 0.6544 +vn -0.7778 -0.1111 0.6186 +vn -0.7942 -0.1426 0.5907 +vn -0.8027 -0.1602 0.5744 +vn -0.8040 -0.1624 0.5720 +vn -0.7979 -0.1491 0.5840 +vn -0.7831 -0.1212 0.6099 +vn -0.7595 -0.0817 0.6453 +vn -0.7296 -0.0342 0.6830 +vn -0.6953 0.0173 0.7185 +vn -0.6584 0.0676 0.7496 +vn -0.6225 0.1108 0.7747 +vn -0.5921 0.1421 0.7932 +vn -0.5723 0.1583 0.8046 +vn -0.5672 0.1581 0.8082 +vn -0.5801 0.1415 0.8021 +vn -0.6087 0.1110 0.7855 +vn -0.6460 0.0714 0.7599 +vn -0.6846 0.0278 0.7284 +vn -0.7192 -0.0161 0.6945 +vn -0.7480 -0.0581 0.6612 +vn -0.7711 -0.0960 0.6294 +vn -0.7893 -0.1269 0.6008 +vn -0.8011 -0.1471 0.5801 +vn -0.8056 -0.1535 0.5722 +vn -0.8021 -0.1450 0.5793 +vn -0.7896 -0.1215 0.6015 +vn -0.7672 -0.0848 0.6357 +vn -0.7346 -0.0392 0.6773 +vn -0.7358 -0.0388 0.6761 +vn -0.7209 -0.0210 0.6927 +vn -0.6862 0.0284 0.7268 +vn -0.6490 0.0753 0.7570 +vn -0.6143 0.1142 0.7808 +vn -0.5879 0.1414 0.7965 +vn -0.5744 0.1547 0.8038 +vn -0.5761 0.1536 0.8028 +vn -0.5907 0.1388 0.7949 +vn -0.6147 0.1112 0.7808 +vn -0.6478 0.0723 0.7583 +vn -0.6870 0.0255 0.7262 +vn -0.7260 -0.0244 0.6872 +vn -0.7593 -0.0719 0.6468 +vn -0.7832 -0.1119 0.6116 +vn -0.7970 -0.1404 0.5874 +vn -0.8016 -0.1556 0.5773 +vn -0.7994 -0.1572 0.5798 +vn -0.7918 -0.1454 0.5932 +vn -0.7784 -0.1201 0.6161 +vn -0.7583 -0.0824 0.6466 +vn -0.7309 -0.0357 0.6815 +vn -0.6970 0.0143 0.7169 +vn -0.6596 0.0617 0.7490 +vn -0.6239 0.1013 0.7749 +vn -0.5952 0.1296 0.7930 +vn -0.5772 0.1452 0.8036 +vn -0.5721 0.1482 0.8067 +vn -0.5814 0.1383 0.8017 +vn -0.6050 0.1155 0.7878 +vn -0.6399 0.0798 0.7643 +vn -0.6808 0.0333 0.7317 +vn -0.7206 -0.0187 0.6930 +vn -0.7541 -0.0691 0.6531 +vn -0.7790 -0.1121 0.6169 +vn -0.7950 -0.1433 0.5894 +vn -0.8030 -0.1602 0.5741 +vn -0.8036 -0.1616 0.5727 +vn -0.7972 -0.1476 0.5854 +vn -0.7828 -0.1193 0.6107 +vn -0.7594 -0.0788 0.6458 +vn -0.7279 -0.0302 0.6850 +vn -0.6918 0.0216 0.7218 +vn -0.6548 0.0718 0.7524 +vn -0.6207 0.1147 0.7756 +vn -0.5934 0.1456 0.7916 +vn -0.5764 0.1614 0.8010 +vn -0.5722 0.1609 0.8042 +vn -0.5828 0.1448 0.7996 +vn -0.6083 0.1147 0.7853 +vn -0.6437 0.0748 0.7616 +vn -0.6819 0.0306 0.7308 +vn -0.7177 -0.0136 0.6962 +vn -0.7481 -0.0556 0.6612 +vn -0.7718 -0.0936 0.6289 +vn -0.7892 -0.1251 0.6012 +vn -0.8004 -0.1466 0.5812 +vn -0.8046 -0.1543 0.5734 +vn -0.8012 -0.1464 0.5802 +vn -0.7894 -0.1231 0.6013 +vn -0.7682 -0.0866 0.6342 +vn -0.7375 -0.0407 0.6740 +vn -0.6985 0.0113 0.7155 +vn -0.6998 0.0092 0.7142 +vn -0.6846 0.0304 0.7282 +vn -0.6486 0.0755 0.7573 +vn -0.6151 0.1135 0.7802 +vn -0.5890 0.1405 0.7958 +vn -0.5749 0.1542 0.8035 +vn -0.5754 0.1535 0.8033 +vn -0.5904 0.1387 0.7951 +vn -0.6485 0.0733 0.7577 +vn -0.6856 0.0275 0.7274 +vn -0.7237 -0.0213 0.6898 +vn -0.7576 -0.0678 0.6492 +vn -0.7833 -0.1071 0.6122 +vn -0.7993 -0.1353 0.5855 +vn -0.8053 -0.1505 0.5734 +vn -0.8028 -0.1516 0.5766 +vn -0.7939 -0.1396 0.5918 +vn -0.7786 -0.1149 0.6168 +vn -0.7565 -0.0780 0.6493 +vn -0.7279 -0.0317 0.6849 +vn -0.6943 0.0188 0.7194 +vn -0.6587 0.0670 0.7494 +vn -0.6249 0.1073 0.7733 +vn -0.5974 0.1359 0.7903 +vn -0.5800 0.1510 0.8004 +vn -0.5745 0.1525 0.8041 +vn -0.5819 0.1411 0.8009 +vn -0.6031 0.1172 0.7890 +vn -0.6368 0.0813 0.7667 +vn -0.6783 0.0351 0.7339 +vn -0.7200 -0.0171 0.6937 +vn -0.7549 -0.0681 0.6522 +vn -0.7802 -0.1113 0.6155 +vn -0.7962 -0.1424 0.5880 +vn -0.8037 -0.1588 0.5734 +vn -0.8037 -0.1597 0.5731 +vn -0.7966 -0.1452 0.5867 +vn -0.7819 -0.1168 0.6123 +vn -0.7589 -0.0767 0.6466 +vn -0.7274 -0.0286 0.6856 +vn -0.6897 0.0229 0.7237 +vn -0.6512 0.0727 0.7554 +vn -0.6172 0.1155 0.7783 +vn -0.5919 0.1464 0.7926 +vn -0.5780 0.1625 0.7997 +vn -0.5765 0.1624 0.8007 +vn -0.5873 0.1468 0.7959 +vn -0.6104 0.1176 0.7833 +vn -0.6433 0.0782 0.7616 +vn -0.6800 0.0338 0.7324 +vn -0.7155 -0.0107 0.6985 +vn -0.7468 -0.0528 0.6630 +vn -0.7721 -0.0907 0.6290 +vn -0.7903 -0.1225 0.6003 +vn -0.8013 -0.1453 0.5803 +vn -0.8049 -0.1549 0.5728 +vn -0.8007 -0.1484 0.5803 +vn -0.7887 -0.1257 0.6017 +vn -0.7681 -0.0893 0.6340 +vn -0.7386 -0.0432 0.6727 +vn -0.7018 0.0068 0.7123 +vn -0.6601 0.0576 0.7489 +vn -0.6617 0.0551 0.7477 +vn -0.6485 0.0747 0.7575 +vn -0.6158 0.1115 0.7799 +vn -0.5901 0.1383 0.7953 +vn -0.5757 0.1527 0.8032 +vn -0.5753 0.1529 0.8035 +vn -0.5894 0.1388 0.7958 +vn -0.6493 0.0736 0.7569 +vn -0.6854 0.0286 0.7275 +vn -0.7217 -0.0194 0.6919 +vn -0.7548 -0.0652 0.6526 +vn -0.7814 -0.1039 0.6153 +vn -0.7992 -0.1319 0.5864 +vn -0.8075 -0.1469 0.5713 +vn -0.8062 -0.1481 0.5728 +vn -0.7968 -0.1354 0.5889 +vn -0.7806 -0.1103 0.6152 +vn -0.7569 -0.0736 0.6493 +vn -0.7259 -0.0274 0.6872 +vn -0.6907 0.0235 0.7228 +vn -0.6550 0.0727 0.7521 +vn -0.6229 0.1139 0.7739 +vn -0.5977 0.1429 0.7888 +vn -0.5823 0.1581 0.7974 +vn -0.5783 0.1588 0.8002 +vn -0.5857 0.1460 0.7972 +vn -0.6046 0.1208 0.7873 +vn -0.6353 0.0844 0.7676 +vn -0.6750 0.0386 0.7367 +vn -0.7177 -0.0131 0.6962 +vn -0.7550 -0.0646 0.6525 +vn -0.7815 -0.1086 0.6143 +vn -0.7975 -0.1399 0.5868 +vn -0.8049 -0.1563 0.5724 +vn -0.8044 -0.1571 0.5730 +vn -0.7966 -0.1426 0.5875 +vn -0.7814 -0.1144 0.6135 +vn -0.7584 -0.0751 0.6475 +vn -0.7275 -0.0284 0.6855 +vn -0.6900 0.0214 0.7235 +vn -0.6499 0.0698 0.7568 +vn -0.6141 0.1119 0.7812 +vn -0.5885 0.1431 0.7957 +vn -0.5763 0.1599 0.8014 +vn -0.5778 0.1609 0.8002 +vn -0.5912 0.1464 0.7931 +vn -0.6141 0.1184 0.7803 +vn -0.6449 0.0798 0.7601 +vn -0.6799 0.0355 0.7324 +vn -0.7140 -0.0092 0.7001 +vn -0.7447 -0.0512 0.6655 +vn -0.7707 -0.0887 0.6310 +vn -0.7905 -0.1202 0.6005 +vn -0.8028 -0.1432 0.5788 +vn -0.8068 -0.1541 0.5704 +vn -0.8020 -0.1494 0.5784 +vn -0.7887 -0.1276 0.6014 +vn -0.7675 -0.0911 0.6345 +vn -0.7385 -0.0446 0.6728 +vn -0.7028 0.0059 0.7113 +vn -0.6637 0.0544 0.7459 +vn -0.6242 0.0970 0.7752 +vn -0.6261 0.0960 0.7738 +vn -0.6170 0.1089 0.7794 +vn -0.5914 0.1352 0.7950 +vn -0.5764 0.1499 0.8033 +vn -0.5751 0.1513 0.8039 +vn -0.5884 0.1384 0.7966 +vn -0.6146 0.1117 0.7808 +vn -0.6493 0.0735 0.7570 +vn -0.6861 0.0280 0.7269 +vn -0.7212 -0.0197 0.6925 +vn -0.7526 -0.0652 0.6553 +vn -0.7784 -0.1037 0.6191 +vn -0.7969 -0.1317 0.5895 +vn -0.8070 -0.1468 0.5719 +vn -0.8080 -0.1479 0.5702 +vn -0.7996 -0.1350 0.5852 +vn -0.7827 -0.1091 0.6127 +vn -0.7585 -0.0721 0.6476 +vn -0.7261 -0.0258 0.6871 +vn -0.6881 0.0254 0.7251 +vn -0.6503 0.0753 0.7559 +vn -0.6183 0.1173 0.7771 +vn -0.5953 0.1471 0.7899 +vn -0.5827 0.1625 0.7963 +vn -0.5811 0.1632 0.7973 +vn -0.5906 0.1498 0.7929 +vn -0.6094 0.1240 0.7830 +vn -0.6372 0.0874 0.7657 +vn -0.6733 0.0422 0.7381 +vn -0.7141 -0.0084 0.6999 +vn -0.7529 -0.0592 0.6555 +vn -0.7823 -0.1035 0.6142 +vn -0.7994 -0.1358 0.5852 +vn -0.8065 -0.1528 0.5711 +vn -0.8057 -0.1540 0.5719 +vn -0.7973 -0.1400 0.5871 +vn -0.7815 -0.1124 0.6137 +vn -0.7582 -0.0740 0.6478 +vn -0.7279 -0.0287 0.6850 +vn -0.6917 0.0191 0.7219 +vn -0.6519 0.0652 0.7555 +vn -0.6140 0.1057 0.7822 +vn -0.5857 0.1365 0.7989 +vn -0.5726 0.1540 0.8053 +vn -0.5754 0.1562 0.8028 +vn -0.5915 0.1430 0.7935 +vn -0.6170 0.1162 0.7783 +vn -0.6478 0.0789 0.7577 +vn -0.6813 0.0351 0.7311 +vn -0.7141 -0.0100 0.7000 +vn -0.7431 -0.0521 0.6671 +vn -0.7682 -0.0893 0.6338 +vn -0.7887 -0.1200 0.6029 +vn -0.8027 -0.1423 0.5791 +vn -0.8085 -0.1532 0.5681 +vn -0.8047 -0.1492 0.5746 +vn -0.7906 -0.1281 0.5987 +vn -0.7675 -0.0914 0.6344 +vn -0.7375 -0.0443 0.6738 +vn -0.7022 0.0070 0.7119 +vn -0.6644 0.0562 0.7452 +vn -0.6281 0.0980 0.7719 +vn -0.5949 0.1277 0.7935 +vn -0.5973 0.1293 0.7915 +vn -0.5932 0.1328 0.7940 +vn -0.5773 0.1475 0.8030 +vn -0.5748 0.1496 0.8045 +vn -0.5871 0.1378 0.7977 +vn -0.6129 0.1118 0.7821 +vn -0.6483 0.0735 0.7578 +vn -0.6867 0.0269 0.7264 +vn -0.7221 -0.0220 0.6914 +vn -0.7519 -0.0679 0.6558 +vn -0.7760 -0.1067 0.6216 +vn -0.7938 -0.1350 0.5930 +vn -0.8045 -0.1505 0.5745 +vn -0.8072 -0.1519 0.5704 +vn -0.8009 -0.1388 0.5824 +vn -0.7848 -0.1120 0.6095 +vn -0.7601 -0.0739 0.6455 +vn -0.7276 -0.0273 0.6854 +vn -0.6881 0.0242 0.7252 +vn -0.6474 0.0742 0.7585 +vn -0.6133 0.1163 0.7812 +vn -0.5905 0.1460 0.7937 +vn -0.5806 0.1614 0.7981 +vn -0.5821 0.1621 0.7968 +vn -0.5940 0.1490 0.7905 +vn -0.6148 0.1234 0.7789 +vn -0.6419 0.0875 0.7617 +vn -0.6746 0.0436 0.7369 +vn -0.7116 -0.0052 0.7026 +vn -0.7488 -0.0544 0.6605 +vn -0.7803 -0.0979 0.6176 +vn -0.8007 -0.1305 0.5846 +vn -0.8089 -0.1484 0.5688 +vn -0.8078 -0.1506 0.5698 +vn -0.7990 -0.1375 0.5853 +vn -0.7826 -0.1108 0.6126 +vn -0.7588 -0.0735 0.6471 +vn -0.7286 -0.0293 0.6843 +vn -0.6934 0.0172 0.7203 +vn -0.6555 0.0617 0.7526 +vn -0.6178 0.1003 0.7799 +vn -0.5864 0.1299 0.7995 +vn -0.5694 0.1474 0.8087 +vn -0.5707 0.1503 0.8073 +vn -0.5881 0.1382 0.7969 +vn -0.6163 0.1124 0.7794 +vn -0.6496 0.0760 0.7565 +vn -0.6836 0.0328 0.7291 +vn -0.7157 -0.0126 0.6983 +vn -0.7434 -0.0556 0.6665 +vn -0.7665 -0.0929 0.6355 +vn -0.7857 -0.1231 0.6062 +vn -0.8002 -0.1445 0.5820 +vn -0.8079 -0.1544 0.5687 +vn -0.8063 -0.1498 0.5721 +vn -0.7935 -0.1285 0.5947 +vn -0.7693 -0.0912 0.6323 +vn -0.7370 -0.0428 0.6746 +vn -0.7005 0.0096 0.7136 +vn -0.6630 0.0596 0.7462 +vn -0.6282 0.1021 0.7713 +vn -0.5991 0.1336 0.7894 +vn -0.5760 0.1484 0.8038 +vn -0.5789 0.1525 0.8010 +vn -0.5794 0.1477 0.8015 +vn -0.5752 0.1497 0.8042 +vn -0.5859 0.1382 0.7985 +vn -0.6110 0.1125 0.7836 +vn -0.6467 0.0740 0.7591 +vn -0.6867 0.0265 0.7264 +vn -0.7238 -0.0241 0.6896 +vn -0.7533 -0.0712 0.6538 +vn -0.7754 -0.1103 0.6217 +vn -0.7917 -0.1389 0.5950 +vn -0.8016 -0.1550 0.5773 +vn -0.8048 -0.1571 0.5724 +vn -0.7999 -0.1444 0.5824 +vn -0.7856 -0.1171 0.6075 +vn -0.7613 -0.0774 0.6437 +vn -0.7288 -0.0294 0.6841 +vn -0.6897 0.0225 0.7238 +vn -0.6475 0.0726 0.7586 +vn -0.6106 0.1144 0.7836 +vn -0.5860 0.1433 0.7974 +vn -0.5765 0.1578 0.8017 +vn -0.5805 0.1579 0.7988 +vn -0.5951 0.1446 0.7905 +vn -0.6180 0.1194 0.7770 +vn -0.6466 0.0842 0.7581 +vn -0.6780 0.0414 0.7338 +vn -0.7114 -0.0059 0.7028 +vn -0.7451 -0.0536 0.6647 +vn -0.7757 -0.0963 0.6236 +vn -0.7986 -0.1286 0.5879 +vn -0.8103 -0.1467 0.5674 +vn -0.8104 -0.1493 0.5665 +vn -0.8014 -0.1369 0.5822 +vn -0.7847 -0.1109 0.6098 +vn -0.7604 -0.0741 0.6452 +vn -0.7298 -0.0303 0.6830 +vn -0.6949 0.0157 0.7189 +vn -0.6582 0.0598 0.7504 +vn -0.6226 0.0978 0.7763 +vn -0.5912 0.1267 0.7965 +vn -0.5701 0.1437 0.8089 +vn -0.5668 0.1468 0.8106 +vn -0.5825 0.1351 0.8015 +vn -0.6121 0.1097 0.7831 +vn -0.6485 0.0732 0.7577 +vn -0.6849 0.0299 0.7280 +vn -0.7178 -0.0157 0.6960 +vn -0.7454 -0.0595 0.6639 +vn -0.7669 -0.0976 0.6342 +vn -0.7836 -0.1279 0.6079 +vn -0.7966 -0.1489 0.5858 +vn -0.8046 -0.1582 0.5724 +vn -0.8049 -0.1529 0.5733 +vn -0.7947 -0.1309 0.5926 +vn -0.7718 -0.0926 0.6291 +vn -0.7378 -0.0423 0.6736 +vn -0.6988 0.0118 0.7152 +vn -0.6604 0.0628 0.7483 +vn -0.6261 0.1056 0.7725 +vn -0.5989 0.1372 0.7890 +vn -0.5808 0.1558 0.7990 +vn -0.5701 0.1577 0.8062 +vn -0.5736 0.1605 0.8032 +vn -0.5773 0.1521 0.8022 +vn -0.5862 0.1403 0.7979 +vn -0.6098 0.1143 0.7842 +vn -0.6451 0.0754 0.7604 +vn -0.6858 0.0271 0.7272 +vn -0.7247 -0.0244 0.6886 +vn -0.7557 -0.0724 0.6509 +vn -0.7770 -0.1116 0.6195 +vn -0.7913 -0.1397 0.5953 +vn -0.8001 -0.1558 0.5792 +vn -0.8028 -0.1585 0.5748 +vn -0.7983 -0.1467 0.5841 +vn -0.7850 -0.1201 0.6077 +vn -0.7617 -0.0799 0.6430 +vn -0.7289 -0.0302 0.6839 +vn -0.6903 0.0227 0.7232 +vn -0.6489 0.0729 0.7573 +vn -0.6106 0.1145 0.7836 +vn -0.5838 0.1429 0.7992 +vn -0.5728 0.1563 0.8046 +vn -0.5772 0.1553 0.8017 +vn -0.5940 0.1412 0.7920 +vn -0.6190 0.1155 0.7768 +vn -0.6495 0.0797 0.7562 +vn -0.6821 0.0365 0.7303 +vn -0.7140 -0.0108 0.7001 +vn -0.7443 -0.0585 0.6653 +vn -0.7716 -0.1014 0.6279 +vn -0.7935 -0.1340 0.5936 +vn -0.8074 -0.1521 0.5701 +vn -0.8108 -0.1541 0.5646 +vn -0.8034 -0.1408 0.5785 +vn -0.7869 -0.1141 0.6064 +vn -0.7625 -0.0766 0.6424 +vn -0.7314 -0.0322 0.6812 +vn -0.6960 0.0146 0.7179 +vn -0.6596 0.0593 0.7492 +vn -0.6253 0.0980 0.7742 +vn -0.5961 0.1273 0.7927 +vn -0.5749 0.1444 0.8054 +vn -0.5670 0.1476 0.8104 +vn -0.5780 0.1361 0.8046 +vn -0.6063 0.1104 0.7875 +vn -0.6445 0.0733 0.7611 +vn -0.6842 0.0290 0.7287 +vn -0.7195 -0.0177 0.6942 +vn -0.7479 -0.0622 0.6608 +vn -0.7693 -0.1008 0.6308 +vn -0.7842 -0.1310 0.6065 +vn -0.7946 -0.1516 0.5878 +vn -0.8010 -0.1607 0.5766 +vn -0.8016 -0.1556 0.5772 +vn -0.7932 -0.1339 0.5940 +vn -0.7726 -0.0954 0.6277 +vn -0.7391 -0.0438 0.6721 +vn -0.6980 0.0128 0.7159 +vn -0.6576 0.0653 0.7505 +vn -0.6232 0.1082 0.7745 +vn -0.5974 0.1388 0.7898 +vn -0.5816 0.1560 0.7984 +vn -0.5766 0.1595 0.8013 +vn -0.5791 0.1507 0.8012 +vn -0.5834 0.1491 0.7984 +vn -0.5885 0.1425 0.7958 +vn -0.6104 0.1164 0.7835 +vn -0.6443 0.0772 0.7608 +vn -0.6848 0.0285 0.7282 +vn -0.7244 -0.0236 0.6890 +vn -0.7570 -0.0721 0.6494 +vn -0.7794 -0.1115 0.6165 +vn -0.7924 -0.1390 0.5939 +vn -0.7996 -0.1539 0.5804 +vn -0.8018 -0.1562 0.5768 +vn -0.7972 -0.1449 0.5860 +vn -0.7844 -0.1192 0.6087 +vn -0.7616 -0.0799 0.6431 +vn -0.7288 -0.0303 0.6840 +vn -0.6896 0.0236 0.7238 +vn -0.6493 0.0743 0.7569 +vn -0.6123 0.1156 0.7821 +vn -0.5842 0.1435 0.7988 +vn -0.5712 0.1561 0.8058 +vn -0.5745 0.1539 0.8039 +vn -0.5916 0.1386 0.7942 +vn -0.6186 0.1118 0.7777 +vn -0.6511 0.0752 0.7553 +vn -0.6855 0.0309 0.7273 +vn -0.7183 -0.0175 0.6955 +vn -0.7468 -0.0658 0.6618 +vn -0.7707 -0.1093 0.6277 +vn -0.7895 -0.1426 0.5970 +vn -0.8021 -0.1613 0.5750 +vn -0.8071 -0.1630 0.5674 +vn -0.8027 -0.1481 0.5777 +vn -0.7879 -0.1195 0.6040 +vn -0.7640 -0.0804 0.6401 +vn -0.7328 -0.0345 0.6796 +vn -0.6969 0.0136 0.7170 +vn -0.6600 0.0595 0.7489 +vn -0.6259 0.0992 0.7735 +vn -0.5980 0.1295 0.7909 +vn -0.5791 0.1477 0.8018 +vn -0.5710 0.1517 0.8068 +vn -0.5777 0.1405 0.8041 +vn -0.6019 0.1147 0.7903 +vn -0.6395 0.0768 0.7650 +vn -0.6814 0.0309 0.7312 +vn -0.7198 -0.0174 0.6939 +vn -0.7502 -0.0632 0.6582 +vn -0.7720 -0.1024 0.6273 +vn -0.7863 -0.1323 0.6035 +vn -0.7949 -0.1517 0.5875 +vn -0.7992 -0.1600 0.5793 +vn -0.7987 -0.1548 0.5815 +vn -0.7906 -0.1340 0.5975 +vn -0.7716 -0.0966 0.6287 +vn -0.7397 -0.0455 0.6713 +vn -0.6979 0.0121 0.7160 +vn -0.6553 0.0664 0.7525 +vn -0.6201 0.1098 0.7768 +vn -0.5954 0.1396 0.7912 +vn -0.5817 0.1554 0.7984 +vn -0.5790 0.1576 0.7999 +vn -0.5872 0.1465 0.7960 +vn -0.6024 0.1249 0.7883 +vn -0.6062 0.1228 0.7858 +vn -0.6127 0.1173 0.7815 +vn -0.6450 0.0784 0.7601 +vn -0.6843 0.0296 0.7285 +vn -0.7238 -0.0229 0.6896 +vn -0.7571 -0.0720 0.6493 +vn -0.7808 -0.1118 0.6146 +vn -0.7944 -0.1389 0.5913 +vn -0.8000 -0.1528 0.5802 +vn -0.8008 -0.1540 0.5788 +vn -0.7962 -0.1423 0.5881 +vn -0.7837 -0.1171 0.6099 +vn -0.7616 -0.0790 0.6432 +vn -0.7292 -0.0304 0.6836 +vn -0.6892 0.0230 0.7242 +vn -0.6482 0.0741 0.7578 +vn -0.6128 0.1157 0.7817 +vn -0.5862 0.1436 0.7973 +vn -0.5723 0.1558 0.8051 +vn -0.5739 0.1528 0.8045 +vn -0.5900 0.1364 0.7958 +vn -0.6172 0.1086 0.7793 +vn -0.6511 0.0714 0.7555 +vn -0.6874 0.0270 0.7257 +vn -0.7220 -0.0218 0.6915 +vn -0.7511 -0.0704 0.6564 +vn -0.7733 -0.1142 0.6236 +vn -0.7890 -0.1481 0.5962 +vn -0.7987 -0.1676 0.5779 +vn -0.8022 -0.1700 0.5722 +vn -0.7987 -0.1550 0.5814 +vn -0.7862 -0.1249 0.6051 +vn -0.7641 -0.0838 0.6396 +vn -0.7335 -0.0364 0.6787 +vn -0.6974 0.0130 0.7165 +vn -0.6599 0.0600 0.7489 +vn -0.6254 0.1005 0.7738 +vn -0.5977 0.1316 0.7908 +vn -0.5800 0.1507 0.8006 +vn -0.5741 0.1560 0.8037 +vn -0.5809 0.1459 0.8008 +vn -0.6014 0.1205 0.7898 +vn -0.6358 0.0821 0.7674 +vn -0.6778 0.0349 0.7344 +vn -0.7185 -0.0151 0.6954 +vn -0.7515 -0.0624 0.6567 +vn -0.7747 -0.1026 0.6239 +vn -0.7889 -0.1329 0.5999 +vn -0.7964 -0.1515 0.5855 +vn -0.7989 -0.1581 0.5803 +vn -0.7967 -0.1521 0.5848 +vn -0.7881 -0.1316 0.6013 +vn -0.7699 -0.0956 0.6309 +vn -0.7397 -0.0461 0.6713 +vn -0.6988 0.0105 0.7153 +vn -0.6543 0.0651 0.7533 +vn -0.6171 0.1093 0.7792 +vn -0.5927 0.1390 0.7933 +vn -0.5807 0.1541 0.7994 +vn -0.5801 0.1557 0.7995 +vn -0.5899 0.1445 0.7944 +vn -0.6094 0.1214 0.7835 +vn -0.6354 0.0872 0.7673 +vn -0.6375 0.0871 0.7655 +vn -0.6469 0.0779 0.7585 +vn -0.6848 0.0297 0.7280 +vn -0.7236 -0.0229 0.6898 +vn -0.7569 -0.0725 0.6495 +vn -0.7811 -0.1128 0.6141 +vn -0.7956 -0.1400 0.5893 +vn -0.8013 -0.1532 0.5783 +vn -0.8003 -0.1532 0.5796 +vn -0.7947 -0.1408 0.5904 +vn -0.7826 -0.1157 0.6116 +vn -0.7615 -0.0784 0.6434 +vn -0.7301 -0.0313 0.6826 +vn -0.6904 0.0208 0.7231 +vn -0.6480 0.0713 0.7583 +vn -0.6114 0.1132 0.7831 +vn -0.5866 0.1419 0.7973 +vn -0.5743 0.1548 0.8038 +vn -0.5753 0.1520 0.8037 +vn -0.5900 0.1353 0.7960 +vn -0.6160 0.1072 0.7804 +vn -0.6499 0.0699 0.7568 +vn -0.6872 0.0258 0.7259 +vn -0.7235 -0.0222 0.6900 +vn -0.7546 -0.0702 0.6524 +vn -0.7777 -0.1134 0.6183 +vn -0.7923 -0.1475 0.5920 +vn -0.7994 -0.1679 0.5769 +vn -0.8000 -0.1715 0.5748 +vn -0.7946 -0.1574 0.5863 +vn -0.7823 -0.1274 0.6098 +vn -0.7617 -0.0855 0.6423 +vn -0.7327 -0.0370 0.6795 +vn -0.6973 0.0133 0.7166 +vn -0.6598 0.0607 0.7490 +vn -0.6248 0.1015 0.7742 +vn -0.5967 0.1328 0.7914 +vn -0.5791 0.1523 0.8009 +vn -0.5743 0.1583 0.8032 +vn -0.5831 0.1492 0.7986 +vn -0.6040 0.1249 0.7871 +vn -0.6355 0.0869 0.7671 +vn -0.6753 0.0392 0.7365 +vn -0.7163 -0.0122 0.6977 +vn -0.7514 -0.0609 0.6570 +vn -0.7766 -0.1022 0.6216 +vn -0.7919 -0.1328 0.5961 +vn -0.7987 -0.1512 0.5824 +vn -0.7995 -0.1567 0.5799 +vn -0.7956 -0.1493 0.5870 +vn -0.7861 -0.1284 0.6046 +vn -0.7680 -0.0934 0.6336 +vn -0.7392 -0.0459 0.6720 +vn -0.6999 0.0088 0.7141 +vn -0.6556 0.0624 0.7525 +vn -0.6160 0.1066 0.7805 +vn -0.5898 0.1365 0.7959 +vn -0.5785 0.1515 0.8014 +vn -0.5796 0.1529 0.8004 +vn -0.5910 0.1418 0.7941 +vn -0.6115 0.1193 0.7822 +vn -0.6395 0.0862 0.7639 +vn -0.6726 0.0437 0.7387 +vn -0.6732 0.0443 0.7381 +vn -0.6861 0.0287 0.7270 +vn -0.7238 -0.0233 0.6895 +vn -0.7569 -0.0730 0.6495 +vn -0.7812 -0.1139 0.6137 +vn -0.7960 -0.1418 0.5884 +vn -0.8022 -0.1550 0.5766 +vn -0.8008 -0.1541 0.5788 +vn -0.7935 -0.1405 0.5921 +vn -0.7809 -0.1151 0.6139 +vn -0.7607 -0.0785 0.6443 +vn -0.7309 -0.0327 0.6816 +vn -0.6926 0.0179 0.7211 +vn -0.6501 0.0672 0.7568 +vn -0.6115 0.1087 0.7837 +vn -0.5848 0.1378 0.7994 +vn -0.5739 0.1520 0.8047 +vn -0.5766 0.1506 0.8030 +vn -0.5910 0.1348 0.7953 +vn -0.6158 0.1071 0.7805 +vn -0.6485 0.0703 0.7579 +vn -0.6855 0.0270 0.7275 +vn -0.7226 -0.0199 0.6910 +vn -0.7554 -0.0666 0.6518 +vn -0.7807 -0.1084 0.6154 +vn -0.7968 -0.1415 0.5874 +vn -0.8036 -0.1620 0.5727 +vn -0.8021 -0.1665 0.5734 +vn -0.7938 -0.1537 0.5884 +vn -0.7790 -0.1247 0.6144 +vn -0.7578 -0.0833 0.6471 +vn -0.7299 -0.0349 0.6826 +vn -0.6962 0.0150 0.7176 +vn -0.6596 0.0621 0.7490 +vn -0.6247 0.1025 0.7741 +vn -0.5962 0.1333 0.7917 +vn -0.5781 0.1525 0.8016 +vn -0.5733 0.1583 0.8039 +vn -0.5828 0.1496 0.7987 +vn -0.6056 0.1260 0.7857 +vn -0.6377 0.0888 0.7651 +vn -0.6753 0.0416 0.7364 +vn -0.7147 -0.0102 0.6993 +vn -0.7502 -0.0599 0.6584 +vn -0.7771 -0.1020 0.6211 +vn -0.7939 -0.1329 0.5933 +vn -0.8014 -0.1510 0.5786 +vn -0.8014 -0.1558 0.5775 +vn -0.7954 -0.1472 0.5878 +vn -0.7844 -0.1255 0.6073 +vn -0.7662 -0.0909 0.6361 +vn -0.7383 -0.0450 0.6729 +vn -0.7009 0.0076 0.7132 +vn -0.6581 0.0596 0.7505 +vn -0.6176 0.1033 0.7796 +vn -0.5885 0.1334 0.7974 +vn -0.5758 0.1483 0.8040 +vn -0.5777 0.1495 0.8025 +vn -0.5904 0.1386 0.7951 +vn -0.6120 0.1167 0.7822 +vn -0.6407 0.0844 0.7631 +vn -0.6741 0.0435 0.7373 +vn -0.7099 -0.0033 0.7043 +vn -0.7095 -0.0032 0.7047 +vn -0.7242 -0.0235 0.6891 +vn -0.7570 -0.0726 0.6493 +vn -0.7816 -0.1139 0.6132 +vn -0.7967 -0.1426 0.5873 +vn -0.8029 -0.1565 0.5752 +vn -0.8014 -0.1557 0.5774 +vn -0.7933 -0.1413 0.5922 +vn -0.7793 -0.1151 0.6160 +vn -0.7591 -0.0785 0.6462 +vn -0.7309 -0.0335 0.6816 +vn -0.6946 0.0157 0.7192 +vn -0.6536 0.0637 0.7541 +vn -0.6143 0.1045 0.7821 +vn -0.5848 0.1335 0.8001 +vn -0.5712 0.1482 0.8073 +vn -0.5748 0.1481 0.8047 +vn -0.5911 0.1340 0.7953 +vn -0.6161 0.1076 0.7803 +vn -0.6477 0.0717 0.7585 +vn -0.6834 0.0294 0.7294 +vn -0.7201 -0.0163 0.6936 +vn -0.7539 -0.0617 0.6541 +vn -0.7809 -0.1025 0.6162 +vn -0.7991 -0.1341 0.5860 +vn -0.8080 -0.1534 0.5688 +vn -0.8070 -0.1580 0.5690 +vn -0.7968 -0.1460 0.5863 +vn -0.7790 -0.1180 0.6158 +vn -0.7550 -0.0775 0.6511 +vn -0.7263 -0.0300 0.6867 +vn -0.6939 0.0187 0.7198 +vn -0.6591 0.0643 0.7492 +vn -0.6252 0.1034 0.7736 +vn -0.5968 0.1331 0.7912 +vn -0.5782 0.1514 0.8017 +vn -0.5727 0.1568 0.8046 +vn -0.5820 0.1479 0.7996 +vn -0.6053 0.1243 0.7862 +vn -0.6389 0.0874 0.7642 +vn -0.6769 0.0409 0.7349 +vn -0.7146 -0.0101 0.6995 +vn -0.7490 -0.0598 0.6598 +vn -0.7764 -0.1023 0.6219 +vn -0.7944 -0.1335 0.5925 +vn -0.8032 -0.1514 0.5761 +vn -0.8036 -0.1554 0.5744 +vn -0.7967 -0.1458 0.5865 +vn -0.7836 -0.1231 0.6089 +vn -0.7645 -0.0885 0.6385 +vn -0.7373 -0.0438 0.6742 +vn -0.7015 0.0070 0.7126 +vn -0.6605 0.0575 0.7486 +vn -0.6208 0.1005 0.7775 +vn -0.5900 0.1308 0.7967 +vn -0.5742 0.1462 0.8055 +vn -0.5749 0.1474 0.8048 +vn -0.5884 0.1364 0.7970 +vn -0.6110 0.1146 0.7833 +vn -0.6405 0.0828 0.7634 +vn -0.6746 0.0425 0.7369 +vn -0.7100 -0.0039 0.7042 +vn -0.7434 -0.0511 0.6668 +vn -0.7430 -0.0520 0.6672 +vn -0.7567 -0.0705 0.6500 +vn -0.7820 -0.1112 0.6133 +vn -0.7978 -0.1406 0.5863 +vn -0.8043 -0.1559 0.5734 +vn -0.8026 -0.1560 0.5757 +vn -0.7938 -0.1419 0.5914 +vn -0.7785 -0.1149 0.6170 +vn -0.7572 -0.0777 0.6485 +vn -0.7296 -0.0329 0.6830 +vn -0.6954 0.0156 0.7184 +vn -0.6567 0.0626 0.7515 +vn -0.6185 0.1027 0.7790 +vn -0.5878 0.1314 0.7982 +vn -0.5708 0.1462 0.8079 +vn -0.5712 0.1466 0.8076 +vn -0.5879 0.1333 0.7978 +vn -0.6150 0.1081 0.7811 +vn -0.6470 0.0732 0.7589 +vn -0.6819 0.0317 0.7307 +vn -0.7175 -0.0133 0.6964 +vn -0.7509 -0.0579 0.6578 +vn -0.7789 -0.0979 0.6194 +vn -0.7986 -0.1289 0.5878 +vn -0.8094 -0.1472 0.5685 +vn -0.8108 -0.1509 0.5654 +vn -0.8017 -0.1388 0.5813 +vn -0.7823 -0.1112 0.6128 +vn -0.7552 -0.0714 0.6515 +vn -0.7238 -0.0248 0.6895 +vn -0.6909 0.0228 0.7226 +vn -0.6580 0.0667 0.7500 +vn -0.6261 0.1038 0.7727 +vn -0.5986 0.1321 0.7901 +vn -0.5799 0.1494 0.8008 +vn -0.5735 0.1541 0.8045 +vn -0.5817 0.1450 0.8003 +vn -0.6044 0.1216 0.7873 +vn -0.6384 0.0851 0.7649 +vn -0.6777 0.0388 0.7343 +vn -0.7154 -0.0114 0.6986 +vn -0.7484 -0.0599 0.6605 +vn -0.7754 -0.1021 0.6232 +vn -0.7940 -0.1335 0.5931 +vn -0.8038 -0.1516 0.5753 +vn -0.8051 -0.1555 0.5724 +vn -0.7985 -0.1451 0.5843 +vn -0.7842 -0.1214 0.6084 +vn -0.7634 -0.0863 0.6402 +vn -0.7360 -0.0422 0.6756 +vn -0.7015 0.0071 0.7125 +vn -0.6623 0.0561 0.7471 +vn -0.6239 0.0985 0.7753 +vn -0.5929 0.1292 0.7948 +vn -0.5748 0.1458 0.8051 +vn -0.5728 0.1478 0.8062 +vn -0.5856 0.1368 0.7989 +vn -0.6089 0.1146 0.7849 +vn -0.6392 0.0826 0.7645 +vn -0.6742 0.0421 0.7373 +vn -0.7103 -0.0045 0.7039 +vn -0.7436 -0.0531 0.6664 +vn -0.7708 -0.0960 0.6298 +vn -0.7710 -0.0981 0.6292 +vn -0.7812 -0.1072 0.6150 +vn -0.7986 -0.1366 0.5861 +vn -0.8063 -0.1530 0.5713 +vn -0.8050 -0.1546 0.5728 +vn -0.7956 -0.1413 0.5891 +vn -0.7789 -0.1143 0.6166 +vn -0.7559 -0.0760 0.6503 +vn -0.7274 -0.0303 0.6855 +vn -0.6943 0.0184 0.7194 +vn -0.6580 0.0650 0.7502 +vn -0.6222 0.1045 0.7758 +vn -0.5921 0.1328 0.7948 +vn -0.5734 0.1476 0.8059 +vn -0.5702 0.1480 0.8080 +vn -0.5838 0.1346 0.8006 +vn -0.6112 0.1093 0.7838 +vn -0.6454 0.0746 0.7602 +vn -0.6809 0.0333 0.7316 +vn -0.7482 -0.0562 0.6611 +vn -0.7758 -0.0963 0.6236 +vn -0.7964 -0.1274 0.5912 +vn -0.8083 -0.1458 0.5705 +vn -0.8113 -0.1491 0.5653 +vn -0.8048 -0.1366 0.5776 +vn -0.7869 -0.1091 0.6073 +vn -0.7586 -0.0693 0.6478 +vn -0.7241 -0.0227 0.6892 +vn -0.6887 0.0248 0.7246 +vn -0.6558 0.0683 0.7518 +vn -0.6264 0.1046 0.7724 +vn -0.6008 0.1319 0.7884 +vn -0.5825 0.1484 0.7991 +vn -0.5757 0.1527 0.8033 +vn -0.5825 0.1435 0.8000 +vn -0.6037 0.1203 0.7880 +vn -0.6370 0.0842 0.7662 +vn -0.6768 0.0382 0.7351 +vn -0.7158 -0.0120 0.6982 +vn -0.7743 -0.1011 0.6247 +vn -0.7932 -0.1324 0.5944 +vn -0.8037 -0.1508 0.5756 +vn -0.8058 -0.1548 0.5715 +vn -0.7998 -0.1443 0.5827 +vn -0.7855 -0.1200 0.6070 +vn -0.7635 -0.0843 0.6403 +vn -0.7350 -0.0404 0.6768 +vn -0.7012 0.0076 0.7129 +vn -0.6636 0.0550 0.7461 +vn -0.6265 0.0964 0.7734 +vn -0.5958 0.1274 0.7930 +vn -0.5766 0.1450 0.8040 +vn -0.5722 0.1485 0.8065 +vn -0.5831 0.1382 0.8005 +vn -0.6065 0.1158 0.7866 +vn -0.6375 0.0834 0.7659 +vn -0.6732 0.0427 0.7382 +vn -0.7102 -0.0040 0.7040 +vn -0.7444 -0.0528 0.6656 +vn -0.7722 -0.0984 0.6277 +vn -0.7904 -0.1338 0.5978 +vn -0.7916 -0.1353 0.5959 +vn -0.7976 -0.1339 0.5881 +vn -0.8075 -0.1507 0.5703 +vn -0.8076 -0.1532 0.5694 +vn -0.7984 -0.1405 0.5854 +vn -0.7807 -0.1132 0.6145 +vn -0.7556 -0.0738 0.6508 +vn -0.7250 -0.0265 0.6882 +vn -0.6912 0.0233 0.7222 +vn -0.6566 0.0701 0.7509 +vn -0.6236 0.1092 0.7740 +vn -0.5959 0.1371 0.7912 +vn -0.5777 0.1516 0.8021 +vn -0.5726 0.1520 0.8056 +vn -0.5828 0.1384 0.8007 +vn -0.6075 0.1125 0.7862 +vn -0.6421 0.0767 0.7627 +vn -0.6796 0.0345 0.7327 +vn -0.7150 -0.0109 0.6990 +vn -0.7468 -0.0561 0.6627 +vn -0.7734 -0.0969 0.6264 +vn -0.7935 -0.1289 0.5947 +vn -0.8060 -0.1481 0.5731 +vn -0.8097 -0.1520 0.5667 +vn -0.8046 -0.1399 0.5770 +vn -0.7897 -0.1125 0.6031 +vn -0.7630 -0.0725 0.6423 +vn -0.7271 -0.0249 0.6861 +vn -0.6884 0.0242 0.7248 +vn -0.6530 0.0693 0.7541 +vn -0.6239 0.1068 0.7741 +vn -0.6012 0.1345 0.7876 +vn -0.5850 0.1509 0.7968 +vn -0.5783 0.1547 0.8010 +vn -0.5844 0.1453 0.7983 +vn -0.6041 0.1221 0.7874 +vn -0.6360 0.0859 0.7669 +vn -0.6753 0.0397 0.7364 +vn -0.7153 -0.0112 0.6987 +vn -0.7490 -0.0602 0.6598 +vn -0.7739 -0.1015 0.6251 +vn -0.7917 -0.1322 0.5963 +vn -0.8029 -0.1503 0.5769 +vn -0.8058 -0.1543 0.5716 +vn -0.8005 -0.1437 0.5818 +vn -0.7867 -0.1193 0.6057 +vn -0.7645 -0.0832 0.6392 +vn -0.7350 -0.0392 0.6769 +vn -0.7009 0.0081 0.7132 +vn -0.6645 0.0541 0.7453 +vn -0.6288 0.0945 0.7718 +vn -0.5986 0.1252 0.7912 +vn -0.5788 0.1434 0.8028 +vn -0.5726 0.1480 0.8063 +vn -0.5815 0.1389 0.8016 +vn -0.6039 0.1170 0.7884 +vn -0.6355 0.0844 0.7674 +vn -0.6762 0.0378 0.7357 +vn -0.7047 -0.0082 0.7094 +vn -0.7441 -0.0500 0.6661 +vn -0.7732 -0.0950 0.6270 +vn -0.7935 -0.1318 0.5941 +vn -0.8019 -0.1586 0.5759 +vn -0.8043 -0.1560 0.5733 +vn -0.8062 -0.1504 0.5721 +vn -0.8088 -0.1529 0.5678 +vn -0.8012 -0.1403 0.5817 +vn -0.7834 -0.1126 0.6112 +vn -0.7566 -0.0720 0.6498 +vn -0.7234 -0.0232 0.6900 +vn -0.6876 0.0278 0.7255 +vn -0.6530 0.0751 0.7536 +vn -0.6224 0.1139 0.7743 +vn -0.5977 0.1414 0.7891 +vn -0.5816 0.1557 0.7984 +vn -0.5767 0.1563 0.8018 +vn -0.5851 0.1431 0.7982 +vn -0.6069 0.1172 0.7861 +vn -0.6396 0.0804 0.7645 +vn -0.6777 0.0365 0.7344 +vn -0.7145 -0.0104 0.6995 +vn -0.7466 -0.0566 0.6629 +vn -0.7725 -0.0983 0.6273 +vn -0.7917 -0.1313 0.5966 +vn -0.8036 -0.1516 0.5755 +vn -0.8077 -0.1566 0.5683 +vn -0.8032 -0.1451 0.5777 +vn -0.7895 -0.1182 0.6022 +vn -0.7657 -0.0783 0.6384 +vn -0.7310 -0.0298 0.6817 +vn -0.6901 0.0211 0.7233 +vn -0.6510 0.0685 0.7560 +vn -0.6195 0.1078 0.7776 +vn -0.5978 0.1367 0.7899 +vn -0.5852 0.1537 0.7962 +vn -0.5811 0.1575 0.7984 +vn -0.5874 0.1476 0.7957 +vn -0.6061 0.1242 0.7856 +vn -0.6365 0.0880 0.7662 +vn -0.6747 0.0415 0.7369 +vn -0.7145 -0.0101 0.6995 +vn -0.7494 -0.0604 0.6593 +vn -0.7749 -0.1029 0.6236 +vn -0.7910 -0.1338 0.5969 +vn -0.8010 -0.1515 0.5791 +vn -0.8047 -0.1552 0.5730 +vn -0.8003 -0.1446 0.5819 +vn -0.7873 -0.1201 0.6048 +vn -0.7654 -0.0839 0.6380 +vn -0.7358 -0.0394 0.6760 +vn -0.7010 0.0082 0.7130 +vn -0.6650 0.0540 0.7449 +vn -0.6305 0.0938 0.7705 +vn -0.6011 0.1243 0.7895 +vn -0.5810 0.1432 0.8012 +vn -0.5737 0.1488 0.8054 +vn -0.5808 0.1408 0.8018 +vn -0.6016 0.1195 0.7898 +vn -0.6330 0.0869 0.7692 +vn -0.6696 0.0460 0.7413 +vn -0.7384 -0.0404 0.6731 +vn -0.7111 0.0064 0.7030 +vn -0.7723 -0.0901 0.6287 +vn -0.7943 -0.1259 0.5943 +vn -0.8068 -0.1498 0.5716 +vn -0.8060 -0.1643 0.5687 +vn -0.8094 -0.1585 0.5654 +vn -0.8073 -0.1541 0.5696 +vn -0.8022 -0.1413 0.5800 +vn -0.7859 -0.1133 0.6078 +vn -0.7588 -0.0721 0.6473 +vn -0.7236 -0.0222 0.6898 +vn -0.6850 0.0297 0.7279 +vn -0.6487 0.0775 0.7571 +vn -0.6189 0.1161 0.7768 +vn -0.5970 0.1430 0.7893 +vn -0.5838 0.1572 0.7965 +vn -0.5806 0.1582 0.7986 +vn -0.5888 0.1458 0.7950 +vn -0.6089 0.1206 0.7840 +vn -0.6395 0.0839 0.7642 +vn -0.6766 0.0388 0.7353 +vn -0.7141 -0.0100 0.6999 +vn -0.7469 -0.0576 0.6624 +vn -0.7728 -0.1001 0.6267 +vn -0.7912 -0.1337 0.5967 +vn -0.8023 -0.1548 0.5765 +vn -0.8059 -0.1606 0.5698 +vn -0.8016 -0.1498 0.5787 +vn -0.7884 -0.1232 0.6026 +vn -0.7659 -0.0835 0.6374 +vn -0.7338 -0.0350 0.6784 +vn -0.6933 0.0169 0.7204 +vn -0.6513 0.0658 0.7559 +vn -0.6161 0.1065 0.7804 +vn -0.5925 0.1363 0.7939 +vn -0.5814 0.1536 0.7989 +vn -0.5813 0.1577 0.7982 +vn -0.5907 0.1478 0.7932 +vn -0.6095 0.1241 0.7830 +vn -0.6386 0.0880 0.7645 +vn -0.6753 0.0419 0.7363 +vn -0.7143 -0.0097 0.6998 +vn -0.7494 -0.0604 0.6594 +vn -0.7760 -0.1038 0.6221 +vn -0.7923 -0.1353 0.5950 +vn -0.8001 -0.1529 0.5800 +vn -0.8028 -0.1565 0.5753 +vn -0.7992 -0.1459 0.5831 +vn -0.7871 -0.1217 0.6047 +vn -0.7660 -0.0854 0.6372 +vn -0.7365 -0.0406 0.6752 +vn -0.7013 0.0080 0.7128 +vn -0.6647 0.0547 0.7451 +vn -0.6310 0.0948 0.7699 +vn -0.6028 0.1254 0.7880 +vn -0.5829 0.1447 0.7996 +vn -0.5749 0.1511 0.8041 +vn -0.5808 0.1440 0.8012 +vn -0.6002 0.1234 0.7902 +vn -0.6308 0.0907 0.7706 +vn -0.6678 0.0487 0.7427 +vn -0.7053 0.0020 0.7089 +vn -0.7399 -0.0449 0.6712 +vn -0.7698 -0.0878 0.6322 +vn -0.7928 -0.1224 0.5971 +vn -0.8070 -0.1451 0.5724 +vn -0.8116 -0.1533 0.5636 +vn -0.8024 -0.1505 0.5775 +vn -0.8061 -0.1456 0.5735 +vn -0.7869 -0.1157 0.6062 +vn -0.7611 -0.0742 0.6444 +vn -0.7253 -0.0237 0.6880 +vn -0.6846 0.0288 0.7284 +vn -0.6458 0.0768 0.7596 +vn -0.6148 0.1153 0.7802 +vn -0.5942 0.1416 0.7917 +vn -0.5838 0.1552 0.7969 +vn -0.5829 0.1563 0.7973 +vn -0.5922 0.1448 0.7927 +vn -0.6120 0.1206 0.7816 +vn -0.6413 0.0848 0.7626 +vn -0.6771 0.0396 0.7348 +vn -0.7143 -0.0103 0.6997 +vn -0.7474 -0.0593 0.6617 +vn -0.7734 -0.1023 0.6255 +vn -0.7917 -0.1361 0.5956 +vn -0.8021 -0.1573 0.5761 +vn -0.8050 -0.1633 0.5704 +vn -0.8002 -0.1529 0.5798 +vn -0.7872 -0.1263 0.6036 +vn -0.7650 -0.0865 0.6381 +vn -0.7344 -0.0380 0.6776 +vn -0.6962 0.0137 0.7177 +vn -0.6538 0.0631 0.7540 +vn -0.6155 0.1046 0.7811 +vn -0.5885 0.1347 0.7971 +vn -0.5762 0.1519 0.8031 +vn -0.5779 0.1555 0.8011 +vn -0.5912 0.1455 0.7933 +vn -0.6130 0.1219 0.7806 +vn -0.6418 0.0862 0.7620 +vn -0.6769 0.0408 0.7349 +vn -0.7491 -0.0605 0.6596 +vn -0.7762 -0.1043 0.6217 +vn -0.7937 -0.1362 0.5928 +vn -0.8014 -0.1540 0.5780 +vn -0.8017 -0.1572 0.5766 +vn -0.7973 -0.1466 0.5854 +vn -0.7862 -0.1227 0.6057 +vn -0.7659 -0.0866 0.6371 +vn -0.7368 -0.0415 0.6748 +vn -0.7014 0.0078 0.7127 +vn -0.6640 0.0558 0.7456 +vn -0.6299 0.0972 0.7705 +vn -0.6030 0.1282 0.7873 +vn -0.5843 0.1474 0.7980 +vn -0.5762 0.1541 0.8026 +vn -0.5812 0.1474 0.8003 +vn -0.5997 0.1271 0.7900 +vn -0.6297 0.0941 0.7711 +vn -0.6669 0.0510 0.7434 +vn -0.7050 0.0022 0.7092 +vn -0.7390 -0.0463 0.6721 +vn -0.7672 -0.0895 0.6351 +vn -0.7895 -0.1234 0.6012 +vn -0.8045 -0.1449 0.5760 +vn -0.8110 -0.1521 0.5648 +vn -0.8079 -0.1439 0.5714 +vn -0.7902 -0.1220 0.6006 +vn -0.7939 -0.1205 0.5960 +vn -0.7853 -0.1183 0.6077 +vn -0.7622 -0.0772 0.6428 +vn -0.7275 -0.0267 0.6856 +vn -0.6860 0.0263 0.7271 +vn -0.6452 0.0746 0.7603 +vn -0.6121 0.1129 0.7826 +vn -0.5908 0.1386 0.7948 +vn -0.5819 0.1514 0.7990 +vn -0.5833 0.1520 0.7978 +vn -0.5942 0.1407 0.7919 +vn -0.6145 0.1175 0.7801 +vn -0.6435 0.0829 0.7609 +vn -0.6786 0.0385 0.7335 +vn -0.7153 -0.0116 0.6987 +vn -0.7484 -0.0616 0.6604 +vn -0.7741 -0.1052 0.6243 +vn -0.7920 -0.1383 0.5946 +vn -0.8024 -0.1589 0.5752 +vn -0.8049 -0.1645 0.5702 +vn -0.7995 -0.1538 0.5806 +vn -0.7860 -0.1272 0.6050 +vn -0.7335 -0.0381 0.6786 +vn -0.6972 0.0132 0.7168 +vn -0.6569 0.0621 0.7514 +vn -0.6177 0.1036 0.7795 +vn -0.5878 0.1337 0.7979 +vn -0.5725 0.1504 0.8060 +vn -0.5733 0.1532 0.8049 +vn -0.5883 0.1422 0.7960 +vn -0.6136 0.1183 0.7807 +vn -0.6448 0.0828 0.7598 +vn -0.6792 0.0385 0.7330 +vn -0.7152 -0.0110 0.6988 +vn -0.7490 -0.0605 0.6597 +vn -0.7761 -0.1039 0.6219 +vn -0.7942 -0.1361 0.5921 +vn -0.8030 -0.1542 0.5756 +vn -0.8029 -0.1574 0.5750 +vn -0.7962 -0.1464 0.5871 +vn -0.7845 -0.1225 0.6079 +vn -0.7652 -0.0869 0.6378 +vn -0.7368 -0.0419 0.6748 +vn -0.7013 0.0079 0.7128 +vn -0.6631 0.0570 0.7463 +vn -0.6279 0.0997 0.7718 +vn -0.6010 0.1319 0.7883 +vn -0.5845 0.1512 0.7972 +vn -0.5777 0.1573 0.8009 +vn -0.5824 0.1502 0.7989 +vn -0.6002 0.1298 0.7892 +vn -0.6297 0.0963 0.7708 +vn -0.6721 0.0453 0.7391 +vn -0.7008 -0.0054 0.7133 +vn -0.7401 -0.0494 0.6706 +vn -0.7667 -0.0943 0.6349 +vn -0.7864 -0.1285 0.6041 +vn -0.8003 -0.1494 0.5807 +vn -0.8074 -0.1556 0.5691 +vn -0.8064 -0.1466 0.5728 +vn -0.7953 -0.1229 0.5936 +vn -0.7687 -0.0837 0.6341 +vn -0.7725 -0.0862 0.6290 +vn -0.7612 -0.0792 0.6436 +vn -0.7289 -0.0295 0.6840 +vn -0.6883 0.0236 0.7251 +vn -0.6465 0.0723 0.7594 +vn -0.6115 0.1108 0.7834 +vn -0.5885 0.1364 0.7969 +vn -0.5792 0.1484 0.8015 +vn -0.5822 0.1480 0.7994 +vn -0.5947 0.1362 0.7923 +vn -0.6158 0.1134 0.7797 +vn -0.6449 0.0797 0.7601 +vn -0.6798 0.0366 0.7324 +vn -0.7165 -0.0128 0.6975 +vn -0.7497 -0.0630 0.6587 +vn -0.7754 -0.1074 0.6223 +vn -0.7923 -0.1403 0.5937 +vn -0.8022 -0.1596 0.5753 +vn -0.8050 -0.1641 0.5702 +vn -0.7994 -0.1528 0.5810 +vn -0.7853 -0.1258 0.6061 +vn -0.7626 -0.0855 0.6412 +vn -0.7320 -0.0364 0.6803 +vn -0.6962 0.0151 0.7176 +vn -0.6585 0.0633 0.7499 +vn -0.6212 0.1039 0.7767 +vn -0.5900 0.1338 0.7962 +vn -0.5719 0.1501 0.8064 +vn -0.5703 0.1522 0.8072 +vn -0.5846 0.1402 0.7991 +vn -0.6114 0.1152 0.7829 +vn -0.6454 0.0793 0.7597 +vn -0.6811 0.0356 0.7313 +vn -0.7161 -0.0121 0.6979 +vn -0.7488 -0.0599 0.6601 +vn -0.7757 -0.1024 0.6227 +vn -0.7943 -0.1345 0.5923 +vn -0.8039 -0.1531 0.5746 +vn -0.8047 -0.1566 0.5726 +vn -0.7972 -0.1455 0.5859 +vn -0.7833 -0.1213 0.6097 +vn -0.7638 -0.0861 0.6396 +vn -0.7364 -0.0417 0.6752 +vn -0.7011 0.0080 0.7130 +vn -0.6623 0.0576 0.7470 +vn -0.6259 0.1014 0.7732 +vn -0.5978 0.1348 0.7902 +vn -0.5821 0.1548 0.7982 +vn -0.5785 0.1605 0.7997 +vn -0.5848 0.1525 0.7967 +vn -0.6021 0.1311 0.7876 +vn -0.6309 0.0970 0.7698 +vn -0.6677 0.0519 0.7426 +vn -0.7378 -0.0456 0.6734 +vn -0.7116 0.0070 0.7025 +vn -0.7689 -0.0991 0.6316 +vn -0.7863 -0.1346 0.6030 +vn -0.7969 -0.1557 0.5836 +vn -0.8025 -0.1615 0.5743 +vn -0.8021 -0.1520 0.5775 +vn -0.7934 -0.1281 0.5950 +vn -0.7740 -0.0915 0.6265 +vn -0.7390 -0.0402 0.6725 +vn -0.7430 -0.0455 0.6677 +vn -0.7289 -0.0307 0.6839 +vn -0.6901 0.0215 0.7233 +vn -0.6486 0.0704 0.7578 +vn -0.6124 0.1097 0.7829 +vn -0.5877 0.1358 0.7976 +vn -0.5771 0.1479 0.8031 +vn -0.5802 0.1469 0.8011 +vn -0.5941 0.1340 0.7931 +vn -0.6161 0.1107 0.7798 +vn -0.6453 0.0774 0.7599 +vn -0.6801 0.0353 0.7322 +vn -0.7168 -0.0128 0.6971 +vn -0.7506 -0.0621 0.6578 +vn -0.7772 -0.1063 0.6203 +vn -0.7940 -0.1397 0.5917 +vn -0.8022 -0.1585 0.5756 +vn -0.8044 -0.1619 0.5716 +vn -0.7994 -0.1498 0.5818 +vn -0.7852 -0.1227 0.6069 +vn -0.7620 -0.0827 0.6423 +vn -0.7307 -0.0342 0.6818 +vn -0.6946 0.0170 0.7192 +vn -0.6579 0.0648 0.7503 +vn -0.6237 0.1047 0.7746 +vn -0.5940 0.1340 0.7932 +vn -0.5742 0.1504 0.8047 +vn -0.5700 0.1524 0.8074 +vn -0.5822 0.1400 0.8009 +vn -0.6085 0.1143 0.7852 +vn -0.6437 0.0775 0.7613 +vn -0.6815 0.0335 0.7310 +vn -0.7167 -0.0131 0.6972 +vn -0.7482 -0.0586 0.6608 +vn -0.7748 -0.0995 0.6243 +vn -0.7940 -0.1311 0.5936 +vn -0.8045 -0.1501 0.5746 +vn -0.8062 -0.1545 0.5711 +vn -0.7993 -0.1439 0.5835 +vn -0.7841 -0.1196 0.6089 +vn -0.7627 -0.0844 0.6412 +vn -0.7355 -0.0410 0.6763 +vn -0.7011 0.0078 0.7130 +vn -0.6619 0.0572 0.7473 +vn -0.6243 0.1015 0.7745 +vn -0.5949 0.1357 0.7923 +vn -0.5782 0.1565 0.8007 +vn -0.5764 0.1624 0.8009 +vn -0.5866 0.1535 0.7952 +vn -0.6055 0.1311 0.7850 +vn -0.6334 0.0962 0.7678 +vn -0.6694 0.0506 0.7411 +vn -0.7082 -0.0015 0.7060 +vn -0.7439 -0.0545 0.6660 +vn -0.7716 -0.1016 0.6279 +vn -0.7891 -0.1376 0.5986 +vn -0.7973 -0.1593 0.5822 +vn -0.7995 -0.1654 0.5774 +vn -0.7973 -0.1562 0.5830 +vn -0.7891 -0.1327 0.5997 +vn -0.7723 -0.0966 0.6278 +vn -0.7448 -0.0509 0.6653 +vn -0.7031 0.0049 0.7110 +vn -0.7072 -0.0000 0.7070 +vn -0.6913 0.0200 0.7223 +vn -0.6507 0.0682 0.7562 +vn -0.6139 0.1082 0.7819 +vn -0.5877 0.1355 0.7976 +vn -0.5756 0.1488 0.8040 +vn -0.5780 0.1483 0.8024 +vn -0.5926 0.1352 0.7940 +vn -0.6161 0.1110 0.7798 +vn -0.6456 0.0772 0.7597 +vn -0.6799 0.0352 0.7324 +vn -0.7162 -0.0120 0.6978 +vn -0.7502 -0.0600 0.6585 +vn -0.7777 -0.1033 0.6201 +vn -0.7960 -0.1364 0.5897 +vn -0.8041 -0.1556 0.5737 +vn -0.8042 -0.1592 0.5726 +vn -0.7985 -0.1472 0.5836 +vn -0.7851 -0.1203 0.6075 +vn -0.7620 -0.0807 0.6425 +vn -0.7304 -0.0327 0.6822 +vn -0.6937 0.0180 0.7201 +vn -0.6564 0.0656 0.7515 +vn -0.6234 0.1053 0.7747 +vn -0.5968 0.1345 0.7910 +vn -0.5780 0.1514 0.8019 +vn -0.5718 0.1540 0.8058 +vn -0.5817 0.1417 0.8009 +vn -0.6064 0.1156 0.7866 +vn -0.6414 0.0782 0.7632 +vn -0.6802 0.0338 0.7322 +vn -0.7166 -0.0127 0.6973 +vn -0.7475 -0.0567 0.6618 +vn -0.7732 -0.0953 0.6269 +vn -0.7930 -0.1258 0.5961 +vn -0.8047 -0.1447 0.5758 +vn -0.8076 -0.1499 0.5704 +vn -0.8015 -0.1406 0.5811 +vn -0.7866 -0.1173 0.6062 +vn -0.7636 -0.0824 0.6404 +vn -0.7348 -0.0397 0.6771 +vn -0.7011 0.0075 0.7130 +vn -0.6625 0.0558 0.7470 +vn -0.6240 0.0997 0.7750 +vn -0.5929 0.1341 0.7940 +vn -0.5748 0.1553 0.8033 +vn -0.5726 0.1615 0.8038 +vn -0.5854 0.1523 0.7963 +vn -0.6084 0.1291 0.7830 +vn -0.6374 0.0938 0.7648 +vn -0.6721 0.0482 0.7389 +vn -0.7098 -0.0036 0.7044 +vn -0.7450 -0.0560 0.6646 +vn -0.7732 -0.1025 0.6258 +vn -0.7917 -0.1381 0.5950 +vn -0.8003 -0.1594 0.5780 +vn -0.8004 -0.1656 0.5761 +vn -0.7949 -0.1569 0.5861 +vn -0.7849 -0.1342 0.6048 +vn -0.7686 -0.0989 0.6320 +vn -0.7436 -0.0536 0.6665 +vn -0.7091 -0.0024 0.7051 +vn -0.6645 0.0500 0.7455 +vn -0.6678 0.0490 0.7427 +vn -0.6531 0.0660 0.7544 +vn -0.6160 0.1056 0.7806 +vn -0.5882 0.1338 0.7975 +vn -0.5743 0.1485 0.8050 +vn -0.5755 0.1493 0.8040 +vn -0.5903 0.1369 0.7955 +vn -0.6152 0.1125 0.7803 +vn -0.6462 0.0779 0.7591 +vn -0.6803 0.0355 0.7320 +vn -0.7156 -0.0116 0.6984 +vn -0.7489 -0.0590 0.6600 +vn -0.7767 -0.1014 0.6216 +vn -0.7962 -0.1341 0.5899 +vn -0.8062 -0.1534 0.5714 +vn -0.8063 -0.1575 0.5702 +vn -0.7984 -0.1462 0.5841 +vn -0.7843 -0.1201 0.6087 +vn -0.7619 -0.0808 0.6427 +vn -0.7305 -0.0325 0.6821 +vn -0.6553 0.0668 0.7524 +vn -0.6217 0.1069 0.7759 +vn -0.5963 0.1364 0.7910 +vn -0.5802 0.1537 0.7998 +vn -0.5746 0.1573 0.8031 +vn -0.5831 0.1456 0.7992 +vn -0.6061 0.1192 0.7863 +vn -0.6399 0.0810 0.7642 +vn -0.6783 0.0358 0.7338 +vn -0.7155 -0.0111 0.6985 +vn -0.7468 -0.0548 0.6628 +vn -0.7713 -0.0920 0.6297 +vn -0.7906 -0.1211 0.6003 +vn -0.8034 -0.1395 0.5788 +vn -0.8080 -0.1451 0.5709 +vn -0.8036 -0.1369 0.5791 +vn -0.7897 -0.1151 0.6025 +vn -0.7665 -0.0814 0.6370 +vn -0.7360 -0.0389 0.6759 +vn -0.7014 0.0074 0.7127 +vn -0.6638 0.0540 0.7459 +vn -0.6253 0.0969 0.7743 +vn -0.5928 0.1311 0.7946 +vn -0.5728 0.1523 0.8054 +vn -0.5692 0.1584 0.8068 +vn -0.5820 0.1490 0.7994 +vn -0.6080 0.1251 0.7840 +vn -0.6406 0.0894 0.7626 +vn -0.6756 0.0445 0.7359 +vn -0.7118 -0.0064 0.7024 +vn -0.7458 -0.0577 0.6636 +vn -0.7737 -0.1033 0.6250 +vn -0.7929 -0.1380 0.5935 +vn -0.8027 -0.1587 0.5748 +vn -0.8033 -0.1642 0.5724 +vn -0.7960 -0.1550 0.5850 +vn -0.7830 -0.1322 0.6077 +vn -0.7649 -0.0972 0.6367 +vn -0.7401 -0.0520 0.6704 +vn -0.7076 -0.0006 0.7066 +vn -0.6688 0.0515 0.7417 +vn -0.6267 0.0942 0.7735 +vn -0.6286 0.0978 0.7715 +vn -0.6191 0.1040 0.7784 +vn -0.5901 0.1321 0.7964 +vn -0.5739 0.1473 0.8055 +vn -0.5731 0.1490 0.8058 +vn -0.5871 0.1373 0.7978 +vn -0.6129 0.1130 0.7820 +vn -0.6460 0.0778 0.7594 +vn -0.6814 0.0345 0.7310 +vn -0.7161 -0.0128 0.6978 +vn -0.7480 -0.0598 0.6610 +vn -0.7750 -0.1014 0.6238 +vn -0.7949 -0.1333 0.5919 +vn -0.8063 -0.1522 0.5715 +vn -0.8084 -0.1562 0.5675 +vn -0.8007 -0.1450 0.5812 +vn -0.7845 -0.1193 0.6084 +vn -0.7613 -0.0808 0.6434 +vn -0.6927 0.0194 0.7209 +vn -0.6542 0.0682 0.7532 +vn -0.6200 0.1088 0.7770 +vn -0.5944 0.1381 0.7922 +vn -0.5797 0.1550 0.7999 +vn -0.5763 0.1589 0.8016 +vn -0.5852 0.1484 0.7972 +vn -0.6075 0.1226 0.7848 +vn -0.6402 0.0841 0.7635 +vn -0.6778 0.0378 0.7342 +vn -0.7144 -0.0102 0.6996 +vn -0.7458 -0.0547 0.6638 +vn -0.7702 -0.0919 0.6312 +vn -0.7880 -0.1205 0.6038 +vn -0.8005 -0.1390 0.5830 +vn -0.8064 -0.1447 0.5733 +vn -0.8041 -0.1371 0.5785 +vn -0.7922 -0.1161 0.5991 +vn -0.7703 -0.0831 0.6323 +vn -0.7392 -0.0409 0.6722 +vn -0.7027 0.0060 0.7115 +vn -0.6650 0.0526 0.7449 +vn -0.6277 0.0949 0.7726 +vn -0.5944 0.1287 0.7937 +vn -0.5727 0.1499 0.8059 +vn -0.5672 0.1559 0.8087 +vn -0.5789 0.1461 0.8022 +vn -0.6052 0.1215 0.7867 +vn -0.6406 0.0848 0.7631 +vn -0.6782 0.0400 0.7338 +vn -0.7140 -0.0096 0.7000 +vn -0.7468 -0.0594 0.6624 +vn -0.7738 -0.1036 0.6249 +vn -0.7930 -0.1372 0.5936 +vn -0.8036 -0.1570 0.5741 +vn -0.8055 -0.1616 0.5701 +vn -0.7988 -0.1513 0.5823 +vn -0.7840 -0.1274 0.6075 +vn -0.7630 -0.0918 0.6399 +vn -0.7363 -0.0466 0.6750 +vn -0.7038 0.0048 0.7103 +vn -0.6668 0.0567 0.7430 +vn -0.6290 0.1028 0.7705 +vn -0.5947 0.1328 0.7929 +vn -0.5963 0.1375 0.7909 +vn -0.5934 0.1324 0.7939 +vn -0.5755 0.1475 0.8044 +vn -0.5721 0.1492 0.8065 +vn -0.5842 0.1376 0.7998 +vn -0.6098 0.1132 0.7844 +vn -0.6443 0.0774 0.7608 +vn -0.6820 0.0331 0.7306 +vn -0.7175 -0.0153 0.6963 +vn -0.7482 -0.0623 0.6605 +vn -0.7735 -0.1032 0.6254 +vn -0.7925 -0.1340 0.5949 +vn -0.8045 -0.1519 0.5741 +vn -0.8083 -0.1554 0.5678 +vn -0.8028 -0.1438 0.5787 +vn -0.7869 -0.1178 0.6056 +vn -0.7620 -0.0795 0.6427 +vn -0.7298 -0.0318 0.6829 +vn -0.6921 0.0200 0.7215 +vn -0.6532 0.0691 0.7540 +vn -0.6187 0.1098 0.7779 +vn -0.5931 0.1387 0.7931 +vn -0.5786 0.1547 0.8007 +vn -0.5764 0.1575 0.8018 +vn -0.5863 0.1472 0.7966 +vn -0.6089 0.1226 0.7837 +vn -0.6417 0.0847 0.7622 +vn -0.6789 0.0379 0.7332 +vn -0.7149 -0.0115 0.6991 +vn -0.7456 -0.0575 0.6639 +vn -0.7693 -0.0958 0.6316 +vn -0.7863 -0.1244 0.6051 +vn -0.7976 -0.1428 0.5860 +vn -0.8032 -0.1493 0.5766 +vn -0.8021 -0.1420 0.5801 +vn -0.7924 -0.1211 0.5978 +vn -0.7729 -0.0880 0.6284 +vn -0.7054 0.0024 0.7088 +vn -0.6656 0.0506 0.7445 +vn -0.6289 0.0938 0.7718 +vn -0.5969 0.1281 0.7920 +vn -0.5741 0.1496 0.8050 +vn -0.5669 0.1557 0.8089 +vn -0.5769 0.1456 0.8037 +vn -0.6025 0.1205 0.7890 +vn -0.6385 0.0830 0.7651 +vn -0.6783 0.0373 0.7338 +vn -0.7156 -0.0118 0.6984 +vn -0.7478 -0.0603 0.6612 +vn -0.7738 -0.1032 0.6250 +vn -0.7924 -0.1355 0.5947 +vn -0.8033 -0.1543 0.5752 +vn -0.8061 -0.1581 0.5702 +vn -0.8005 -0.1471 0.5810 +vn -0.7861 -0.1223 0.6058 +vn -0.7633 -0.0858 0.6402 +vn -0.7340 -0.0405 0.6779 +vn -0.6998 0.0103 0.7143 +vn -0.6630 0.0616 0.7460 +vn -0.6272 0.1072 0.7714 +vn -0.5971 0.1413 0.7896 +vn -0.5748 0.1574 0.8030 +vn -0.5772 0.1605 0.8007 +vn -0.5789 0.1498 0.8015 +vn -0.5736 0.1512 0.8050 +vn -0.5833 0.1392 0.8002 +vn -0.6071 0.1145 0.7863 +vn -0.6417 0.0782 0.7629 +vn -0.6813 0.0328 0.7313 +vn -0.7190 -0.0169 0.6948 +vn -0.7499 -0.0651 0.6583 +vn -0.7732 -0.1061 0.6251 +vn -0.7904 -0.1362 0.5973 +vn -0.8015 -0.1531 0.5780 +vn -0.8060 -0.1558 0.5710 +vn -0.8024 -0.1439 0.5792 +vn -0.7888 -0.1178 0.6033 +vn -0.7643 -0.0793 0.6399 +vn -0.7308 -0.0318 0.6819 +vn -0.6919 0.0197 0.7217 +vn -0.6525 0.0690 0.7547 +vn -0.6177 0.1098 0.7787 +vn -0.5921 0.1385 0.7938 +vn -0.5782 0.1538 0.8013 +vn -0.5766 0.1555 0.8021 +vn -0.5871 0.1441 0.7966 +vn -0.6095 0.1198 0.7837 +vn -0.6425 0.0827 0.7618 +vn -0.6806 0.0359 0.7317 +vn -0.7169 -0.0146 0.6970 +vn -0.7470 -0.0623 0.6618 +vn -0.7696 -0.1022 0.6302 +vn -0.7853 -0.1315 0.6049 +vn -0.7954 -0.1494 0.5874 +vn -0.8002 -0.1558 0.5791 +vn -0.7989 -0.1489 0.5828 +vn -0.7902 -0.1279 0.5994 +vn -0.7729 -0.0943 0.6275 +vn -0.7455 -0.0509 0.6645 +vn -0.7089 -0.0020 0.7053 +vn -0.6673 0.0476 0.7432 +vn -0.6283 0.0925 0.7724 +vn -0.5972 0.1281 0.7917 +vn -0.5758 0.1508 0.8036 +vn -0.5677 0.1577 0.8080 +vn -0.5765 0.1477 0.8036 +vn -0.6008 0.1221 0.7900 +vn -0.6363 0.0840 0.7668 +vn -0.6767 0.0378 0.7352 +vn -0.7157 -0.0114 0.6983 +vn -0.7487 -0.0593 0.6602 +vn -0.7742 -0.1015 0.6247 +vn -0.7920 -0.1333 0.5958 +vn -0.8024 -0.1516 0.5772 +vn -0.8055 -0.1551 0.5719 +vn -0.8008 -0.1439 0.5813 +vn -0.7875 -0.1191 0.6047 +vn -0.7649 -0.0826 0.6388 +vn -0.7340 -0.0375 0.6780 +vn -0.6976 0.0126 0.7164 +vn -0.6593 0.0631 0.7492 +vn -0.6239 0.1080 0.7739 +vn -0.5959 0.1419 0.7904 +vn -0.5786 0.1611 0.7995 +vn -0.5708 0.1636 0.8045 +vn -0.5742 0.1641 0.8021 +vn -0.5772 0.1546 0.8018 +vn -0.5850 0.1422 0.7984 +vn -0.6065 0.1170 0.7864 +vn -0.6395 0.0802 0.7645 +vn -0.6794 0.0344 0.7330 +vn -0.7191 -0.0162 0.6947 +vn -0.7522 -0.0656 0.6556 +vn -0.7753 -0.1079 0.6222 +vn -0.7900 -0.1382 0.5973 +vn -0.7989 -0.1548 0.5811 +vn -0.8026 -0.1570 0.5754 +vn -0.7998 -0.1449 0.5824 +vn -0.7884 -0.1192 0.6035 +vn -0.7662 -0.0812 0.6374 +vn -0.7332 -0.0339 0.6791 +vn -0.6931 0.0176 0.7206 +vn -0.6522 0.0673 0.7551 +vn -0.6167 0.1086 0.7797 +vn -0.5911 0.1376 0.7947 +vn -0.5777 0.1526 0.8018 +vn -0.5770 0.1537 0.8021 +vn -0.5882 0.1416 0.7962 +vn -0.6102 0.1169 0.7835 +vn -0.6424 0.0804 0.7621 +vn -0.6811 0.0341 0.7314 +vn -0.7499 -0.0661 0.6582 +vn -0.7720 -0.1078 0.6264 +vn -0.7861 -0.1385 0.6024 +vn -0.7941 -0.1567 0.5872 +vn -0.7976 -0.1621 0.5810 +vn -0.7959 -0.1547 0.5853 +vn -0.7870 -0.1334 0.6023 +vn -0.7703 -0.0990 0.6299 +vn -0.7451 -0.0548 0.6646 +vn -0.7109 -0.0049 0.7033 +vn -0.6701 0.0456 0.7408 +vn -0.6289 0.0915 0.7721 +vn -0.5954 0.1280 0.7931 +vn -0.5749 0.1518 0.8040 +vn -0.5683 0.1600 0.8071 +vn -0.5769 0.1508 0.8028 +vn -0.6005 0.1253 0.7897 +vn -0.6352 0.0867 0.7675 +vn -0.6750 0.0400 0.7367 +vn -0.7144 -0.0095 0.6997 +vn -0.7486 -0.0569 0.6606 +vn -0.7750 -0.0985 0.6243 +vn -0.7925 -0.1306 0.5958 +vn -0.8019 -0.1492 0.5784 +vn -0.8045 -0.1531 0.5739 +vn -0.8001 -0.1423 0.5827 +vn -0.7877 -0.1181 0.6045 +vn -0.7664 -0.0824 0.6371 +vn -0.7359 -0.0381 0.6760 +vn -0.6983 0.0108 0.7158 +vn -0.6579 0.0601 0.7507 +vn -0.6208 0.1044 0.7769 +vn -0.5929 0.1384 0.7933 +vn -0.5776 0.1580 0.8009 +vn -0.5757 0.1617 0.8015 +vn -0.5829 0.1515 0.7982 +vn -0.5864 0.1497 0.7960 +vn -0.5889 0.1455 0.7950 +vn -0.6085 0.1199 0.7844 +vn -0.6392 0.0829 0.7645 +vn -0.6776 0.0369 0.7345 +vn -0.7177 -0.0138 0.6962 +vn -0.7530 -0.0636 0.6549 +vn -0.7784 -0.1065 0.6186 +vn -0.7926 -0.1379 0.5939 +vn -0.7988 -0.1549 0.5813 +vn -0.8001 -0.1572 0.5789 +vn -0.7965 -0.1455 0.5868 +vn -0.7861 -0.1205 0.6062 +vn -0.7664 -0.0837 0.6369 +vn -0.7357 -0.0375 0.6762 +vn -0.6959 0.0135 0.7180 +vn -0.6531 0.0635 0.7545 +vn -0.6158 0.1059 0.7807 +vn -0.5897 0.1358 0.7961 +vn -0.5767 0.1512 0.8028 +vn -0.5769 0.1523 0.8025 +vn -0.5890 0.1399 0.7959 +vn -0.6114 0.1151 0.7829 +vn -0.6424 0.0793 0.7622 +vn -0.6803 0.0341 0.7321 +vn -0.7195 -0.0165 0.6942 +vn -0.7527 -0.0664 0.6550 +vn -0.7758 -0.1094 0.6213 +vn -0.7894 -0.1414 0.5973 +vn -0.7955 -0.1605 0.5843 +vn -0.7963 -0.1658 0.5817 +vn -0.7931 -0.1573 0.5884 +vn -0.7841 -0.1351 0.6057 +vn -0.7670 -0.0998 0.6338 +vn -0.7422 -0.0547 0.6679 +vn -0.7101 -0.0043 0.7040 +vn -0.6717 0.0465 0.7393 +vn -0.6312 0.0924 0.7700 +vn -0.5956 0.1289 0.7929 +vn -0.5726 0.1525 0.8055 +vn -0.5664 0.1612 0.8082 +vn -0.5766 0.1531 0.8026 +vn -0.6008 0.1280 0.7891 +vn -0.6353 0.0892 0.7671 +vn -0.6745 0.0419 0.7371 +vn -0.7130 -0.0080 0.7011 +vn -0.7471 -0.0553 0.6624 +vn -0.7744 -0.0960 0.6254 +vn -0.7934 -0.1278 0.5952 +vn -0.8028 -0.1474 0.5777 +vn -0.8042 -0.1522 0.5745 +vn -0.7992 -0.1422 0.5839 +vn -0.7872 -0.1187 0.6051 +vn -0.7671 -0.0840 0.6360 +vn -0.7381 -0.0408 0.6735 +vn -0.7012 0.0070 0.7129 +vn -0.6599 0.0549 0.7493 +vn -0.6203 0.0982 0.7781 +vn -0.5901 0.1320 0.7964 +vn -0.5744 0.1521 0.8043 +vn -0.5741 0.1567 0.8036 +vn -0.5873 0.1457 0.7961 +vn -0.6078 0.1238 0.7844 +vn -0.6105 0.1210 0.7827 +vn -0.6126 0.1215 0.7809 +vn -0.6415 0.0845 0.7624 +vn -0.6774 0.0387 0.7346 +vn -0.7160 -0.0116 0.6980 +vn -0.7517 -0.0609 0.6566 +vn -0.7794 -0.1034 0.6178 +vn -0.7962 -0.1346 0.5899 +vn -0.8020 -0.1520 0.5777 +vn -0.8004 -0.1548 0.5791 +vn -0.7944 -0.1438 0.5901 +vn -0.7834 -0.1201 0.6098 +vn -0.7650 -0.0849 0.6384 +vn -0.7370 -0.0406 0.6747 +vn -0.6994 0.0092 0.7147 +vn -0.6562 0.0589 0.7523 +vn -0.6161 0.1022 0.7810 +vn -0.5878 0.1335 0.7979 +vn -0.5747 0.1499 0.8045 +vn -0.5757 0.1514 0.8035 +vn -0.5889 0.1391 0.7961 +vn -0.6121 0.1144 0.7824 +vn -0.6429 0.0791 0.7618 +vn -0.6792 0.0354 0.7331 +vn -0.7180 -0.0135 0.6959 +vn -0.7534 -0.0627 0.6545 +vn -0.7793 -0.1060 0.6175 +vn -0.7942 -0.1387 0.5915 +vn -0.7997 -0.1584 0.5790 +vn -0.7984 -0.1639 0.5794 +vn -0.7920 -0.1550 0.5904 +vn -0.7812 -0.1321 0.6100 +vn -0.7638 -0.0961 0.6383 +vn -0.7383 -0.0502 0.6726 +vn -0.7068 0.0004 0.7074 +vn -0.6709 0.0506 0.7398 +vn -0.6330 0.0957 0.7682 +vn -0.5981 0.1315 0.7906 +vn -0.5731 0.1543 0.8048 +vn -0.5643 0.1620 0.8094 +vn -0.5744 0.1536 0.8040 +vn -0.6002 0.1288 0.7894 +vn -0.6358 0.0900 0.7666 +vn -0.6751 0.0422 0.7365 +vn -0.7129 -0.0084 0.7011 +vn -0.7459 -0.0561 0.6637 +vn -0.7724 -0.0967 0.6277 +vn -0.7921 -0.1276 0.5968 +vn -0.8038 -0.1471 0.5765 +vn -0.8055 -0.1528 0.5726 +vn -0.7992 -0.1436 0.5837 +vn -0.7866 -0.1207 0.6055 +vn -0.7670 -0.0864 0.6358 +vn -0.7394 -0.0438 0.6718 +vn -0.7043 0.0034 0.7098 +vn -0.6640 0.0506 0.7460 +vn -0.6234 0.0932 0.7763 +vn -0.5899 0.1266 0.7974 +vn -0.5713 0.1468 0.8075 +vn -0.5703 0.1517 0.8073 +vn -0.5849 0.1414 0.7987 +vn -0.6103 0.1175 0.7833 +vn -0.6404 0.0854 0.7633 +vn -0.6418 0.0830 0.7623 +vn -0.6455 0.0837 0.7591 +vn -0.6794 0.0382 0.7328 +vn -0.7154 -0.0116 0.6985 +vn -0.7496 -0.0603 0.6591 +vn -0.7777 -0.1021 0.6202 +vn -0.7967 -0.1325 0.5896 +vn -0.8053 -0.1489 0.5738 +vn -0.8038 -0.1514 0.5753 +vn -0.7952 -0.1408 0.5898 +vn -0.7821 -0.1181 0.6119 +vn -0.7634 -0.0846 0.6404 +vn -0.7369 -0.0420 0.6746 +vn -0.7018 0.0067 0.7123 +vn -0.6603 0.0562 0.7489 +vn -0.6187 0.1003 0.7792 +vn -0.5867 0.1330 0.7988 +vn -0.5715 0.1507 0.8066 +vn -0.5729 0.1528 0.8052 +vn -0.5875 0.1403 0.7970 +vn -0.6120 0.1151 0.7824 +vn -0.6433 0.0797 0.7615 +vn -0.6785 0.0367 0.7336 +vn -0.7155 -0.0105 0.6985 +vn -0.7512 -0.0577 0.6575 +vn -0.7801 -0.0999 0.6176 +vn -0.7981 -0.1322 0.5879 +vn -0.8052 -0.1517 0.5733 +vn -0.8033 -0.1573 0.5744 +vn -0.7945 -0.1484 0.5887 +vn -0.7803 -0.1255 0.6126 +vn -0.7607 -0.0897 0.6428 +vn -0.7344 -0.0435 0.6773 +vn -0.7023 0.0075 0.7118 +vn -0.6677 0.0573 0.7422 +vn -0.6328 0.1014 0.7676 +vn -0.6006 0.1361 0.7879 +vn -0.5763 0.1580 0.8018 +vn -0.5657 0.1647 0.8080 +vn -0.5730 0.1550 0.8047 +vn -0.5983 0.1293 0.7907 +vn -0.6354 0.0898 0.7669 +vn -0.6761 0.0412 0.7356 +vn -0.7141 -0.0104 0.6999 +vn -0.7462 -0.0592 0.6630 +vn -0.7713 -0.1006 0.6285 +vn -0.7896 -0.1316 0.5993 +vn -0.8018 -0.1505 0.5782 +vn -0.8062 -0.1558 0.5707 +vn -0.8004 -0.1465 0.5812 +vn -0.7866 -0.1233 0.6050 +vn -0.7664 -0.0887 0.6361 +vn -0.7356 -0.0396 0.6763 +vn -0.7103 0.0076 0.7038 +vn -0.6676 0.0484 0.7429 +vn -0.6282 0.0904 0.7728 +vn -0.5933 0.1233 0.7955 +vn -0.5709 0.1435 0.8084 +vn -0.5668 0.1486 0.8103 +vn -0.5806 0.1386 0.8023 +vn -0.6073 0.1151 0.7860 +vn -0.6409 0.0812 0.7633 +vn -0.6758 0.0414 0.7359 +vn -0.6761 0.0403 0.7357 +vn -0.6830 0.0348 0.7296 +vn -0.7171 -0.0149 0.6968 +vn -0.7487 -0.0634 0.6598 +vn -0.7751 -0.1051 0.6230 +vn -0.7942 -0.1350 0.5924 +vn -0.8048 -0.1506 0.5741 +vn -0.8061 -0.1518 0.5720 +vn -0.7980 -0.1400 0.5861 +vn -0.7829 -0.1169 0.6110 +vn -0.7626 -0.0838 0.6414 +vn -0.7361 -0.0418 0.6755 +vn -0.7024 0.0063 0.7117 +vn -0.6627 0.0561 0.7467 +vn -0.6218 0.1013 0.7765 +vn -0.5876 0.1356 0.7977 +vn -0.5687 0.1546 0.8079 +vn -0.5690 0.1570 0.8072 +vn -0.5849 0.1440 0.7982 +vn -0.6113 0.1177 0.7826 +vn -0.6438 0.0810 0.7609 +vn -0.6790 0.0372 0.7331 +vn -0.7142 -0.0097 0.6999 +vn -0.7476 -0.0555 0.6619 +vn -0.7769 -0.0959 0.6222 +vn -0.7982 -0.1268 0.5889 +vn -0.8086 -0.1453 0.5701 +vn -0.8086 -0.1502 0.5689 +vn -0.7995 -0.1411 0.5838 +vn -0.7828 -0.1182 0.6109 +vn -0.7598 -0.0827 0.6448 +vn -0.7311 -0.0371 0.6812 +vn -0.6976 0.0142 0.7163 +vn -0.6626 0.0643 0.7461 +vn -0.6298 0.1081 0.7692 +vn -0.6009 0.1420 0.7866 +vn -0.5793 0.1632 0.7986 +vn -0.5695 0.1691 0.8044 +vn -0.5753 0.1584 0.8024 +vn -0.5981 0.1313 0.7906 +vn -0.6347 0.0902 0.7674 +vn -0.6767 0.0400 0.7351 +vn -0.7159 -0.0130 0.6980 +vn -0.7480 -0.0628 0.6607 +vn -0.7720 -0.1050 0.6268 +vn -0.7886 -0.1363 0.5995 +vn -0.7990 -0.1551 0.5809 +vn -0.8039 -0.1600 0.5728 +vn -0.8008 -0.1500 0.5797 +vn -0.7874 -0.1257 0.6035 +vn -0.7659 -0.0898 0.6366 +vn -0.7386 -0.0460 0.6725 +vn -0.6743 0.0419 0.7372 +vn -0.7017 -0.0047 0.7125 +vn -0.6324 0.0894 0.7694 +vn -0.5988 0.1214 0.7916 +vn -0.5743 0.1413 0.8063 +vn -0.5658 0.1468 0.8113 +vn -0.5764 0.1375 0.8055 +vn -0.6024 0.1147 0.7898 +vn -0.6375 0.0812 0.7662 +vn -0.6749 0.0403 0.7368 +vn -0.7100 -0.0038 0.7041 +vn -0.7100 -0.0042 0.7042 +vn -0.7202 -0.0197 0.6934 +vn -0.7501 -0.0683 0.6578 +vn -0.7741 -0.1101 0.6234 +vn -0.7914 -0.1404 0.5949 +vn -0.8018 -0.1561 0.5769 +vn -0.8046 -0.1566 0.5728 +vn -0.7990 -0.1430 0.5840 +vn -0.7847 -0.1178 0.6085 +vn -0.7630 -0.0833 0.6409 +vn -0.7353 -0.0408 0.6764 +vn -0.7017 0.0073 0.7124 +vn -0.6632 0.0571 0.7463 +vn -0.6235 0.1027 0.7750 +vn -0.5894 0.1380 0.7959 +vn -0.5683 0.1581 0.8075 +vn -0.5659 0.1609 0.8086 +vn -0.5818 0.1472 0.7999 +vn -0.6100 0.1197 0.7833 +vn -0.6446 0.0815 0.7602 +vn -0.6806 0.0362 0.7317 +vn -0.7149 -0.0116 0.6991 +vn -0.7457 -0.0573 0.6638 +vn -0.7724 -0.0970 0.6276 +vn -0.7941 -0.1267 0.5945 +vn -0.8076 -0.1440 0.5719 +vn -0.8109 -0.1474 0.5662 +vn -0.8040 -0.1371 0.5785 +vn -0.7874 -0.1136 0.6059 +vn -0.7621 -0.0780 0.6427 +vn -0.7302 -0.0327 0.6825 +vn -0.6940 0.0180 0.7197 +vn -0.6572 0.0683 0.7505 +vn -0.6247 0.1117 0.7729 +vn -0.5986 0.1449 0.7878 +vn -0.5806 0.1653 0.7972 +vn -0.5735 0.1707 0.8012 +vn -0.5800 0.1596 0.7988 +vn -0.6014 0.1322 0.7879 +vn -0.6358 0.0905 0.7665 +vn -0.6773 0.0392 0.7346 +vn -0.7175 -0.0147 0.6964 +vn -0.7502 -0.0652 0.6579 +vn -0.7740 -0.1074 0.6240 +vn -0.7895 -0.1386 0.5979 +vn -0.7982 -0.1571 0.5815 +vn -0.8013 -0.1617 0.5760 +vn -0.7986 -0.1518 0.5823 +vn -0.7875 -0.1270 0.6030 +vn -0.7660 -0.0897 0.6365 +vn -0.7374 -0.0447 0.6739 +vn -0.7048 0.0034 0.7094 +vn -0.6698 0.0501 0.7409 +vn -0.6349 0.0910 0.7671 +vn -0.6037 0.1226 0.7877 +vn -0.5800 0.1422 0.8021 +vn -0.5686 0.1481 0.8092 +vn -0.5743 0.1394 0.8066 +vn -0.5974 0.1171 0.7933 +vn -0.6323 0.0836 0.7702 +vn -0.6717 0.0421 0.7396 +vn -0.7094 -0.0034 0.7048 +vn -0.7410 -0.0485 0.6698 +vn -0.7415 -0.0489 0.6691 +vn -0.7529 -0.0711 0.6542 +vn -0.7755 -0.1134 0.6210 +vn -0.7908 -0.1444 0.5948 +vn -0.7993 -0.1609 0.5790 +vn -0.8014 -0.1617 0.5758 +vn -0.7968 -0.1476 0.5859 +vn -0.7844 -0.1207 0.6083 +vn -0.7635 -0.0838 0.6403 +vn -0.7350 -0.0398 0.6769 +vn -0.7007 0.0088 0.7133 +vn -0.6626 0.0582 0.7467 +vn -0.6241 0.1034 0.7745 +vn -0.5695 0.1592 0.8064 +vn -0.5652 0.1625 0.8088 +vn -0.5795 0.1485 0.8014 +vn -0.6083 0.1198 0.7846 +vn -0.6447 0.0803 0.7602 +vn -0.6825 0.0337 0.7301 +vn -0.7172 -0.0153 0.6966 +vn -0.7466 -0.0619 0.6624 +vn -0.7702 -0.1017 0.6296 +vn -0.7889 -0.1314 0.6003 +vn -0.8025 -0.1482 0.5779 +vn -0.8086 -0.1506 0.5687 +vn -0.8050 -0.1388 0.5768 +vn -0.7909 -0.1140 0.6012 +vn -0.7663 -0.0778 0.6378 +vn -0.7325 -0.0327 0.6799 +vn -0.6933 0.0173 0.7204 +vn -0.6538 0.0670 0.7537 +vn -0.6197 0.1101 0.7770 +vn -0.5947 0.1422 0.7913 +vn -0.5796 0.1618 0.7986 +vn -0.5758 0.1669 0.8003 +vn -0.5845 0.1562 0.7962 +vn -0.6061 0.1295 0.7847 +vn -0.6388 0.0887 0.7642 +vn -0.6784 0.0384 0.7336 +vn -0.7183 -0.0151 0.6956 +vn -0.7518 -0.0652 0.6561 +vn -0.7761 -0.1069 0.6214 +vn -0.7914 -0.1375 0.5956 +vn -0.7992 -0.1555 0.5805 +vn -0.8007 -0.1600 0.5772 +vn -0.7965 -0.1504 0.5857 +vn -0.7857 -0.1263 0.6055 +vn -0.7658 -0.0890 0.6369 +vn -0.7367 -0.0428 0.6749 +vn -0.7029 0.0061 0.7112 +vn -0.6681 0.0532 0.7421 +vn -0.6349 0.0945 0.7668 +vn -0.6061 0.1265 0.7853 +vn -0.5846 0.1466 0.7979 +vn -0.5735 0.1531 0.8047 +vn -0.5761 0.1451 0.8043 +vn -0.5950 0.1230 0.7943 +vn -0.6276 0.0888 0.7734 +vn -0.6675 0.0461 0.7432 +vn -0.7074 -0.0008 0.7068 +vn -0.7419 -0.0478 0.6688 +vn -0.7671 -0.0905 0.6351 +vn -0.7684 -0.0906 0.6335 +vn -0.7787 -0.1122 0.6172 +vn -0.7930 -0.1440 0.5919 +vn -0.7996 -0.1617 0.5783 +vn -0.7998 -0.1637 0.5775 +vn -0.7940 -0.1502 0.5890 +vn -0.7818 -0.1229 0.6113 +vn -0.7621 -0.0848 0.6418 +vn -0.7343 -0.0392 0.6776 +vn -0.6998 0.0101 0.7142 +vn -0.6617 0.0593 0.7474 +vn -0.6240 0.1037 0.7745 +vn -0.5919 0.1381 0.7941 +vn -0.5710 0.1585 0.8055 +vn -0.5660 0.1621 0.8083 +vn -0.5788 0.1485 0.8018 +vn -0.6069 0.1194 0.7858 +vn -0.6440 0.0790 0.7609 +vn -0.6836 0.0314 0.7292 +vn -0.7198 -0.0186 0.6939 +vn -0.7493 -0.0663 0.6589 +vn -0.7712 -0.1071 0.6275 +vn -0.7867 -0.1373 0.6019 +vn -0.7973 -0.1546 0.5835 +vn -0.8031 -0.1573 0.5747 +vn -0.8017 -0.1450 0.5799 +vn -0.7909 -0.1191 0.6003 +vn -0.7692 -0.0820 0.6337 +vn -0.7368 -0.0369 0.6750 +vn -0.6965 0.0124 0.7175 +vn -0.6540 0.0612 0.7540 +vn -0.6168 0.1039 0.7802 +vn -0.5907 0.1358 0.7953 +vn -0.5770 0.1545 0.8020 +vn -0.5754 0.1594 0.8021 +vn -0.5866 0.1493 0.7960 +vn -0.6097 0.1240 0.7829 +vn -0.6422 0.0851 0.7618 +vn -0.6801 0.0367 0.7322 +vn -0.7184 -0.0150 0.6955 +vn -0.7520 -0.0637 0.6560 +vn -0.7773 -0.1043 0.6204 +vn -0.7933 -0.1340 0.5939 +vn -0.8011 -0.1513 0.5790 +vn -0.8020 -0.1556 0.5767 +vn -0.7964 -0.1463 0.5868 +vn -0.7842 -0.1232 0.6081 +vn -0.7645 -0.0874 0.6387 +vn -0.7361 -0.0416 0.6756 +vn -0.7013 0.0080 0.7127 +vn -0.6656 0.0556 0.7442 +vn -0.6327 0.0973 0.7682 +vn -0.6055 0.1299 0.7852 +vn -0.5863 0.1509 0.7959 +vn -0.5773 0.1585 0.8010 +vn -0.5802 0.1516 0.8003 +vn -0.5964 0.1300 0.7921 +vn -0.6259 0.0953 0.7741 +vn -0.6642 0.0513 0.7458 +vn -0.7046 0.0027 0.7096 +vn -0.7411 -0.0456 0.6699 +vn -0.7696 -0.0895 0.6322 +vn -0.7869 -0.1256 0.6041 +vn -0.7889 -0.1252 0.6016 +vn -0.7968 -0.1392 0.5879 +vn -0.8029 -0.1580 0.5747 +vn -0.8013 -0.1612 0.5761 +vn -0.7933 -0.1487 0.5903 +vn -0.7794 -0.1219 0.6146 +vn -0.7592 -0.0837 0.6454 +vn -0.7323 -0.0378 0.6799 +vn -0.6986 0.0117 0.7154 +vn -0.6608 0.0607 0.7481 +vn -0.6239 0.1041 0.7745 +vn -0.5928 0.1375 0.7935 +vn -0.5727 0.1570 0.8046 +vn -0.5676 0.1605 0.8075 +vn -0.5792 0.1473 0.8017 +vn -0.6061 0.1188 0.7864 +vn -0.6430 0.0784 0.7618 +vn -0.6832 0.0308 0.7295 +vn -0.7213 -0.0195 0.6923 +vn -0.7524 -0.0679 0.6552 +vn -0.7745 -0.1095 0.6230 +vn -0.7882 -0.1407 0.5990 +vn -0.7956 -0.1588 0.5846 +vn -0.7984 -0.1625 0.5798 +vn -0.7963 -0.1512 0.5857 +vn -0.7871 -0.1253 0.6039 +vn -0.7687 -0.0879 0.6335 +vn -0.7399 -0.0426 0.6713 +vn -0.7017 0.0062 0.7125 +vn -0.6583 0.0540 0.7508 +vn -0.6176 0.0960 0.7805 +vn -0.5880 0.1279 0.7986 +vn -0.5737 0.1465 0.8058 +vn -0.5732 0.1512 0.8053 +vn -0.5856 0.1416 0.7981 +vn -0.6103 0.1177 0.7833 +vn -0.6438 0.0808 0.7609 +vn -0.6814 0.0345 0.7311 +vn -0.7510 -0.0620 0.6573 +vn -0.7767 -0.1011 0.6216 +vn -0.7940 -0.1297 0.5939 +vn -0.8027 -0.1464 0.5781 +vn -0.8039 -0.1504 0.5755 +vn -0.7978 -0.1414 0.5860 +vn -0.7846 -0.1191 0.6084 +vn -0.7639 -0.0847 0.6398 +vn -0.7355 -0.0405 0.6763 +vn -0.7007 0.0084 0.7134 +vn -0.6638 0.0560 0.7458 +vn -0.6300 0.0977 0.7704 +vn -0.6029 0.1307 0.7870 +vn -0.5850 0.1524 0.7965 +vn -0.5782 0.1610 0.7999 +vn -0.5831 0.1552 0.7974 +vn -0.5999 0.1346 0.7887 +vn -0.6277 0.1001 0.7720 +vn -0.6637 0.0553 0.7459 +vn -0.7028 0.0054 0.7114 +vn -0.7394 -0.0442 0.6717 +vn -0.7693 -0.0887 0.6326 +vn -0.7903 -0.1243 0.6000 +vn -0.7996 -0.1494 0.5816 +vn -0.8019 -0.1484 0.5787 +vn -0.8072 -0.1519 0.5703 +vn -0.8054 -0.1558 0.5718 +vn -0.7957 -0.1441 0.5883 +vn -0.7792 -0.1178 0.6156 +vn -0.7569 -0.0798 0.6486 +vn -0.7293 -0.0342 0.6833 +vn -0.6966 0.0146 0.7172 +vn -0.6600 0.0626 0.7486 +vn -0.6237 0.1050 0.7746 +vn -0.5937 0.1371 0.7929 +vn -0.5745 0.1556 0.8035 +vn -0.5696 0.1586 0.8065 +vn -0.5803 0.1458 0.8012 +vn -0.6058 0.1181 0.7868 +vn -0.6418 0.0786 0.7628 +vn -0.6819 0.0318 0.7307 +vn -0.7207 -0.0175 0.6930 +vn -0.7540 -0.0655 0.6535 +vn -0.7781 -0.1074 0.6189 +vn -0.7922 -0.1393 0.5941 +vn -0.7981 -0.1582 0.5814 +vn -0.7978 -0.1628 0.5805 +vn -0.7927 -0.1527 0.5901 +vn -0.7825 -0.1281 0.6092 +vn -0.7653 -0.0913 0.6372 +vn -0.7396 -0.0464 0.6713 +vn -0.7054 0.0019 0.7088 +vn -0.6645 0.0491 0.7456 +vn -0.6229 0.0904 0.7770 +vn -0.5889 0.1220 0.7989 +vn -0.5706 0.1410 0.8090 +vn -0.5698 0.1458 0.8087 +vn -0.5828 0.1365 0.8010 +vn -0.6079 0.1135 0.7858 +vn -0.6427 0.0779 0.7621 +vn -0.6812 0.0333 0.7313 +vn -0.7182 -0.0148 0.6956 +vn -0.7500 -0.0606 0.6587 +vn -0.7750 -0.0988 0.6242 +vn -0.7929 -0.1267 0.5961 +vn -0.8030 -0.1428 0.5786 +vn -0.8052 -0.1466 0.5746 +vn -0.7996 -0.1377 0.5844 +vn -0.7862 -0.1161 0.6069 +vn -0.7358 -0.0398 0.6760 +vn -0.7008 0.0080 0.7132 +vn -0.6634 0.0550 0.7462 +vn -0.6284 0.0961 0.7719 +vn -0.6003 0.1286 0.7894 +vn -0.5823 0.1504 0.7989 +vn -0.5766 0.1596 0.8013 +vn -0.5835 0.1545 0.7972 +vn -0.6024 0.1346 0.7867 +vn -0.6310 0.1007 0.7692 +vn -0.6660 0.0558 0.7438 +vn -0.7033 0.0052 0.7109 +vn -0.7384 -0.0452 0.6728 +vn -0.7679 -0.0898 0.6341 +vn -0.7897 -0.1249 0.6006 +vn -0.8028 -0.1479 0.5776 +vn -0.8049 -0.1586 0.5717 +vn -0.8070 -0.1570 0.5693 +vn -0.8097 -0.1515 0.5670 +vn -0.8000 -0.1397 0.5835 +vn -0.7817 -0.1133 0.6132 +vn -0.7567 -0.0752 0.6494 +vn -0.7269 -0.0296 0.6861 +vn -0.6940 0.0186 0.7197 +vn -0.6590 0.0650 0.7493 +vn -0.6239 0.1057 0.7743 +vn -0.5946 0.1367 0.7923 +vn -0.5765 0.1542 0.8024 +vn -0.5719 0.1568 0.8052 +vn -0.5820 0.1441 0.8003 +vn -0.6060 0.1174 0.7867 +vn -0.6404 0.0792 0.7639 +vn -0.6799 0.0337 0.7325 +vn -0.7185 -0.0142 0.6953 +vn -0.7530 -0.0606 0.6552 +vn -0.7798 -0.1018 0.6176 +vn -0.7964 -0.1336 0.5899 +vn -0.8028 -0.1529 0.5763 +vn -0.8012 -0.1579 0.5772 +vn -0.7933 -0.1484 0.5905 +vn -0.7802 -0.1250 0.6129 +vn -0.7616 -0.0896 0.6418 +vn -0.7368 -0.0457 0.6746 +vn -0.7057 0.0018 0.7085 +vn -0.6689 0.0484 0.7418 +vn -0.6296 0.0896 0.7717 +vn -0.5942 0.1214 0.7951 +vn -0.5708 0.1407 0.8089 +vn -0.5658 0.1458 0.8115 +vn -0.5788 0.1366 0.8039 +vn -0.6042 0.1137 0.7886 +vn -0.6393 0.0784 0.7649 +vn -0.6792 0.0342 0.7331 +vn -0.7174 -0.0136 0.6965 +vn -0.7494 -0.0592 0.6594 +vn -0.7738 -0.0977 0.6258 +vn -0.7909 -0.1258 0.5988 +vn -0.8015 -0.1421 0.5808 +vn -0.8050 -0.1461 0.5750 +vn -0.8007 -0.1373 0.5831 +vn -0.7880 -0.1159 0.6046 +vn -0.7668 -0.0828 0.6365 +vn -0.7374 -0.0405 0.6742 +vn -0.7019 0.0067 0.7123 +vn -0.6641 0.0533 0.7457 +vn -0.6287 0.0940 0.7719 +vn -0.5995 0.1255 0.7904 +vn -0.5801 0.1466 0.8012 +vn -0.5740 0.1554 0.8040 +vn -0.5819 0.1504 0.7992 +vn -0.6026 0.1308 0.7872 +vn -0.6333 0.0973 0.7678 +vn -0.6693 0.0526 0.7411 +vn -0.7058 0.0018 0.7084 +vn -0.7390 -0.0487 0.6719 +vn -0.7668 -0.0932 0.6351 +vn -0.7878 -0.1276 0.6025 +vn -0.8014 -0.1492 0.5792 +vn -0.8069 -0.1567 0.5694 +vn -0.8025 -0.1514 0.5771 +vn -0.8039 -0.1497 0.5755 +vn -0.7837 -0.1281 0.6077 +vn -0.7850 -0.1281 0.6060 +vn -0.7711 -0.1042 0.6282 +vn -0.7951 -0.1505 0.5874 +vn -0.8013 -0.1594 0.5766 +vn -0.8017 -0.1541 0.5775 +vn -0.7945 -0.1346 0.5921 +vn -0.7776 -0.1018 0.6203 +vn -0.7499 -0.0582 0.6589 +vn -0.7128 -0.0085 0.7013 +vn -0.6696 0.0420 0.7415 +vn -0.6275 0.0874 0.7737 +vn -0.5956 0.1220 0.7939 +vn -0.5791 0.1432 0.8026 +vn -0.5776 0.1505 0.8023 +vn -0.5878 0.1448 0.7960 +vn -0.6059 0.1272 0.7853 +vn -0.6305 0.0985 0.7699 +vn -0.6613 0.0600 0.7477 +vn -0.6963 0.0146 0.7175 +vn -0.7317 -0.0331 0.6807 +vn -0.7633 -0.0780 0.6413 +vn -0.7875 -0.1147 0.6055 +vn -0.8023 -0.1395 0.5804 +vn -0.8068 -0.1502 0.5713 +vn -0.8027 -0.1468 0.5780 +vn -0.7925 -0.1305 0.5958 +vn -0.7757 -0.1021 0.6227 +vn -0.7508 -0.0626 0.6575 +vn -0.7179 -0.0146 0.6960 +vn -0.6793 0.0373 0.7329 +vn -0.6396 0.0869 0.7638 +vn -0.6052 0.1280 0.7857 +vn -0.5811 0.1556 0.7988 +vn -0.5697 0.1675 0.8046 +vn -0.5734 0.1634 0.8028 +vn -0.5923 0.1435 0.7928 +vn -0.6230 0.1092 0.7745 +vn -0.6602 0.0636 0.7483 +vn -0.6983 0.0114 0.7157 +vn -0.7327 -0.0418 0.6793 +vn -0.7599 -0.0905 0.6436 +vn -0.7783 -0.1295 0.6143 +vn -0.7902 -0.1552 0.5929 +vn -0.7979 -0.1669 0.5791 +vn -0.8010 -0.1640 0.5757 +vn -0.7973 -0.1463 0.5855 +vn -0.7837 -0.1144 0.6104 +vn -0.7580 -0.0705 0.6484 +vn -0.7212 -0.0190 0.6924 +vn -0.6791 0.0337 0.7332 +vn -0.6392 0.0812 0.7647 +vn -0.6073 0.1190 0.7855 +vn -0.5866 0.1447 0.7968 +vn -0.5777 0.1571 0.8010 +vn -0.5799 0.1559 0.7996 +vn -0.5926 0.1406 0.7931 +vn -0.6171 0.1110 0.7790 +vn -0.6529 0.0685 0.7543 +vn -0.6934 0.0181 0.7203 +vn -0.7309 -0.0330 0.6816 +vn -0.7610 -0.0783 0.6439 +vn -0.7824 -0.1134 0.6123 +vn -0.7957 -0.1364 0.5900 +vn -0.8024 -0.1469 0.5784 +vn -0.8028 -0.1465 0.5779 +vn -0.7994 -0.1401 0.5842 +vn -0.7884 -0.1223 0.6028 +vn -0.7702 -0.0950 0.6306 +vn -0.7444 -0.0561 0.6654 +vn -0.7112 -0.0066 0.7030 +vn -0.6728 0.0481 0.7383 +vn -0.6343 0.0985 0.7668 +vn -0.6022 0.1363 0.7866 +vn -0.5809 0.1587 0.7983 +vn -0.5807 0.1499 0.8001 +vn -0.6014 0.1223 0.7895 +vn -0.6321 0.0855 0.7701 +vn -0.6685 0.0436 0.7424 +vn -0.7065 -0.0008 0.7076 +vn -0.7419 -0.0455 0.6689 +vn -0.7707 -0.0854 0.6315 +vn -0.7908 -0.1176 0.6007 +vn -0.8023 -0.1421 0.5797 +vn -0.8058 -0.1562 0.5712 +vn -0.8018 -0.1563 0.5768 +vn -0.7902 -0.1392 0.5967 +vn -0.7707 -0.1043 0.6286 +vn -0.7429 -0.0555 0.6671 +vn -0.7080 -0.0021 0.7062 +vn -0.6696 0.0478 0.7412 +vn -0.6322 0.0901 0.7696 +vn -0.6003 0.1226 0.7903 +vn -0.5781 0.1444 0.8031 +vn -0.5683 0.1548 0.8081 +vn -0.5926 0.1342 0.7942 +vn -0.6244 0.0986 0.7748 +vn -0.6622 0.0543 0.7474 +vn -0.7006 0.0075 0.7134 +vn -0.7360 -0.0396 0.6759 +vn -0.7651 -0.0842 0.6383 +vn -0.7865 -0.1230 0.6052 +vn -0.7996 -0.1520 0.5809 +vn -0.8047 -0.1660 0.5699 +vn -0.8024 -0.1597 0.5750 +vn -0.7922 -0.1344 0.5953 +vn -0.7730 -0.0958 0.6270 +vn -0.7451 -0.0502 0.6650 +vn -0.7104 -0.0032 0.7038 +vn -0.6722 0.0418 0.7392 +vn -0.6343 0.0836 0.7685 +vn -0.6008 0.1215 0.7901 +vn -0.5771 0.1501 0.8027 +vn -0.5683 0.1625 0.8065 +vn -0.5760 0.1565 0.8023 +vn -0.5980 0.1335 0.7902 +vn -0.6297 0.0976 0.7707 +vn -0.6656 0.0540 0.7443 +vn -0.7335 -0.0369 0.6787 +vn -0.7608 -0.0794 0.6441 +vn -0.7821 -0.1169 0.6121 +vn -0.7963 -0.1447 0.5873 +vn -0.8033 -0.1588 0.5740 +vn -0.8028 -0.1568 0.5752 +vn -0.7945 -0.1380 0.5914 +vn -0.7917 -0.1283 0.5972 +vn -0.7775 -0.1045 0.6201 +vn -0.7780 -0.1026 0.6198 +vn -0.7962 -0.1343 0.5899 +vn -0.8049 -0.1530 0.5733 +vn -0.8049 -0.1574 0.5721 +vn -0.7972 -0.1472 0.5854 +vn -0.7826 -0.1227 0.6102 +vn -0.7613 -0.0858 0.6427 +vn -0.7334 -0.0392 0.6786 +vn -0.6993 0.0121 0.7147 +vn -0.6614 0.0621 0.7474 +vn -0.6246 0.1044 0.7739 +vn -0.5947 0.1347 0.7925 +vn -0.5764 0.1509 0.8031 +vn -0.5725 0.1527 0.8055 +vn -0.5835 0.1412 0.7997 +vn -0.6062 0.1180 0.7865 +vn -0.6373 0.0841 0.7660 +vn -0.6741 0.0414 0.7374 +vn -0.7124 -0.0060 0.7017 +vn -0.7469 -0.0525 0.6628 +vn -0.7742 -0.0929 0.6261 +vn -0.7927 -0.1234 0.5970 +vn -0.8024 -0.1417 0.5797 +vn -0.8039 -0.1473 0.5762 +vn -0.7985 -0.1400 0.5855 +vn -0.7870 -0.1203 0.6051 +vn -0.7686 -0.0889 0.6335 +vn -0.7419 -0.0479 0.6688 +vn -0.7070 -0.0008 0.7072 +vn -0.6667 0.0470 0.7439 +vn -0.6271 0.0897 0.7738 +vn -0.5937 0.1223 0.7953 +vn -0.5709 0.1422 0.8086 +vn -0.5650 0.1480 0.8117 +vn -0.5784 0.1391 0.8038 +vn -0.6064 0.1161 0.7866 +vn -0.6419 0.0814 0.7624 +vn -0.6783 0.0384 0.7337 +vn -0.7118 -0.0085 0.7023 +vn -0.7412 -0.0551 0.6690 +vn -0.7657 -0.0968 0.6359 +vn -0.7849 -0.1290 0.6059 +vn -0.7987 -0.1490 0.5829 +vn -0.8060 -0.1549 0.5712 +vn -0.8051 -0.1462 0.5747 +vn -0.7944 -0.1238 0.5946 +vn -0.7729 -0.0897 0.6281 +vn -0.7429 -0.0475 0.6677 +vn -0.7074 -0.0012 0.7068 +vn -0.6685 0.0461 0.7423 +vn -0.6307 0.0896 0.7708 +vn -0.5996 0.1248 0.7905 +vn -0.5795 0.1480 0.8014 +vn -0.5730 0.1571 0.8043 +vn -0.5803 0.1512 0.8002 +vn -0.6013 0.1306 0.7882 +vn -0.6319 0.0976 0.7688 +vn -0.6659 0.0559 0.7439 +vn -0.7005 0.0090 0.7136 +vn -0.7345 -0.0391 0.6775 +vn -0.7653 -0.0837 0.6381 +vn -0.7901 -0.1196 0.6012 +vn -0.8061 -0.1429 0.5742 +vn -0.8112 -0.1502 0.5650 +vn -0.8108 -0.1507 0.5655 +vn -0.8026 -0.1396 0.5799 +vn -0.7863 -0.1169 0.6066 +vn -0.7622 -0.0818 0.6422 +vn -0.7310 -0.0356 0.6814 +vn -0.6947 0.0173 0.7191 +vn -0.6569 0.0692 0.7508 +vn -0.6224 0.1124 0.7746 +vn -0.5958 0.1421 0.7904 +vn -0.5807 0.1565 0.7989 +vn -0.5788 0.1554 0.8005 +vn -0.5901 0.1404 0.7950 +vn -0.6131 0.1133 0.7818 +vn -0.6450 0.0764 0.7603 +vn -0.6821 0.0320 0.7306 +vn -0.7197 -0.0175 0.6941 +vn -0.7531 -0.0674 0.6544 +vn -0.7790 -0.1104 0.6172 +vn -0.7961 -0.1406 0.5886 +vn -0.8048 -0.1552 0.5728 +vn -0.8059 -0.1543 0.5716 +vn -0.7994 -0.1398 0.5843 +vn -0.7853 -0.1138 0.6085 +vn -0.7632 -0.0790 0.6412 +vn -0.7332 -0.0358 0.6790 +vn -0.6966 0.0142 0.7173 +vn -0.6576 0.0647 0.7506 +vn -0.6218 0.1079 0.7757 +vn -0.5947 0.1383 0.7919 +vn -0.5800 0.1531 0.8000 +vn -0.5787 0.1525 0.8011 +vn -0.5896 0.1386 0.7957 +vn -0.6108 0.1152 0.7833 +vn -0.6400 0.0837 0.7638 +vn -0.6746 0.0433 0.7369 +vn -0.7107 -0.0049 0.7035 +vn -0.7439 -0.0565 0.6659 +vn -0.7702 -0.1041 0.6292 +vn -0.7881 -0.1393 0.5995 +vn -0.7978 -0.1570 0.5820 +vn -0.8000 -0.1580 0.5787 +vn -0.7951 -0.1452 0.5888 +vn -0.7827 -0.1201 0.6106 +vn -0.7626 -0.0844 0.6413 +vn -0.7348 -0.0404 0.6771 +vn -0.7007 0.0086 0.7134 +vn -0.6633 0.0584 0.7461 +vn -0.6274 0.1028 0.7718 +vn -0.5989 0.1346 0.7895 +vn -0.5816 0.1514 0.7993 +vn -0.5770 0.1546 0.8020 +vn -0.5854 0.1447 0.7977 +vn -0.6059 0.1224 0.7861 +vn -0.6364 0.0884 0.7662 +vn -0.6735 0.0443 0.7378 +vn -0.7121 -0.0066 0.7020 +vn -0.7463 -0.0565 0.6632 +vn -0.7726 -0.0982 0.6272 +vn -0.7904 -0.1294 0.5988 +vn -0.8000 -0.1487 0.5813 +vn -0.8021 -0.1555 0.5766 +vn -0.7972 -0.1488 0.5850 +vn -0.7593 -0.0730 0.6466 +g Plane_Plane_curtain +usemtl curtain +s 1 +f 7954/8132/7286 8016/8133/7287 7953/8134/7288 +f 7955/8135/7289 8017/8136/7290 7954/8132/7286 +f 7956/8137/7291 8018/8138/7292 7955/8135/7289 +f 7957/8139/7293 8019/8140/7294 7956/8137/7291 +f 7958/8141/7295 8020/8142/7296 7957/8139/7293 +f 7959/8143/7297 8021/8144/7298 7958/8141/7295 +f 7960/8145/7299 8022/8146/7300 7959/8143/7297 +f 7961/8147/7301 8023/8148/7302 7960/8145/7299 +f 7962/8149/7303 8024/8150/7304 7961/8147/7301 +f 7963/8151/7305 8025/8152/7306 7962/8149/7303 +f 7964/8153/7307 8026/8154/7308 7963/8151/7305 +f 7965/8155/7309 8027/8156/7310 7964/8153/7307 +f 7966/8157/7311 8028/8158/7312 7965/8155/7309 +f 7967/8159/7313 8029/8160/7314 7966/8157/7311 +f 7968/8161/7315 8030/8162/7316 7967/8159/7313 +f 7969/8163/7317 8031/8164/7318 7968/8161/7315 +f 7970/8165/7319 8032/8166/7320 7969/8163/7317 +f 7971/8167/7321 8033/8168/7322 7970/8165/7319 +f 7972/8169/7323 8034/8170/7324 7971/8167/7321 +f 7973/8171/7325 8035/8172/7326 7972/8169/7323 +f 7974/8173/7327 8036/8174/7328 7973/8171/7325 +f 7975/8175/7329 8037/8176/7330 7974/8173/7327 +f 7976/8177/7331 8038/8178/7332 7975/8175/7329 +f 7977/8179/7333 8039/8180/7334 7976/8177/7331 +f 7978/8181/7335 8040/8182/7336 7977/8179/7333 +f 7979/8183/7337 8041/8184/7338 7978/8181/7335 +f 7980/8185/7339 8042/8186/7340 7979/8183/7337 +f 7981/8187/7341 8043/8188/7342 7980/8185/7339 +f 7982/8189/7343 8044/8190/7344 7981/8187/7341 +f 7983/8191/7345 8045/8192/7346 7982/8189/7343 +f 7984/8193/7347 8046/8194/7348 7983/8191/7345 +f 7985/8195/7349 8047/8196/7350 7984/8193/7347 +f 7986/8197/7351 8048/8198/7352 7985/8195/7349 +f 7987/8199/7353 8049/8200/7354 7986/8197/7351 +f 7988/8201/7355 8050/8202/7356 7987/8199/7353 +f 7989/8203/7357 8051/8204/7358 7988/8201/7355 +f 7990/8205/7359 8052/8206/7360 7989/8203/7357 +f 7991/8207/7361 8053/8208/7362 7990/8205/7359 +f 7992/8209/7363 8054/8210/7364 7991/8207/7361 +f 7993/8211/7365 8055/8212/7366 7992/8209/7363 +f 7994/8213/7367 8056/8214/7368 7993/8211/7365 +f 7995/8215/7369 8057/8216/7370 7994/8213/7367 +f 7996/8217/7371 8058/8218/7372 7995/8215/7369 +f 7997/8219/7373 8059/8220/7374 7996/8217/7371 +f 7998/8221/7375 8060/8222/7376 7997/8219/7373 +f 7999/8223/7377 8061/8224/7378 7998/8221/7375 +f 8000/8225/7379 8062/8226/7380 7999/8223/7377 +f 8001/8227/7381 8063/8228/7382 8000/8225/7379 +f 8002/8229/7383 8064/8230/7384 8001/8227/7381 +f 8003/8231/7385 8065/8232/7386 8002/8229/7383 +f 8004/8233/7387 8066/8234/7388 8003/8231/7385 +f 8005/8235/7389 8067/8236/7390 8004/8233/7387 +f 8006/8237/7391 8068/8238/7392 8005/8235/7389 +f 8007/8239/7393 8069/8240/7394 8006/8237/7391 +f 8008/8241/7395 8070/8242/7396 8007/8239/7393 +f 8009/8243/7397 8071/8244/7398 8008/8241/7395 +f 8010/8245/7399 8072/8246/7400 8009/8243/7397 +f 8011/8247/7401 8073/8248/7402 8010/8245/7399 +f 8012/8249/7403 8074/8250/7404 8011/8247/7401 +f 8013/8251/7405 8075/8252/7406 8012/8249/7403 +f 8014/8253/7407 8076/8254/7408 8013/8251/7405 +f 8015/8255/7409 8077/8256/7410 8014/8253/7407 +f 8017/8136/7290 8079/8257/7411 8016/8133/7287 +f 8018/8138/7292 8080/8258/7412 8017/8136/7290 +f 8019/8140/7294 8081/8259/7413 8018/8138/7292 +f 8020/8142/7296 8082/8260/7414 8019/8140/7294 +f 8021/8144/7298 8083/8261/7415 8020/8142/7296 +f 8022/8146/7300 8084/8262/7416 8021/8144/7298 +f 8023/8148/7302 8085/8263/7417 8022/8146/7300 +f 8024/8150/7304 8086/8264/7418 8023/8148/7302 +f 8025/8152/7306 8087/8265/7419 8024/8150/7304 +f 8026/8154/7308 8088/8266/7420 8025/8152/7306 +f 8027/8156/7310 8089/8267/7421 8026/8154/7308 +f 8028/8158/7312 8090/8268/7422 8027/8156/7310 +f 8029/8160/7314 8091/8269/7423 8028/8158/7312 +f 8030/8162/7316 8092/8270/7424 8029/8160/7314 +f 8031/8164/7318 8093/8271/7425 8030/8162/7316 +f 8032/8166/7320 8094/8272/7426 8031/8164/7318 +f 8033/8168/7322 8095/8273/7427 8032/8166/7320 +f 8034/8170/7324 8096/8274/7428 8033/8168/7322 +f 8035/8172/7326 8097/8275/7429 8034/8170/7324 +f 8036/8174/7328 8098/8276/7430 8035/8172/7326 +f 8037/8176/7330 8099/8277/7431 8036/8174/7328 +f 8038/8178/7332 8100/8278/7432 8037/8176/7330 +f 8039/8180/7334 8101/8279/7433 8038/8178/7332 +f 8040/8182/7336 8102/8280/7434 8039/8180/7334 +f 8041/8184/7338 8103/8281/7435 8040/8182/7336 +f 8042/8186/7340 8104/8282/7436 8041/8184/7338 +f 8043/8188/7342 8105/8283/7437 8042/8186/7340 +f 8044/8190/7344 8106/8284/7438 8043/8188/7342 +f 8045/8192/7346 8107/8285/7439 8044/8190/7344 +f 8046/8194/7348 8108/8286/7440 8045/8192/7346 +f 8047/8196/7350 8109/8287/7441 8046/8194/7348 +f 8048/8198/7352 8110/8288/7442 8047/8196/7350 +f 8049/8200/7354 8111/8289/7443 8048/8198/7352 +f 8050/8202/7356 8112/8290/7444 8049/8200/7354 +f 8051/8204/7358 8113/8291/7445 8050/8202/7356 +f 8052/8206/7360 8114/8292/7446 8051/8204/7358 +f 8053/8208/7362 8115/8293/7447 8052/8206/7360 +f 8054/8210/7364 8116/8294/7448 8053/8208/7362 +f 8055/8212/7366 8117/8295/7449 8054/8210/7364 +f 8056/8214/7368 8118/8296/7450 8055/8212/7366 +f 8057/8216/7370 8119/8297/7451 8056/8214/7368 +f 8058/8218/7372 8120/8298/7452 8057/8216/7370 +f 8059/8220/7374 8121/8299/7453 8058/8218/7372 +f 8060/8222/7376 8122/8300/7454 8059/8220/7374 +f 8061/8224/7378 8123/8301/7455 8060/8222/7376 +f 8062/8226/7380 8124/8302/7456 8061/8224/7378 +f 8063/8228/7382 8125/8303/7457 8062/8226/7380 +f 8064/8230/7384 8126/8304/7458 8063/8228/7382 +f 8065/8232/7386 8127/8305/7459 8064/8230/7384 +f 8066/8234/7388 8128/8306/7460 8065/8232/7386 +f 8067/8236/7390 8129/8307/7461 8066/8234/7388 +f 8068/8238/7392 8130/8308/7462 8067/8236/7390 +f 8069/8240/7394 8131/8309/7463 8068/8238/7392 +f 8070/8242/7396 8132/8310/7464 8069/8240/7394 +f 8071/8244/7398 8133/8311/7465 8070/8242/7396 +f 8072/8246/7400 8134/8312/7466 8071/8244/7398 +f 8073/8248/7402 8135/8313/7467 8072/8246/7400 +f 8074/8250/7404 8136/8314/7468 8073/8248/7402 +f 8075/8252/7406 8137/8315/7469 8074/8250/7404 +f 8076/8254/7408 8138/8316/7470 8075/8252/7406 +f 8077/8256/7410 8139/8317/7471 8076/8254/7408 +f 8078/8318/7472 8140/8319/7473 8077/8256/7410 +f 8080/8258/7412 8142/8320/7474 8079/8257/7411 +f 8081/8259/7413 8143/8321/7475 8080/8258/7412 +f 8082/8260/7414 8144/8322/7476 8081/8259/7413 +f 8083/8261/7415 8145/8323/7477 8082/8260/7414 +f 8084/8262/7416 8146/8324/7478 8083/8261/7415 +f 8085/8263/7417 8147/8325/7479 8084/8262/7416 +f 8086/8264/7418 8148/8326/7480 8085/8263/7417 +f 8087/8265/7419 8149/8327/7481 8086/8264/7418 +f 8088/8266/7420 8150/8328/7482 8087/8265/7419 +f 8089/8267/7421 8151/8329/7483 8088/8266/7420 +f 8090/8268/7422 8152/8330/7484 8089/8267/7421 +f 8091/8269/7423 8153/8331/7485 8090/8268/7422 +f 8092/8270/7424 8154/8332/7486 8091/8269/7423 +f 8093/8271/7425 8155/8333/7487 8092/8270/7424 +f 8094/8272/7426 8156/8334/7488 8093/8271/7425 +f 8095/8273/7427 8157/8335/7489 8094/8272/7426 +f 8096/8274/7428 8158/8336/7490 8095/8273/7427 +f 8097/8275/7429 8159/8337/7491 8096/8274/7428 +f 8098/8276/7430 8160/8338/7492 8097/8275/7429 +f 8099/8277/7431 8161/8339/7493 8098/8276/7430 +f 8100/8278/7432 8162/8340/7494 8099/8277/7431 +f 8101/8279/7433 8163/8341/7495 8100/8278/7432 +f 8102/8280/7434 8164/8342/7496 8101/8279/7433 +f 8103/8281/7435 8165/8343/7497 8102/8280/7434 +f 8104/8282/7436 8166/8344/7498 8103/8281/7435 +f 8105/8283/7437 8167/8345/7499 8104/8282/7436 +f 8106/8284/7438 8168/8346/7500 8105/8283/7437 +f 8107/8285/7439 8169/8347/7501 8106/8284/7438 +f 8108/8286/7440 8170/8348/7502 8107/8285/7439 +f 8109/8287/7441 8171/8349/7503 8108/8286/7440 +f 8110/8288/7442 8172/8350/7504 8109/8287/7441 +f 8111/8289/7443 8173/8351/7505 8110/8288/7442 +f 8112/8290/7444 8174/8352/7506 8111/8289/7443 +f 8113/8291/7445 8175/8353/7507 8112/8290/7444 +f 8114/8292/7446 8176/8354/7508 8113/8291/7445 +f 8115/8293/7447 8177/8355/7509 8114/8292/7446 +f 8116/8294/7448 8178/8356/7510 8115/8293/7447 +f 8117/8295/7449 8179/8357/7511 8116/8294/7448 +f 8118/8296/7450 8180/8358/7512 8117/8295/7449 +f 8119/8297/7451 8181/8359/7513 8118/8296/7450 +f 8120/8298/7452 8182/8360/7514 8119/8297/7451 +f 8121/8299/7453 8183/8361/7515 8120/8298/7452 +f 8122/8300/7454 8184/8362/7516 8121/8299/7453 +f 8123/8301/7455 8185/8363/7517 8122/8300/7454 +f 8124/8302/7456 8186/8364/7518 8123/8301/7455 +f 8125/8303/7457 8187/8365/7519 8124/8302/7456 +f 8126/8304/7458 8188/8366/7520 8125/8303/7457 +f 8127/8305/7459 8189/8367/7521 8126/8304/7458 +f 8128/8306/7460 8190/8368/7522 8127/8305/7459 +f 8129/8307/7461 8191/8369/7523 8128/8306/7460 +f 8130/8308/7462 8192/8370/7524 8129/8307/7461 +f 8131/8309/7463 8193/8371/7525 8130/8308/7462 +f 8132/8310/7464 8194/8372/7526 8131/8309/7463 +f 8133/8311/7465 8195/8373/7527 8132/8310/7464 +f 8134/8312/7466 8196/8374/7528 8133/8311/7465 +f 8135/8313/7467 8197/8375/7529 8134/8312/7466 +f 8136/8314/7468 8198/8376/7530 8135/8313/7467 +f 8137/8315/7469 8199/8377/7531 8136/8314/7468 +f 8138/8316/7470 8200/8378/7532 8137/8315/7469 +f 8139/8317/7471 8201/8379/7533 8138/8316/7470 +f 8140/8319/7473 8202/8380/7534 8139/8317/7471 +f 8141/8381/7535 8203/8382/7536 8140/8319/7473 +f 8143/8321/7475 8205/8383/7537 8142/8320/7474 +f 8144/8322/7476 8206/8384/7538 8143/8321/7475 +f 8145/8323/7477 8207/8385/7539 8144/8322/7476 +f 8146/8324/7478 8208/8386/7540 8145/8323/7477 +f 8147/8325/7479 8209/8387/7541 8146/8324/7478 +f 8148/8326/7480 8210/8388/7542 8147/8325/7479 +f 8149/8327/7481 8211/8389/7543 8148/8326/7480 +f 8150/8328/7482 8212/8390/7544 8149/8327/7481 +f 8151/8329/7483 8213/8391/7545 8150/8328/7482 +f 8152/8330/7484 8214/8392/7546 8151/8329/7483 +f 8153/8331/7485 8215/8393/7547 8152/8330/7484 +f 8154/8332/7486 8216/8394/7548 8153/8331/7485 +f 8155/8333/7487 8217/8395/7549 8154/8332/7486 +f 8156/8334/7488 8218/8396/7550 8155/8333/7487 +f 8157/8335/7489 8219/8397/7551 8156/8334/7488 +f 8158/8336/7490 8220/8398/7552 8157/8335/7489 +f 8159/8337/7491 8221/8399/7553 8158/8336/7490 +f 8160/8338/7492 8222/8400/7554 8159/8337/7491 +f 8161/8339/7493 8223/8401/7555 8160/8338/7492 +f 8162/8340/7494 8224/8402/7556 8161/8339/7493 +f 8163/8341/7495 8225/8403/7557 8162/8340/7494 +f 8164/8342/7496 8226/8404/7558 8163/8341/7495 +f 8165/8343/7497 8227/8405/7559 8164/8342/7496 +f 8166/8344/7498 8228/8406/7560 8165/8343/7497 +f 8167/8345/7499 8229/8407/7561 8166/8344/7498 +f 8168/8346/7500 8230/8408/7562 8167/8345/7499 +f 8169/8347/7501 8231/8409/7563 8168/8346/7500 +f 8170/8348/7502 8232/8410/7564 8169/8347/7501 +f 8171/8349/7503 8233/8411/7565 8170/8348/7502 +f 8172/8350/7504 8234/8412/7566 8171/8349/7503 +f 8173/8351/7505 8235/8413/7567 8172/8350/7504 +f 8174/8352/7506 8236/8414/7568 8173/8351/7505 +f 8175/8353/7507 8237/8415/7569 8174/8352/7506 +f 8176/8354/7508 8238/8416/7570 8175/8353/7507 +f 8177/8355/7509 8239/8417/7571 8176/8354/7508 +f 8178/8356/7510 8240/8418/7572 8177/8355/7509 +f 8179/8357/7511 8241/8419/7573 8178/8356/7510 +f 8180/8358/7512 8242/8420/7574 8179/8357/7511 +f 8181/8359/7513 8243/8421/7575 8180/8358/7512 +f 8182/8360/7514 8244/8422/7576 8181/8359/7513 +f 8183/8361/7515 8245/8423/7577 8182/8360/7514 +f 8184/8362/7516 8246/8424/7578 8183/8361/7515 +f 8185/8363/7517 8247/8425/7579 8184/8362/7516 +f 8186/8364/7518 8248/8426/7580 8185/8363/7517 +f 8187/8365/7519 8249/8427/7581 8186/8364/7518 +f 8188/8366/7520 8250/8428/7582 8187/8365/7519 +f 8189/8367/7521 8251/8429/7583 8188/8366/7520 +f 8190/8368/7522 8252/8430/7584 8189/8367/7521 +f 8191/8369/7523 8253/8431/7585 8190/8368/7522 +f 8192/8370/7524 8254/8432/7586 8191/8369/7523 +f 8193/8371/7525 8255/8433/7587 8192/8370/7524 +f 8194/8372/7526 8256/8434/7588 8193/8371/7525 +f 8195/8373/7527 8257/8435/7589 8194/8372/7526 +f 8196/8374/7528 8258/8436/7590 8195/8373/7527 +f 8197/8375/7529 8259/8437/7591 8196/8374/7528 +f 8198/8376/7530 8260/8438/7592 8197/8375/7529 +f 8199/8377/7531 8261/8439/7593 8198/8376/7530 +f 8200/8378/7532 8262/8440/7594 8199/8377/7531 +f 8201/8379/7533 8263/8441/7595 8200/8378/7532 +f 8202/8380/7534 8264/8442/7596 8201/8379/7533 +f 8203/8382/7536 8265/8443/7597 8202/8380/7534 +f 8204/8444/7598 8266/8445/7599 8203/8382/7536 +f 8206/8384/7538 8268/8446/7600 8205/8383/7537 +f 8207/8385/7539 8269/8447/7601 8206/8384/7538 +f 8208/8386/7540 8270/8448/7602 8207/8385/7539 +f 8209/8387/7541 8271/8449/7603 8208/8386/7540 +f 8210/8388/7542 8272/8450/7604 8209/8387/7541 +f 8211/8389/7543 8273/8451/7605 8210/8388/7542 +f 8212/8390/7544 8274/8452/7606 8211/8389/7543 +f 8213/8391/7545 8275/8453/7607 8212/8390/7544 +f 8214/8392/7546 8276/8454/7608 8213/8391/7545 +f 8215/8393/7547 8277/8455/7609 8214/8392/7546 +f 8216/8394/7548 8278/8456/7610 8215/8393/7547 +f 8217/8395/7549 8279/8457/7611 8216/8394/7548 +f 8218/8396/7550 8280/8458/7612 8217/8395/7549 +f 8219/8397/7551 8281/8459/7613 8218/8396/7550 +f 8220/8398/7552 8282/8460/7614 8219/8397/7551 +f 8221/8399/7553 8283/8461/7615 8220/8398/7552 +f 8222/8400/7554 8284/8462/7616 8221/8399/7553 +f 8223/8401/7555 8285/8463/7617 8222/8400/7554 +f 8224/8402/7556 8286/8464/7618 8223/8401/7555 +f 8225/8403/7557 8287/8465/7619 8224/8402/7556 +f 8226/8404/7558 8288/8466/7620 8225/8403/7557 +f 8227/8405/7559 8289/8467/7621 8226/8404/7558 +f 8228/8406/7560 8290/8468/7622 8227/8405/7559 +f 8229/8407/7561 8291/8469/7623 8228/8406/7560 +f 8230/8408/7562 8292/8470/7624 8229/8407/7561 +f 8231/8409/7563 8293/8471/7625 8230/8408/7562 +f 8232/8410/7564 8294/8472/7626 8231/8409/7563 +f 8233/8411/7565 8295/8473/7627 8232/8410/7564 +f 8234/8412/7566 8296/8474/7628 8233/8411/7565 +f 8235/8413/7567 8297/8475/7629 8234/8412/7566 +f 8236/8414/7568 8298/8476/7630 8235/8413/7567 +f 8237/8415/7569 8299/8477/7631 8236/8414/7568 +f 8238/8416/7570 8300/8478/7632 8237/8415/7569 +f 8239/8417/7571 8301/8479/7633 8238/8416/7570 +f 8240/8418/7572 8302/8480/7634 8239/8417/7571 +f 8241/8419/7573 8303/8481/7635 8240/8418/7572 +f 8242/8420/7574 8304/8482/7636 8241/8419/7573 +f 8243/8421/7575 8305/8483/7637 8242/8420/7574 +f 8244/8422/7576 8306/8484/7638 8243/8421/7575 +f 8245/8423/7577 8307/8485/7639 8244/8422/7576 +f 8246/8424/7578 8308/8486/7640 8245/8423/7577 +f 8247/8425/7579 8309/8487/7641 8246/8424/7578 +f 8248/8426/7580 8310/8488/7642 8247/8425/7579 +f 8249/8427/7581 8311/8489/7643 8248/8426/7580 +f 8250/8428/7582 8312/8490/7644 8249/8427/7581 +f 8251/8429/7583 8313/8491/7645 8250/8428/7582 +f 8252/8430/7584 8314/8492/7646 8251/8429/7583 +f 8253/8431/7585 8315/8493/7647 8252/8430/7584 +f 8254/8432/7586 8316/8494/7648 8253/8431/7585 +f 8255/8433/7587 8317/8495/7649 8254/8432/7586 +f 8256/8434/7588 8318/8496/7650 8255/8433/7587 +f 8257/8435/7589 8319/8497/7651 8256/8434/7588 +f 8258/8436/7590 8320/8498/7652 8257/8435/7589 +f 8259/8437/7591 8321/8499/7653 8258/8436/7590 +f 8260/8438/7592 8322/8500/7654 8259/8437/7591 +f 8261/8439/7593 8323/8501/7655 8260/8438/7592 +f 8262/8440/7594 8324/8502/7656 8261/8439/7593 +f 8263/8441/7595 8325/8503/7657 8262/8440/7594 +f 8264/8442/7596 8326/8504/7658 8263/8441/7595 +f 8265/8443/7597 8327/8505/7659 8264/8442/7596 +f 8266/8445/7599 8328/8506/7660 8265/8443/7597 +f 8267/8507/7661 8329/8508/7662 8266/8445/7599 +f 8269/8447/7601 8331/8509/7663 8268/8446/7600 +f 8270/8448/7602 8332/8510/7664 8269/8447/7601 +f 8271/8449/7603 8333/8511/7665 8270/8448/7602 +f 8272/8450/7604 8334/8512/7666 8271/8449/7603 +f 8273/8451/7605 8335/8513/7667 8272/8450/7604 +f 8274/8452/7606 8336/8514/7668 8273/8451/7605 +f 8275/8453/7607 8337/8515/7669 8274/8452/7606 +f 8276/8454/7608 8338/8516/7670 8275/8453/7607 +f 8277/8455/7609 8339/8517/7671 8276/8454/7608 +f 8278/8456/7610 8340/8518/7672 8277/8455/7609 +f 8279/8457/7611 8341/8519/7673 8278/8456/7610 +f 8280/8458/7612 8342/8520/7674 8279/8457/7611 +f 8281/8459/7613 8343/8521/7675 8280/8458/7612 +f 8282/8460/7614 8344/8522/7676 8281/8459/7613 +f 8283/8461/7615 8345/8523/7677 8282/8460/7614 +f 8284/8462/7616 8346/8524/7678 8283/8461/7615 +f 8285/8463/7617 8347/8525/7679 8284/8462/7616 +f 8286/8464/7618 8348/8526/7680 8285/8463/7617 +f 8287/8465/7619 8349/8527/7681 8286/8464/7618 +f 8288/8466/7620 8350/8528/7682 8287/8465/7619 +f 8289/8467/7621 8351/8529/7683 8288/8466/7620 +f 8290/8468/7622 8352/8530/7684 8289/8467/7621 +f 8291/8469/7623 8353/8531/7685 8290/8468/7622 +f 8292/8470/7624 8354/8532/7686 8291/8469/7623 +f 8293/8471/7625 8355/8533/7687 8292/8470/7624 +f 8294/8472/7626 8356/8534/7688 8293/8471/7625 +f 8295/8473/7627 8357/8535/7689 8294/8472/7626 +f 8296/8474/7628 8358/8536/7690 8295/8473/7627 +f 8297/8475/7629 8359/8537/7691 8296/8474/7628 +f 8298/8476/7630 8360/8538/7692 8297/8475/7629 +f 8299/8477/7631 8361/8539/7693 8298/8476/7630 +f 8300/8478/7632 8362/8540/7694 8299/8477/7631 +f 8301/8479/7633 8363/8541/7695 8300/8478/7632 +f 8302/8480/7634 8364/8542/7696 8301/8479/7633 +f 8303/8481/7635 8365/8543/7697 8302/8480/7634 +f 8304/8482/7636 8366/8544/7698 8303/8481/7635 +f 8305/8483/7637 8367/8545/7699 8304/8482/7636 +f 8306/8484/7638 8368/8546/7700 8305/8483/7637 +f 8307/8485/7639 8369/8547/7701 8306/8484/7638 +f 8308/8486/7640 8370/8548/7702 8307/8485/7639 +f 8309/8487/7641 8371/8549/7703 8308/8486/7640 +f 8310/8488/7642 8372/8550/7704 8309/8487/7641 +f 8311/8489/7643 8373/8551/7705 8310/8488/7642 +f 8312/8490/7644 8374/8552/7706 8311/8489/7643 +f 8313/8491/7645 8375/8553/7707 8312/8490/7644 +f 8314/8492/7646 8376/8554/7708 8313/8491/7645 +f 8315/8493/7647 8377/8555/7709 8314/8492/7646 +f 8316/8494/7648 8378/8556/7710 8315/8493/7647 +f 8317/8495/7649 8379/8557/7711 8316/8494/7648 +f 8318/8496/7650 8380/8558/7712 8317/8495/7649 +f 8319/8497/7651 8381/8559/7713 8318/8496/7650 +f 8320/8498/7652 8382/8560/7714 8319/8497/7651 +f 8321/8499/7653 8383/8561/7715 8320/8498/7652 +f 8322/8500/7654 8384/8562/7716 8321/8499/7653 +f 8323/8501/7655 8385/8563/7717 8322/8500/7654 +f 8324/8502/7656 8386/8564/7718 8323/8501/7655 +f 8325/8503/7657 8387/8565/7719 8324/8502/7656 +f 8326/8504/7658 8388/8566/7720 8325/8503/7657 +f 8327/8505/7659 8389/8567/7721 8326/8504/7658 +f 8328/8506/7660 8390/8568/7722 8327/8505/7659 +f 8329/8508/7662 8391/8569/7723 8328/8506/7660 +f 8330/8570/7724 8392/8571/7725 8329/8508/7662 +f 8332/8510/7664 8394/8572/7726 8331/8509/7663 +f 8333/8511/7665 8395/8573/7727 8332/8510/7664 +f 8334/8512/7666 8396/8574/7728 8333/8511/7665 +f 8335/8513/7667 8397/8575/7729 8334/8512/7666 +f 8336/8514/7668 8398/8576/7730 8335/8513/7667 +f 8337/8515/7669 8399/8577/7731 8336/8514/7668 +f 8338/8516/7670 8400/8578/7732 8337/8515/7669 +f 8339/8517/7671 8401/8579/7733 8338/8516/7670 +f 8340/8518/7672 8402/8580/7734 8339/8517/7671 +f 8341/8519/7673 8403/8581/7735 8340/8518/7672 +f 8342/8520/7674 8404/8582/7736 8341/8519/7673 +f 8343/8521/7675 8405/8583/7737 8342/8520/7674 +f 8344/8522/7676 8406/8584/7738 8343/8521/7675 +f 8345/8523/7677 8407/8585/7739 8344/8522/7676 +f 8346/8524/7678 8408/8586/7740 8345/8523/7677 +f 8347/8525/7679 8409/8587/7741 8346/8524/7678 +f 8348/8526/7680 8410/8588/7742 8347/8525/7679 +f 8349/8527/7681 8411/8589/7743 8348/8526/7680 +f 8350/8528/7682 8412/8590/7744 8349/8527/7681 +f 8351/8529/7683 8413/8591/7745 8350/8528/7682 +f 8352/8530/7684 8414/8592/7746 8351/8529/7683 +f 8353/8531/7685 8415/8593/7747 8352/8530/7684 +f 8354/8532/7686 8416/8594/7748 8353/8531/7685 +f 8355/8533/7687 8417/8595/7749 8354/8532/7686 +f 8356/8534/7688 8418/8596/7750 8355/8533/7687 +f 8357/8535/7689 8419/8597/7751 8356/8534/7688 +f 8358/8536/7690 8420/8598/7752 8357/8535/7689 +f 8359/8537/7691 8421/8599/7753 8358/8536/7690 +f 8360/8538/7692 8422/8600/7754 8359/8537/7691 +f 8361/8539/7693 8423/8601/7755 8360/8538/7692 +f 8362/8540/7694 8424/8602/7756 8361/8539/7693 +f 8363/8541/7695 8425/8603/7757 8362/8540/7694 +f 8364/8542/7696 8426/8604/7758 8363/8541/7695 +f 8365/8543/7697 8427/8605/7759 8364/8542/7696 +f 8366/8544/7698 8428/8606/7760 8365/8543/7697 +f 8367/8545/7699 8429/8607/7761 8366/8544/7698 +f 8368/8546/7700 8430/8608/7762 8367/8545/7699 +f 8369/8547/7701 8431/8609/7763 8368/8546/7700 +f 8370/8548/7702 8432/8610/7764 8369/8547/7701 +f 8371/8549/7703 8433/8611/7765 8370/8548/7702 +f 8372/8550/7704 8434/8612/7766 8371/8549/7703 +f 8373/8551/7705 8435/8613/7767 8372/8550/7704 +f 8374/8552/7706 8436/8614/7768 8373/8551/7705 +f 8375/8553/7707 8437/8615/7769 8374/8552/7706 +f 8376/8554/7708 8438/8616/7770 8375/8553/7707 +f 8377/8555/7709 8439/8617/7771 8376/8554/7708 +f 8378/8556/7710 8440/8618/7772 8377/8555/7709 +f 8379/8557/7711 8441/8619/7773 8378/8556/7710 +f 8380/8558/7712 8442/8620/7774 8379/8557/7711 +f 8381/8559/7713 8443/8621/7775 8380/8558/7712 +f 8382/8560/7714 8444/8622/7776 8381/8559/7713 +f 8383/8561/7715 8445/8623/7777 8382/8560/7714 +f 8384/8562/7716 8446/8624/7778 8383/8561/7715 +f 8385/8563/7717 8447/8625/7779 8384/8562/7716 +f 8386/8564/7718 8448/8626/7780 8385/8563/7717 +f 8387/8565/7719 8449/8627/7781 8386/8564/7718 +f 8388/8566/7720 8450/8628/7782 8387/8565/7719 +f 8389/8567/7721 8451/8629/7783 8388/8566/7720 +f 8390/8568/7722 8452/8630/7784 8389/8567/7721 +f 8391/8569/7723 8453/8631/7785 8390/8568/7722 +f 8392/8571/7725 8454/8632/7786 8391/8569/7723 +f 8393/8633/7787 8455/8634/7788 8392/8571/7725 +f 8395/8573/7727 8457/8635/7789 8394/8572/7726 +f 8396/8574/7728 8458/8636/7790 8395/8573/7727 +f 8397/8575/7729 8459/8637/7791 8396/8574/7728 +f 8398/8576/7730 8460/8638/7792 8397/8575/7729 +f 8399/8577/7731 8461/8639/7793 8398/8576/7730 +f 8400/8578/7732 8462/8640/7794 8399/8577/7731 +f 8401/8579/7733 8463/8641/7795 8400/8578/7732 +f 8402/8580/7734 8464/8642/7796 8401/8579/7733 +f 8403/8581/7735 8465/8643/7797 8402/8580/7734 +f 8404/8582/7736 8466/8644/7798 8403/8581/7735 +f 8405/8583/7737 8467/8645/7799 8404/8582/7736 +f 8406/8584/7738 8468/8646/7800 8405/8583/7737 +f 8407/8585/7739 8469/8647/7801 8406/8584/7738 +f 8408/8586/7740 8470/8648/7802 8407/8585/7739 +f 8409/8587/7741 8471/8649/7803 8408/8586/7740 +f 8410/8588/7742 8472/8650/7804 8409/8587/7741 +f 8411/8589/7743 8473/8651/7805 8410/8588/7742 +f 8412/8590/7744 8474/8652/7806 8411/8589/7743 +f 8413/8591/7745 8475/8653/7807 8412/8590/7744 +f 8414/8592/7746 8476/8654/7808 8413/8591/7745 +f 8415/8593/7747 8477/8655/7809 8414/8592/7746 +f 8416/8594/7748 8478/8656/7810 8415/8593/7747 +f 8417/8595/7749 8479/8657/7811 8416/8594/7748 +f 8418/8596/7750 8480/8658/7812 8417/8595/7749 +f 8419/8597/7751 8481/8659/7813 8418/8596/7750 +f 8420/8598/7752 8482/8660/7814 8419/8597/7751 +f 8421/8599/7753 8483/8661/7815 8420/8598/7752 +f 8422/8600/7754 8484/8662/7816 8421/8599/7753 +f 8423/8601/7755 8485/8663/7817 8422/8600/7754 +f 8424/8602/7756 8486/8664/7818 8423/8601/7755 +f 8425/8603/7757 8487/8665/7819 8424/8602/7756 +f 8426/8604/7758 8488/8666/7820 8425/8603/7757 +f 8427/8605/7759 8489/8667/7821 8426/8604/7758 +f 8428/8606/7760 8490/8668/7822 8427/8605/7759 +f 8429/8607/7761 8491/8669/7823 8428/8606/7760 +f 8430/8608/7762 8492/8670/7824 8429/8607/7761 +f 8431/8609/7763 8493/8671/7825 8430/8608/7762 +f 8432/8610/7764 8494/8672/7826 8431/8609/7763 +f 8433/8611/7765 8495/8673/7827 8432/8610/7764 +f 8434/8612/7766 8496/8674/7828 8433/8611/7765 +f 8435/8613/7767 8497/8675/7829 8434/8612/7766 +f 8436/8614/7768 8498/8676/7830 8435/8613/7767 +f 8437/8615/7769 8499/8677/7831 8436/8614/7768 +f 8438/8616/7770 8500/8678/7832 8437/8615/7769 +f 8439/8617/7771 8501/8679/7833 8438/8616/7770 +f 8440/8618/7772 8502/8680/7834 8439/8617/7771 +f 8441/8619/7773 8503/8681/7835 8440/8618/7772 +f 8442/8620/7774 8504/8682/7836 8441/8619/7773 +f 8443/8621/7775 8505/8683/7837 8442/8620/7774 +f 8444/8622/7776 8506/8684/7838 8443/8621/7775 +f 8445/8623/7777 8507/8685/7839 8444/8622/7776 +f 8446/8624/7778 8508/8686/7840 8445/8623/7777 +f 8447/8625/7779 8509/8687/7841 8446/8624/7778 +f 8448/8626/7780 8510/8688/7842 8447/8625/7779 +f 8449/8627/7781 8511/8689/7843 8448/8626/7780 +f 8450/8628/7782 8512/8690/7844 8449/8627/7781 +f 8451/8629/7783 8513/8691/7845 8450/8628/7782 +f 8452/8630/7784 8514/8692/7846 8451/8629/7783 +f 8453/8631/7785 8515/8693/7847 8452/8630/7784 +f 8454/8632/7786 8516/8694/7848 8453/8631/7785 +f 8455/8634/7788 8517/8695/7849 8454/8632/7786 +f 8456/8696/7850 8518/8697/7851 8455/8634/7788 +f 8458/8636/7790 8520/8698/7852 8457/8635/7789 +f 8459/8637/7791 8521/8699/7853 8458/8636/7790 +f 8460/8638/7792 8522/8700/7854 8459/8637/7791 +f 8461/8639/7793 8523/8701/7855 8460/8638/7792 +f 8462/8640/7794 8524/8702/7856 8461/8639/7793 +f 8463/8641/7795 8525/8703/7857 8462/8640/7794 +f 8464/8642/7796 8526/8704/7858 8463/8641/7795 +f 8465/8643/7797 8527/8705/7859 8464/8642/7796 +f 8466/8644/7798 8528/8706/7860 8465/8643/7797 +f 8467/8645/7799 8529/8707/7861 8466/8644/7798 +f 8468/8646/7800 8530/8708/7862 8467/8645/7799 +f 8469/8647/7801 8531/8709/7863 8468/8646/7800 +f 8470/8648/7802 8532/8710/7864 8469/8647/7801 +f 8471/8649/7803 8533/8711/7865 8470/8648/7802 +f 8472/8650/7804 8534/8712/7866 8471/8649/7803 +f 8473/8651/7805 8535/8713/7867 8472/8650/7804 +f 8474/8652/7806 8536/8714/7868 8473/8651/7805 +f 8475/8653/7807 8537/8715/7869 8474/8652/7806 +f 8476/8654/7808 8538/8716/7870 8475/8653/7807 +f 8477/8655/7809 8539/8717/7871 8476/8654/7808 +f 8478/8656/7810 8540/8718/7872 8477/8655/7809 +f 8479/8657/7811 8541/8719/7873 8478/8656/7810 +f 8480/8658/7812 8542/8720/7874 8479/8657/7811 +f 8481/8659/7813 8543/8721/7875 8480/8658/7812 +f 8482/8660/7814 8544/8722/7876 8481/8659/7813 +f 8483/8661/7815 8545/8723/7877 8482/8660/7814 +f 8484/8662/7816 8546/8724/7878 8483/8661/7815 +f 8485/8663/7817 8547/8725/7879 8484/8662/7816 +f 8486/8664/7818 8548/8726/7880 8485/8663/7817 +f 8487/8665/7819 8549/8727/7881 8486/8664/7818 +f 8488/8666/7820 8550/8728/7882 8487/8665/7819 +f 8489/8667/7821 8551/8729/7883 8488/8666/7820 +f 8490/8668/7822 8552/8730/7884 8489/8667/7821 +f 8491/8669/7823 8553/8731/7885 8490/8668/7822 +f 8492/8670/7824 8554/8732/7886 8491/8669/7823 +f 8493/8671/7825 8555/8733/7887 8492/8670/7824 +f 8494/8672/7826 8556/8734/7888 8493/8671/7825 +f 8495/8673/7827 8557/8735/7889 8494/8672/7826 +f 8496/8674/7828 8558/8736/7890 8495/8673/7827 +f 8497/8675/7829 8559/8737/7891 8496/8674/7828 +f 8498/8676/7830 8560/8738/7892 8497/8675/7829 +f 8499/8677/7831 8561/8739/7893 8498/8676/7830 +f 8500/8678/7832 8562/8740/7894 8499/8677/7831 +f 8501/8679/7833 8563/8741/7895 8500/8678/7832 +f 8502/8680/7834 8564/8742/7896 8501/8679/7833 +f 8503/8681/7835 8565/8743/7897 8502/8680/7834 +f 8504/8682/7836 8566/8744/7898 8503/8681/7835 +f 8505/8683/7837 8567/8745/7899 8504/8682/7836 +f 8506/8684/7838 8568/8746/7900 8505/8683/7837 +f 8507/8685/7839 8569/8747/7901 8506/8684/7838 +f 8508/8686/7840 8570/8748/7902 8507/8685/7839 +f 8509/8687/7841 8571/8749/7903 8508/8686/7840 +f 8510/8688/7842 8572/8750/7904 8509/8687/7841 +f 8511/8689/7843 8573/8751/7905 8510/8688/7842 +f 8512/8690/7844 8574/8752/7906 8511/8689/7843 +f 8513/8691/7845 8575/8753/7907 8512/8690/7844 +f 8514/8692/7846 8576/8754/7908 8513/8691/7845 +f 8515/8693/7847 8577/8755/7909 8514/8692/7846 +f 8516/8694/7848 8578/8756/7910 8515/8693/7847 +f 8517/8695/7849 8579/8757/7911 8516/8694/7848 +f 8518/8697/7851 8580/8758/7912 8517/8695/7849 +f 8519/8759/7913 8581/8760/7914 8518/8697/7851 +f 8521/8699/7853 8583/8761/7915 8520/8698/7852 +f 8522/8700/7854 8584/8762/7916 8521/8699/7853 +f 8523/8701/7855 8585/8763/7917 8522/8700/7854 +f 8524/8702/7856 8586/8764/7918 8523/8701/7855 +f 8525/8703/7857 8587/8765/7919 8524/8702/7856 +f 8526/8704/7858 8588/8766/7920 8525/8703/7857 +f 8527/8705/7859 8589/8767/7921 8526/8704/7858 +f 8528/8706/7860 8590/8768/7922 8527/8705/7859 +f 8529/8707/7861 8591/8769/7923 8528/8706/7860 +f 8530/8708/7862 8592/8770/7924 8529/8707/7861 +f 8531/8709/7863 8593/8771/7925 8530/8708/7862 +f 8532/8710/7864 8594/8772/7926 8531/8709/7863 +f 8533/8711/7865 8595/8773/7927 8532/8710/7864 +f 8534/8712/7866 8596/8774/7928 8533/8711/7865 +f 8535/8713/7867 8597/8775/7929 8534/8712/7866 +f 8536/8714/7868 8598/8776/7930 8535/8713/7867 +f 8537/8715/7869 8599/8777/7931 8536/8714/7868 +f 8538/8716/7870 8600/8778/7932 8537/8715/7869 +f 8539/8717/7871 8601/8779/7933 8538/8716/7870 +f 8540/8718/7872 8602/8780/7934 8539/8717/7871 +f 8541/8719/7873 8603/8781/7935 8540/8718/7872 +f 8542/8720/7874 8604/8782/7936 8541/8719/7873 +f 8543/8721/7875 8605/8783/7937 8542/8720/7874 +f 8544/8722/7876 8606/8784/7938 8543/8721/7875 +f 8545/8723/7877 8607/8785/7939 8544/8722/7876 +f 8546/8724/7878 8608/8786/7940 8545/8723/7877 +f 8547/8725/7879 8609/8787/7941 8546/8724/7878 +f 8548/8726/7880 8610/8788/7942 8547/8725/7879 +f 8549/8727/7881 8611/8789/7943 8548/8726/7880 +f 8550/8728/7882 8612/8790/7944 8549/8727/7881 +f 8551/8729/7883 8613/8791/7945 8550/8728/7882 +f 8552/8730/7884 8614/8792/7946 8551/8729/7883 +f 8553/8731/7885 8615/8793/7947 8552/8730/7884 +f 8554/8732/7886 8616/8794/7948 8553/8731/7885 +f 8555/8733/7887 8617/8795/7949 8554/8732/7886 +f 8556/8734/7888 8618/8796/7950 8555/8733/7887 +f 8557/8735/7889 8619/8797/7951 8556/8734/7888 +f 8558/8736/7890 8620/8798/7952 8557/8735/7889 +f 8559/8737/7891 8621/8799/7953 8558/8736/7890 +f 8560/8738/7892 8622/8800/7954 8559/8737/7891 +f 8561/8739/7893 8623/8801/7955 8560/8738/7892 +f 8562/8740/7894 8624/8802/7956 8561/8739/7893 +f 8563/8741/7895 8625/8803/7957 8562/8740/7894 +f 8564/8742/7896 8626/8804/7958 8563/8741/7895 +f 8565/8743/7897 8627/8805/7959 8564/8742/7896 +f 8566/8744/7898 8628/8806/7960 8565/8743/7897 +f 8567/8745/7899 8629/8807/7961 8566/8744/7898 +f 8568/8746/7900 8630/8808/7962 8567/8745/7899 +f 8569/8747/7901 8631/8809/7963 8568/8746/7900 +f 8570/8748/7902 8632/8810/7964 8569/8747/7901 +f 8571/8749/7903 8633/8811/7965 8570/8748/7902 +f 8572/8750/7904 8634/8812/7966 8571/8749/7903 +f 8573/8751/7905 8635/8813/7967 8572/8750/7904 +f 8574/8752/7906 8636/8814/7968 8573/8751/7905 +f 8575/8753/7907 8637/8815/7969 8574/8752/7906 +f 8576/8754/7908 8638/8816/7970 8575/8753/7907 +f 8577/8755/7909 8639/8817/7971 8576/8754/7908 +f 8578/8756/7910 8640/8818/7972 8577/8755/7909 +f 8579/8757/7911 8641/8819/7973 8578/8756/7910 +f 8580/8758/7912 8642/8820/7974 8579/8757/7911 +f 8581/8760/7914 8643/8821/7975 8580/8758/7912 +f 8582/8822/7976 8644/8823/7977 8581/8760/7914 +f 8584/8762/7916 8646/8824/7978 8583/8761/7915 +f 8585/8763/7917 8647/8825/7979 8584/8762/7916 +f 8586/8764/7918 8648/8826/7980 8585/8763/7917 +f 8587/8765/7919 8649/8827/7981 8586/8764/7918 +f 8588/8766/7920 8650/8828/7982 8587/8765/7919 +f 8589/8767/7921 8651/8829/7983 8588/8766/7920 +f 8590/8768/7922 8652/8830/7984 8589/8767/7921 +f 8591/8769/7923 8653/8831/7985 8590/8768/7922 +f 8592/8770/7924 8654/8832/7986 8591/8769/7923 +f 8593/8771/7925 8655/8833/7987 8592/8770/7924 +f 8594/8772/7926 8656/8834/7988 8593/8771/7925 +f 8595/8773/7927 8657/8835/7989 8594/8772/7926 +f 8596/8774/7928 8658/8836/7990 8595/8773/7927 +f 8597/8775/7929 8659/8837/7991 8596/8774/7928 +f 8598/8776/7930 8660/8838/7992 8597/8775/7929 +f 8599/8777/7931 8661/8839/7993 8598/8776/7930 +f 8600/8778/7932 8662/8840/7994 8599/8777/7931 +f 8601/8779/7933 8663/8841/7995 8600/8778/7932 +f 8602/8780/7934 8664/8842/7996 8601/8779/7933 +f 8603/8781/7935 8665/8843/7997 8602/8780/7934 +f 8604/8782/7936 8666/8844/7998 8603/8781/7935 +f 8605/8783/7937 8667/8845/7999 8604/8782/7936 +f 8606/8784/7938 8668/8846/8000 8605/8783/7937 +f 8607/8785/7939 8669/8847/8001 8606/8784/7938 +f 8608/8786/7940 8670/8848/8002 8607/8785/7939 +f 8609/8787/7941 8671/8849/8003 8608/8786/7940 +f 8610/8788/7942 8672/8850/8004 8609/8787/7941 +f 8611/8789/7943 8673/8851/8005 8610/8788/7942 +f 8612/8790/7944 8674/8852/8006 8611/8789/7943 +f 8613/8791/7945 8675/8853/8007 8612/8790/7944 +f 8614/8792/7946 8676/8854/8008 8613/8791/7945 +f 8615/8793/7947 8677/8855/8009 8614/8792/7946 +f 8616/8794/7948 8678/8856/8010 8615/8793/7947 +f 8617/8795/7949 8679/8857/8011 8616/8794/7948 +f 8618/8796/7950 8680/8858/8012 8617/8795/7949 +f 8619/8797/7951 8681/8859/8013 8618/8796/7950 +f 8620/8798/7952 8682/8860/8014 8619/8797/7951 +f 8621/8799/7953 8683/8861/8015 8620/8798/7952 +f 8622/8800/7954 8684/8862/8016 8621/8799/7953 +f 8623/8801/7955 8685/8863/8017 8622/8800/7954 +f 8624/8802/7956 8686/8864/8018 8623/8801/7955 +f 8625/8803/7957 8687/8865/8019 8624/8802/7956 +f 8626/8804/7958 8688/8866/8020 8625/8803/7957 +f 8627/8805/7959 8689/8867/8021 8626/8804/7958 +f 8628/8806/7960 8690/8868/8022 8627/8805/7959 +f 8629/8807/7961 8691/8869/8023 8628/8806/7960 +f 8630/8808/7962 8692/8870/8024 8629/8807/7961 +f 8631/8809/7963 8693/8871/8025 8630/8808/7962 +f 8632/8810/7964 8694/8872/8026 8631/8809/7963 +f 8633/8811/7965 8695/8873/8027 8632/8810/7964 +f 8634/8812/7966 8696/8874/8028 8633/8811/7965 +f 8635/8813/7967 8697/8875/8029 8634/8812/7966 +f 8636/8814/7968 8698/8876/8030 8635/8813/7967 +f 8637/8815/7969 8699/8877/8031 8636/8814/7968 +f 8638/8816/7970 8700/8878/8032 8637/8815/7969 +f 8639/8817/7971 8701/8879/8033 8638/8816/7970 +f 8640/8818/7972 8702/8880/8034 8639/8817/7971 +f 8641/8819/7973 8703/8881/8035 8640/8818/7972 +f 8642/8820/7974 8704/8882/8036 8641/8819/7973 +f 8643/8821/7975 8705/8883/8037 8642/8820/7974 +f 8644/8823/7977 8706/8884/8038 8643/8821/7975 +f 8645/8885/8039 8707/8886/8040 8644/8823/7977 +f 8647/8825/7979 8709/8887/8041 8646/8824/7978 +f 8648/8826/7980 8710/8888/8042 8647/8825/7979 +f 8649/8827/7981 8711/8889/8043 8648/8826/7980 +f 8650/8828/7982 8712/8890/8044 8649/8827/7981 +f 8651/8829/7983 8713/8891/8045 8650/8828/7982 +f 8652/8830/7984 8714/8892/8046 8651/8829/7983 +f 8653/8831/7985 8715/8893/8047 8652/8830/7984 +f 8654/8832/7986 8716/8894/8048 8653/8831/7985 +f 8655/8833/7987 8717/8895/8049 8654/8832/7986 +f 8656/8834/7988 8718/8896/8050 8655/8833/7987 +f 8657/8835/7989 8719/8897/8051 8656/8834/7988 +f 8658/8836/7990 8720/8898/8052 8657/8835/7989 +f 8659/8837/7991 8721/8899/8053 8658/8836/7990 +f 8660/8838/7992 8722/8900/8054 8659/8837/7991 +f 8661/8839/7993 8723/8901/8055 8660/8838/7992 +f 8662/8840/7994 8724/8902/8056 8661/8839/7993 +f 8663/8841/7995 8725/8903/8057 8662/8840/7994 +f 8664/8842/7996 8726/8904/8058 8663/8841/7995 +f 8665/8843/7997 8727/8905/8059 8664/8842/7996 +f 8666/8844/7998 8728/8906/8060 8665/8843/7997 +f 8667/8845/7999 8729/8907/8061 8666/8844/7998 +f 8668/8846/8000 8730/8908/8062 8667/8845/7999 +f 8669/8847/8001 8731/8909/8063 8668/8846/8000 +f 8670/8848/8002 8732/8910/8064 8669/8847/8001 +f 8671/8849/8003 8733/8911/8065 8670/8848/8002 +f 8672/8850/8004 8734/8912/8066 8671/8849/8003 +f 8673/8851/8005 8735/8913/8067 8672/8850/8004 +f 8674/8852/8006 8736/8914/8068 8673/8851/8005 +f 8675/8853/8007 8737/8915/8069 8674/8852/8006 +f 8676/8854/8008 8738/8916/8070 8675/8853/8007 +f 8677/8855/8009 8739/8917/8071 8676/8854/8008 +f 8678/8856/8010 8740/8918/8072 8677/8855/8009 +f 8679/8857/8011 8741/8919/8073 8678/8856/8010 +f 8680/8858/8012 8742/8920/8074 8679/8857/8011 +f 8681/8859/8013 8743/8921/8075 8680/8858/8012 +f 8682/8860/8014 8744/8922/8076 8681/8859/8013 +f 8683/8861/8015 8745/8923/8077 8682/8860/8014 +f 8684/8862/8016 8746/8924/8078 8683/8861/8015 +f 8685/8863/8017 8747/8925/8079 8684/8862/8016 +f 8686/8864/8018 8748/8926/8080 8685/8863/8017 +f 8687/8865/8019 8749/8927/8081 8686/8864/8018 +f 8688/8866/8020 8750/8928/8082 8687/8865/8019 +f 8689/8867/8021 8751/8929/8083 8688/8866/8020 +f 8690/8868/8022 8752/8930/8084 8689/8867/8021 +f 8691/8869/8023 8753/8931/8085 8690/8868/8022 +f 8692/8870/8024 8754/8932/8086 8691/8869/8023 +f 8693/8871/8025 8755/8933/8087 8692/8870/8024 +f 8694/8872/8026 8756/8934/8088 8693/8871/8025 +f 8695/8873/8027 8757/8935/8089 8694/8872/8026 +f 8696/8874/8028 8758/8936/8090 8695/8873/8027 +f 8697/8875/8029 8759/8937/8091 8696/8874/8028 +f 8698/8876/8030 8760/8938/8092 8697/8875/8029 +f 8699/8877/8031 8761/8939/8093 8698/8876/8030 +f 8700/8878/8032 8762/8940/8094 8699/8877/8031 +f 8701/8879/8033 8763/8941/8095 8700/8878/8032 +f 8702/8880/8034 8764/8942/8096 8701/8879/8033 +f 8703/8881/8035 8765/8943/8097 8702/8880/8034 +f 8704/8882/8036 8766/8944/8098 8703/8881/8035 +f 8705/8883/8037 8767/8945/8099 8704/8882/8036 +f 8706/8884/8038 8768/8946/8100 8705/8883/8037 +f 8707/8886/8040 8769/8947/8101 8706/8884/8038 +f 8708/8948/8102 8770/8949/8103 8707/8886/8040 +f 8710/8888/8042 8772/8950/8104 8709/8887/8041 +f 8711/8889/8043 8773/8951/8105 8710/8888/8042 +f 8712/8890/8044 8774/8952/8106 8711/8889/8043 +f 8713/8891/8045 8775/8953/8107 8712/8890/8044 +f 8714/8892/8046 8776/8954/8108 8713/8891/8045 +f 8715/8893/8047 8777/8955/8109 8714/8892/8046 +f 8716/8894/8048 8778/8956/8110 8715/8893/8047 +f 8717/8895/8049 8779/8957/8111 8716/8894/8048 +f 8718/8896/8050 8780/8958/8112 8717/8895/8049 +f 8719/8897/8051 8781/8959/8113 8718/8896/8050 +f 8720/8898/8052 8782/8960/8114 8719/8897/8051 +f 8721/8899/8053 8783/8961/8115 8720/8898/8052 +f 8722/8900/8054 8784/8962/8116 8721/8899/8053 +f 8723/8901/8055 8785/8963/8117 8722/8900/8054 +f 8724/8902/8056 8786/8964/8118 8723/8901/8055 +f 8725/8903/8057 8787/8965/8119 8724/8902/8056 +f 8726/8904/8058 8788/8966/8120 8725/8903/8057 +f 8727/8905/8059 8789/8967/8121 8726/8904/8058 +f 8728/8906/8060 8790/8968/8122 8727/8905/8059 +f 8729/8907/8061 8791/8969/8123 8728/8906/8060 +f 8730/8908/8062 8792/8970/8124 8729/8907/8061 +f 8731/8909/8063 8793/8971/8125 8730/8908/8062 +f 8732/8910/8064 8794/8972/8126 8731/8909/8063 +f 8733/8911/8065 8795/8973/8127 8732/8910/8064 +f 8734/8912/8066 8796/8974/8128 8733/8911/8065 +f 8735/8913/8067 8797/8975/8129 8734/8912/8066 +f 8736/8914/8068 8798/8976/8130 8735/8913/8067 +f 8737/8915/8069 8799/8977/8131 8736/8914/8068 +f 8738/8916/8070 8800/8978/8132 8737/8915/8069 +f 8739/8917/8071 8801/8979/8133 8738/8916/8070 +f 8740/8918/8072 8802/8980/8134 8739/8917/8071 +f 8741/8919/8073 8803/8981/8135 8740/8918/8072 +f 8742/8920/8074 8804/8982/8136 8741/8919/8073 +f 8743/8921/8075 8805/8983/8137 8742/8920/8074 +f 8744/8922/8076 8806/8984/8138 8743/8921/8075 +f 8745/8923/8077 8807/8985/8139 8744/8922/8076 +f 8746/8924/8078 8808/8986/8140 8745/8923/8077 +f 8747/8925/8079 8809/8987/8141 8746/8924/8078 +f 8748/8926/8080 8810/8988/8142 8747/8925/8079 +f 8749/8927/8081 8811/8989/8143 8748/8926/8080 +f 8750/8928/8082 8812/8990/8144 8749/8927/8081 +f 8751/8929/8083 8813/8991/8145 8750/8928/8082 +f 8752/8930/8084 8814/8992/8146 8751/8929/8083 +f 8753/8931/8085 8815/8993/8147 8752/8930/8084 +f 8754/8932/8086 8816/8994/8148 8753/8931/8085 +f 8755/8933/8087 8817/8995/8149 8754/8932/8086 +f 8756/8934/8088 8818/8996/8150 8755/8933/8087 +f 8757/8935/8089 8819/8997/8151 8756/8934/8088 +f 8758/8936/8090 8820/8998/8152 8757/8935/8089 +f 8759/8937/8091 8821/8999/8153 8758/8936/8090 +f 8760/8938/8092 8822/9000/8154 8759/8937/8091 +f 8761/8939/8093 8823/9001/8155 8760/8938/8092 +f 8762/8940/8094 8824/9002/8156 8761/8939/8093 +f 8763/8941/8095 8825/9003/8157 8762/8940/8094 +f 8764/8942/8096 8826/9004/8158 8763/8941/8095 +f 8765/8943/8097 8827/9005/8159 8764/8942/8096 +f 8766/8944/8098 8828/9006/8160 8765/8943/8097 +f 8767/8945/8099 8829/9007/8161 8766/8944/8098 +f 8768/8946/8100 8830/9008/8162 8767/8945/8099 +f 8769/8947/8101 8831/9009/8163 8768/8946/8100 +f 8770/8949/8103 8832/9010/8164 8769/8947/8101 +f 8771/9011/8165 8833/9012/8166 8770/8949/8103 +f 8773/8951/8105 8835/9013/8167 8772/8950/8104 +f 8774/8952/8106 8836/9014/8168 8773/8951/8105 +f 8775/8953/8107 8837/9015/8169 8774/8952/8106 +f 8776/8954/8108 8838/9016/8170 8775/8953/8107 +f 8777/8955/8109 8839/9017/8171 8776/8954/8108 +f 8778/8956/8110 8840/9018/8172 8777/8955/8109 +f 8779/8957/8111 8841/9019/8173 8778/8956/8110 +f 8780/8958/8112 8842/9020/8174 8779/8957/8111 +f 8781/8959/8113 8843/9021/8175 8780/8958/8112 +f 8782/8960/8114 8844/9022/8176 8781/8959/8113 +f 8783/8961/8115 8845/9023/8177 8782/8960/8114 +f 8784/8962/8116 8846/9024/8178 8783/8961/8115 +f 8785/8963/8117 8847/9025/8179 8784/8962/8116 +f 8786/8964/8118 8848/9026/8180 8785/8963/8117 +f 8787/8965/8119 8849/9027/8181 8786/8964/8118 +f 8788/8966/8120 8850/9028/8182 8787/8965/8119 +f 8789/8967/8121 8851/9029/8183 8788/8966/8120 +f 8790/8968/8122 8852/9030/8184 8789/8967/8121 +f 8791/8969/8123 8853/9031/8185 8790/8968/8122 +f 8792/8970/8124 8854/9032/8186 8791/8969/8123 +f 8793/8971/8125 8855/9033/8187 8792/8970/8124 +f 8794/8972/8126 8856/9034/8188 8793/8971/8125 +f 8795/8973/8127 8857/9035/8189 8794/8972/8126 +f 8796/8974/8128 8858/9036/8190 8795/8973/8127 +f 8797/8975/8129 8859/9037/8191 8796/8974/8128 +f 8798/8976/8130 8860/9038/8192 8797/8975/8129 +f 8799/8977/8131 8861/9039/8193 8798/8976/8130 +f 8800/8978/8132 8862/9040/8194 8799/8977/8131 +f 8801/8979/8133 8863/9041/8195 8800/8978/8132 +f 8802/8980/8134 8864/9042/8196 8801/8979/8133 +f 8803/8981/8135 8865/9043/8197 8802/8980/8134 +f 8804/8982/8136 8866/9044/8198 8803/8981/8135 +f 8805/8983/8137 8867/9045/8199 8804/8982/8136 +f 8806/8984/8138 8868/9046/8014 8805/8983/8137 +f 8807/8985/8139 8869/9047/8200 8806/8984/8138 +f 8808/8986/8140 8870/9048/8201 8807/8985/8139 +f 8809/8987/8141 8871/9049/8202 8808/8986/8140 +f 8810/8988/8142 8872/9050/8203 8809/8987/8141 +f 8811/8989/8143 8873/9051/8204 8810/8988/8142 +f 8812/8990/8144 8874/9052/8205 8811/8989/8143 +f 8813/8991/8145 8875/9053/8206 8812/8990/8144 +f 8814/8992/8146 8876/9054/8207 8813/8991/8145 +f 8815/8993/8147 8877/9055/8208 8814/8992/8146 +f 8816/8994/8148 8878/9056/8209 8815/8993/8147 +f 8817/8995/8149 8879/9057/8210 8816/8994/8148 +f 8818/8996/8150 8880/9058/8211 8817/8995/8149 +f 8819/8997/8151 8881/9059/8212 8818/8996/8150 +f 8820/8998/8152 8882/9060/8213 8819/8997/8151 +f 8821/8999/8153 8883/9061/8214 8820/8998/8152 +f 8822/9000/8154 8884/9062/8215 8821/8999/8153 +f 8823/9001/8155 8885/9063/8216 8822/9000/8154 +f 8824/9002/8156 8886/9064/8217 8823/9001/8155 +f 8825/9003/8157 8887/9065/8218 8824/9002/8156 +f 8826/9004/8158 8888/9066/8219 8825/9003/8157 +f 8827/9005/8159 8889/9067/8220 8826/9004/8158 +f 8828/9006/8160 8890/9068/8221 8827/9005/8159 +f 8829/9007/8161 8891/9069/8222 8828/9006/8160 +f 8830/9008/8162 8892/9070/8223 8829/9007/8161 +f 8831/9009/8163 8893/9071/8224 8830/9008/8162 +f 8832/9010/8164 8894/9072/8225 8831/9009/8163 +f 8833/9012/8166 8895/9073/8226 8832/9010/8164 +f 8834/9074/8227 8896/9075/8228 8833/9012/8166 +f 8836/9014/8168 8898/9076/8229 8835/9013/8167 +f 8837/9015/8169 8899/9077/8230 8836/9014/8168 +f 8838/9016/8170 8900/9078/8231 8837/9015/8169 +f 8839/9017/8171 8901/9079/8232 8838/9016/8170 +f 8840/9018/8172 8902/9080/8233 8839/9017/8171 +f 8841/9019/8173 8903/9081/8234 8840/9018/8172 +f 8842/9020/8174 8904/9082/8235 8841/9019/8173 +f 8843/9021/8175 8905/9083/8236 8842/9020/8174 +f 8844/9022/8176 8906/9084/8237 8843/9021/8175 +f 8845/9023/8177 8907/9085/8238 8844/9022/8176 +f 8846/9024/8178 8908/9086/8239 8845/9023/8177 +f 8847/9025/8179 8909/9087/8240 8846/9024/8178 +f 8848/9026/8180 8910/9088/8241 8847/9025/8179 +f 8849/9027/8181 8911/9089/8242 8848/9026/8180 +f 8850/9028/8182 8912/9090/8243 8849/9027/8181 +f 8851/9029/8183 8913/9091/8244 8850/9028/8182 +f 8852/9030/8184 8914/9092/8245 8851/9029/8183 +f 8853/9031/8185 8915/9093/8246 8852/9030/8184 +f 8854/9032/8186 8916/9094/8247 8853/9031/8185 +f 8855/9033/8187 8917/9095/8248 8854/9032/8186 +f 8856/9034/8188 8918/9096/8249 8855/9033/8187 +f 8857/9035/8189 8919/9097/8250 8856/9034/8188 +f 8858/9036/8190 8920/9098/8251 8857/9035/8189 +f 8859/9037/8191 8921/9099/8252 8858/9036/8190 +f 8860/9038/8192 8922/9100/8253 8859/9037/8191 +f 8861/9039/8193 8923/9101/8254 8860/9038/8192 +f 8862/9040/8194 8924/9102/8255 8861/9039/8193 +f 8863/9041/8195 8925/9103/8256 8862/9040/8194 +f 8864/9042/8196 8926/9104/8069 8863/9041/8195 +f 8865/9043/8197 8927/9105/8257 8864/9042/8196 +f 8866/9044/8198 8928/9106/8258 8865/9043/8197 +f 8867/9045/8199 8929/9107/8259 8866/9044/8198 +f 8868/9046/8014 8930/9108/8260 8867/9045/8199 +f 8869/9047/8200 8931/9109/8261 8868/9046/8014 +f 8870/9048/8201 8932/9110/8262 8869/9047/8200 +f 8871/9049/8202 8933/9111/8263 8870/9048/8201 +f 8872/9050/8203 8934/9112/8264 8871/9049/8202 +f 8873/9051/8204 8935/9113/8265 8872/9050/8203 +f 8874/9052/8205 8936/9114/8266 8873/9051/8204 +f 8875/9053/8206 8937/9115/8267 8874/9052/8205 +f 8876/9054/8207 8938/9116/8268 8875/9053/8206 +f 8877/9055/8208 8939/9117/8269 8876/9054/8207 +f 8878/9056/8209 8940/9118/8270 8877/9055/8208 +f 8879/9057/8210 8941/9119/8271 8878/9056/8209 +f 8880/9058/8211 8942/9120/8272 8879/9057/8210 +f 8881/9059/8212 8943/9121/8273 8880/9058/8211 +f 8882/9060/8213 8944/9122/8274 8881/9059/8212 +f 8883/9061/8214 8945/9123/8275 8882/9060/8213 +f 8884/9062/8215 8946/9124/8276 8883/9061/8214 +f 8885/9063/8216 8947/9125/8277 8884/9062/8215 +f 8886/9064/8217 8948/9126/8278 8885/9063/8216 +f 8887/9065/8218 8949/9127/8279 8886/9064/8217 +f 8888/9066/8219 8950/9128/8280 8887/9065/8218 +f 8889/9067/8220 8951/9129/8281 8888/9066/8219 +f 8890/9068/8221 8952/9130/8282 8889/9067/8220 +f 8891/9069/8222 8953/9131/8283 8890/9068/8221 +f 8892/9070/8223 8954/9132/8284 8891/9069/8222 +f 8893/9071/8224 8955/9133/8285 8892/9070/8223 +f 8894/9072/8225 8956/9134/8286 8893/9071/8224 +f 8895/9073/8226 8957/9135/8287 8894/9072/8225 +f 8896/9075/8228 8958/9136/8288 8895/9073/8226 +f 8897/9137/8289 8959/9138/8290 8896/9075/8228 +f 8899/9077/8230 8961/9139/8291 8898/9076/8229 +f 8900/9078/8231 8962/9140/8292 8899/9077/8230 +f 8901/9079/8232 8963/9141/8293 8900/9078/8231 +f 8902/9080/8233 8964/9142/8294 8901/9079/8232 +f 8903/9081/8234 8965/9143/8295 8902/9080/8233 +f 8904/9082/8235 8966/9144/8296 8903/9081/8234 +f 8905/9083/8236 8967/9145/8297 8904/9082/8235 +f 8906/9084/8237 8968/9146/8298 8905/9083/8236 +f 8907/9085/8238 8969/9147/8299 8906/9084/8237 +f 8908/9086/8239 8970/9148/8300 8907/9085/8238 +f 8909/9087/8240 8971/9149/8301 8908/9086/8239 +f 8910/9088/8241 8972/9150/8302 8909/9087/8240 +f 8911/9089/8242 8973/9151/8303 8910/9088/8241 +f 8912/9090/8243 8974/9152/8304 8911/9089/8242 +f 8913/9091/8244 8975/9153/8305 8912/9090/8243 +f 8914/9092/8245 8976/9154/8306 8913/9091/8244 +f 8915/9093/8246 8977/9155/8307 8914/9092/8245 +f 8916/9094/8247 8978/9156/7628 8915/9093/8246 +f 8917/9095/8248 8979/9157/8308 8916/9094/8247 +f 8918/9096/8249 8980/9158/8309 8917/9095/8248 +f 8919/9097/8250 8981/9159/8310 8918/9096/8249 +f 8920/9098/8251 8982/9160/8311 8919/9097/8250 +f 8921/9099/8252 8983/9161/8312 8920/9098/8251 +f 8922/9100/8253 8984/9162/8313 8921/9099/8252 +f 8923/9101/8254 8985/9163/8314 8922/9100/8253 +f 8924/9102/8255 8986/9164/8315 8923/9101/8254 +f 8925/9103/8256 8987/9165/8316 8924/9102/8255 +f 8926/9104/8069 8988/9166/8317 8925/9103/8256 +f 8927/9105/8257 8989/9167/8318 8926/9104/8069 +f 8928/9106/8258 8990/9168/8319 8927/9105/8257 +f 8929/9107/8259 8991/9169/8320 8928/9106/8258 +f 8930/9108/8260 8992/9170/8321 8929/9107/8259 +f 8931/9109/8261 8993/9171/8322 8930/9108/8260 +f 8932/9110/8262 8994/9172/8323 8931/9109/8261 +f 8933/9111/8263 8995/9173/8324 8932/9110/8262 +f 8934/9112/8264 8996/9174/8325 8933/9111/8263 +f 8935/9113/8265 8997/9175/8326 8934/9112/8264 +f 8936/9114/8266 8998/9176/8327 8935/9113/8265 +f 8937/9115/8267 8999/9177/8328 8936/9114/8266 +f 8938/9116/8268 9000/9178/8329 8937/9115/8267 +f 8939/9117/8269 9001/9179/8330 8938/9116/8268 +f 8940/9118/8270 9002/9180/8331 8939/9117/8269 +f 8941/9119/8271 9003/9181/8332 8940/9118/8270 +f 8942/9120/8272 9004/9182/8333 8941/9119/8271 +f 8943/9121/8273 9005/9183/8334 8942/9120/8272 +f 8944/9122/8274 9006/9184/8335 8943/9121/8273 +f 8945/9123/8275 9007/9185/8336 8944/9122/8274 +f 8946/9124/8276 9008/9186/8337 8945/9123/8275 +f 8947/9125/8277 9009/9187/8338 8946/9124/8276 +f 8948/9126/8278 9010/9188/8339 8947/9125/8277 +f 8949/9127/8279 9011/9189/8340 8948/9126/8278 +f 8950/9128/8280 9012/9190/8341 8949/9127/8279 +f 8951/9129/8281 9013/9191/8342 8950/9128/8280 +f 8952/9130/8282 9014/9192/8343 8951/9129/8281 +f 8953/9131/8283 9015/9193/8344 8952/9130/8282 +f 8954/9132/8284 9016/9194/8345 8953/9131/8283 +f 8955/9133/8285 9017/9195/8346 8954/9132/8284 +f 8956/9134/8286 9018/9196/8347 8955/9133/8285 +f 8957/9135/8287 9019/9197/8348 8956/9134/8286 +f 8958/9136/8288 9020/9198/8349 8957/9135/8287 +f 8959/9138/8290 9021/9199/8350 8958/9136/8288 +f 8960/9200/8351 9022/9201/8352 8959/9138/8290 +f 8962/9140/8292 9024/9202/8353 8961/9139/8291 +f 8963/9141/8293 9025/9203/8354 8962/9140/8292 +f 8964/9142/8294 9026/9204/8355 8963/9141/8293 +f 8965/9143/8295 9027/9205/8356 8964/9142/8294 +f 8966/9144/8296 9028/9206/8357 8965/9143/8295 +f 8967/9145/8297 9029/9207/8358 8966/9144/8296 +f 8968/9146/8298 9030/9208/8359 8967/9145/8297 +f 8969/9147/8299 9031/9209/8360 8968/9146/8298 +f 8970/9148/8300 9032/9210/8361 8969/9147/8299 +f 8971/9149/8301 9033/9211/8362 8970/9148/8300 +f 8972/9150/8302 9034/9212/8363 8971/9149/8301 +f 8973/9151/8303 9035/9213/8364 8972/9150/8302 +f 8974/9152/8304 9036/9214/8365 8973/9151/8303 +f 8975/9153/8305 9037/9215/8366 8974/9152/8304 +f 8976/9154/8306 9038/9216/8367 8975/9153/8305 +f 8977/9155/8307 9039/9217/8368 8976/9154/8306 +f 8978/9156/7628 9040/9218/8369 8977/9155/8307 +f 8979/9157/8308 9041/9219/8370 8978/9156/7628 +f 8980/9158/8309 9042/9220/8371 8979/9157/8308 +f 8981/9159/8310 9043/9221/8372 8980/9158/8309 +f 8982/9160/8311 9044/9222/8373 8981/9159/8310 +f 8983/9161/8312 9045/9223/8374 8982/9160/8311 +f 8984/9162/8313 9046/9224/8375 8983/9161/8312 +f 8985/9163/8314 9047/9225/8376 8984/9162/8313 +f 8986/9164/8315 9048/9226/8377 8985/9163/8314 +f 8987/9165/8316 9049/9227/8378 8986/9164/8315 +f 8988/9166/8317 9050/9228/8379 8987/9165/8316 +f 8989/9167/8318 9051/9229/8380 8988/9166/8317 +f 8990/9168/8319 9052/9230/8381 8989/9167/8318 +f 8991/9169/8320 9053/9231/8382 8990/9168/8319 +f 8992/9170/8321 9054/9232/8383 8991/9169/8320 +f 8993/9171/8322 9055/9233/8384 8992/9170/8321 +f 8994/9172/8323 9056/9234/8385 8993/9171/8322 +f 8995/9173/8324 9057/9235/8386 8994/9172/8323 +f 8996/9174/8325 9058/9236/8387 8995/9173/8324 +f 8997/9175/8326 9059/9237/8388 8996/9174/8325 +f 8998/9176/8327 9060/9238/8389 8997/9175/8326 +f 8999/9177/8328 9061/9239/8390 8998/9176/8327 +f 9000/9178/8329 9062/9240/8391 8999/9177/8328 +f 9001/9179/8330 9063/9241/8392 9000/9178/8329 +f 9002/9180/8331 9064/9242/8393 9001/9179/8330 +f 9003/9181/8332 9065/9243/8394 9002/9180/8331 +f 9004/9182/8333 9066/9244/8395 9003/9181/8332 +f 9005/9183/8334 9067/9245/8396 9004/9182/8333 +f 9006/9184/8335 9068/9246/8397 9005/9183/8334 +f 9007/9185/8336 9069/9247/8398 9006/9184/8335 +f 9008/9186/8337 9070/9248/8399 9007/9185/8336 +f 9009/9187/8338 9071/9249/8400 9008/9186/8337 +f 9010/9188/8339 9072/9250/8401 9009/9187/8338 +f 9011/9189/8340 9073/9251/8402 9010/9188/8339 +f 9012/9190/8341 9074/9252/8403 9011/9189/8340 +f 9013/9191/8342 9075/9253/8404 9012/9190/8341 +f 9014/9192/8343 9076/9254/8405 9013/9191/8342 +f 9015/9193/8344 9077/9255/8406 9014/9192/8343 +f 9016/9194/8345 9078/9256/8407 9015/9193/8344 +f 9017/9195/8346 9079/9257/8408 9016/9194/8345 +f 9018/9196/8347 9080/9258/8409 9017/9195/8346 +f 9019/9197/8348 9081/9259/8410 9018/9196/8347 +f 9020/9198/8349 9082/9260/8411 9019/9197/8348 +f 9021/9199/8350 9083/9261/8412 9020/9198/8349 +f 9022/9201/8352 9084/9262/8413 9021/9199/8350 +f 9023/9263/8414 9085/9264/8415 9022/9201/8352 +f 9025/9203/8354 9087/9265/8416 9024/9202/8353 +f 9026/9204/8355 9088/9266/8417 9025/9203/8354 +f 9027/9205/8356 9089/9267/8418 9026/9204/8355 +f 9028/9206/8357 9090/9268/8419 9027/9205/8356 +f 9029/9207/8358 9091/9269/8420 9028/9206/8357 +f 9030/9208/8359 9092/9270/8421 9029/9207/8358 +f 9031/9209/8360 9093/9271/8422 9030/9208/8359 +f 9032/9210/8361 9094/9272/8423 9031/9209/8360 +f 9033/9211/8362 9095/9273/8424 9032/9210/8361 +f 9034/9212/8363 9096/9274/8425 9033/9211/8362 +f 9035/9213/8364 9097/9275/8426 9034/9212/8363 +f 9036/9214/8365 9098/9276/8427 9035/9213/8364 +f 9037/9215/8366 9099/9277/8428 9036/9214/8365 +f 9038/9216/8367 9100/9278/8429 9037/9215/8366 +f 9039/9217/8368 9101/9279/8430 9038/9216/8367 +f 9040/9218/8369 9102/9280/8431 9039/9217/8368 +f 9041/9219/8370 9103/9281/8432 9040/9218/8369 +f 9042/9220/8371 9104/9282/8433 9041/9219/8370 +f 9043/9221/8372 9105/9283/8434 9042/9220/8371 +f 9044/9222/8373 9106/9284/8435 9043/9221/8372 +f 9045/9223/8374 9107/9285/8436 9044/9222/8373 +f 9046/9224/8375 9108/9286/8437 9045/9223/8374 +f 9047/9225/8376 9109/9287/8438 9046/9224/8375 +f 9048/9226/8377 9110/9288/8439 9047/9225/8376 +f 9049/9227/8378 9111/9289/8440 9048/9226/8377 +f 9050/9228/8379 9112/9290/8441 9049/9227/8378 +f 9051/9229/8380 9113/9291/8442 9050/9228/8379 +f 9052/9230/8381 9114/9292/8443 9051/9229/8380 +f 9053/9231/8382 9115/9293/8444 9052/9230/8381 +f 9054/9232/8383 9116/9294/8445 9053/9231/8382 +f 9055/9233/8384 9117/9295/8446 9054/9232/8383 +f 9056/9234/8385 9118/9296/8447 9055/9233/8384 +f 9057/9235/8386 9119/9297/8448 9056/9234/8385 +f 9058/9236/8387 9120/9298/8449 9057/9235/8386 +f 9059/9237/8388 9121/9299/8450 9058/9236/8387 +f 9060/9238/8389 9122/9300/8451 9059/9237/8388 +f 9061/9239/8390 9123/9301/8452 9060/9238/8389 +f 9062/9240/8391 9124/9302/8453 9061/9239/8390 +f 9063/9241/8392 9125/9303/8454 9062/9240/8391 +f 9064/9242/8393 9126/9304/8455 9063/9241/8392 +f 9065/9243/8394 9127/9305/8456 9064/9242/8393 +f 9066/9244/8395 9128/9306/8457 9065/9243/8394 +f 9067/9245/8396 9129/9307/8458 9066/9244/8395 +f 9068/9246/8397 9130/9308/8459 9067/9245/8396 +f 9069/9247/8398 9131/9309/8460 9068/9246/8397 +f 9070/9248/8399 9132/9310/8461 9069/9247/8398 +f 9071/9249/8400 9133/9311/8462 9070/9248/8399 +f 9072/9250/8401 9134/9312/8463 9071/9249/8400 +f 9073/9251/8402 9135/9313/8464 9072/9250/8401 +f 9074/9252/8403 9136/9314/8465 9073/9251/8402 +f 9075/9253/8404 9137/9315/8466 9074/9252/8403 +f 9076/9254/8405 9138/9316/8467 9075/9253/8404 +f 9077/9255/8406 9139/9317/8468 9076/9254/8405 +f 9078/9256/8407 9140/9318/8469 9077/9255/8406 +f 9079/9257/8408 9141/9319/8470 9078/9256/8407 +f 9080/9258/8409 9142/9320/8471 9079/9257/8408 +f 9081/9259/8410 9143/9321/8472 9080/9258/8409 +f 9082/9260/8411 9144/9322/8473 9081/9259/8410 +f 9083/9261/8412 9145/9323/8474 9082/9260/8411 +f 9084/9262/8413 9146/9324/8475 9083/9261/8412 +f 9085/9264/8415 9147/9325/8476 9084/9262/8413 +f 9086/9326/8477 9148/9327/8478 9085/9264/8415 +f 9088/9266/8417 9150/9328/8479 9087/9265/8416 +f 9089/9267/8418 9151/9329/8480 9088/9266/8417 +f 9090/9268/8419 9152/9330/8481 9089/9267/8418 +f 9091/9269/8420 9153/9331/8482 9090/9268/8419 +f 9092/9270/8421 9154/9332/8483 9091/9269/8420 +f 9093/9271/8422 9155/9333/8484 9092/9270/8421 +f 9094/9272/8423 9156/9334/8485 9093/9271/8422 +f 9095/9273/8424 9157/9335/8486 9094/9272/8423 +f 9096/9274/8425 9158/9336/8487 9095/9273/8424 +f 9097/9275/8426 9159/9337/8488 9096/9274/8425 +f 9098/9276/8427 9160/9338/8489 9097/9275/8426 +f 9099/9277/8428 9161/9339/8490 9098/9276/8427 +f 9100/9278/8429 9162/9340/8491 9099/9277/8428 +f 9101/9279/8430 9163/9341/8492 9100/9278/8429 +f 9102/9280/8431 9164/9342/8493 9101/9279/8430 +f 9103/9281/8432 9165/9343/8494 9102/9280/8431 +f 9104/9282/8433 9166/9344/8495 9103/9281/8432 +f 9105/9283/8434 9167/9345/8496 9104/9282/8433 +f 9106/9284/8435 9168/9346/8497 9105/9283/8434 +f 9107/9285/8436 9169/9347/8498 9106/9284/8435 +f 9108/9286/8437 9170/9348/8499 9107/9285/8436 +f 9109/9287/8438 9171/9349/8500 9108/9286/8437 +f 9110/9288/8439 9172/9350/8501 9109/9287/8438 +f 9111/9289/8440 9173/9351/8502 9110/9288/8439 +f 9112/9290/8441 9174/9352/8503 9111/9289/8440 +f 9113/9291/8442 9175/9353/8504 9112/9290/8441 +f 9114/9292/8443 9176/9354/8505 9113/9291/8442 +f 9115/9293/8444 9177/9355/8506 9114/9292/8443 +f 9116/9294/8445 9178/9356/7318 9115/9293/8444 +f 9117/9295/8446 9179/9357/8507 9116/9294/8445 +f 9118/9296/8447 9180/9358/8508 9117/9295/8446 +f 9119/9297/8448 9181/9359/8509 9118/9296/8447 +f 9120/9298/8449 9182/9360/8510 9119/9297/8448 +f 9121/9299/8450 9183/9361/8511 9120/9298/8449 +f 9122/9300/8451 9184/9362/8512 9121/9299/8450 +f 9123/9301/8452 9185/9363/8513 9122/9300/8451 +f 9124/9302/8453 9186/9364/8514 9123/9301/8452 +f 9125/9303/8454 9187/9365/8515 9124/9302/8453 +f 9126/9304/8455 9188/9366/8516 9125/9303/8454 +f 9127/9305/8456 9189/9367/8517 9126/9304/8455 +f 9128/9306/8457 9190/9368/8518 9127/9305/8456 +f 9129/9307/8458 9191/9369/8519 9128/9306/8457 +f 9130/9308/8459 9192/9370/8520 9129/9307/8458 +f 9131/9309/8460 9193/9371/8521 9130/9308/8459 +f 9132/9310/8461 9194/9372/8522 9131/9309/8460 +f 9133/9311/8462 9195/9373/8523 9132/9310/8461 +f 9134/9312/8463 9196/9374/8524 9133/9311/8462 +f 9135/9313/8464 9197/9375/8525 9134/9312/8463 +f 9136/9314/8465 9198/9376/8526 9135/9313/8464 +f 9137/9315/8466 9199/9377/8527 9136/9314/8465 +f 9138/9316/8467 9200/9378/8528 9137/9315/8466 +f 9139/9317/8468 9201/9379/8529 9138/9316/8467 +f 9140/9318/8469 9202/9380/8530 9139/9317/8468 +f 9141/9319/8470 9203/9381/8531 9140/9318/8469 +f 9142/9320/8471 9204/9382/8532 9141/9319/8470 +f 9143/9321/8472 9205/9383/8533 9142/9320/8471 +f 9144/9322/8473 9206/9384/8534 9143/9321/8472 +f 9145/9323/8474 9207/9385/8535 9144/9322/8473 +f 9146/9324/8475 9208/9386/8536 9145/9323/8474 +f 9147/9325/8476 9209/9387/8537 9146/9324/8475 +f 9148/9327/8478 9210/9388/8538 9147/9325/8476 +f 9149/9389/8539 9211/9390/8540 9148/9327/8478 +f 9151/9329/8480 9213/9391/8541 9150/9328/8479 +f 9152/9330/8481 9214/9392/8542 9151/9329/8480 +f 9153/9331/8482 9215/9393/8543 9152/9330/8481 +f 9154/9332/8483 9216/9394/8544 9153/9331/8482 +f 9155/9333/8484 9217/9395/8545 9154/9332/8483 +f 9156/9334/8485 9218/9396/8546 9155/9333/8484 +f 9157/9335/8486 9219/9397/8547 9156/9334/8485 +f 9158/9336/8487 9220/9398/8548 9157/9335/8486 +f 9159/9337/8488 9221/9399/8549 9158/9336/8487 +f 9160/9338/8489 9222/9400/8550 9159/9337/8488 +f 9161/9339/8490 9223/9401/8551 9160/9338/8489 +f 9162/9340/8491 9224/9402/8552 9161/9339/8490 +f 9163/9341/8492 9225/9403/8553 9162/9340/8491 +f 9164/9342/8493 9226/9404/8554 9163/9341/8492 +f 9165/9343/8494 9227/9405/8555 9164/9342/8493 +f 9166/9344/8495 9228/9406/8556 9165/9343/8494 +f 9167/9345/8496 9229/9407/8557 9166/9344/8495 +f 9168/9346/8497 9230/9408/8558 9167/9345/8496 +f 9169/9347/8498 9231/9409/8559 9168/9346/8497 +f 9170/9348/8499 9232/9410/8560 9169/9347/8498 +f 9171/9349/8500 9233/9411/8561 9170/9348/8499 +f 9172/9350/8501 9234/9412/8562 9171/9349/8500 +f 9173/9351/8502 9235/9413/8563 9172/9350/8501 +f 9174/9352/8503 9236/9414/8564 9173/9351/8502 +f 9175/9353/8504 9237/9415/8565 9174/9352/8503 +f 9176/9354/8505 9238/9416/8566 9175/9353/8504 +f 9177/9355/8506 9239/9417/8567 9176/9354/8505 +f 9178/9356/7318 9240/9418/8568 9177/9355/8506 +f 9179/9357/8507 9241/9419/8569 9178/9356/7318 +f 9180/9358/8508 9242/9420/8570 9179/9357/8507 +f 9181/9359/8509 9243/9421/8571 9180/9358/8508 +f 9182/9360/8510 9244/9422/8572 9181/9359/8509 +f 9183/9361/8511 9245/9423/8573 9182/9360/8510 +f 9184/9362/8512 9246/9424/8574 9183/9361/8511 +f 9185/9363/8513 9247/9425/8575 9184/9362/8512 +f 9186/9364/8514 9248/9426/8576 9185/9363/8513 +f 9187/9365/8515 9249/9427/8577 9186/9364/8514 +f 9188/9366/8516 9250/9428/8578 9187/9365/8515 +f 9189/9367/8517 9251/9429/8579 9188/9366/8516 +f 9190/9368/8518 9252/9430/8580 9189/9367/8517 +f 9191/9369/8519 9253/9431/8581 9190/9368/8518 +f 9192/9370/8520 9254/9432/8582 9191/9369/8519 +f 9193/9371/8521 9255/9433/8583 9192/9370/8520 +f 9194/9372/8522 9256/9434/8584 9193/9371/8521 +f 9195/9373/8523 9257/9435/8585 9194/9372/8522 +f 9196/9374/8524 9258/9436/8586 9195/9373/8523 +f 9197/9375/8525 9259/9437/8587 9196/9374/8524 +f 9198/9376/8526 9260/9438/8588 9197/9375/8525 +f 9199/9377/8527 9261/9439/8589 9198/9376/8526 +f 9200/9378/8528 9262/9440/8590 9199/9377/8527 +f 9201/9379/8529 9263/9441/8591 9200/9378/8528 +f 9202/9380/8530 9264/9442/8592 9201/9379/8529 +f 9203/9381/8531 9265/9443/8593 9202/9380/8530 +f 9204/9382/8532 9266/9444/8594 9203/9381/8531 +f 9205/9383/8533 9267/9445/8595 9204/9382/8532 +f 9206/9384/8534 9268/9446/8596 9205/9383/8533 +f 9207/9385/8535 9269/9447/8597 9206/9384/8534 +f 9208/9386/8536 9270/9448/8598 9207/9385/8535 +f 9209/9387/8537 9271/9449/8599 9208/9386/8536 +f 9210/9388/8538 9272/9450/8600 9209/9387/8537 +f 9211/9390/8540 9273/9451/8601 9210/9388/8538 +f 9212/9452/8602 9274/9453/8603 9211/9390/8540 +f 9214/9392/8542 9276/9454/8604 9213/9391/8541 +f 9215/9393/8543 9277/9455/8605 9214/9392/8542 +f 9216/9394/8544 9278/9456/8606 9215/9393/8543 +f 9217/9395/8545 9279/9457/8607 9216/9394/8544 +f 9218/9396/8546 9280/9458/8608 9217/9395/8545 +f 9219/9397/8547 9281/9459/8609 9218/9396/8546 +f 9220/9398/8548 9282/9460/8610 9219/9397/8547 +f 9221/9399/8549 9283/9461/8611 9220/9398/8548 +f 9222/9400/8550 9284/9462/8612 9221/9399/8549 +f 9223/9401/8551 9285/9463/8613 9222/9400/8550 +f 9224/9402/8552 9286/9464/8614 9223/9401/8551 +f 9225/9403/8553 9287/9465/8615 9224/9402/8552 +f 9226/9404/8554 9288/9466/8616 9225/9403/8553 +f 9227/9405/8555 9289/9467/8617 9226/9404/8554 +f 9228/9406/8556 9290/9468/8618 9227/9405/8555 +f 9229/9407/8557 9291/9469/8619 9228/9406/8556 +f 9230/9408/8558 9292/9470/8620 9229/9407/8557 +f 9231/9409/8559 9293/9471/8621 9230/9408/8558 +f 9232/9410/8560 9294/9472/8622 9231/9409/8559 +f 9233/9411/8561 9295/9473/8623 9232/9410/8560 +f 9234/9412/8562 9296/9474/8624 9233/9411/8561 +f 9235/9413/8563 9297/9475/8625 9234/9412/8562 +f 9236/9414/8564 9298/9476/8626 9235/9413/8563 +f 9237/9415/8565 9299/9477/8627 9236/9414/8564 +f 9238/9416/8566 9300/9478/8628 9237/9415/8565 +f 9239/9417/8567 9301/9479/8629 9238/9416/8566 +f 9240/9418/8568 9302/9480/8630 9239/9417/8567 +f 9241/9419/8569 9303/9481/8631 9240/9418/8568 +f 9242/9420/8570 9304/9482/8632 9241/9419/8569 +f 9243/9421/8571 9305/9483/8633 9242/9420/8570 +f 9244/9422/8572 9306/9484/8634 9243/9421/8571 +f 9245/9423/8573 9307/9485/8635 9244/9422/8572 +f 9246/9424/8574 9308/9486/8636 9245/9423/8573 +f 9247/9425/8575 9309/9487/8637 9246/9424/8574 +f 9248/9426/8576 9310/9488/8638 9247/9425/8575 +f 9249/9427/8577 9311/9489/8639 9248/9426/8576 +f 9250/9428/8578 9312/9490/8640 9249/9427/8577 +f 9251/9429/8579 9313/9491/8641 9250/9428/8578 +f 9252/9430/8580 9314/9492/8642 9251/9429/8579 +f 9253/9431/8581 9315/9493/8643 9252/9430/8580 +f 9254/9432/8582 9316/9494/8644 9253/9431/8581 +f 9255/9433/8583 9317/9495/8645 9254/9432/8582 +f 9256/9434/8584 9318/9496/8646 9255/9433/8583 +f 9257/9435/8585 9319/9497/8647 9256/9434/8584 +f 9258/9436/8586 9320/9498/8648 9257/9435/8585 +f 9259/9437/8587 9321/9499/8649 9258/9436/8586 +f 9260/9438/8588 9322/9500/8650 9259/9437/8587 +f 9261/9439/8589 9323/9501/8651 9260/9438/8588 +f 9262/9440/8590 9324/9502/8652 9261/9439/8589 +f 9263/9441/8591 9325/9503/8653 9262/9440/8590 +f 9264/9442/8592 9326/9504/8654 9263/9441/8591 +f 9265/9443/8593 9327/9505/8655 9264/9442/8592 +f 9266/9444/8594 9328/9506/8656 9265/9443/8593 +f 9267/9445/8595 9329/9507/8657 9266/9444/8594 +f 9268/9446/8596 9330/9508/8658 9267/9445/8595 +f 9269/9447/8597 9331/9509/8659 9268/9446/8596 +f 9270/9448/8598 9332/9510/8660 9269/9447/8597 +f 9271/9449/8599 9333/9511/8661 9270/9448/8598 +f 9272/9450/8600 9334/9512/8662 9271/9449/8599 +f 9273/9451/8601 9335/9513/8663 9272/9450/8600 +f 9274/9453/8603 9336/9514/8664 9273/9451/8601 +f 9275/9515/8665 9337/9516/8666 9274/9453/8603 +f 9277/9455/8605 9339/9517/8667 9276/9454/8604 +f 9278/9456/8606 9340/9518/8668 9277/9455/8605 +f 9279/9457/8607 9341/9519/8669 9278/9456/8606 +f 9280/9458/8608 9342/9520/8670 9279/9457/8607 +f 9281/9459/8609 9343/9521/8671 9280/9458/8608 +f 9282/9460/8610 9344/9522/8672 9281/9459/8609 +f 9283/9461/8611 9345/9523/8673 9282/9460/8610 +f 9284/9462/8612 9346/9524/8674 9283/9461/8611 +f 9285/9463/8613 9347/9525/8675 9284/9462/8612 +f 9286/9464/8614 9348/9526/8676 9285/9463/8613 +f 9287/9465/8615 9349/9527/8677 9286/9464/8614 +f 9288/9466/8616 9350/9528/8678 9287/9465/8615 +f 9289/9467/8617 9351/9529/8679 9288/9466/8616 +f 9290/9468/8618 9352/9530/8680 9289/9467/8617 +f 9291/9469/8619 9353/9531/8681 9290/9468/8618 +f 9292/9470/8620 9354/9532/8682 9291/9469/8619 +f 9293/9471/8621 9355/9533/8683 9292/9470/8620 +f 9294/9472/8622 9356/9534/8684 9293/9471/8621 +f 9295/9473/8623 9357/9535/8685 9294/9472/8622 +f 9296/9474/8624 9358/9536/8686 9295/9473/8623 +f 9297/9475/8625 9359/9537/8687 9296/9474/8624 +f 9298/9476/8626 9360/9538/8688 9297/9475/8625 +f 9299/9477/8627 9361/9539/8689 9298/9476/8626 +f 9300/9478/8628 9362/9540/8690 9299/9477/8627 +f 9301/9479/8629 9363/9541/8691 9300/9478/8628 +f 9302/9480/8630 9364/9542/8692 9301/9479/8629 +f 9303/9481/8631 9365/9543/8693 9302/9480/8630 +f 9304/9482/8632 9366/9544/8694 9303/9481/8631 +f 9305/9483/8633 9367/9545/8695 9304/9482/8632 +f 9306/9484/8634 9368/9546/8696 9305/9483/8633 +f 9307/9485/8635 9369/9547/8697 9306/9484/8634 +f 9308/9486/8636 9370/9548/8698 9307/9485/8635 +f 9309/9487/8637 9371/9549/8699 9308/9486/8636 +f 9310/9488/8638 9372/9550/8700 9309/9487/8637 +f 9311/9489/8639 9373/9551/8701 9310/9488/8638 +f 9312/9490/8640 9374/9552/8702 9311/9489/8639 +f 9313/9491/8641 9375/9553/8703 9312/9490/8640 +f 9314/9492/8642 9376/9554/8704 9313/9491/8641 +f 9315/9493/8643 9377/9555/8705 9314/9492/8642 +f 9316/9494/8644 9378/9556/8706 9315/9493/8643 +f 9317/9495/8645 9379/9557/8707 9316/9494/8644 +f 9318/9496/8646 9380/9558/8708 9317/9495/8645 +f 9319/9497/8647 9381/9559/8709 9318/9496/8646 +f 9320/9498/8648 9382/9560/8710 9319/9497/8647 +f 9321/9499/8649 9383/9561/8711 9320/9498/8648 +f 9322/9500/8650 9384/9562/8712 9321/9499/8649 +f 9323/9501/8651 9385/9563/8713 9322/9500/8650 +f 9324/9502/8652 9386/9564/8714 9323/9501/8651 +f 9325/9503/8653 9387/9565/8715 9324/9502/8652 +f 9326/9504/8654 9388/9566/8716 9325/9503/8653 +f 9327/9505/8655 9389/9567/8717 9326/9504/8654 +f 9328/9506/8656 9390/9568/8718 9327/9505/8655 +f 9329/9507/8657 9391/9569/8719 9328/9506/8656 +f 9330/9508/8658 9392/9570/8720 9329/9507/8657 +f 9331/9509/8659 9393/9571/8721 9330/9508/8658 +f 9332/9510/8660 9394/9572/8722 9331/9509/8659 +f 9333/9511/8661 9395/9573/8723 9332/9510/8660 +f 9334/9512/8662 9396/9574/8724 9333/9511/8661 +f 9335/9513/8663 9397/9575/8725 9334/9512/8662 +f 9336/9514/8664 9398/9576/8726 9335/9513/8663 +f 9337/9516/8666 9399/9577/8727 9336/9514/8664 +f 9338/9578/8728 9400/9579/8729 9337/9516/8666 +f 9340/9518/8668 9402/9580/8730 9339/9517/8667 +f 9341/9519/8669 9403/9581/8731 9340/9518/8668 +f 9342/9520/8670 9404/9582/8732 9341/9519/8669 +f 9343/9521/8671 9405/9583/8733 9342/9520/8670 +f 9344/9522/8672 9406/9584/8734 9343/9521/8671 +f 9345/9523/8673 9407/9585/8735 9344/9522/8672 +f 9346/9524/8674 9408/9586/8736 9345/9523/8673 +f 9347/9525/8675 9409/9587/8737 9346/9524/8674 +f 9348/9526/8676 9410/9588/8738 9347/9525/8675 +f 9349/9527/8677 9411/9589/8739 9348/9526/8676 +f 9350/9528/8678 9412/9590/8740 9349/9527/8677 +f 9351/9529/8679 9413/9591/8741 9350/9528/8678 +f 9352/9530/8680 9414/9592/8742 9351/9529/8679 +f 9353/9531/8681 9415/9593/8743 9352/9530/8680 +f 9354/9532/8682 9416/9594/8744 9353/9531/8681 +f 9355/9533/8683 9417/9595/8745 9354/9532/8682 +f 9356/9534/8684 9418/9596/8746 9355/9533/8683 +f 9357/9535/8685 9419/9597/8747 9356/9534/8684 +f 9358/9536/8686 9420/9598/8748 9357/9535/8685 +f 9359/9537/8687 9421/9599/8749 9358/9536/8686 +f 9360/9538/8688 9422/9600/8750 9359/9537/8687 +f 9361/9539/8689 9423/9601/8751 9360/9538/8688 +f 9362/9540/8690 9424/9602/8752 9361/9539/8689 +f 9363/9541/8691 9425/9603/8753 9362/9540/8690 +f 9364/9542/8692 9426/9604/8754 9363/9541/8691 +f 9365/9543/8693 9427/9605/8755 9364/9542/8692 +f 9366/9544/8694 9428/9606/8756 9365/9543/8693 +f 9367/9545/8695 9429/9607/8757 9366/9544/8694 +f 9368/9546/8696 9430/9608/8758 9367/9545/8695 +f 9369/9547/8697 9431/9609/8759 9368/9546/8696 +f 9370/9548/8698 9432/9610/8760 9369/9547/8697 +f 9371/9549/8699 9433/9611/8761 9370/9548/8698 +f 9372/9550/8700 9434/9612/8762 9371/9549/8699 +f 9373/9551/8701 9435/9613/8763 9372/9550/8700 +f 9374/9552/8702 9436/9614/8764 9373/9551/8701 +f 9375/9553/8703 9437/9615/8765 9374/9552/8702 +f 9376/9554/8704 9438/9616/8766 9375/9553/8703 +f 9377/9555/8705 9439/9617/8767 9376/9554/8704 +f 9378/9556/8706 9440/9618/8768 9377/9555/8705 +f 9379/9557/8707 9441/9619/8769 9378/9556/8706 +f 9380/9558/8708 9442/9620/8770 9379/9557/8707 +f 9381/9559/8709 9443/9621/8771 9380/9558/8708 +f 9382/9560/8710 9444/9622/8772 9381/9559/8709 +f 9383/9561/8711 9445/9623/8773 9382/9560/8710 +f 9384/9562/8712 9446/9624/8774 9383/9561/8711 +f 9385/9563/8713 9447/9625/8775 9384/9562/8712 +f 9386/9564/8714 9448/9626/8776 9385/9563/8713 +f 9387/9565/8715 9449/9627/7628 9386/9564/8714 +f 9388/9566/8716 9450/9628/8777 9387/9565/8715 +f 9389/9567/8717 9451/9629/8778 9388/9566/8716 +f 9390/9568/8718 9452/9630/8779 9389/9567/8717 +f 9391/9569/8719 9453/9631/8780 9390/9568/8718 +f 9392/9570/8720 9454/9632/8781 9391/9569/8719 +f 9393/9571/8721 9455/9633/8782 9392/9570/8720 +f 9394/9572/8722 9456/9634/8783 9393/9571/8721 +f 9395/9573/8723 9457/9635/8784 9394/9572/8722 +f 9396/9574/8724 9458/9636/8785 9395/9573/8723 +f 9397/9575/8725 9459/9637/8786 9396/9574/8724 +f 9398/9576/8726 9460/9638/8787 9397/9575/8725 +f 9399/9577/8727 9461/9639/8788 9398/9576/8726 +f 9400/9579/8729 9462/9640/8789 9399/9577/8727 +f 9401/9641/8790 9463/9642/8791 9400/9579/8729 +f 9403/9581/8731 9465/9643/8792 9402/9580/8730 +f 9404/9582/8732 9466/9644/8793 9403/9581/8731 +f 9405/9583/8733 9467/9645/8794 9404/9582/8732 +f 9406/9584/8734 9468/9646/8795 9405/9583/8733 +f 9407/9585/8735 9469/9647/8796 9406/9584/8734 +f 9408/9586/8736 9470/9648/8797 9407/9585/8735 +f 9409/9587/8737 9471/9649/8798 9408/9586/8736 +f 9410/9588/8738 9472/9650/8799 9409/9587/8737 +f 9411/9589/8739 9473/9651/8800 9410/9588/8738 +f 9412/9590/8740 9474/9652/8801 9411/9589/8739 +f 9413/9591/8741 9475/9653/8802 9412/9590/8740 +f 9414/9592/8742 9476/9654/8803 9413/9591/8741 +f 9415/9593/8743 9477/9655/8804 9414/9592/8742 +f 9416/9594/8744 9478/9656/8805 9415/9593/8743 +f 9417/9595/8745 9479/9657/8806 9416/9594/8744 +f 9418/9596/8746 9480/9658/8807 9417/9595/8745 +f 9419/9597/8747 9481/9659/8808 9418/9596/8746 +f 9420/9598/8748 9482/9660/8809 9419/9597/8747 +f 9421/9599/8749 9483/9661/8810 9420/9598/8748 +f 9422/9600/8750 9484/9662/8811 9421/9599/8749 +f 9423/9601/8751 9485/9663/8812 9422/9600/8750 +f 9424/9602/8752 9486/9664/8813 9423/9601/8751 +f 9425/9603/8753 9487/9665/8814 9424/9602/8752 +f 9426/9604/8754 9488/9666/7910 9425/9603/8753 +f 9427/9605/8755 9489/9667/8815 9426/9604/8754 +f 9428/9606/8756 9490/9668/8816 9427/9605/8755 +f 9429/9607/8757 9491/9669/8817 9428/9606/8756 +f 9430/9608/8758 9492/9670/8818 9429/9607/8757 +f 9431/9609/8759 9493/9671/8819 9430/9608/8758 +f 9432/9610/8760 9494/9672/8820 9431/9609/8759 +f 9433/9611/8761 9495/9673/8821 9432/9610/8760 +f 9434/9612/8762 9496/9674/8822 9433/9611/8761 +f 9435/9613/8763 9497/9675/8823 9434/9612/8762 +f 9436/9614/8764 9498/9676/8824 9435/9613/8763 +f 9437/9615/8765 9499/9677/8825 9436/9614/8764 +f 9438/9616/8766 9500/9678/8826 9437/9615/8765 +f 9439/9617/8767 9501/9679/8827 9438/9616/8766 +f 9440/9618/8768 9502/9680/8828 9439/9617/8767 +f 9441/9619/8769 9503/9681/8829 9440/9618/8768 +f 9442/9620/8770 9504/9682/8830 9441/9619/8769 +f 9443/9621/8771 9505/9683/8831 9442/9620/8770 +f 9444/9622/8772 9506/9684/8832 9443/9621/8771 +f 9445/9623/8773 9507/9685/8833 9444/9622/8772 +f 9446/9624/8774 9508/9686/8834 9445/9623/8773 +f 9447/9625/8775 9509/9687/8835 9446/9624/8774 +f 9448/9626/8776 9510/9688/8836 9447/9625/8775 +f 9449/9627/7628 9511/9689/8837 9448/9626/8776 +f 9450/9628/8777 9512/9690/8838 9449/9627/7628 +f 9451/9629/8778 9513/9691/8839 9450/9628/8777 +f 9452/9630/8779 9514/9692/8840 9451/9629/8778 +f 9453/9631/8780 9515/9693/8841 9452/9630/8779 +f 9454/9632/8781 9516/9694/8842 9453/9631/8780 +f 9455/9633/8782 9517/9695/8843 9454/9632/8781 +f 9456/9634/8783 9518/9696/8844 9455/9633/8782 +f 9457/9635/8784 9519/9697/8845 9456/9634/8783 +f 9458/9636/8785 9520/9698/8846 9457/9635/8784 +f 9459/9637/8786 9521/9699/8847 9458/9636/8785 +f 9460/9638/8787 9522/9700/8848 9459/9637/8786 +f 9461/9639/8788 9523/9701/8849 9460/9638/8787 +f 9462/9640/8789 9524/9702/8850 9461/9639/8788 +f 9463/9642/8791 9525/9703/8851 9462/9640/8789 +f 9464/9704/8852 9526/9705/8853 9463/9642/8791 +f 9466/9644/8793 9528/9706/8854 9465/9643/8792 +f 9467/9645/8794 9529/9707/8855 9466/9644/8793 +f 9468/9646/8795 9530/9708/8856 9467/9645/8794 +f 9469/9647/8796 9531/9709/8857 9468/9646/8795 +f 9470/9648/8797 9532/9710/8858 9469/9647/8796 +f 9471/9649/8798 9533/9711/8859 9470/9648/8797 +f 9472/9650/8799 9534/9712/8860 9471/9649/8798 +f 9473/9651/8800 9535/9713/8861 9472/9650/8799 +f 9474/9652/8801 9536/9714/8862 9473/9651/8800 +f 9475/9653/8802 9537/9715/8863 9474/9652/8801 +f 9476/9654/8803 9538/9716/8864 9475/9653/8802 +f 9477/9655/8804 9539/9717/8865 9476/9654/8803 +f 9478/9656/8805 9540/9718/8866 9477/9655/8804 +f 9479/9657/8806 9541/9719/8867 9478/9656/8805 +f 9480/9658/8807 9542/9720/8868 9479/9657/8806 +f 9481/9659/8808 9543/9721/8869 9480/9658/8807 +f 9482/9660/8809 9544/9722/8870 9481/9659/8808 +f 9483/9661/8810 9545/9723/8871 9482/9660/8809 +f 9484/9662/8811 9546/9724/8872 9483/9661/8810 +f 9485/9663/8812 9547/9725/8873 9484/9662/8811 +f 9486/9664/8813 9548/9726/8874 9485/9663/8812 +f 9487/9665/8814 9549/9727/8875 9486/9664/8813 +f 9488/9666/7910 9550/9728/8876 9487/9665/8814 +f 9489/9667/8815 9551/9729/8877 9488/9666/7910 +f 9490/9668/8816 9552/9730/8878 9489/9667/8815 +f 9491/9669/8817 9553/9731/8879 9490/9668/8816 +f 9492/9670/8818 9554/9732/8880 9491/9669/8817 +f 9493/9671/8819 9555/9733/8881 9492/9670/8818 +f 9494/9672/8820 9556/9734/8882 9493/9671/8819 +f 9495/9673/8821 9557/9735/8883 9494/9672/8820 +f 9496/9674/8822 9558/9736/8884 9495/9673/8821 +f 9497/9675/8823 9559/9737/8885 9496/9674/8822 +f 9498/9676/8824 9560/9738/8886 9497/9675/8823 +f 9499/9677/8825 9561/9739/8887 9498/9676/8824 +f 9500/9678/8826 9562/9740/8888 9499/9677/8825 +f 9501/9679/8827 9563/9741/8889 9500/9678/8826 +f 9502/9680/8828 9564/9742/8890 9501/9679/8827 +f 9503/9681/8829 9565/9743/8891 9502/9680/8828 +f 9504/9682/8830 9566/9744/8892 9503/9681/8829 +f 9505/9683/8831 9567/9745/8893 9504/9682/8830 +f 9506/9684/8832 9568/9746/8894 9505/9683/8831 +f 9507/9685/8833 9569/9747/8895 9506/9684/8832 +f 9508/9686/8834 9570/9748/8896 9507/9685/8833 +f 9509/9687/8835 9571/9749/8897 9508/9686/8834 +f 9510/9688/8836 9572/9750/8898 9509/9687/8835 +f 9511/9689/8837 9573/9751/8899 9510/9688/8836 +f 9512/9690/8838 9574/9752/8900 9511/9689/8837 +f 9513/9691/8839 9575/9753/8901 9512/9690/8838 +f 9514/9692/8840 9576/9754/8902 9513/9691/8839 +f 9515/9693/8841 9577/9755/8903 9514/9692/8840 +f 9516/9694/8842 9578/9756/8904 9515/9693/8841 +f 9517/9695/8843 9579/9757/8905 9516/9694/8842 +f 9518/9696/8844 9580/9758/8906 9517/9695/8843 +f 9519/9697/8845 9581/9759/8907 9518/9696/8844 +f 9520/9698/8846 9582/9760/8908 9519/9697/8845 +f 9521/9699/8847 9583/9761/8909 9520/9698/8846 +f 9522/9700/8848 9584/9762/8910 9521/9699/8847 +f 9523/9701/8849 9585/9763/8911 9522/9700/8848 +f 9524/9702/8850 9586/9764/8912 9523/9701/8849 +f 9525/9703/8851 9587/9765/8913 9524/9702/8850 +f 9526/9705/8853 9588/9766/8914 9525/9703/8851 +f 9527/9767/8915 9589/9768/8916 9526/9705/8853 +f 9529/9707/8855 9591/9769/8917 9528/9706/8854 +f 9530/9708/8856 9592/9770/8918 9529/9707/8855 +f 9531/9709/8857 9593/9771/8919 9530/9708/8856 +f 9532/9710/8858 9594/9772/8920 9531/9709/8857 +f 9533/9711/8859 9595/9773/8921 9532/9710/8858 +f 9534/9712/8860 9596/9774/8922 9533/9711/8859 +f 9535/9713/8861 9597/9775/8923 9534/9712/8860 +f 9536/9714/8862 9598/9776/8924 9535/9713/8861 +f 9537/9715/8863 9599/9777/8925 9536/9714/8862 +f 9538/9716/8864 9600/9778/8926 9537/9715/8863 +f 9539/9717/8865 9601/9779/8927 9538/9716/8864 +f 9540/9718/8866 9602/9780/8928 9539/9717/8865 +f 9541/9719/8867 9603/9781/8929 9540/9718/8866 +f 9542/9720/8868 9604/9782/8930 9541/9719/8867 +f 9543/9721/8869 9605/9783/8931 9542/9720/8868 +f 9544/9722/8870 9606/9784/8932 9543/9721/8869 +f 9545/9723/8871 9607/9785/8933 9544/9722/8870 +f 9546/9724/8872 9608/9786/8934 9545/9723/8871 +f 9547/9725/8873 9609/9787/8935 9546/9724/8872 +f 9548/9726/8874 9610/9788/8936 9547/9725/8873 +f 9549/9727/8875 9611/9789/8937 9548/9726/8874 +f 9550/9728/8876 9612/9790/8938 9549/9727/8875 +f 9551/9729/8877 9613/9791/8939 9550/9728/8876 +f 9552/9730/8878 9614/9792/8940 9551/9729/8877 +f 9553/9731/8879 9615/9793/8941 9552/9730/8878 +f 9554/9732/8880 9616/9794/8942 9553/9731/8879 +f 9555/9733/8881 9617/9795/8943 9554/9732/8880 +f 9556/9734/8882 9618/9796/8944 9555/9733/8881 +f 9557/9735/8883 9619/9797/8945 9556/9734/8882 +f 9558/9736/8884 9620/9798/8946 9557/9735/8883 +f 9559/9737/8885 9621/9799/8947 9558/9736/8884 +f 9560/9738/8886 9622/9800/8948 9559/9737/8885 +f 9561/9739/8887 9623/9801/8949 9560/9738/8886 +f 9562/9740/8888 9624/9802/8950 9561/9739/8887 +f 9563/9741/8889 9625/9803/8951 9562/9740/8888 +f 9564/9742/8890 9626/9804/8952 9563/9741/8889 +f 9565/9743/8891 9627/9805/8953 9564/9742/8890 +f 9566/9744/8892 9628/9806/8954 9565/9743/8891 +f 9567/9745/8893 9629/9807/8955 9566/9744/8892 +f 9568/9746/8894 9630/9808/8956 9567/9745/8893 +f 9569/9747/8895 9631/9809/8957 9568/9746/8894 +f 9570/9748/8896 9632/9810/8958 9569/9747/8895 +f 9571/9749/8897 9633/9811/8959 9570/9748/8896 +f 9572/9750/8898 9634/9812/8960 9571/9749/8897 +f 9573/9751/8899 9635/9813/8961 9572/9750/8898 +f 9574/9752/8900 9636/9814/8962 9573/9751/8899 +f 9575/9753/8901 9637/9815/8963 9574/9752/8900 +f 9576/9754/8902 9638/9816/8964 9575/9753/8901 +f 9577/9755/8903 9639/9817/8965 9576/9754/8902 +f 9578/9756/8904 9640/9818/8966 9577/9755/8903 +f 9579/9757/8905 9641/9819/8967 9578/9756/8904 +f 9580/9758/8906 9642/9820/8968 9579/9757/8905 +f 9581/9759/8907 9643/9821/8969 9580/9758/8906 +f 9582/9760/8908 9644/9822/8970 9581/9759/8907 +f 9583/9761/8909 9645/9823/8971 9582/9760/8908 +f 9584/9762/8910 9646/9824/8972 9583/9761/8909 +f 9585/9763/8911 9647/9825/8973 9584/9762/8910 +f 9586/9764/8912 9648/9826/8974 9585/9763/8911 +f 9587/9765/8913 9649/9827/8975 9586/9764/8912 +f 9588/9766/8914 9650/9828/8976 9587/9765/8913 +f 9589/9768/8916 9651/9829/8977 9588/9766/8914 +f 9590/9830/8978 9652/9831/8979 9589/9768/8916 +f 9592/9770/8918 9654/9832/8980 9591/9769/8917 +f 9593/9771/8919 9655/9833/8981 9592/9770/8918 +f 9594/9772/8920 9656/9834/8982 9593/9771/8919 +f 9595/9773/8921 9657/9835/8983 9594/9772/8920 +f 9596/9774/8922 9658/9836/8984 9595/9773/8921 +f 9597/9775/8923 9659/9837/8985 9596/9774/8922 +f 9598/9776/8924 9660/9838/8986 9597/9775/8923 +f 9599/9777/8925 9661/9839/7877 9598/9776/8924 +f 9600/9778/8926 9662/9840/8987 9599/9777/8925 +f 9601/9779/8927 9663/9841/8988 9600/9778/8926 +f 9602/9780/8928 9664/9842/8989 9601/9779/8927 +f 9603/9781/8929 9665/9843/8990 9602/9780/8928 +f 9604/9782/8930 9666/9844/8991 9603/9781/8929 +f 9605/9783/8931 9667/9845/8992 9604/9782/8930 +f 9606/9784/8932 9668/9846/8993 9605/9783/8931 +f 9607/9785/8933 9669/9847/8994 9606/9784/8932 +f 9608/9786/8934 9670/9848/8995 9607/9785/8933 +f 9609/9787/8935 9671/9849/8996 9608/9786/8934 +f 9610/9788/8936 9672/9850/8997 9609/9787/8935 +f 9611/9789/8937 9673/9851/8998 9610/9788/8936 +f 9612/9790/8938 9674/9852/8999 9611/9789/8937 +f 9613/9791/8939 9675/9853/9000 9612/9790/8938 +f 9614/9792/8940 9676/9854/9001 9613/9791/8939 +f 9615/9793/8941 9677/9855/9002 9614/9792/8940 +f 9616/9794/8942 9678/9856/9003 9615/9793/8941 +f 9617/9795/8943 9679/9857/9004 9616/9794/8942 +f 9618/9796/8944 9680/9858/9005 9617/9795/8943 +f 9619/9797/8945 9681/9859/9006 9618/9796/8944 +f 9620/9798/8946 9682/9860/9007 9619/9797/8945 +f 9621/9799/8947 9683/9861/9008 9620/9798/8946 +f 9622/9800/8948 9684/9862/9009 9621/9799/8947 +f 9623/9801/8949 9685/9863/9010 9622/9800/8948 +f 9624/9802/8950 9686/9864/9011 9623/9801/8949 +f 9625/9803/8951 9687/9865/9012 9624/9802/8950 +f 9626/9804/8952 9688/9866/9013 9625/9803/8951 +f 9627/9805/8953 9689/9867/9014 9626/9804/8952 +f 9628/9806/8954 9690/9868/9015 9627/9805/8953 +f 9629/9807/8955 9691/9869/9016 9628/9806/8954 +f 9630/9808/8956 9692/9870/9017 9629/9807/8955 +f 9631/9809/8957 9693/9871/9018 9630/9808/8956 +f 9632/9810/8958 9694/9872/9019 9631/9809/8957 +f 9633/9811/8959 9695/9873/9020 9632/9810/8958 +f 9634/9812/8960 9696/9874/9021 9633/9811/8959 +f 9635/9813/8961 9697/9875/9022 9634/9812/8960 +f 9636/9814/8962 9698/9876/9023 9635/9813/8961 +f 9637/9815/8963 9699/9877/9024 9636/9814/8962 +f 9638/9816/8964 9700/9878/9025 9637/9815/8963 +f 9639/9817/8965 9701/9879/9026 9638/9816/8964 +f 9640/9818/8966 9702/9880/9027 9639/9817/8965 +f 9641/9819/8967 9703/9881/9028 9640/9818/8966 +f 9642/9820/8968 9704/9882/9029 9641/9819/8967 +f 9643/9821/8969 9705/9883/9030 9642/9820/8968 +f 9644/9822/8970 9706/9884/9031 9643/9821/8969 +f 9645/9823/8971 9707/9885/9032 9644/9822/8970 +f 9646/9824/8972 9708/9886/9033 9645/9823/8971 +f 9647/9825/8973 9709/9887/9034 9646/9824/8972 +f 9648/9826/8974 9710/9888/9035 9647/9825/8973 +f 9649/9827/8975 9711/9889/9036 9648/9826/8974 +f 9650/9828/8976 9712/9890/9037 9649/9827/8975 +f 9651/9829/8977 9713/9891/9038 9650/9828/8976 +f 9652/9831/8979 9714/9892/9039 9651/9829/8977 +f 9653/9893/9040 9715/9894/9041 9652/9831/8979 +f 9655/9833/8981 9717/9895/9042 9654/9832/8980 +f 9656/9834/8982 9718/9896/9043 9655/9833/8981 +f 9657/9835/8983 9719/9897/9044 9656/9834/8982 +f 9658/9836/8984 9720/9898/9045 9657/9835/8983 +f 9659/9837/8985 9721/9899/9046 9658/9836/8984 +f 9660/9838/8986 9722/9900/9047 9659/9837/8985 +f 9661/9839/7877 9723/9901/9043 9660/9838/8986 +f 9662/9840/8987 9724/9902/9048 9661/9839/7877 +f 9663/9841/8988 9725/9903/9049 9662/9840/8987 +f 9664/9842/8989 9726/9904/9050 9663/9841/8988 +f 9665/9843/8990 9727/9905/9051 9664/9842/8989 +f 9666/9844/8991 9728/9906/9052 9665/9843/8990 +f 9667/9845/8992 9729/9907/9053 9666/9844/8991 +f 9668/9846/8993 9730/9908/9054 9667/9845/8992 +f 9669/9847/8994 9731/9909/9055 9668/9846/8993 +f 9670/9848/8995 9732/9910/9056 9669/9847/8994 +f 9671/9849/8996 9733/9911/9057 9670/9848/8995 +f 9672/9850/8997 9734/9912/9058 9671/9849/8996 +f 9673/9851/8998 9735/9913/9059 9672/9850/8997 +f 9674/9852/8999 9736/9914/9060 9673/9851/8998 +f 9675/9853/9000 9737/9915/9061 9674/9852/8999 +f 9676/9854/9001 9738/9916/9062 9675/9853/9000 +f 9677/9855/9002 9739/9917/9063 9676/9854/9001 +f 9678/9856/9003 9740/9918/9064 9677/9855/9002 +f 9679/9857/9004 9741/9919/9065 9678/9856/9003 +f 9680/9858/9005 9742/9920/9066 9679/9857/9004 +f 9681/9859/9006 9743/9921/9067 9680/9858/9005 +f 9682/9860/9007 9744/9922/9068 9681/9859/9006 +f 9683/9861/9008 9745/9923/9069 9682/9860/9007 +f 9684/9862/9009 9746/9924/9070 9683/9861/9008 +f 9685/9863/9010 9747/9925/9071 9684/9862/9009 +f 9686/9864/9011 9748/9926/9072 9685/9863/9010 +f 9687/9865/9012 9749/9927/9073 9686/9864/9011 +f 9688/9866/9013 9750/9928/9074 9687/9865/9012 +f 9689/9867/9014 9751/9929/9075 9688/9866/9013 +f 9690/9868/9015 9752/9930/9076 9689/9867/9014 +f 9691/9869/9016 9753/9931/9077 9690/9868/9015 +f 9692/9870/9017 9754/9932/9078 9691/9869/9016 +f 9693/9871/9018 9755/9933/9079 9692/9870/9017 +f 9694/9872/9019 9756/9934/9080 9693/9871/9018 +f 9695/9873/9020 9757/9935/9081 9694/9872/9019 +f 9696/9874/9021 9758/9936/9082 9695/9873/9020 +f 9697/9875/9022 9759/9937/9083 9696/9874/9021 +f 9698/9876/9023 9760/9938/9084 9697/9875/9022 +f 9699/9877/9024 9761/9939/9085 9698/9876/9023 +f 9700/9878/9025 9762/9940/9086 9699/9877/9024 +f 9701/9879/9026 9763/9941/9087 9700/9878/9025 +f 9702/9880/9027 9764/9942/9088 9701/9879/9026 +f 9703/9881/9028 9765/9943/9089 9702/9880/9027 +f 9704/9882/9029 9766/9944/9090 9703/9881/9028 +f 9705/9883/9030 9767/9945/9091 9704/9882/9029 +f 9706/9884/9031 9768/9946/9092 9705/9883/9030 +f 9707/9885/9032 9769/9947/9093 9706/9884/9031 +f 9708/9886/9033 9770/9948/9094 9707/9885/9032 +f 9709/9887/9034 9771/9949/9095 9708/9886/9033 +f 9710/9888/9035 9772/9950/9096 9709/9887/9034 +f 9711/9889/9036 9773/9951/9097 9710/9888/9035 +f 9712/9890/9037 9774/9952/9098 9711/9889/9036 +f 9713/9891/9038 9775/9953/9099 9712/9890/9037 +f 9714/9892/9039 9776/9954/9100 9713/9891/9038 +f 9715/9894/9041 9777/9955/9101 9714/9892/9039 +f 9716/9956/9102 9778/9957/9103 9715/9894/9041 +f 9718/9896/9043 9780/9958/9104 9717/9895/9042 +f 9719/9897/9044 9781/9959/9105 9718/9896/9043 +f 9720/9898/9045 9782/9960/9106 9719/9897/9044 +f 9721/9899/9046 9783/9961/9107 9720/9898/9045 +f 9722/9900/9047 9784/9962/9108 9721/9899/9046 +f 9723/9901/9043 9785/9963/9109 9722/9900/9047 +f 9724/9902/9048 9786/9964/9110 9723/9901/9043 +f 9725/9903/9049 9787/9965/9111 9724/9902/9048 +f 9726/9904/9050 9788/9966/9112 9725/9903/9049 +f 9727/9905/9051 9789/9967/9113 9726/9904/9050 +f 9728/9906/9052 9790/9968/9114 9727/9905/9051 +f 9729/9907/9053 9791/9969/9115 9728/9906/9052 +f 9730/9908/9054 9792/9970/9116 9729/9907/9053 +f 9731/9909/9055 9793/9971/9117 9730/9908/9054 +f 9732/9910/9056 9794/9972/9118 9731/9909/9055 +f 9733/9911/9057 9795/9973/9119 9732/9910/9056 +f 9734/9912/9058 9796/9974/9120 9733/9911/9057 +f 9735/9913/9059 9797/9975/9121 9734/9912/9058 +f 9736/9914/9060 9798/9976/9122 9735/9913/9059 +f 9737/9915/9061 9799/9977/9123 9736/9914/9060 +f 9738/9916/9062 9800/9978/9124 9737/9915/9061 +f 9739/9917/9063 9801/9979/9125 9738/9916/9062 +f 9740/9918/9064 9802/9980/9126 9739/9917/9063 +f 9741/9919/9065 9803/9981/9127 9740/9918/9064 +f 9742/9920/9066 9804/9982/9128 9741/9919/9065 +f 9743/9921/9067 9805/9983/9129 9742/9920/9066 +f 9744/9922/9068 9806/9984/9130 9743/9921/9067 +f 9745/9923/9069 9807/9985/9131 9744/9922/9068 +f 9746/9924/9070 9808/9986/9132 9745/9923/9069 +f 9747/9925/9071 9809/9987/9133 9746/9924/9070 +f 9748/9926/9072 9810/9988/9134 9747/9925/9071 +f 9749/9927/9073 9811/9989/9135 9748/9926/9072 +f 9750/9928/9074 9812/9990/9136 9749/9927/9073 +f 9751/9929/9075 9813/9991/9137 9750/9928/9074 +f 9752/9930/9076 9814/9992/9138 9751/9929/9075 +f 9753/9931/9077 9815/9993/9139 9752/9930/9076 +f 9754/9932/9078 9816/9994/9140 9753/9931/9077 +f 9755/9933/9079 9817/9995/9141 9754/9932/9078 +f 9756/9934/9080 9818/9996/9142 9755/9933/9079 +f 9757/9935/9081 9819/9997/9143 9756/9934/9080 +f 9758/9936/9082 9820/9998/9144 9757/9935/9081 +f 9759/9937/9083 9821/9999/9145 9758/9936/9082 +f 9760/9938/9084 9822/10000/9146 9759/9937/9083 +f 9761/9939/9085 9823/10001/9147 9760/9938/9084 +f 9762/9940/9086 9824/10002/9148 9761/9939/9085 +f 9763/9941/9087 9825/10003/9149 9762/9940/9086 +f 9764/9942/9088 9826/10004/9150 9763/9941/9087 +f 9765/9943/9089 9827/10005/9151 9764/9942/9088 +f 9766/9944/9090 9828/10006/9152 9765/9943/9089 +f 9767/9945/9091 9829/10007/9153 9766/9944/9090 +f 9768/9946/9092 9830/10008/9154 9767/9945/9091 +f 9769/9947/9093 9831/10009/9155 9768/9946/9092 +f 9770/9948/9094 9832/10010/9156 9769/9947/9093 +f 9771/9949/9095 9833/10011/9157 9770/9948/9094 +f 9772/9950/9096 9834/10012/9158 9771/9949/9095 +f 9773/9951/9097 9835/10013/9159 9772/9950/9096 +f 9774/9952/9098 9836/10014/9160 9773/9951/9097 +f 9775/9953/9099 9837/10015/9161 9774/9952/9098 +f 9776/9954/9100 9838/10016/9162 9775/9953/9099 +f 9777/9955/9101 9839/10017/9163 9776/9954/9100 +f 9778/9957/9103 9840/10018/9164 9777/9955/9101 +f 9779/10019/9165 9841/10020/9166 9778/9957/9103 +f 9781/9959/9105 9843/10021/9167 9780/9958/9104 +f 9782/9960/9106 9844/10022/9168 9781/9959/9105 +f 9783/9961/9107 9845/10023/9169 9782/9960/9106 +f 9784/9962/9108 9846/10024/9170 9783/9961/9107 +f 9785/9963/9109 9847/10025/9171 9784/9962/9108 +f 9786/9964/9110 9848/10026/9172 9785/9963/9109 +f 9787/9965/9111 9849/10027/9173 9786/9964/9110 +f 9788/9966/9112 9850/10028/9174 9787/9965/9111 +f 9789/9967/9113 9851/10029/9175 9788/9966/9112 +f 9790/9968/9114 9852/10030/9176 9789/9967/9113 +f 9791/9969/9115 9853/10031/9177 9790/9968/9114 +f 9792/9970/9116 9854/10032/9178 9791/9969/9115 +f 9793/9971/9117 9855/10033/9179 9792/9970/9116 +f 9794/9972/9118 9856/10034/9180 9793/9971/9117 +f 9795/9973/9119 9857/10035/9181 9794/9972/9118 +f 9796/9974/9120 9858/10036/9182 9795/9973/9119 +f 9797/9975/9121 9859/10037/9183 9796/9974/9120 +f 9798/9976/9122 9860/10038/9184 9797/9975/9121 +f 9799/9977/9123 9861/10039/9185 9798/9976/9122 +f 9800/9978/9124 9862/10040/9186 9799/9977/9123 +f 9801/9979/9125 9863/10041/9187 9800/9978/9124 +f 9802/9980/9126 9864/10042/9188 9801/9979/9125 +f 9803/9981/9127 9865/10043/9189 9802/9980/9126 +f 9804/9982/9128 9866/10044/9190 9803/9981/9127 +f 9805/9983/9129 9867/10045/9191 9804/9982/9128 +f 9806/9984/9130 9868/10046/9192 9805/9983/9129 +f 9807/9985/9131 9869/10047/9193 9806/9984/9130 +f 9808/9986/9132 9870/10048/9194 9807/9985/9131 +f 9809/9987/9133 9871/10049/9195 9808/9986/9132 +f 9810/9988/9134 9872/10050/9196 9809/9987/9133 +f 9811/9989/9135 9873/10051/9197 9810/9988/9134 +f 9812/9990/9136 9874/10052/9198 9811/9989/9135 +f 9813/9991/9137 9875/10053/9199 9812/9990/9136 +f 9814/9992/9138 9876/10054/9200 9813/9991/9137 +f 9815/9993/9139 9877/10055/9201 9814/9992/9138 +f 9816/9994/9140 9878/10056/9202 9815/9993/9139 +f 9817/9995/9141 9879/10057/9203 9816/9994/9140 +f 9818/9996/9142 9880/10058/9204 9817/9995/9141 +f 9819/9997/9143 9881/10059/9205 9818/9996/9142 +f 9820/9998/9144 9882/10060/9206 9819/9997/9143 +f 9821/9999/9145 9883/10061/9207 9820/9998/9144 +f 9822/10000/9146 9884/10062/9208 9821/9999/9145 +f 9823/10001/9147 9885/10063/9209 9822/10000/9146 +f 9824/10002/9148 9886/10064/9210 9823/10001/9147 +f 9825/10003/9149 9887/10065/9211 9824/10002/9148 +f 9826/10004/9150 9888/10066/9212 9825/10003/9149 +f 9827/10005/9151 9889/10067/9213 9826/10004/9150 +f 9828/10006/9152 9890/10068/9214 9827/10005/9151 +f 9829/10007/9153 9891/10069/9215 9828/10006/9152 +f 9830/10008/9154 9892/10070/9216 9829/10007/9153 +f 9831/10009/9155 9893/10071/9217 9830/10008/9154 +f 9832/10010/9156 9894/10072/9218 9831/10009/9155 +f 9833/10011/9157 9895/10073/9219 9832/10010/9156 +f 9834/10012/9158 9896/10074/9220 9833/10011/9157 +f 9835/10013/9159 9897/10075/9221 9834/10012/9158 +f 9836/10014/9160 9898/10076/9222 9835/10013/9159 +f 9837/10015/9161 9899/10077/9223 9836/10014/9160 +f 9838/10016/9162 9900/10078/9224 9837/10015/9161 +f 9839/10017/9163 9901/10079/9225 9838/10016/9162 +f 9840/10018/9164 9902/10080/9226 9839/10017/9163 +f 9841/10020/9166 9903/10081/9227 9840/10018/9164 +f 9842/10082/9228 9904/10083/9229 9841/10020/9166 +f 9844/10022/9168 9906/10084/9230 9843/10021/9167 +f 9845/10023/9169 9907/10085/9231 9844/10022/9168 +f 9846/10024/9170 9908/10086/9232 9845/10023/9169 +f 9847/10025/9171 9909/10087/9233 9846/10024/9170 +f 9848/10026/9172 9910/10088/9234 9847/10025/9171 +f 9849/10027/9173 9911/10089/9235 9848/10026/9172 +f 9850/10028/9174 9912/10090/9236 9849/10027/9173 +f 9851/10029/9175 9913/10091/9237 9850/10028/9174 +f 9852/10030/9176 9914/10092/9238 9851/10029/9175 +f 9853/10031/9177 9915/10093/9239 9852/10030/9176 +f 9854/10032/9178 9916/10094/9240 9853/10031/9177 +f 9855/10033/9179 9917/10095/9241 9854/10032/9178 +f 9856/10034/9180 9918/10096/9242 9855/10033/9179 +f 9857/10035/9181 9919/10097/9243 9856/10034/9180 +f 9858/10036/9182 9920/10098/9244 9857/10035/9181 +f 9859/10037/9183 9921/10099/9245 9858/10036/9182 +f 9860/10038/9184 9922/10100/9246 9859/10037/9183 +f 9861/10039/9185 9923/10101/9247 9860/10038/9184 +f 9862/10040/9186 9924/10102/9248 9861/10039/9185 +f 9863/10041/9187 9925/10103/9249 9862/10040/9186 +f 9864/10042/9188 9926/10104/9250 9863/10041/9187 +f 9865/10043/9189 9927/10105/9251 9864/10042/9188 +f 9866/10044/9190 9928/10106/9252 9865/10043/9189 +f 9867/10045/9191 9929/10107/9253 9866/10044/9190 +f 9868/10046/9192 9930/10108/9254 9867/10045/9191 +f 9869/10047/9193 9931/10109/9255 9868/10046/9192 +f 9870/10048/9194 9932/10110/9256 9869/10047/9193 +f 9871/10049/9195 9933/10111/9257 9870/10048/9194 +f 9872/10050/9196 9934/10112/9258 9871/10049/9195 +f 9873/10051/9197 9935/10113/9259 9872/10050/9196 +f 9874/10052/9198 9936/10114/9260 9873/10051/9197 +f 9875/10053/9199 9937/10115/9261 9874/10052/9198 +f 9876/10054/9200 9938/10116/9262 9875/10053/9199 +f 9877/10055/9201 9939/10117/9263 9876/10054/9200 +f 9878/10056/9202 9940/10118/9264 9877/10055/9201 +f 9879/10057/9203 9941/10119/9265 9878/10056/9202 +f 9880/10058/9204 9942/10120/9266 9879/10057/9203 +f 9881/10059/9205 9943/10121/9267 9880/10058/9204 +f 9882/10060/9206 9944/10122/9268 9881/10059/9205 +f 9883/10061/9207 9945/10123/9269 9882/10060/9206 +f 9884/10062/9208 9946/10124/9270 9883/10061/9207 +f 9885/10063/9209 9947/10125/9271 9884/10062/9208 +f 9886/10064/9210 9948/10126/9272 9885/10063/9209 +f 9887/10065/9211 9949/10127/9273 9886/10064/9210 +f 9888/10066/9212 9950/10128/9274 9887/10065/9211 +f 9889/10067/9213 9951/10129/9275 9888/10066/9212 +f 9890/10068/9214 9952/10130/9276 9889/10067/9213 +f 9891/10069/9215 9953/10131/9277 9890/10068/9214 +f 9892/10070/9216 9954/10132/9278 9891/10069/9215 +f 9893/10071/9217 9955/10133/9279 9892/10070/9216 +f 9894/10072/9218 9956/10134/9280 9893/10071/9217 +f 9895/10073/9219 9957/10135/9281 9894/10072/9218 +f 9896/10074/9220 9958/10136/9282 9895/10073/9219 +f 9897/10075/9221 9959/10137/9283 9896/10074/9220 +f 9898/10076/9222 9960/10138/9284 9897/10075/9221 +f 9899/10077/9223 9961/10139/9285 9898/10076/9222 +f 9900/10078/9224 9962/10140/9286 9899/10077/9223 +f 9901/10079/9225 9963/10141/9287 9900/10078/9224 +f 9902/10080/9226 9964/10142/9288 9901/10079/9225 +f 9903/10081/9227 9965/10143/9289 9902/10080/9226 +f 9904/10083/9229 9966/10144/9290 9903/10081/9227 +f 9905/10145/9291 9967/10146/9292 9904/10083/9229 +f 9907/10085/9231 9969/10147/9293 9906/10084/9230 +f 9908/10086/9232 9970/10148/9294 9907/10085/9231 +f 9909/10087/9233 9971/10149/9295 9908/10086/9232 +f 9910/10088/9234 9972/10150/9296 9909/10087/9233 +f 9911/10089/9235 9973/10151/9297 9910/10088/9234 +f 9912/10090/9236 9974/10152/9298 9911/10089/9235 +f 9913/10091/9237 9975/10153/9299 9912/10090/9236 +f 9914/10092/9238 9976/10154/9300 9913/10091/9237 +f 9915/10093/9239 9977/10155/9301 9914/10092/9238 +f 9916/10094/9240 9978/10156/9302 9915/10093/9239 +f 9917/10095/9241 9979/10157/9303 9916/10094/9240 +f 9918/10096/9242 9980/10158/9304 9917/10095/9241 +f 9919/10097/9243 9981/10159/9305 9918/10096/9242 +f 9920/10098/9244 9982/10160/9306 9919/10097/9243 +f 9921/10099/9245 9983/10161/9307 9920/10098/9244 +f 9922/10100/9246 9984/10162/9308 9921/10099/9245 +f 9923/10101/9247 9985/10163/9309 9922/10100/9246 +f 9924/10102/9248 9986/10164/9310 9923/10101/9247 +f 9925/10103/9249 9987/10165/9311 9924/10102/9248 +f 9926/10104/9250 9988/10166/9312 9925/10103/9249 +f 9927/10105/9251 9989/10167/9313 9926/10104/9250 +f 9928/10106/9252 9990/10168/9314 9927/10105/9251 +f 9929/10107/9253 9991/10169/9315 9928/10106/9252 +f 9930/10108/9254 9992/10170/9316 9929/10107/9253 +f 9931/10109/9255 9993/10171/9317 9930/10108/9254 +f 9932/10110/9256 9994/10172/9318 9931/10109/9255 +f 9933/10111/9257 9995/10173/9319 9932/10110/9256 +f 9934/10112/9258 9996/10174/9320 9933/10111/9257 +f 9935/10113/9259 9997/10175/9321 9934/10112/9258 +f 9936/10114/9260 9998/10176/9322 9935/10113/9259 +f 9937/10115/9261 9999/10177/9323 9936/10114/9260 +f 9938/10116/9262 10000/10178/9324 9937/10115/9261 +f 9939/10117/9263 10001/10179/9325 9938/10116/9262 +f 9940/10118/9264 10002/10180/9326 9939/10117/9263 +f 9941/10119/9265 10003/10181/9327 9940/10118/9264 +f 9942/10120/9266 10004/10182/9328 9941/10119/9265 +f 9943/10121/9267 10005/10183/9329 9942/10120/9266 +f 9944/10122/9268 10006/10184/9330 9943/10121/9267 +f 9945/10123/9269 10007/10185/9331 9944/10122/9268 +f 9946/10124/9270 10008/10186/9332 9945/10123/9269 +f 9947/10125/9271 10009/10187/9333 9946/10124/9270 +f 9948/10126/9272 10010/10188/9334 9947/10125/9271 +f 9949/10127/9273 10011/10189/9335 9948/10126/9272 +f 9950/10128/9274 10012/10190/9336 9949/10127/9273 +f 9951/10129/9275 10013/10191/9337 9950/10128/9274 +f 9952/10130/9276 10014/10192/9338 9951/10129/9275 +f 9953/10131/9277 10015/10193/9339 9952/10130/9276 +f 9954/10132/9278 10016/10194/9340 9953/10131/9277 +f 9955/10133/9279 10017/10195/9341 9954/10132/9278 +f 9956/10134/9280 10018/10196/9342 9955/10133/9279 +f 9957/10135/9281 10019/10197/9343 9956/10134/9280 +f 9958/10136/9282 10020/10198/9344 9957/10135/9281 +f 9959/10137/9283 10021/10199/9345 9958/10136/9282 +f 9960/10138/9284 10022/10200/9346 9959/10137/9283 +f 9961/10139/9285 10023/10201/9347 9960/10138/9284 +f 9962/10140/9286 10024/10202/9348 9961/10139/9285 +f 9963/10141/9287 10025/10203/9349 9962/10140/9286 +f 9964/10142/9288 10026/10204/9350 9963/10141/9287 +f 9965/10143/9289 10027/10205/9351 9964/10142/9288 +f 9966/10144/9290 10028/10206/9352 9965/10143/9289 +f 9967/10146/9292 10029/10207/9353 9966/10144/9290 +f 9968/10208/9354 10030/10209/9355 9967/10146/9292 +f 9970/10148/9294 10032/10210/9356 9969/10147/9293 +f 9971/10149/9295 10033/10211/9357 9970/10148/9294 +f 9972/10150/9296 10034/10212/9358 9971/10149/9295 +f 9973/10151/9297 10035/10213/9359 9972/10150/9296 +f 9974/10152/9298 10036/10214/9360 9973/10151/9297 +f 9975/10153/9299 10037/10215/9361 9974/10152/9298 +f 9976/10154/9300 10038/10216/9362 9975/10153/9299 +f 9977/10155/9301 10039/10217/9363 9976/10154/9300 +f 9978/10156/9302 10040/10218/9364 9977/10155/9301 +f 9979/10157/9303 10041/10219/9365 9978/10156/9302 +f 9980/10158/9304 10042/10220/9366 9979/10157/9303 +f 9981/10159/9305 10043/10221/9367 9980/10158/9304 +f 9982/10160/9306 10044/10222/9368 9981/10159/9305 +f 9983/10161/9307 10045/10223/9369 9982/10160/9306 +f 9984/10162/9308 10046/10224/9370 9983/10161/9307 +f 9985/10163/9309 10047/10225/9371 9984/10162/9308 +f 9986/10164/9310 10048/10226/9372 9985/10163/9309 +f 9987/10165/9311 10049/10227/9373 9986/10164/9310 +f 9988/10166/9312 10050/10228/9374 9987/10165/9311 +f 9989/10167/9313 10051/10229/9375 9988/10166/9312 +f 9990/10168/9314 10052/10230/9376 9989/10167/9313 +f 9991/10169/9315 10053/10231/9377 9990/10168/9314 +f 9992/10170/9316 10054/10232/9378 9991/10169/9315 +f 9993/10171/9317 10055/10233/9379 9992/10170/9316 +f 9994/10172/9318 10056/10234/9380 9993/10171/9317 +f 9995/10173/9319 10057/10235/9381 9994/10172/9318 +f 9996/10174/9320 10058/10236/9382 9995/10173/9319 +f 9997/10175/9321 10059/10237/9383 9996/10174/9320 +f 9998/10176/9322 10060/10238/9384 9997/10175/9321 +f 9999/10177/9323 10061/10239/9385 9998/10176/9322 +f 10000/10178/9324 10062/10240/9386 9999/10177/9323 +f 10001/10179/9325 10063/10241/9387 10000/10178/9324 +f 10002/10180/9326 10064/10242/9388 10001/10179/9325 +f 10003/10181/9327 10065/10243/9389 10002/10180/9326 +f 10004/10182/9328 10066/10244/9390 10003/10181/9327 +f 10005/10183/9329 10067/10245/9391 10004/10182/9328 +f 10006/10184/9330 10068/10246/9392 10005/10183/9329 +f 10007/10185/9331 10069/10247/9393 10006/10184/9330 +f 10008/10186/9332 10070/10248/9394 10007/10185/9331 +f 10009/10187/9333 10071/10249/9395 10008/10186/9332 +f 10010/10188/9334 10072/10250/9396 10009/10187/9333 +f 10011/10189/9335 10073/10251/9397 10010/10188/9334 +f 10012/10190/9336 10074/10252/9398 10011/10189/9335 +f 10013/10191/9337 10075/10253/9399 10012/10190/9336 +f 10014/10192/9338 10076/10254/9400 10013/10191/9337 +f 10015/10193/9339 10077/10255/9401 10014/10192/9338 +f 10016/10194/9340 10078/10256/9402 10015/10193/9339 +f 10017/10195/9341 10079/10257/9403 10016/10194/9340 +f 10018/10196/9342 10080/10258/9404 10017/10195/9341 +f 10019/10197/9343 10081/10259/9405 10018/10196/9342 +f 10020/10198/9344 10082/10260/9406 10019/10197/9343 +f 10021/10199/9345 10083/10261/9407 10020/10198/9344 +f 10022/10200/9346 10084/10262/9408 10021/10199/9345 +f 10023/10201/9347 10085/10263/9409 10022/10200/9346 +f 10024/10202/9348 10086/10264/9410 10023/10201/9347 +f 10025/10203/9349 10087/10265/9411 10024/10202/9348 +f 10026/10204/9350 10088/10266/9412 10025/10203/9349 +f 10027/10205/9351 10089/10267/9413 10026/10204/9350 +f 10028/10206/9352 10090/10268/9414 10027/10205/9351 +f 10029/10207/9353 10091/10269/9415 10028/10206/9352 +f 10030/10209/9355 10092/10270/9416 10029/10207/9353 +f 10031/10271/9417 10093/10272/9418 10030/10209/9355 +f 10033/10211/9357 10095/10273/9419 10032/10210/9356 +f 10034/10212/9358 10096/10274/9420 10033/10211/9357 +f 10035/10213/9359 10097/10275/9421 10034/10212/9358 +f 10036/10214/9360 10098/10276/9422 10035/10213/9359 +f 10037/10215/9361 10099/10277/9423 10036/10214/9360 +f 10038/10216/9362 10100/10278/9424 10037/10215/9361 +f 10039/10217/9363 10101/10279/9425 10038/10216/9362 +f 10040/10218/9364 10102/10280/9426 10039/10217/9363 +f 10041/10219/9365 10103/10281/9427 10040/10218/9364 +f 10042/10220/9366 10104/10282/9428 10041/10219/9365 +f 10043/10221/9367 10105/10283/9429 10042/10220/9366 +f 10044/10222/9368 10106/10284/9430 10043/10221/9367 +f 10045/10223/9369 10107/10285/9431 10044/10222/9368 +f 10046/10224/9370 10108/10286/9432 10045/10223/9369 +f 10047/10225/9371 10109/10287/9433 10046/10224/9370 +f 10048/10226/9372 10110/10288/9434 10047/10225/9371 +f 10049/10227/9373 10111/10289/9435 10048/10226/9372 +f 10050/10228/9374 10112/10290/9436 10049/10227/9373 +f 10051/10229/9375 10113/10291/9437 10050/10228/9374 +f 10052/10230/9376 10114/10292/9438 10051/10229/9375 +f 10053/10231/9377 10115/10293/9439 10052/10230/9376 +f 10054/10232/9378 10116/10294/9440 10053/10231/9377 +f 10055/10233/9379 10117/10295/9441 10054/10232/9378 +f 10056/10234/9380 10118/10296/9442 10055/10233/9379 +f 10057/10235/9381 10119/10297/9443 10056/10234/9380 +f 10058/10236/9382 10120/10298/9444 10057/10235/9381 +f 10059/10237/9383 10121/10299/9445 10058/10236/9382 +f 10060/10238/9384 10122/10300/9446 10059/10237/9383 +f 10061/10239/9385 10123/10301/9447 10060/10238/9384 +f 10062/10240/9386 10124/10302/9448 10061/10239/9385 +f 10063/10241/9387 10125/10303/9449 10062/10240/9386 +f 10064/10242/9388 10126/10304/9450 10063/10241/9387 +f 10065/10243/9389 10127/10305/9451 10064/10242/9388 +f 10066/10244/9390 10128/10306/9452 10065/10243/9389 +f 10067/10245/9391 10129/10307/9453 10066/10244/9390 +f 10068/10246/9392 10130/10308/9454 10067/10245/9391 +f 10069/10247/9393 10131/10309/9455 10068/10246/9392 +f 10070/10248/9394 10132/10310/9456 10069/10247/9393 +f 10071/10249/9395 10133/10311/9457 10070/10248/9394 +f 10072/10250/9396 10134/10312/9458 10071/10249/9395 +f 10073/10251/9397 10135/10313/9459 10072/10250/9396 +f 10074/10252/9398 10136/10314/9460 10073/10251/9397 +f 10075/10253/9399 10137/10315/9461 10074/10252/9398 +f 10076/10254/9400 10138/10316/9462 10075/10253/9399 +f 10077/10255/9401 10139/10317/9463 10076/10254/9400 +f 10078/10256/9402 10140/10318/9464 10077/10255/9401 +f 10079/10257/9403 10141/10319/9465 10078/10256/9402 +f 10080/10258/9404 10142/10320/9466 10079/10257/9403 +f 10081/10259/9405 10143/10321/9467 10080/10258/9404 +f 10082/10260/9406 10144/10322/9468 10081/10259/9405 +f 10083/10261/9407 10145/10323/9469 10082/10260/9406 +f 10084/10262/9408 10146/10324/9470 10083/10261/9407 +f 10085/10263/9409 10147/10325/9471 10084/10262/9408 +f 10086/10264/9410 10148/10326/9472 10085/10263/9409 +f 10087/10265/9411 10149/10327/9473 10086/10264/9410 +f 10088/10266/9412 10150/10328/9474 10087/10265/9411 +f 10089/10267/9413 10151/10329/9475 10088/10266/9412 +f 10090/10268/9414 10152/10330/9476 10089/10267/9413 +f 10091/10269/9415 10153/10331/9477 10090/10268/9414 +f 10092/10270/9416 10154/10332/9478 10091/10269/9415 +f 10093/10272/9418 10155/10333/9479 10092/10270/9416 +f 10094/10334/9480 10156/10335/9481 10093/10272/9418 +f 10096/10274/9420 10158/10336/9482 10095/10273/9419 +f 10097/10275/9421 10159/10337/9483 10096/10274/9420 +f 10098/10276/9422 10160/10338/9484 10097/10275/9421 +f 10099/10277/9423 10161/10339/9485 10098/10276/9422 +f 10100/10278/9424 10162/10340/9486 10099/10277/9423 +f 10101/10279/9425 10163/10341/9487 10100/10278/9424 +f 10102/10280/9426 10164/10342/9488 10101/10279/9425 +f 10103/10281/9427 10165/10343/9489 10102/10280/9426 +f 10104/10282/9428 10166/10344/9490 10103/10281/9427 +f 10105/10283/9429 10167/10345/9491 10104/10282/9428 +f 10106/10284/9430 10168/10346/9492 10105/10283/9429 +f 10107/10285/9431 10169/10347/9493 10106/10284/9430 +f 10108/10286/9432 10170/10348/9494 10107/10285/9431 +f 10109/10287/9433 10171/10349/9495 10108/10286/9432 +f 10110/10288/9434 10172/10350/9496 10109/10287/9433 +f 10111/10289/9435 10173/10351/9497 10110/10288/9434 +f 10112/10290/9436 10174/10352/9498 10111/10289/9435 +f 10113/10291/9437 10175/10353/9499 10112/10290/9436 +f 10114/10292/9438 10176/10354/9500 10113/10291/9437 +f 10115/10293/9439 10177/10355/9501 10114/10292/9438 +f 10116/10294/9440 10178/10356/9502 10115/10293/9439 +f 10117/10295/9441 10179/10357/9503 10116/10294/9440 +f 10118/10296/9442 10180/10358/9504 10117/10295/9441 +f 10119/10297/9443 10181/10359/9505 10118/10296/9442 +f 10120/10298/9444 10182/10360/9506 10119/10297/9443 +f 10121/10299/9445 10183/10361/9507 10120/10298/9444 +f 10122/10300/9446 10184/10362/9508 10121/10299/9445 +f 10123/10301/9447 10185/10363/9509 10122/10300/9446 +f 10124/10302/9448 10186/10364/9510 10123/10301/9447 +f 10125/10303/9449 10187/10365/9511 10124/10302/9448 +f 10126/10304/9450 10188/10366/9512 10125/10303/9449 +f 10127/10305/9451 10189/10367/9513 10126/10304/9450 +f 10128/10306/9452 10190/10368/9514 10127/10305/9451 +f 10129/10307/9453 10191/10369/9515 10128/10306/9452 +f 10130/10308/9454 10192/10370/9516 10129/10307/9453 +f 10131/10309/9455 10193/10371/9517 10130/10308/9454 +f 10132/10310/9456 10194/10372/9518 10131/10309/9455 +f 10133/10311/9457 10195/10373/9519 10132/10310/9456 +f 10134/10312/9458 10196/10374/9520 10133/10311/9457 +f 10135/10313/9459 10197/10375/9521 10134/10312/9458 +f 10136/10314/9460 10198/10376/9522 10135/10313/9459 +f 10137/10315/9461 10199/10377/9523 10136/10314/9460 +f 10138/10316/9462 10200/10378/9524 10137/10315/9461 +f 10139/10317/9463 10201/10379/9525 10138/10316/9462 +f 10140/10318/9464 10202/10380/9526 10139/10317/9463 +f 10141/10319/9465 10203/10381/9527 10140/10318/9464 +f 10142/10320/9466 10204/10382/9528 10141/10319/9465 +f 10143/10321/9467 10205/10383/9529 10142/10320/9466 +f 10144/10322/9468 10206/10384/9530 10143/10321/9467 +f 10145/10323/9469 10207/10385/9531 10144/10322/9468 +f 10146/10324/9470 10208/10386/9532 10145/10323/9469 +f 10147/10325/9471 10209/10387/9533 10146/10324/9470 +f 10148/10326/9472 10210/10388/9534 10147/10325/9471 +f 10149/10327/9473 10211/10389/9535 10148/10326/9472 +f 10150/10328/9474 10212/10390/9536 10149/10327/9473 +f 10151/10329/9475 10213/10391/9537 10150/10328/9474 +f 10152/10330/9476 10214/10392/9538 10151/10329/9475 +f 10153/10331/9477 10215/10393/9539 10152/10330/9476 +f 10154/10332/9478 10216/10394/9540 10153/10331/9477 +f 10155/10333/9479 10217/10395/9541 10154/10332/9478 +f 10156/10335/9481 10218/10396/9542 10155/10333/9479 +f 10157/10397/9543 10219/10398/9544 10156/10335/9481 +f 10159/10337/9483 10221/10399/9545 10158/10336/9482 +f 10160/10338/9484 10222/10400/9546 10159/10337/9483 +f 10161/10339/9485 10223/10401/9547 10160/10338/9484 +f 10162/10340/9486 10224/10402/9548 10161/10339/9485 +f 10163/10341/9487 10225/10403/9549 10162/10340/9486 +f 10164/10342/9488 10226/10404/9550 10163/10341/9487 +f 10165/10343/9489 10227/10405/9551 10164/10342/9488 +f 10166/10344/9490 10228/10406/9552 10165/10343/9489 +f 10167/10345/9491 10229/10407/9553 10166/10344/9490 +f 10168/10346/9492 10230/10408/9554 10167/10345/9491 +f 10169/10347/9493 10231/10409/9555 10168/10346/9492 +f 10170/10348/9494 10232/10410/9556 10169/10347/9493 +f 10171/10349/9495 10233/10411/9557 10170/10348/9494 +f 10172/10350/9496 10234/10412/9558 10171/10349/9495 +f 10173/10351/9497 10235/10413/9559 10172/10350/9496 +f 10174/10352/9498 10236/10414/9560 10173/10351/9497 +f 10175/10353/9499 10237/10415/9561 10174/10352/9498 +f 10176/10354/9500 10238/10416/9562 10175/10353/9499 +f 10177/10355/9501 10239/10417/9563 10176/10354/9500 +f 10178/10356/9502 10240/10418/9564 10177/10355/9501 +f 10179/10357/9503 10241/10419/9565 10178/10356/9502 +f 10180/10358/9504 10242/10420/9566 10179/10357/9503 +f 10181/10359/9505 10243/10421/9567 10180/10358/9504 +f 10182/10360/9506 10244/10422/9568 10181/10359/9505 +f 10183/10361/9507 10245/10423/9569 10182/10360/9506 +f 10184/10362/9508 10246/10424/9570 10183/10361/9507 +f 10185/10363/9509 10247/10425/9571 10184/10362/9508 +f 10186/10364/9510 10248/10426/9572 10185/10363/9509 +f 10187/10365/9511 10249/10427/9573 10186/10364/9510 +f 10188/10366/9512 10250/10428/9574 10187/10365/9511 +f 10189/10367/9513 10251/10429/9575 10188/10366/9512 +f 10190/10368/9514 10252/10430/9576 10189/10367/9513 +f 10191/10369/9515 10253/10431/9577 10190/10368/9514 +f 10192/10370/9516 10254/10432/9578 10191/10369/9515 +f 10193/10371/9517 10255/10433/9579 10192/10370/9516 +f 10194/10372/9518 10256/10434/9580 10193/10371/9517 +f 10195/10373/9519 10257/10435/9581 10194/10372/9518 +f 10196/10374/9520 10258/10436/9582 10195/10373/9519 +f 10197/10375/9521 10259/10437/9583 10196/10374/9520 +f 10198/10376/9522 10260/10438/9584 10197/10375/9521 +f 10199/10377/9523 10261/10439/9585 10198/10376/9522 +f 10200/10378/9524 10262/10440/9586 10199/10377/9523 +f 10201/10379/9525 10263/10441/9587 10200/10378/9524 +f 10202/10380/9526 10264/10442/9588 10201/10379/9525 +f 10203/10381/9527 10265/10443/9589 10202/10380/9526 +f 10204/10382/9528 10266/10444/9590 10203/10381/9527 +f 10205/10383/9529 10267/10445/9591 10204/10382/9528 +f 10206/10384/9530 10268/10446/9592 10205/10383/9529 +f 10207/10385/9531 10269/10447/9593 10206/10384/9530 +f 10208/10386/9532 10270/10448/9594 10207/10385/9531 +f 10209/10387/9533 10271/10449/9595 10208/10386/9532 +f 10210/10388/9534 10272/10450/9596 10209/10387/9533 +f 10211/10389/9535 10273/10451/9597 10210/10388/9534 +f 10212/10390/9536 10274/10452/9598 10211/10389/9535 +f 10213/10391/9537 10275/10453/9599 10212/10390/9536 +f 10214/10392/9538 10276/10454/9600 10213/10391/9537 +f 10215/10393/9539 10277/10455/9601 10214/10392/9538 +f 10216/10394/9540 10278/10456/9602 10215/10393/9539 +f 10217/10395/9541 10279/10457/9603 10216/10394/9540 +f 10218/10396/9542 10280/10458/9604 10217/10395/9541 +f 10219/10398/9544 10281/10459/9605 10218/10396/9542 +f 10220/10460/9606 10282/10461/9607 10219/10398/9544 +f 10222/10400/9546 10284/10462/9608 10221/10399/9545 +f 10223/10401/9547 10285/10463/9609 10222/10400/9546 +f 10224/10402/9548 10286/10464/9610 10223/10401/9547 +f 10225/10403/9549 10287/10465/9611 10224/10402/9548 +f 10226/10404/9550 10288/10466/9612 10225/10403/9549 +f 10227/10405/9551 10289/10467/9613 10226/10404/9550 +f 10228/10406/9552 10290/10468/9614 10227/10405/9551 +f 10229/10407/9553 10291/10469/9615 10228/10406/9552 +f 10230/10408/9554 10292/10470/9616 10229/10407/9553 +f 10231/10409/9555 10293/10471/9617 10230/10408/9554 +f 10232/10410/9556 10294/10472/9618 10231/10409/9555 +f 10233/10411/9557 10295/10473/9619 10232/10410/9556 +f 10234/10412/9558 10296/10474/9620 10233/10411/9557 +f 10235/10413/9559 10297/10475/9621 10234/10412/9558 +f 10236/10414/9560 10298/10476/9622 10235/10413/9559 +f 10237/10415/9561 10299/10477/9623 10236/10414/9560 +f 10238/10416/9562 10300/10478/9624 10237/10415/9561 +f 10239/10417/9563 10301/10479/9625 10238/10416/9562 +f 10240/10418/9564 10302/10480/9626 10239/10417/9563 +f 10241/10419/9565 10303/10481/9627 10240/10418/9564 +f 10242/10420/9566 10304/10482/9628 10241/10419/9565 +f 10243/10421/9567 10305/10483/9629 10242/10420/9566 +f 10244/10422/9568 10306/10484/9630 10243/10421/9567 +f 10245/10423/9569 10307/10485/9631 10244/10422/9568 +f 10246/10424/9570 10308/10486/9632 10245/10423/9569 +f 10247/10425/9571 10309/10487/9633 10246/10424/9570 +f 10248/10426/9572 10310/10488/9634 10247/10425/9571 +f 10249/10427/9573 10311/10489/9635 10248/10426/9572 +f 10250/10428/9574 10312/10490/9636 10249/10427/9573 +f 10251/10429/9575 10313/10491/9637 10250/10428/9574 +f 10252/10430/9576 10314/10492/9638 10251/10429/9575 +f 10253/10431/9577 10315/10493/9639 10252/10430/9576 +f 10254/10432/9578 10316/10494/9640 10253/10431/9577 +f 10255/10433/9579 10317/10495/9641 10254/10432/9578 +f 10256/10434/9580 10318/10496/9642 10255/10433/9579 +f 10257/10435/9581 10319/10497/9643 10256/10434/9580 +f 10258/10436/9582 10320/10498/9644 10257/10435/9581 +f 10259/10437/9583 10321/10499/9645 10258/10436/9582 +f 10260/10438/9584 10322/10500/9646 10259/10437/9583 +f 10261/10439/9585 10323/10501/9647 10260/10438/9584 +f 10262/10440/9586 10324/10502/9648 10261/10439/9585 +f 10263/10441/9587 10325/10503/9649 10262/10440/9586 +f 10264/10442/9588 10326/10504/9650 10263/10441/9587 +f 10265/10443/9589 10327/10505/9651 10264/10442/9588 +f 10266/10444/9590 10328/10506/9652 10265/10443/9589 +f 10267/10445/9591 10329/10507/9653 10266/10444/9590 +f 10268/10446/9592 10330/10508/9654 10267/10445/9591 +f 10269/10447/9593 10331/10509/9655 10268/10446/9592 +f 10270/10448/9594 10332/10510/9656 10269/10447/9593 +f 10271/10449/9595 10333/10511/9657 10270/10448/9594 +f 10272/10450/9596 10334/10512/9658 10271/10449/9595 +f 10273/10451/9597 10335/10513/9659 10272/10450/9596 +f 10274/10452/9598 10336/10514/9660 10273/10451/9597 +f 10275/10453/9599 10337/10515/9661 10274/10452/9598 +f 10276/10454/9600 10338/10516/9662 10275/10453/9599 +f 10277/10455/9601 10339/10517/9663 10276/10454/9600 +f 10278/10456/9602 10340/10518/9664 10277/10455/9601 +f 10279/10457/9603 10341/10519/9665 10278/10456/9602 +f 10280/10458/9604 10342/10520/9666 10279/10457/9603 +f 10281/10459/9605 10343/10521/9667 10280/10458/9604 +f 10282/10461/9607 10344/10522/9668 10281/10459/9605 +f 10283/10523/9669 10345/10524/9670 10282/10461/9607 +f 10285/10463/9609 10347/10525/9671 10284/10462/9608 +f 10286/10464/9610 10348/10526/9672 10285/10463/9609 +f 10287/10465/9611 10349/10527/9673 10286/10464/9610 +f 10288/10466/9612 10350/10528/9674 10287/10465/9611 +f 10289/10467/9613 10351/10529/9675 10288/10466/9612 +f 10290/10468/9614 10352/10530/9676 10289/10467/9613 +f 10291/10469/9615 10353/10531/9677 10290/10468/9614 +f 10292/10470/9616 10354/10532/9678 10291/10469/9615 +f 10293/10471/9617 10355/10533/9679 10292/10470/9616 +f 10294/10472/9618 10356/10534/9680 10293/10471/9617 +f 10295/10473/9619 10357/10535/9681 10294/10472/9618 +f 10296/10474/9620 10358/10536/9682 10295/10473/9619 +f 10297/10475/9621 10359/10537/9683 10296/10474/9620 +f 10298/10476/9622 10360/10538/9684 10297/10475/9621 +f 10299/10477/9623 10361/10539/9685 10298/10476/9622 +f 10300/10478/9624 10362/10540/9686 10299/10477/9623 +f 10301/10479/9625 10363/10541/9687 10300/10478/9624 +f 10302/10480/9626 10364/10542/9688 10301/10479/9625 +f 10303/10481/9627 10365/10543/9689 10302/10480/9626 +f 10304/10482/9628 10366/10544/9690 10303/10481/9627 +f 10305/10483/9629 10367/10545/9691 10304/10482/9628 +f 10306/10484/9630 10368/10546/9692 10305/10483/9629 +f 10307/10485/9631 10369/10547/9693 10306/10484/9630 +f 10308/10486/9632 10370/10548/9694 10307/10485/9631 +f 10309/10487/9633 10371/10549/9695 10308/10486/9632 +f 10310/10488/9634 10372/10550/9696 10309/10487/9633 +f 10311/10489/9635 10373/10551/9697 10310/10488/9634 +f 10312/10490/9636 10374/10552/9698 10311/10489/9635 +f 10313/10491/9637 10375/10553/9699 10312/10490/9636 +f 10314/10492/9638 10376/10554/9700 10313/10491/9637 +f 10315/10493/9639 10377/10555/9701 10314/10492/9638 +f 10316/10494/9640 10378/10556/9702 10315/10493/9639 +f 10317/10495/9641 10379/10557/9703 10316/10494/9640 +f 10318/10496/9642 10380/10558/9704 10317/10495/9641 +f 10319/10497/9643 10381/10559/9705 10318/10496/9642 +f 10320/10498/9644 10382/10560/9706 10319/10497/9643 +f 10321/10499/9645 10383/10561/9707 10320/10498/9644 +f 10322/10500/9646 10384/10562/9708 10321/10499/9645 +f 10323/10501/9647 10385/10563/9709 10322/10500/9646 +f 10324/10502/9648 10386/10564/9710 10323/10501/9647 +f 10325/10503/9649 10387/10565/9711 10324/10502/9648 +f 10326/10504/9650 10388/10566/9712 10325/10503/9649 +f 10327/10505/9651 10389/10567/9713 10326/10504/9650 +f 10328/10506/9652 10390/10568/9714 10327/10505/9651 +f 10329/10507/9653 10391/10569/9715 10328/10506/9652 +f 10330/10508/9654 10392/10570/9716 10329/10507/9653 +f 10331/10509/9655 10393/10571/9717 10330/10508/9654 +f 10332/10510/9656 10394/10572/9718 10331/10509/9655 +f 10333/10511/9657 10395/10573/9719 10332/10510/9656 +f 10334/10512/9658 10396/10574/9720 10333/10511/9657 +f 10335/10513/9659 10397/10575/9721 10334/10512/9658 +f 10336/10514/9660 10398/10576/9722 10335/10513/9659 +f 10337/10515/9661 10399/10577/9723 10336/10514/9660 +f 10338/10516/9662 10400/10578/9724 10337/10515/9661 +f 10339/10517/9663 10401/10579/9725 10338/10516/9662 +f 10340/10518/9664 10402/10580/9726 10339/10517/9663 +f 10341/10519/9665 10403/10581/9727 10340/10518/9664 +f 10342/10520/9666 10404/10582/9728 10341/10519/9665 +f 10343/10521/9667 10405/10583/9729 10342/10520/9666 +f 10344/10522/9668 10406/10584/9730 10343/10521/9667 +f 10345/10524/9670 10407/10585/9731 10344/10522/9668 +f 10346/10586/9732 10408/10587/9733 10345/10524/9670 +f 10348/10526/9672 10410/10588/9734 10347/10525/9671 +f 10349/10527/9673 10411/10589/9735 10348/10526/9672 +f 10350/10528/9674 10412/10590/9736 10349/10527/9673 +f 10351/10529/9675 10413/10591/9737 10350/10528/9674 +f 10352/10530/9676 10414/10592/9738 10351/10529/9675 +f 10353/10531/9677 10415/10593/9739 10352/10530/9676 +f 10354/10532/9678 10416/10594/9740 10353/10531/9677 +f 10355/10533/9679 10417/10595/9741 10354/10532/9678 +f 10356/10534/9680 10418/10596/9742 10355/10533/9679 +f 10357/10535/9681 10419/10597/9743 10356/10534/9680 +f 10358/10536/9682 10420/10598/9744 10357/10535/9681 +f 10359/10537/9683 10421/10599/9745 10358/10536/9682 +f 10360/10538/9684 10422/10600/9746 10359/10537/9683 +f 10361/10539/9685 10423/10601/9747 10360/10538/9684 +f 10362/10540/9686 10424/10602/9748 10361/10539/9685 +f 10363/10541/9687 10425/10603/9749 10362/10540/9686 +f 10364/10542/9688 10426/10604/9750 10363/10541/9687 +f 10365/10543/9689 10427/10605/9751 10364/10542/9688 +f 10366/10544/9690 10428/10606/8455 10365/10543/9689 +f 10367/10545/9691 10429/10607/9752 10366/10544/9690 +f 10368/10546/9692 10430/10608/9753 10367/10545/9691 +f 10369/10547/9693 10431/10609/9754 10368/10546/9692 +f 10370/10548/9694 10432/10610/9755 10369/10547/9693 +f 10371/10549/9695 10433/10611/9756 10370/10548/9694 +f 10372/10550/9696 10434/10612/9757 10371/10549/9695 +f 10373/10551/9697 10435/10613/9758 10372/10550/9696 +f 10374/10552/9698 10436/10614/9759 10373/10551/9697 +f 10375/10553/9699 10437/10615/9760 10374/10552/9698 +f 10376/10554/9700 10438/10616/9761 10375/10553/9699 +f 10377/10555/9701 10439/10617/9762 10376/10554/9700 +f 10378/10556/9702 10440/10618/9763 10377/10555/9701 +f 10379/10557/9703 10441/10619/9764 10378/10556/9702 +f 10380/10558/9704 10442/10620/9765 10379/10557/9703 +f 10381/10559/9705 10443/10621/9766 10380/10558/9704 +f 10382/10560/9706 10444/10622/9767 10381/10559/9705 +f 10383/10561/9707 10445/10623/9768 10382/10560/9706 +f 10384/10562/9708 10446/10624/9769 10383/10561/9707 +f 10385/10563/9709 10447/10625/9770 10384/10562/9708 +f 10386/10564/9710 10448/10626/9771 10385/10563/9709 +f 10387/10565/9711 10449/10627/9711 10386/10564/9710 +f 10388/10566/9712 10450/10628/9772 10387/10565/9711 +f 10389/10567/9713 10451/10629/9773 10388/10566/9712 +f 10390/10568/9714 10452/10630/9774 10389/10567/9713 +f 10391/10569/9715 10453/10631/9775 10390/10568/9714 +f 10392/10570/9716 10454/10632/9776 10391/10569/9715 +f 10393/10571/9717 10455/10633/9777 10392/10570/9716 +f 10394/10572/9718 10456/10634/9778 10393/10571/9717 +f 10395/10573/9719 10457/10635/9779 10394/10572/9718 +f 10396/10574/9720 10458/10636/9780 10395/10573/9719 +f 10397/10575/9721 10459/10637/9781 10396/10574/9720 +f 10398/10576/9722 10460/10638/9782 10397/10575/9721 +f 10399/10577/9723 10461/10639/9783 10398/10576/9722 +f 10400/10578/9724 10462/10640/9784 10399/10577/9723 +f 10401/10579/9725 10463/10641/9785 10400/10578/9724 +f 10402/10580/9726 10464/10642/9786 10401/10579/9725 +f 10403/10581/9727 10465/10643/9787 10402/10580/9726 +f 10404/10582/9728 10466/10644/9788 10403/10581/9727 +f 10405/10583/9729 10467/10645/9789 10404/10582/9728 +f 10406/10584/9730 10468/10646/9790 10405/10583/9729 +f 10407/10585/9731 10469/10647/9791 10406/10584/9730 +f 10408/10587/9733 10470/10648/9792 10407/10585/9731 +f 10409/10649/9793 10471/10650/9794 10408/10587/9733 +f 10411/10589/9735 10473/10651/9795 10410/10588/9734 +f 10412/10590/9736 10474/10652/9796 10411/10589/9735 +f 10413/10591/9737 10475/10653/9797 10412/10590/9736 +f 10414/10592/9738 10476/10654/9798 10413/10591/9737 +f 10415/10593/9739 10477/10655/9799 10414/10592/9738 +f 10416/10594/9740 10478/10656/9800 10415/10593/9739 +f 10417/10595/9741 10479/10657/9801 10416/10594/9740 +f 10418/10596/9742 10480/10658/9802 10417/10595/9741 +f 10419/10597/9743 10481/10659/9803 10418/10596/9742 +f 10420/10598/9744 10482/10660/9804 10419/10597/9743 +f 10421/10599/9745 10483/10661/9805 10420/10598/9744 +f 10422/10600/9746 10484/10662/9806 10421/10599/9745 +f 10423/10601/9747 10485/10663/9807 10422/10600/9746 +f 10424/10602/9748 10486/10664/9808 10423/10601/9747 +f 10425/10603/9749 10487/10665/9809 10424/10602/9748 +f 10426/10604/9750 10488/10666/9810 10425/10603/9749 +f 10427/10605/9751 10489/10667/9811 10426/10604/9750 +f 10428/10606/8455 10490/10668/9812 10427/10605/9751 +f 10429/10607/9752 10491/10669/9813 10428/10606/8455 +f 10430/10608/9753 10492/10670/9814 10429/10607/9752 +f 10431/10609/9754 10493/10671/9815 10430/10608/9753 +f 10432/10610/9755 10494/10672/9816 10431/10609/9754 +f 10433/10611/9756 10495/10673/9817 10432/10610/9755 +f 10434/10612/9757 10496/10674/9818 10433/10611/9756 +f 10435/10613/9758 10497/10675/9819 10434/10612/9757 +f 10436/10614/9759 10498/10676/9820 10435/10613/9758 +f 10437/10615/9760 10499/10677/9821 10436/10614/9759 +f 10438/10616/9761 10500/10678/9822 10437/10615/9760 +f 10439/10617/9762 10501/10679/9823 10438/10616/9761 +f 10440/10618/9763 10502/10680/9824 10439/10617/9762 +f 10441/10619/9764 10503/10681/9825 10440/10618/9763 +f 10442/10620/9765 10504/10682/9826 10441/10619/9764 +f 10443/10621/9766 10505/10683/9827 10442/10620/9765 +f 10444/10622/9767 10506/10684/9828 10443/10621/9766 +f 10445/10623/9768 10507/10685/9829 10444/10622/9767 +f 10446/10624/9769 10508/10686/9830 10445/10623/9768 +f 10447/10625/9770 10509/10687/9831 10446/10624/9769 +f 10448/10626/9771 10510/10688/9832 10447/10625/9770 +f 10449/10627/9711 10511/10689/9833 10448/10626/9771 +f 10450/10628/9772 10512/10690/9834 10449/10627/9711 +f 10451/10629/9773 10513/10691/9835 10450/10628/9772 +f 10452/10630/9774 10514/10692/9836 10451/10629/9773 +f 10453/10631/9775 10515/10693/9837 10452/10630/9774 +f 10454/10632/9776 10516/10694/9838 10453/10631/9775 +f 10455/10633/9777 10517/10695/9839 10454/10632/9776 +f 10456/10634/9778 10518/10696/9840 10455/10633/9777 +f 10457/10635/9779 10519/10697/9841 10456/10634/9778 +f 10458/10636/9780 10520/10698/9842 10457/10635/9779 +f 10459/10637/9781 10521/10699/9843 10458/10636/9780 +f 10460/10638/9782 10522/10700/9844 10459/10637/9781 +f 10461/10639/9783 10523/10701/9845 10460/10638/9782 +f 10462/10640/9784 10524/10702/9846 10461/10639/9783 +f 10463/10641/9785 10525/10703/9847 10462/10640/9784 +f 10464/10642/9786 10526/10704/9848 10463/10641/9785 +f 10465/10643/9787 10527/10705/9849 10464/10642/9786 +f 10466/10644/9788 10528/10706/9850 10465/10643/9787 +f 10467/10645/9789 10529/10707/9851 10466/10644/9788 +f 10468/10646/9790 10530/10708/9852 10467/10645/9789 +f 10469/10647/9791 10531/10709/9853 10468/10646/9790 +f 10470/10648/9792 10532/10710/9854 10469/10647/9791 +f 10471/10650/9794 10533/10711/9855 10470/10648/9792 +f 10472/10712/9856 10534/10713/9857 10471/10650/9794 +f 10474/10652/9796 10536/10714/9858 10473/10651/9795 +f 10475/10653/9797 10537/10715/9859 10474/10652/9796 +f 10476/10654/9798 10538/10716/9860 10475/10653/9797 +f 10477/10655/9799 10539/10717/9861 10476/10654/9798 +f 10478/10656/9800 10540/10718/9862 10477/10655/9799 +f 10479/10657/9801 10541/10719/9863 10478/10656/9800 +f 10480/10658/9802 10542/10720/9864 10479/10657/9801 +f 10481/10659/9803 10543/10721/9865 10480/10658/9802 +f 10482/10660/9804 10544/10722/9866 10481/10659/9803 +f 10483/10661/9805 10545/10723/9867 10482/10660/9804 +f 10484/10662/9806 10546/10724/9868 10483/10661/9805 +f 10485/10663/9807 10547/10725/9869 10484/10662/9806 +f 10486/10664/9808 10548/10726/9870 10485/10663/9807 +f 10487/10665/9809 10549/10727/9871 10486/10664/9808 +f 10488/10666/9810 10550/10728/9872 10487/10665/9809 +f 10489/10667/9811 10551/10729/9873 10488/10666/9810 +f 10490/10668/9812 10552/10730/9874 10489/10667/9811 +f 10491/10669/9813 10553/10731/9875 10490/10668/9812 +f 10492/10670/9814 10554/10732/9876 10491/10669/9813 +f 10493/10671/9815 10555/10733/9877 10492/10670/9814 +f 10494/10672/9816 10556/10734/9878 10493/10671/9815 +f 10495/10673/9817 10557/10735/9879 10494/10672/9816 +f 10496/10674/9818 10558/10736/9880 10495/10673/9817 +f 10497/10675/9819 10559/10737/9881 10496/10674/9818 +f 10498/10676/9820 10560/10738/9882 10497/10675/9819 +f 10499/10677/9821 10561/10739/9883 10498/10676/9820 +f 10500/10678/9822 10562/10740/9884 10499/10677/9821 +f 10501/10679/9823 10563/10741/9885 10500/10678/9822 +f 10502/10680/9824 10564/10742/9886 10501/10679/9823 +f 10503/10681/9825 10565/10743/9887 10502/10680/9824 +f 10504/10682/9826 10566/10744/9888 10503/10681/9825 +f 10505/10683/9827 10567/10745/9889 10504/10682/9826 +f 10506/10684/9828 10568/10746/9890 10505/10683/9827 +f 10507/10685/9829 10569/10747/9891 10506/10684/9828 +f 10508/10686/9830 10570/10748/9892 10507/10685/9829 +f 10509/10687/9831 10571/10749/9893 10508/10686/9830 +f 10510/10688/9832 10572/10750/9894 10509/10687/9831 +f 10511/10689/9833 10573/10751/9895 10510/10688/9832 +f 10512/10690/9834 10574/10752/9896 10511/10689/9833 +f 10513/10691/9835 10575/10753/9897 10512/10690/9834 +f 10514/10692/9836 10576/10754/9898 10513/10691/9835 +f 10515/10693/9837 10577/10755/9899 10514/10692/9836 +f 10516/10694/9838 10578/10756/9900 10515/10693/9837 +f 10517/10695/9839 10579/10757/9901 10516/10694/9838 +f 10518/10696/9840 10580/10758/9902 10517/10695/9839 +f 10519/10697/9841 10581/10759/9903 10518/10696/9840 +f 10520/10698/9842 10582/10760/9904 10519/10697/9841 +f 10521/10699/9843 10583/10761/9905 10520/10698/9842 +f 10522/10700/9844 10584/10762/9906 10521/10699/9843 +f 10523/10701/9845 10585/10763/9907 10522/10700/9844 +f 10524/10702/9846 10586/10764/9908 10523/10701/9845 +f 10525/10703/9847 10587/10765/9909 10524/10702/9846 +f 10526/10704/9848 10588/10766/9910 10525/10703/9847 +f 10527/10705/9849 10589/10767/9911 10526/10704/9848 +f 10528/10706/9850 10590/10768/9912 10527/10705/9849 +f 10529/10707/9851 10591/10769/9913 10528/10706/9850 +f 10529/10707/9851 10593/10770/9914 10592/10771/9915 +f 10531/10709/9853 10593/10770/9914 10530/10708/9852 +f 10532/10710/9854 10594/10772/9916 10531/10709/9853 +f 10533/10711/9855 10595/10773/9917 10532/10710/9854 +f 10534/10713/9857 10596/10774/9918 10533/10711/9855 +f 10535/10775/9919 10597/10776/9920 10534/10713/9857 +f 10537/10715/9859 10599/10777/9921 10536/10714/9858 +f 10538/10716/9860 10600/10778/9922 10537/10715/9859 +f 10539/10717/9861 10601/10779/9923 10538/10716/9860 +f 10540/10718/9862 10602/10780/9924 10539/10717/9861 +f 10541/10719/9863 10603/10781/9925 10540/10718/9862 +f 10542/10720/9864 10604/10782/9926 10541/10719/9863 +f 10543/10721/9865 10605/10783/9927 10542/10720/9864 +f 10544/10722/9866 10606/10784/9928 10543/10721/9865 +f 10545/10723/9867 10607/10785/9929 10544/10722/9866 +f 10546/10724/9868 10608/10786/9930 10545/10723/9867 +f 10547/10725/9869 10609/10787/9931 10546/10724/9868 +f 10548/10726/9870 10610/10788/9932 10547/10725/9869 +f 10549/10727/9871 10611/10789/9933 10548/10726/9870 +f 10550/10728/9872 10612/10790/9934 10549/10727/9871 +f 10551/10729/9873 10613/10791/9935 10550/10728/9872 +f 10552/10730/9874 10614/10792/9936 10551/10729/9873 +f 10553/10731/9875 10615/10793/9937 10552/10730/9874 +f 10554/10732/9876 10616/10794/9938 10553/10731/9875 +f 10555/10733/9877 10617/10795/9939 10554/10732/9876 +f 10556/10734/9878 10618/10796/9940 10555/10733/9877 +f 10557/10735/9879 10619/10797/9941 10556/10734/9878 +f 10558/10736/9880 10620/10798/9942 10557/10735/9879 +f 10559/10737/9881 10621/10799/9943 10558/10736/9880 +f 10560/10738/9882 10622/10800/9944 10559/10737/9881 +f 10561/10739/9883 10623/10801/9945 10560/10738/9882 +f 10562/10740/9884 10624/10802/9946 10561/10739/9883 +f 10563/10741/9885 10625/10803/9947 10562/10740/9884 +f 10564/10742/9886 10626/10804/9948 10563/10741/9885 +f 10565/10743/9887 10627/10805/9949 10564/10742/9886 +f 10566/10744/9888 10628/10806/9950 10565/10743/9887 +f 10567/10745/9889 10629/10807/9951 10566/10744/9888 +f 10568/10746/9890 10630/10808/9952 10567/10745/9889 +f 10569/10747/9891 10631/10809/9953 10568/10746/9890 +f 10570/10748/9892 10632/10810/9954 10569/10747/9891 +f 10571/10749/9893 10633/10811/9955 10570/10748/9892 +f 10572/10750/9894 10634/10812/9956 10571/10749/9893 +f 10573/10751/9895 10635/10813/9957 10572/10750/9894 +f 10574/10752/9896 10636/10814/9958 10573/10751/9895 +f 10575/10753/9897 10637/10815/9959 10574/10752/9896 +f 10576/10754/9898 10638/10816/9960 10575/10753/9897 +f 10577/10755/9899 10639/10817/9961 10576/10754/9898 +f 10578/10756/9900 10640/10818/9962 10577/10755/9899 +f 10579/10757/9901 10641/10819/9963 10578/10756/9900 +f 10580/10758/9902 10642/10820/9964 10579/10757/9901 +f 10581/10759/9903 10643/10821/9965 10580/10758/9902 +f 10582/10760/9904 10644/10822/9966 10581/10759/9903 +f 10583/10761/9905 10645/10823/9967 10582/10760/9904 +f 10584/10762/9906 10646/10824/9968 10583/10761/9905 +f 10585/10763/9907 10647/10825/9969 10584/10762/9906 +f 10586/10764/9908 10648/10826/9970 10585/10763/9907 +f 10587/10765/9909 10649/10827/9971 10586/10764/9908 +f 10588/10766/9910 10650/10828/9972 10587/10765/9909 +f 10589/10767/9911 10651/10829/9973 10588/10766/9910 +f 10590/10768/9912 10652/10830/9974 10589/10767/9911 +f 10591/10769/9913 10653/10831/9975 10590/10768/9912 +f 10592/10771/9915 10654/10832/9976 10591/10769/9913 +f 10593/10770/9914 10655/10833/9977 10592/10771/9915 +f 10594/10772/9916 10656/10834/9978 10593/10770/9914 +f 10595/10773/9917 10657/10835/9979 10594/10772/9916 +f 10596/10774/9918 10658/10836/9980 10595/10773/9917 +f 10597/10776/9920 10659/10837/9981 10596/10774/9918 +f 10598/10838/9982 10660/10839/9983 10597/10776/9920 +f 10600/10778/9922 10662/10840/9838 10599/10777/9921 +f 10601/10779/9923 10663/10841/9984 10600/10778/9922 +f 10602/10780/9924 10664/10842/9985 10601/10779/9923 +f 10603/10781/9925 10665/10843/9986 10602/10780/9924 +f 10604/10782/9926 10666/10844/9987 10603/10781/9925 +f 10605/10783/9927 10667/10845/9988 10604/10782/9926 +f 10606/10784/9928 10668/10846/9989 10605/10783/9927 +f 10607/10785/9929 10669/10847/9990 10606/10784/9928 +f 10608/10786/9930 10670/10848/9991 10607/10785/9929 +f 10609/10787/9931 10671/10849/9992 10608/10786/9930 +f 10610/10788/9932 10672/10850/9993 10609/10787/9931 +f 10611/10789/9933 10673/10851/9994 10610/10788/9932 +f 10612/10790/9934 10674/10852/9995 10611/10789/9933 +f 10613/10791/9935 10675/10853/9996 10612/10790/9934 +f 10614/10792/9936 10676/10854/9997 10613/10791/9935 +f 10615/10793/9937 10677/10855/9998 10614/10792/9936 +f 10616/10794/9938 10678/10856/9999 10615/10793/9937 +f 10617/10795/9939 10679/10857/10000 10616/10794/9938 +f 10618/10796/9940 10680/10858/10001 10617/10795/9939 +f 10619/10797/9941 10681/10859/10002 10618/10796/9940 +f 10620/10798/9942 10682/10860/10003 10619/10797/9941 +f 10621/10799/9943 10683/10861/10004 10620/10798/9942 +f 10622/10800/9944 10684/10862/10005 10621/10799/9943 +f 10623/10801/9945 10685/10863/10006 10622/10800/9944 +f 10624/10802/9946 10686/10864/10007 10623/10801/9945 +f 10625/10803/9947 10687/10865/10008 10624/10802/9946 +f 10626/10804/9948 10688/10866/10009 10625/10803/9947 +f 10627/10805/9949 10689/10867/10010 10626/10804/9948 +f 10628/10806/9950 10690/10868/10011 10627/10805/9949 +f 10629/10807/9951 10691/10869/10012 10628/10806/9950 +f 10630/10808/9952 10692/10870/10013 10629/10807/9951 +f 10631/10809/9953 10693/10871/10014 10630/10808/9952 +f 10632/10810/9954 10694/10872/10015 10631/10809/9953 +f 10633/10811/9955 10695/10873/10016 10632/10810/9954 +f 10634/10812/9956 10696/10874/9648 10633/10811/9955 +f 10635/10813/9957 10697/10875/10017 10634/10812/9956 +f 10636/10814/9958 10698/10876/10018 10635/10813/9957 +f 10637/10815/9959 10699/10877/10019 10636/10814/9958 +f 10638/10816/9960 10700/10878/10020 10637/10815/9959 +f 10639/10817/9961 10701/10879/10021 10638/10816/9960 +f 10640/10818/9962 10702/10880/10022 10639/10817/9961 +f 10641/10819/9963 10703/10881/10023 10640/10818/9962 +f 10642/10820/9964 10704/10882/10024 10641/10819/9963 +f 10643/10821/9965 10705/10883/10025 10642/10820/9964 +f 10644/10822/9966 10706/10884/10026 10643/10821/9965 +f 10645/10823/9967 10707/10885/10027 10644/10822/9966 +f 10646/10824/9968 10708/10886/10028 10645/10823/9967 +f 10647/10825/9969 10709/10887/10029 10646/10824/9968 +f 10648/10826/9970 10710/10888/10030 10647/10825/9969 +f 10649/10827/9971 10711/10889/10031 10648/10826/9970 +f 10650/10828/9972 10712/10890/10032 10649/10827/9971 +f 10651/10829/9973 10713/10891/10033 10650/10828/9972 +f 10652/10830/9974 10714/10892/10034 10651/10829/9973 +f 10653/10831/9975 10715/10893/10035 10652/10830/9974 +f 10654/10832/9976 10716/10894/10036 10653/10831/9975 +f 10655/10833/9977 10717/10895/10037 10654/10832/9976 +f 10656/10834/9978 10718/10896/10038 10655/10833/9977 +f 10657/10835/9979 10719/10897/10039 10656/10834/9978 +f 10658/10836/9980 10720/10898/10040 10657/10835/9979 +f 10659/10837/9981 10721/10899/10041 10658/10836/9980 +f 10660/10839/9983 10722/10900/10042 10659/10837/9981 +f 10661/10901/10043 10723/10902/10044 10660/10839/9983 +f 10663/10841/9984 10725/10903/10045 10662/10840/9838 +f 10664/10842/9985 10726/10904/10046 10663/10841/9984 +f 10665/10843/9986 10727/10905/10047 10664/10842/9985 +f 10666/10844/9987 10728/10906/10048 10665/10843/9986 +f 10667/10845/9988 10729/10907/10049 10666/10844/9987 +f 10668/10846/9989 10730/10908/10050 10667/10845/9988 +f 10669/10847/9990 10731/10909/10051 10668/10846/9989 +f 10670/10848/9991 10732/10910/10052 10669/10847/9990 +f 10671/10849/9992 10733/10911/10053 10670/10848/9991 +f 10672/10850/9993 10734/10912/10054 10671/10849/9992 +f 10673/10851/9994 10735/10913/10055 10672/10850/9993 +f 10674/10852/9995 10736/10914/10056 10673/10851/9994 +f 10675/10853/9996 10737/10915/10057 10674/10852/9995 +f 10676/10854/9997 10738/10916/10058 10675/10853/9996 +f 10677/10855/9998 10739/10917/10059 10676/10854/9997 +f 10678/10856/9999 10740/10918/10060 10677/10855/9998 +f 10679/10857/10000 10741/10919/10061 10678/10856/9999 +f 10680/10858/10001 10742/10920/10062 10679/10857/10000 +f 10681/10859/10002 10743/10921/10063 10680/10858/10001 +f 10682/10860/10003 10744/10922/10064 10681/10859/10002 +f 10683/10861/10004 10745/10923/10065 10682/10860/10003 +f 10684/10862/10005 10746/10924/8710 10683/10861/10004 +f 10685/10863/10006 10747/10925/10066 10684/10862/10005 +f 10686/10864/10007 10748/10926/10067 10685/10863/10006 +f 10687/10865/10008 10749/10927/10068 10686/10864/10007 +f 10688/10866/10009 10750/10928/10069 10687/10865/10008 +f 10689/10867/10010 10751/10929/10070 10688/10866/10009 +f 10690/10868/10011 10752/10930/10071 10689/10867/10010 +f 10691/10869/10012 10753/10931/10072 10690/10868/10011 +f 10692/10870/10013 10754/10932/10073 10691/10869/10012 +f 10693/10871/10014 10755/10933/10074 10692/10870/10013 +f 10694/10872/10015 10756/10934/10075 10693/10871/10014 +f 10695/10873/10016 10757/10935/10076 10694/10872/10015 +f 10696/10874/9648 10758/10936/10077 10695/10873/10016 +f 10697/10875/10017 10759/10937/10078 10696/10874/9648 +f 10698/10876/10018 10760/10938/10079 10697/10875/10017 +f 10699/10877/10019 10761/10939/10080 10698/10876/10018 +f 10700/10878/10020 10762/10940/10081 10699/10877/10019 +f 10701/10879/10021 10763/10941/10082 10700/10878/10020 +f 10702/10880/10022 10764/10942/10083 10701/10879/10021 +f 10703/10881/10023 10765/10943/10084 10702/10880/10022 +f 10704/10882/10024 10766/10944/10085 10703/10881/10023 +f 10705/10883/10025 10767/10945/10086 10704/10882/10024 +f 10706/10884/10026 10768/10946/10087 10705/10883/10025 +f 10707/10885/10027 10769/10947/10088 10706/10884/10026 +f 10708/10886/10028 10770/10948/10089 10707/10885/10027 +f 10709/10887/10029 10771/10949/10090 10708/10886/10028 +f 10710/10888/10030 10772/10950/10091 10709/10887/10029 +f 10711/10889/10031 10773/10951/10092 10710/10888/10030 +f 10712/10890/10032 10774/10952/10093 10711/10889/10031 +f 10713/10891/10033 10775/10953/10094 10712/10890/10032 +f 10714/10892/10034 10776/10954/10095 10713/10891/10033 +f 10715/10893/10035 10777/10955/10096 10714/10892/10034 +f 10716/10894/10036 10778/10956/10097 10715/10893/10035 +f 10717/10895/10037 10779/10957/10098 10716/10894/10036 +f 10718/10896/10038 10780/10958/10099 10717/10895/10037 +f 10719/10897/10039 10781/10959/10100 10718/10896/10038 +f 10720/10898/10040 10782/10960/10101 10719/10897/10039 +f 10721/10899/10041 10783/10961/10102 10720/10898/10040 +f 10722/10900/10042 10784/10962/10103 10721/10899/10041 +f 10723/10902/10044 10785/10963/10104 10722/10900/10042 +f 10724/10964/10105 10786/10965/10106 10723/10902/10044 +f 10726/10904/10046 10788/10966/10107 10725/10903/10045 +f 10727/10905/10047 10789/10967/10108 10726/10904/10046 +f 10728/10906/10048 10790/10968/10109 10727/10905/10047 +f 10729/10907/10049 10791/10969/10110 10728/10906/10048 +f 10730/10908/10050 10792/10970/10111 10729/10907/10049 +f 10731/10909/10051 10793/10971/10112 10730/10908/10050 +f 10732/10910/10052 10794/10972/10113 10731/10909/10051 +f 10733/10911/10053 10795/10973/10114 10732/10910/10052 +f 10734/10912/10054 10796/10974/10115 10733/10911/10053 +f 10735/10913/10055 10797/10975/10116 10734/10912/10054 +f 10736/10914/10056 10798/10976/10117 10735/10913/10055 +f 10737/10915/10057 10799/10977/10118 10736/10914/10056 +f 10738/10916/10058 10800/10978/10119 10737/10915/10057 +f 10739/10917/10059 10801/10979/10120 10738/10916/10058 +f 10740/10918/10060 10802/10980/10121 10739/10917/10059 +f 10741/10919/10061 10803/10981/10122 10740/10918/10060 +f 10742/10920/10062 10804/10982/10123 10741/10919/10061 +f 10743/10921/10063 10805/10983/10124 10742/10920/10062 +f 10744/10922/10064 10806/10984/10125 10743/10921/10063 +f 10745/10923/10065 10807/10985/10126 10744/10922/10064 +f 10746/10924/8710 10808/10986/10127 10745/10923/10065 +f 10747/10925/10066 10809/10987/10128 10746/10924/8710 +f 10748/10926/10067 10810/10988/10129 10747/10925/10066 +f 10749/10927/10068 10811/10989/10130 10748/10926/10067 +f 10750/10928/10069 10812/10990/10131 10749/10927/10068 +f 10751/10929/10070 10813/10991/10132 10750/10928/10069 +f 10752/10930/10071 10814/10992/10133 10751/10929/10070 +f 10753/10931/10072 10815/10993/10134 10752/10930/10071 +f 10754/10932/10073 10816/10994/10135 10753/10931/10072 +f 10755/10933/10074 10817/10995/10136 10754/10932/10073 +f 10756/10934/10075 10818/10996/10137 10755/10933/10074 +f 10757/10935/10076 10819/10997/10138 10756/10934/10075 +f 10758/10936/10077 10820/10998/10139 10757/10935/10076 +f 10759/10937/10078 10821/10999/10140 10758/10936/10077 +f 10760/10938/10079 10822/11000/10141 10759/10937/10078 +f 10761/10939/10080 10823/11001/10142 10760/10938/10079 +f 10762/10940/10081 10824/11002/10143 10761/10939/10080 +f 10763/10941/10082 10825/11003/10144 10762/10940/10081 +f 10764/10942/10083 10826/11004/10145 10763/10941/10082 +f 10765/10943/10084 10827/11005/10146 10764/10942/10083 +f 10766/10944/10085 10828/11006/10147 10765/10943/10084 +f 10767/10945/10086 10829/11007/10148 10766/10944/10085 +f 10768/10946/10087 10830/11008/10149 10767/10945/10086 +f 10769/10947/10088 10831/11009/10150 10768/10946/10087 +f 10770/10948/10089 10832/11010/10151 10769/10947/10088 +f 10771/10949/10090 10833/11011/10152 10770/10948/10089 +f 10772/10950/10091 10834/11012/10153 10771/10949/10090 +f 10773/10951/10092 10835/11013/10154 10772/10950/10091 +f 10774/10952/10093 10836/11014/10155 10773/10951/10092 +f 10775/10953/10094 10837/11015/10156 10774/10952/10093 +f 10776/10954/10095 10838/11016/10157 10775/10953/10094 +f 10777/10955/10096 10839/11017/10158 10776/10954/10095 +f 10777/10955/10096 10841/11018/10159 10840/11019/10160 +f 10779/10957/10098 10841/11018/10159 10778/10956/10097 +f 10780/10958/10099 10842/11020/10161 10779/10957/10098 +f 10781/10959/10100 10843/11021/10162 10780/10958/10099 +f 10782/10960/10101 10844/11022/10163 10781/10959/10100 +f 10783/10961/10102 10845/11023/10164 10782/10960/10101 +f 10784/10962/10103 10846/11024/10165 10783/10961/10102 +f 10785/10963/10104 10847/11025/10166 10784/10962/10103 +f 10786/10965/10106 10848/11026/10167 10785/10963/10104 +f 10787/11027/10168 10849/11028/10169 10786/10965/10106 +f 10789/10967/10108 10851/11029/10170 10788/10966/10107 +f 10790/10968/10109 10852/11030/10171 10789/10967/10108 +f 10791/10969/10110 10853/11031/10172 10790/10968/10109 +f 10792/10970/10111 10854/11032/10173 10791/10969/10110 +f 10793/10971/10112 10855/11033/10174 10792/10970/10111 +f 10794/10972/10113 10856/11034/10175 10793/10971/10112 +f 10795/10973/10114 10857/11035/10176 10794/10972/10113 +f 10796/10974/10115 10858/11036/10177 10795/10973/10114 +f 10797/10975/10116 10859/11037/10178 10796/10974/10115 +f 10798/10976/10117 10860/11038/10179 10797/10975/10116 +f 10799/10977/10118 10861/11039/10180 10798/10976/10117 +f 10800/10978/10119 10862/11040/10181 10799/10977/10118 +f 10801/10979/10120 10863/11041/10182 10800/10978/10119 +f 10802/10980/10121 10864/11042/10183 10801/10979/10120 +f 10803/10981/10122 10865/11043/10184 10802/10980/10121 +f 10804/10982/10123 10866/11044/10185 10803/10981/10122 +f 10805/10983/10124 10867/11045/10186 10804/10982/10123 +f 10806/10984/10125 10868/11046/10187 10805/10983/10124 +f 10807/10985/10126 10869/11047/10188 10806/10984/10125 +f 10808/10986/10127 10870/11048/10189 10807/10985/10126 +f 10809/10987/10128 10871/11049/10190 10808/10986/10127 +f 10810/10988/10129 10872/11050/10191 10809/10987/10128 +f 10811/10989/10130 10873/11051/10192 10810/10988/10129 +f 10812/10990/10131 10874/11052/10193 10811/10989/10130 +f 10813/10991/10132 10875/11053/10194 10812/10990/10131 +f 10814/10992/10133 10876/11054/10195 10813/10991/10132 +f 10815/10993/10134 10877/11055/10196 10814/10992/10133 +f 10816/10994/10135 10878/11056/10197 10815/10993/10134 +f 10817/10995/10136 10879/11057/10198 10816/10994/10135 +f 10818/10996/10137 10880/11058/10199 10817/10995/10136 +f 10819/10997/10138 10881/11059/10200 10818/10996/10137 +f 10820/10998/10139 10882/11060/10201 10819/10997/10138 +f 10821/10999/10140 10883/11061/10202 10820/10998/10139 +f 10822/11000/10141 10884/11062/10203 10821/10999/10140 +f 10823/11001/10142 10885/11063/10204 10822/11000/10141 +f 10824/11002/10143 10886/11064/10205 10823/11001/10142 +f 10825/11003/10144 10887/11065/10206 10824/11002/10143 +f 10826/11004/10145 10888/11066/10207 10825/11003/10144 +f 10827/11005/10146 10889/11067/10208 10826/11004/10145 +f 10828/11006/10147 10890/11068/10209 10827/11005/10146 +f 10829/11007/10148 10891/11069/10210 10828/11006/10147 +f 10830/11008/10149 10892/11070/10211 10829/11007/10148 +f 10831/11009/10150 10893/11071/10212 10830/11008/10149 +f 10832/11010/10151 10894/11072/10213 10831/11009/10150 +f 10833/11011/10152 10895/11073/10214 10832/11010/10151 +f 10834/11012/10153 10896/11074/10215 10833/11011/10152 +f 10835/11013/10154 10897/11075/10216 10834/11012/10153 +f 10836/11014/10155 10898/11076/10217 10835/11013/10154 +f 10837/11015/10156 10899/11077/10218 10836/11014/10155 +f 10838/11016/10157 10900/11078/10219 10837/11015/10156 +f 10839/11017/10158 10901/11079/10220 10838/11016/10157 +f 10840/11019/10160 10902/11080/10221 10839/11017/10158 +f 10841/11018/10159 10903/11081/10222 10840/11019/10160 +f 10842/11020/10161 10904/11082/10223 10841/11018/10159 +f 10843/11021/10162 10905/11083/10224 10842/11020/10161 +f 10844/11022/10163 10906/11084/10225 10843/11021/10162 +f 10845/11023/10164 10907/11085/10226 10844/11022/10163 +f 10846/11024/10165 10908/11086/10227 10845/11023/10164 +f 10847/11025/10166 10909/11087/10228 10846/11024/10165 +f 10848/11026/10167 10910/11088/10229 10847/11025/10166 +f 10849/11028/10169 10911/11089/10230 10848/11026/10167 +f 10850/11090/10231 10912/11091/10232 10849/11028/10169 +f 10852/11030/10171 10914/11092/10233 10851/11029/10170 +f 10853/11031/10172 10915/11093/10234 10852/11030/10171 +f 10854/11032/10173 10916/11094/10235 10853/11031/10172 +f 10855/11033/10174 10917/11095/10236 10854/11032/10173 +f 10856/11034/10175 10918/11096/10237 10855/11033/10174 +f 10857/11035/10176 10919/11097/10238 10856/11034/10175 +f 10858/11036/10177 10920/11098/10239 10857/11035/10176 +f 10859/11037/10178 10921/11099/10240 10858/11036/10177 +f 10860/11038/10179 10922/11100/10241 10859/11037/10178 +f 10861/11039/10180 10923/11101/10242 10860/11038/10179 +f 10862/11040/10181 10924/11102/10243 10861/11039/10180 +f 10863/11041/10182 10925/11103/10244 10862/11040/10181 +f 10864/11042/10183 10926/11104/10245 10863/11041/10182 +f 10865/11043/10184 10927/11105/10246 10864/11042/10183 +f 10866/11044/10185 10928/11106/10247 10865/11043/10184 +f 10867/11045/10186 10929/11107/10248 10866/11044/10185 +f 10868/11046/10187 10930/11108/10249 10867/11045/10186 +f 10869/11047/10188 10931/11109/10250 10868/11046/10187 +f 10870/11048/10189 10932/11110/10251 10869/11047/10188 +f 10871/11049/10190 10933/11111/10252 10870/11048/10189 +f 10872/11050/10191 10934/11112/10253 10871/11049/10190 +f 10873/11051/10192 10935/11113/10254 10872/11050/10191 +f 10874/11052/10193 10936/11114/10255 10873/11051/10192 +f 10875/11053/10194 10937/11115/10256 10874/11052/10193 +f 10876/11054/10195 10938/11116/10257 10875/11053/10194 +f 10877/11055/10196 10939/11117/10258 10876/11054/10195 +f 10878/11056/10197 10940/11118/10259 10877/11055/10196 +f 10879/11057/10198 10941/11119/10260 10878/11056/10197 +f 10880/11058/10199 10942/11120/10261 10879/11057/10198 +f 10881/11059/10200 10943/11121/10262 10880/11058/10199 +f 10882/11060/10201 10944/11122/10263 10881/11059/10200 +f 10883/11061/10202 10945/11123/10264 10882/11060/10201 +f 10884/11062/10203 10946/11124/10265 10883/11061/10202 +f 10885/11063/10204 10947/11125/10266 10884/11062/10203 +f 10886/11064/10205 10948/11126/10267 10885/11063/10204 +f 10887/11065/10206 10949/11127/10268 10886/11064/10205 +f 10888/11066/10207 10950/11128/10269 10887/11065/10206 +f 10889/11067/10208 10951/11129/10270 10888/11066/10207 +f 10890/11068/10209 10952/11130/10271 10889/11067/10208 +f 10891/11069/10210 10953/11131/10272 10890/11068/10209 +f 10892/11070/10211 10954/11132/10273 10891/11069/10210 +f 10893/11071/10212 10955/11133/10274 10892/11070/10211 +f 10894/11072/10213 10956/11134/10275 10893/11071/10212 +f 10895/11073/10214 10957/11135/10276 10894/11072/10213 +f 10896/11074/10215 10958/11136/10277 10895/11073/10214 +f 10897/11075/10216 10959/11137/10278 10896/11074/10215 +f 10898/11076/10217 10960/11138/10279 10897/11075/10216 +f 10899/11077/10218 10961/11139/10280 10898/11076/10217 +f 10900/11078/10219 10962/11140/10281 10899/11077/10218 +f 10901/11079/10220 10963/11141/10282 10900/11078/10219 +f 10902/11080/10221 10964/11142/10283 10901/11079/10220 +f 10903/11081/10222 10965/11143/10284 10902/11080/10221 +f 10904/11082/10223 10966/11144/10285 10903/11081/10222 +f 10905/11083/10224 10967/11145/10286 10904/11082/10223 +f 10906/11084/10225 10968/11146/10287 10905/11083/10224 +f 10907/11085/10226 10969/11147/10288 10906/11084/10225 +f 10908/11086/10227 10970/11148/10289 10907/11085/10226 +f 10909/11087/10228 10971/11149/10290 10908/11086/10227 +f 10910/11088/10229 10972/11150/10291 10909/11087/10228 +f 10911/11089/10230 10973/11151/10292 10910/11088/10229 +f 10912/11091/10232 10974/11152/10293 10911/11089/10230 +f 10913/11153/10294 10975/11154/10295 10912/11091/10232 +f 10915/11093/10234 10977/11155/10296 10914/11092/10233 +f 10916/11094/10235 10978/11156/10297 10915/11093/10234 +f 10917/11095/10236 10979/11157/10298 10916/11094/10235 +f 10918/11096/10237 10980/11158/10299 10917/11095/10236 +f 10919/11097/10238 10981/11159/10300 10918/11096/10237 +f 10920/11098/10239 10982/11160/10301 10919/11097/10238 +f 10921/11099/10240 10983/11161/10302 10920/11098/10239 +f 10922/11100/10241 10984/11162/10303 10921/11099/10240 +f 10923/11101/10242 10985/11163/10304 10922/11100/10241 +f 10924/11102/10243 10986/11164/10305 10923/11101/10242 +f 10925/11103/10244 10987/11165/10306 10924/11102/10243 +f 10926/11104/10245 10988/11166/10307 10925/11103/10244 +f 10927/11105/10246 10989/11167/10308 10926/11104/10245 +f 10928/11106/10247 10990/11168/10309 10927/11105/10246 +f 10929/11107/10248 10991/11169/10310 10928/11106/10247 +f 10930/11108/10249 10992/11170/10311 10929/11107/10248 +f 10931/11109/10250 10993/11171/10312 10930/11108/10249 +f 10932/11110/10251 10994/11172/10313 10931/11109/10250 +f 10933/11111/10252 10995/11173/10314 10932/11110/10251 +f 10934/11112/10253 10996/11174/7560 10933/11111/10252 +f 10935/11113/10254 10997/11175/10315 10934/11112/10253 +f 10936/11114/10255 10998/11176/10316 10935/11113/10254 +f 10937/11115/10256 10999/11177/10317 10936/11114/10255 +f 10938/11116/10257 11000/11178/10318 10937/11115/10256 +f 10939/11117/10258 11001/11179/10319 10938/11116/10257 +f 10940/11118/10259 11002/11180/10320 10939/11117/10258 +f 10941/11119/10260 11003/11181/10321 10940/11118/10259 +f 10942/11120/10261 11004/11182/10322 10941/11119/10260 +f 10943/11121/10262 11005/11183/10323 10942/11120/10261 +f 10944/11122/10263 11006/11184/10324 10943/11121/10262 +f 10945/11123/10264 11007/11185/10325 10944/11122/10263 +f 10946/11124/10265 11008/11186/10326 10945/11123/10264 +f 10947/11125/10266 11009/11187/10327 10946/11124/10265 +f 10948/11126/10267 11010/11188/10328 10947/11125/10266 +f 10949/11127/10268 11011/11189/10329 10948/11126/10267 +f 10950/11128/10269 11012/11190/10330 10949/11127/10268 +f 10951/11129/10270 11013/11191/10331 10950/11128/10269 +f 10952/11130/10271 11014/11192/10332 10951/11129/10270 +f 10953/11131/10272 11015/11193/10333 10952/11130/10271 +f 10954/11132/10273 11016/11194/10334 10953/11131/10272 +f 10955/11133/10274 11017/11195/10335 10954/11132/10273 +f 10956/11134/10275 11018/11196/10336 10955/11133/10274 +f 10957/11135/10276 11019/11197/10337 10956/11134/10275 +f 10958/11136/10277 11020/11198/10338 10957/11135/10276 +f 10959/11137/10278 11021/11199/10339 10958/11136/10277 +f 10960/11138/10279 11022/11200/10340 10959/11137/10278 +f 10961/11139/10280 11023/11201/10341 10960/11138/10279 +f 10962/11140/10281 11024/11202/10342 10961/11139/10280 +f 10963/11141/10282 11025/11203/10343 10962/11140/10281 +f 10964/11142/10283 11026/11204/10344 10963/11141/10282 +f 10965/11143/10284 11027/11205/10345 10964/11142/10283 +f 10966/11144/10285 11028/11206/10346 10965/11143/10284 +f 10967/11145/10286 11029/11207/10347 10966/11144/10285 +f 10968/11146/10287 11030/11208/10348 10967/11145/10286 +f 10969/11147/10288 11031/11209/10349 10968/11146/10287 +f 10970/11148/10289 11032/11210/10350 10969/11147/10288 +f 10971/11149/10290 11033/11211/10351 10970/11148/10289 +f 10972/11150/10291 11034/11212/10352 10971/11149/10290 +f 10973/11151/10292 11035/11213/10353 10972/11150/10291 +f 10974/11152/10293 11036/11214/10354 10973/11151/10292 +f 10975/11154/10295 11037/11215/10355 10974/11152/10293 +f 10976/11216/10356 11038/11217/10357 10975/11154/10295 +f 10978/11156/10297 11040/11218/10358 10977/11155/10296 +f 10979/11157/10298 11041/11219/10359 10978/11156/10297 +f 10980/11158/10299 11042/11220/10360 10979/11157/10298 +f 10981/11159/10300 11043/11221/10361 10980/11158/10299 +f 10982/11160/10301 11044/11222/10362 10981/11159/10300 +f 10983/11161/10302 11045/11223/10363 10982/11160/10301 +f 10984/11162/10303 11046/11224/10364 10983/11161/10302 +f 10985/11163/10304 11047/11225/10365 10984/11162/10303 +f 10986/11164/10305 11048/11226/10366 10985/11163/10304 +f 10987/11165/10306 11049/11227/10367 10986/11164/10305 +f 10988/11166/10307 11050/11228/10368 10987/11165/10306 +f 10989/11167/10308 11051/11229/10369 10988/11166/10307 +f 10990/11168/10309 11052/11230/10370 10989/11167/10308 +f 10991/11169/10310 11053/11231/10371 10990/11168/10309 +f 10992/11170/10311 11054/11232/10372 10991/11169/10310 +f 10993/11171/10312 11055/11233/10373 10992/11170/10311 +f 10994/11172/10313 11056/11234/10374 10993/11171/10312 +f 10995/11173/10314 11057/11235/7559 10994/11172/10313 +f 10996/11174/7560 11058/11236/10375 10995/11173/10314 +f 10997/11175/10315 11059/11237/10376 10996/11174/7560 +f 10998/11176/10316 11060/11238/10377 10997/11175/10315 +f 10999/11177/10317 11061/11239/10378 10998/11176/10316 +f 11000/11178/10318 11062/11240/10379 10999/11177/10317 +f 11001/11179/10319 11063/11241/10380 11000/11178/10318 +f 11002/11180/10320 11064/11242/10381 11001/11179/10319 +f 11003/11181/10321 11065/11243/10382 11002/11180/10320 +f 11004/11182/10322 11066/11244/10383 11003/11181/10321 +f 11005/11183/10323 11067/11245/10384 11004/11182/10322 +f 11006/11184/10324 11068/11246/10385 11005/11183/10323 +f 11007/11185/10325 11069/11247/10386 11006/11184/10324 +f 11008/11186/10326 11070/11248/10387 11007/11185/10325 +f 11009/11187/10327 11071/11249/10388 11008/11186/10326 +f 11010/11188/10328 11072/11250/10389 11009/11187/10327 +f 11011/11189/10329 11073/11251/10390 11010/11188/10328 +f 11012/11190/10330 11074/11252/10391 11011/11189/10329 +f 11013/11191/10331 11075/11253/10392 11012/11190/10330 +f 11014/11192/10332 11076/11254/10393 11013/11191/10331 +f 11015/11193/10333 11077/11255/10394 11014/11192/10332 +f 11016/11194/10334 11078/11256/10395 11015/11193/10333 +f 11017/11195/10335 11079/11257/10396 11016/11194/10334 +f 11018/11196/10336 11080/11258/10397 11017/11195/10335 +f 11019/11197/10337 11081/11259/10398 11018/11196/10336 +f 11020/11198/10338 11082/11260/10399 11019/11197/10337 +f 11021/11199/10339 11083/11261/10400 11020/11198/10338 +f 11022/11200/10340 11084/11262/10401 11021/11199/10339 +f 11023/11201/10341 11085/11263/10402 11022/11200/10340 +f 11024/11202/10342 11086/11264/10403 11023/11201/10341 +f 11025/11203/10343 11087/11265/10404 11024/11202/10342 +f 11026/11204/10344 11088/11266/10405 11025/11203/10343 +f 11027/11205/10345 11089/11267/10406 11026/11204/10344 +f 11028/11206/10346 11090/11268/10407 11027/11205/10345 +f 11029/11207/10347 11091/11269/10408 11028/11206/10346 +f 11030/11208/10348 11092/11270/10409 11029/11207/10347 +f 11031/11209/10349 11093/11271/10410 11030/11208/10348 +f 11032/11210/10350 11094/11272/10411 11031/11209/10349 +f 11033/11211/10351 11095/11273/10412 11032/11210/10350 +f 11034/11212/10352 11096/11274/10413 11033/11211/10351 +f 11035/11213/10353 11097/11275/10414 11034/11212/10352 +f 11036/11214/10354 11098/11276/10415 11035/11213/10353 +f 11037/11215/10355 11099/11277/10416 11036/11214/10354 +f 11038/11217/10357 11100/11278/10417 11037/11215/10355 +f 11039/11279/10418 11101/11280/10419 11038/11217/10357 +f 11041/11219/10359 11103/11281/10420 11040/11218/10358 +f 11042/11220/10360 11104/11282/10421 11041/11219/10359 +f 11043/11221/10361 11105/11283/10422 11042/11220/10360 +f 11044/11222/10362 11106/11284/10423 11043/11221/10361 +f 11045/11223/10363 11107/11285/10424 11044/11222/10362 +f 11046/11224/10364 11108/11286/10425 11045/11223/10363 +f 11047/11225/10365 11109/11287/10426 11046/11224/10364 +f 11048/11226/10366 11110/11288/10427 11047/11225/10365 +f 11049/11227/10367 11111/11289/10428 11048/11226/10366 +f 11050/11228/10368 11112/11290/10429 11049/11227/10367 +f 11051/11229/10369 11113/11291/10430 11050/11228/10368 +f 11052/11230/10370 11114/11292/10431 11051/11229/10369 +f 11053/11231/10371 11115/11293/10432 11052/11230/10370 +f 11054/11232/10372 11116/11294/10433 11053/11231/10371 +f 11055/11233/10373 11117/11295/10434 11054/11232/10372 +f 11056/11234/10374 11118/11296/10435 11055/11233/10373 +f 11057/11235/7559 11119/11297/10436 11056/11234/10374 +f 11058/11236/10375 11120/11298/10437 11057/11235/7559 +f 11059/11237/10376 11121/11299/10438 11058/11236/10375 +f 11060/11238/10377 11122/11300/10439 11059/11237/10376 +f 11061/11239/10378 11123/11301/10440 11060/11238/10377 +f 11062/11240/10379 11124/11302/10441 11061/11239/10378 +f 11063/11241/10380 11125/11303/10442 11062/11240/10379 +f 11064/11242/10381 11126/11304/10443 11063/11241/10380 +f 11065/11243/10382 11127/11305/10444 11064/11242/10381 +f 11066/11244/10383 11128/11306/10445 11065/11243/10382 +f 11067/11245/10384 11129/11307/10446 11066/11244/10383 +f 11068/11246/10385 11130/11308/10447 11067/11245/10384 +f 11069/11247/10386 11131/11309/10448 11068/11246/10385 +f 11070/11248/10387 11132/11310/10449 11069/11247/10386 +f 11071/11249/10388 11133/11311/10450 11070/11248/10387 +f 11072/11250/10389 11134/11312/10451 11071/11249/10388 +f 11073/11251/10390 11135/11313/10452 11072/11250/10389 +f 11074/11252/10391 11136/11314/10453 11073/11251/10390 +f 11075/11253/10392 11137/11315/10454 11074/11252/10391 +f 11076/11254/10393 11138/11316/10455 11075/11253/10392 +f 11077/11255/10394 11139/11317/10169 11076/11254/10393 +f 11078/11256/10395 11140/11318/10456 11077/11255/10394 +f 11079/11257/10396 11141/11319/10457 11078/11256/10395 +f 11080/11258/10397 11142/11320/10458 11079/11257/10396 +f 11081/11259/10398 11143/11321/10459 11080/11258/10397 +f 11082/11260/10399 11144/11322/10460 11081/11259/10398 +f 11083/11261/10400 11145/11323/10461 11082/11260/10399 +f 11084/11262/10401 11146/11324/10462 11083/11261/10400 +f 11085/11263/10402 11147/11325/10463 11084/11262/10401 +f 11086/11264/10403 11148/11326/10464 11085/11263/10402 +f 11087/11265/10404 11149/11327/10465 11086/11264/10403 +f 11088/11266/10405 11150/11328/10466 11087/11265/10404 +f 11089/11267/10406 11151/11329/10467 11088/11266/10405 +f 11090/11268/10407 11152/11330/10468 11089/11267/10406 +f 11091/11269/10408 11153/11331/10469 11090/11268/10407 +f 11092/11270/10409 11154/11332/10470 11091/11269/10408 +f 11093/11271/10410 11155/11333/10471 11092/11270/10409 +f 11094/11272/10411 11156/11334/10472 11093/11271/10410 +f 11095/11273/10412 11157/11335/10473 11094/11272/10411 +f 11096/11274/10413 11158/11336/10474 11095/11273/10412 +f 11097/11275/10414 11159/11337/10475 11096/11274/10413 +f 11098/11276/10415 11160/11338/10476 11097/11275/10414 +f 11099/11277/10416 11161/11339/10477 11098/11276/10415 +f 11100/11278/10417 11162/11340/10478 11099/11277/10416 +f 11101/11280/10419 11163/11341/10479 11100/11278/10417 +f 11102/11342/10480 11164/11343/10481 11101/11280/10419 +f 11104/11282/10421 11166/11344/10482 11103/11281/10420 +f 11105/11283/10422 11167/11345/10483 11104/11282/10421 +f 11106/11284/10423 11168/11346/10484 11105/11283/10422 +f 11107/11285/10424 11169/11347/10485 11106/11284/10423 +f 11108/11286/10425 11170/11348/10486 11107/11285/10424 +f 11109/11287/10426 11171/11349/10487 11108/11286/10425 +f 11110/11288/10427 11172/11350/10488 11109/11287/10426 +f 11111/11289/10428 11173/11351/10489 11110/11288/10427 +f 11112/11290/10429 11174/11352/10490 11111/11289/10428 +f 11113/11291/10430 11175/11353/10491 11112/11290/10429 +f 11114/11292/10431 11176/11354/10492 11113/11291/10430 +f 11115/11293/10432 11177/11355/10493 11114/11292/10431 +f 11116/11294/10433 11178/11356/10494 11115/11293/10432 +f 11117/11295/10434 11179/11357/10495 11116/11294/10433 +f 11118/11296/10435 11180/11358/10496 11117/11295/10434 +f 11119/11297/10436 11181/11359/10497 11118/11296/10435 +f 11120/11298/10437 11182/11360/10498 11119/11297/10436 +f 11121/11299/10438 11183/11361/10499 11120/11298/10437 +f 11122/11300/10439 11184/11362/10500 11121/11299/10438 +f 11123/11301/10440 11185/11363/10501 11122/11300/10439 +f 11124/11302/10441 11186/11364/10502 11123/11301/10440 +f 11125/11303/10442 11187/11365/10503 11124/11302/10441 +f 11126/11304/10443 11188/11366/10504 11125/11303/10442 +f 11127/11305/10444 11189/11367/10505 11126/11304/10443 +f 11128/11306/10445 11190/11368/10506 11127/11305/10444 +f 11129/11307/10446 11191/11369/10507 11128/11306/10445 +f 11130/11308/10447 11192/11370/10508 11129/11307/10446 +f 11131/11309/10448 11193/11371/10509 11130/11308/10447 +f 11132/11310/10449 11194/11372/10510 11131/11309/10448 +f 11133/11311/10450 11195/11373/10511 11132/11310/10449 +f 11134/11312/10451 11196/11374/10512 11133/11311/10450 +f 11135/11313/10452 11197/11375/10513 11134/11312/10451 +f 11136/11314/10453 11198/11376/10514 11135/11313/10452 +f 11137/11315/10454 11199/11377/10515 11136/11314/10453 +f 11138/11316/10455 11200/11378/10516 11137/11315/10454 +f 11139/11317/10169 11201/11379/10517 11138/11316/10455 +f 11140/11318/10456 11202/11380/10518 11139/11317/10169 +f 11141/11319/10457 11203/11381/10519 11140/11318/10456 +f 11142/11320/10458 11204/11382/10520 11141/11319/10457 +f 11143/11321/10459 11205/11383/10521 11142/11320/10458 +f 11144/11322/10460 11206/11384/10522 11143/11321/10459 +f 11145/11323/10461 11207/11385/10523 11144/11322/10460 +f 11146/11324/10462 11208/11386/10524 11145/11323/10461 +f 11147/11325/10463 11209/11387/10525 11146/11324/10462 +f 11148/11326/10464 11210/11388/10526 11147/11325/10463 +f 11149/11327/10465 11211/11389/10527 11148/11326/10464 +f 11150/11328/10466 11212/11390/10528 11149/11327/10465 +f 11151/11329/10467 11213/11391/10529 11150/11328/10466 +f 11152/11330/10468 11214/11392/10530 11151/11329/10467 +f 11153/11331/10469 11215/11393/10531 11152/11330/10468 +f 11154/11332/10470 11216/11394/10532 11153/11331/10469 +f 11155/11333/10471 11217/11395/10533 11154/11332/10470 +f 11156/11334/10472 11218/11396/10534 11155/11333/10471 +f 11157/11335/10473 11219/11397/10535 11156/11334/10472 +f 11158/11336/10474 11220/11398/10536 11157/11335/10473 +f 11159/11337/10475 11221/11399/10537 11158/11336/10474 +f 11160/11338/10476 11222/11400/10538 11159/11337/10475 +f 11161/11339/10477 11223/11401/10539 11160/11338/10476 +f 11162/11340/10478 11224/11402/10540 11161/11339/10477 +f 11163/11341/10479 11225/11403/10541 11162/11340/10478 +f 11164/11343/10481 11226/11404/10542 11163/11341/10479 +f 11165/11405/10543 11227/11406/10544 11164/11343/10481 +f 11167/11345/10483 11229/11407/10545 11166/11344/10482 +f 11168/11346/10484 11230/11408/10546 11167/11345/10483 +f 11169/11347/10485 11231/11409/10547 11168/11346/10484 +f 11170/11348/10486 11232/11410/10548 11169/11347/10485 +f 11171/11349/10487 11233/11411/10549 11170/11348/10486 +f 11172/11350/10488 11234/11412/10550 11171/11349/10487 +f 11173/11351/10489 11235/11413/10551 11172/11350/10488 +f 11174/11352/10490 11236/11414/10552 11173/11351/10489 +f 11175/11353/10491 11237/11415/10553 11174/11352/10490 +f 11176/11354/10492 11238/11416/10554 11175/11353/10491 +f 11177/11355/10493 11239/11417/10555 11176/11354/10492 +f 11178/11356/10494 11240/11418/10556 11177/11355/10493 +f 11179/11357/10495 11241/11419/10557 11178/11356/10494 +f 11180/11358/10496 11242/11420/10558 11179/11357/10495 +f 11181/11359/10497 11243/11421/10559 11180/11358/10496 +f 11182/11360/10498 11244/11422/10560 11181/11359/10497 +f 11183/11361/10499 11245/11423/10561 11182/11360/10498 +f 11184/11362/10500 11246/11424/10562 11183/11361/10499 +f 11185/11363/10501 11247/11425/10563 11184/11362/10500 +f 11186/11364/10502 11248/11426/10564 11185/11363/10501 +f 11187/11365/10503 11249/11427/10565 11186/11364/10502 +f 11188/11366/10504 11250/11428/10566 11187/11365/10503 +f 11189/11367/10505 11251/11429/10567 11188/11366/10504 +f 11190/11368/10506 11252/11430/10568 11189/11367/10505 +f 11191/11369/10507 11253/11431/10569 11190/11368/10506 +f 11192/11370/10508 11254/11432/10488 11191/11369/10507 +f 11193/11371/10509 11255/11433/10570 11192/11370/10508 +f 11194/11372/10510 11256/11434/10571 11193/11371/10509 +f 11195/11373/10511 11257/11435/10572 11194/11372/10510 +f 11196/11374/10512 11258/11436/10573 11195/11373/10511 +f 11197/11375/10513 11259/11437/10574 11196/11374/10512 +f 11198/11376/10514 11260/11438/10575 11197/11375/10513 +f 11199/11377/10515 11261/11439/10576 11198/11376/10514 +f 11200/11378/10516 11262/11440/10577 11199/11377/10515 +f 11201/11379/10517 11263/11441/10578 11200/11378/10516 +f 11202/11380/10518 11264/11442/10579 11201/11379/10517 +f 11203/11381/10519 11265/11443/10580 11202/11380/10518 +f 11204/11382/10520 11266/11444/10581 11203/11381/10519 +f 11205/11383/10521 11267/11445/10582 11204/11382/10520 +f 11206/11384/10522 11268/11446/10583 11205/11383/10521 +f 11207/11385/10523 11269/11447/10584 11206/11384/10522 +f 11208/11386/10524 11270/11448/10585 11207/11385/10523 +f 11209/11387/10525 11271/11449/10586 11208/11386/10524 +f 11210/11388/10526 11272/11450/10587 11209/11387/10525 +f 11211/11389/10527 11273/11451/10588 11210/11388/10526 +f 11212/11390/10528 11274/11452/10589 11211/11389/10527 +f 11213/11391/10529 11275/11453/10590 11212/11390/10528 +f 11214/11392/10530 11276/11454/10591 11213/11391/10529 +f 11215/11393/10531 11277/11455/10592 11214/11392/10530 +f 11216/11394/10532 11278/11456/10593 11215/11393/10531 +f 11217/11395/10533 11279/11457/10594 11216/11394/10532 +f 11218/11396/10534 11280/11458/10595 11217/11395/10533 +f 11219/11397/10535 11281/11459/10596 11218/11396/10534 +f 11220/11398/10536 11282/11460/10597 11219/11397/10535 +f 11221/11399/10537 11283/11461/10598 11220/11398/10536 +f 11222/11400/10538 11284/11462/10599 11221/11399/10537 +f 11223/11401/10539 11285/11463/10600 11222/11400/10538 +f 11224/11402/10540 11286/11464/10601 11223/11401/10539 +f 11225/11403/10541 11287/11465/10602 11224/11402/10540 +f 11226/11404/10542 11288/11466/10603 11225/11403/10541 +f 11227/11406/10544 11289/11467/10604 11226/11404/10542 +f 11228/11468/10605 11290/11469/10606 11227/11406/10544 +f 11230/11408/10546 11292/11470/10607 11229/11407/10545 +f 11231/11409/10547 11293/11471/10608 11230/11408/10546 +f 11232/11410/10548 11294/11472/10609 11231/11409/10547 +f 11233/11411/10549 11295/11473/10610 11232/11410/10548 +f 11234/11412/10550 11296/11474/10611 11233/11411/10549 +f 11235/11413/10551 11297/11475/10612 11234/11412/10550 +f 11236/11414/10552 11298/11476/10613 11235/11413/10551 +f 11237/11415/10553 11299/11477/10614 11236/11414/10552 +f 11238/11416/10554 11300/11478/10615 11237/11415/10553 +f 11239/11417/10555 11301/11479/10616 11238/11416/10554 +f 11240/11418/10556 11302/11480/10617 11239/11417/10555 +f 11241/11419/10557 11303/11481/10618 11240/11418/10556 +f 11242/11420/10558 11304/11482/10619 11241/11419/10557 +f 11243/11421/10559 11305/11483/10620 11242/11420/10558 +f 11244/11422/10560 11306/11484/10621 11243/11421/10559 +f 11245/11423/10561 11307/11485/10622 11244/11422/10560 +f 11246/11424/10562 11308/11486/10623 11245/11423/10561 +f 11247/11425/10563 11309/11487/10624 11246/11424/10562 +f 11248/11426/10564 11310/11488/10625 11247/11425/10563 +f 11249/11427/10565 11311/11489/10626 11248/11426/10564 +f 11250/11428/10566 11312/11490/10627 11249/11427/10565 +f 11251/11429/10567 11313/11491/10628 11250/11428/10566 +f 11252/11430/10568 11314/11492/10629 11251/11429/10567 +f 11253/11431/10569 11315/11493/10630 11252/11430/10568 +f 11254/11432/10488 11316/11494/10631 11253/11431/10569 +f 11255/11433/10570 11317/11495/10632 11254/11432/10488 +f 11256/11434/10571 11318/11496/10633 11255/11433/10570 +f 11257/11435/10572 11319/11497/10634 11256/11434/10571 +f 11258/11436/10573 11320/11498/10635 11257/11435/10572 +f 11259/11437/10574 11321/11499/10636 11258/11436/10573 +f 11260/11438/10575 11322/11500/10637 11259/11437/10574 +f 11261/11439/10576 11323/11501/10638 11260/11438/10575 +f 11262/11440/10577 11324/11502/10639 11261/11439/10576 +f 11263/11441/10578 11325/11503/10640 11262/11440/10577 +f 11264/11442/10579 11326/11504/10641 11263/11441/10578 +f 11265/11443/10580 11327/11505/10642 11264/11442/10579 +f 11266/11444/10581 11328/11506/10643 11265/11443/10580 +f 11267/11445/10582 11329/11507/10644 11266/11444/10581 +f 11268/11446/10583 11330/11508/10645 11267/11445/10582 +f 11269/11447/10584 11331/11509/10646 11268/11446/10583 +f 11270/11448/10585 11332/11510/10647 11269/11447/10584 +f 11271/11449/10586 11333/11511/10648 11270/11448/10585 +f 11272/11450/10587 11334/11512/10649 11271/11449/10586 +f 11273/11451/10588 11335/11513/10650 11272/11450/10587 +f 11274/11452/10589 11336/11514/10651 11273/11451/10588 +f 11275/11453/10590 11337/11515/10652 11274/11452/10589 +f 11276/11454/10591 11338/11516/10653 11275/11453/10590 +f 11277/11455/10592 11339/11517/10654 11276/11454/10591 +f 11278/11456/10593 11340/11518/10655 11277/11455/10592 +f 11279/11457/10594 11341/11519/10656 11278/11456/10593 +f 11280/11458/10595 11342/11520/10657 11279/11457/10594 +f 11281/11459/10596 11343/11521/10658 11280/11458/10595 +f 11282/11460/10597 11344/11522/10659 11281/11459/10596 +f 11283/11461/10598 11345/11523/10660 11282/11460/10597 +f 11284/11462/10599 11346/11524/10661 11283/11461/10598 +f 11285/11463/10600 11347/11525/10662 11284/11462/10599 +f 11286/11464/10601 11348/11526/10663 11285/11463/10600 +f 11287/11465/10602 11349/11527/10664 11286/11464/10601 +f 11288/11466/10603 11350/11528/10665 11287/11465/10602 +f 11289/11467/10604 11351/11529/10666 11288/11466/10603 +f 11290/11469/10606 11352/11530/10667 11289/11467/10604 +f 11291/11531/10668 11353/11532/10669 11290/11469/10606 +f 11293/11471/10608 11355/11533/10670 11292/11470/10607 +f 11294/11472/10609 11356/11534/10671 11293/11471/10608 +f 11295/11473/10610 11357/11535/10672 11294/11472/10609 +f 11296/11474/10611 11358/11536/10673 11295/11473/10610 +f 11297/11475/10612 11359/11537/10674 11296/11474/10611 +f 11298/11476/10613 11360/11538/10675 11297/11475/10612 +f 11299/11477/10614 11361/11539/10676 11298/11476/10613 +f 11300/11478/10615 11362/11540/10677 11299/11477/10614 +f 11301/11479/10616 11363/11541/10678 11300/11478/10615 +f 11302/11480/10617 11364/11542/10679 11301/11479/10616 +f 11303/11481/10618 11365/11543/10680 11302/11480/10617 +f 11304/11482/10619 11366/11544/10681 11303/11481/10618 +f 11305/11483/10620 11367/11545/10682 11304/11482/10619 +f 11306/11484/10621 11368/11546/10683 11305/11483/10620 +f 11307/11485/10622 11369/11547/10684 11306/11484/10621 +f 11308/11486/10623 11370/11548/10685 11307/11485/10622 +f 11309/11487/10624 11371/11549/10686 11308/11486/10623 +f 11310/11488/10625 11372/11550/10687 11309/11487/10624 +f 11311/11489/10626 11373/11551/10688 11310/11488/10625 +f 11312/11490/10627 11374/11552/10689 11311/11489/10626 +f 11313/11491/10628 11375/11553/10690 11312/11490/10627 +f 11314/11492/10629 11376/11554/10691 11313/11491/10628 +f 11315/11493/10630 11377/11555/10692 11314/11492/10629 +f 11316/11494/10631 11378/11556/10693 11315/11493/10630 +f 11317/11495/10632 11379/11557/10694 11316/11494/10631 +f 11318/11496/10633 11380/11558/10695 11317/11495/10632 +f 11319/11497/10634 11381/11559/10696 11318/11496/10633 +f 11320/11498/10635 11382/11560/10697 11319/11497/10634 +f 11321/11499/10636 11383/11561/10698 11320/11498/10635 +f 11322/11500/10637 11384/11562/10699 11321/11499/10636 +f 11323/11501/10638 11385/11563/10700 11322/11500/10637 +f 11324/11502/10639 11386/11564/10701 11323/11501/10638 +f 11325/11503/10640 11387/11565/10702 11324/11502/10639 +f 11326/11504/10641 11388/11566/10703 11325/11503/10640 +f 11327/11505/10642 11389/11567/10704 11326/11504/10641 +f 11328/11506/10643 11390/11568/10705 11327/11505/10642 +f 11329/11507/10644 11391/11569/10706 11328/11506/10643 +f 11330/11508/10645 11392/11570/10707 11329/11507/10644 +f 11331/11509/10646 11393/11571/10708 11330/11508/10645 +f 11332/11510/10647 11394/11572/10709 11331/11509/10646 +f 11333/11511/10648 11395/11573/10710 11332/11510/10647 +f 11334/11512/10649 11396/11574/10711 11333/11511/10648 +f 11335/11513/10650 11397/11575/10712 11334/11512/10649 +f 11336/11514/10651 11398/11576/10713 11335/11513/10650 +f 11337/11515/10652 11399/11577/10714 11336/11514/10651 +f 11338/11516/10653 11400/11578/10715 11337/11515/10652 +f 11339/11517/10654 11401/11579/10716 11338/11516/10653 +f 11340/11518/10655 11402/11580/10717 11339/11517/10654 +f 11341/11519/10656 11403/11581/10718 11340/11518/10655 +f 11342/11520/10657 11404/11582/10719 11341/11519/10656 +f 11343/11521/10658 11405/11583/10720 11342/11520/10657 +f 11344/11522/10659 11406/11584/10721 11343/11521/10658 +f 11345/11523/10660 11407/11585/10722 11344/11522/10659 +f 11346/11524/10661 11408/11586/10723 11345/11523/10660 +f 11347/11525/10662 11409/11587/10724 11346/11524/10661 +f 11348/11526/10663 11410/11588/10725 11347/11525/10662 +f 11349/11527/10664 11411/11589/10726 11348/11526/10663 +f 11350/11528/10665 11412/11590/10727 11349/11527/10664 +f 11351/11529/10666 11413/11591/10728 11350/11528/10665 +f 11352/11530/10667 11414/11592/10729 11351/11529/10666 +f 11353/11532/10669 11415/11593/10730 11352/11530/10667 +f 11354/11594/10731 11416/11595/10732 11353/11532/10669 +f 11356/11534/10671 11418/11596/10733 11355/11533/10670 +f 11357/11535/10672 11419/11597/10734 11356/11534/10671 +f 11358/11536/10673 11420/11598/10735 11357/11535/10672 +f 11359/11537/10674 11421/11599/10736 11358/11536/10673 +f 11360/11538/10675 11422/11600/10737 11359/11537/10674 +f 11361/11539/10676 11423/11601/10738 11360/11538/10675 +f 11362/11540/10677 11424/11602/10739 11361/11539/10676 +f 11363/11541/10678 11425/11603/10740 11362/11540/10677 +f 11364/11542/10679 11426/11604/10741 11363/11541/10678 +f 11365/11543/10680 11427/11605/10742 11364/11542/10679 +f 11366/11544/10681 11428/11606/10743 11365/11543/10680 +f 11367/11545/10682 11429/11607/10744 11366/11544/10681 +f 11368/11546/10683 11430/11608/10745 11367/11545/10682 +f 11369/11547/10684 11431/11609/10746 11368/11546/10683 +f 11370/11548/10685 11432/11610/10747 11369/11547/10684 +f 11371/11549/10686 11433/11611/10748 11370/11548/10685 +f 11372/11550/10687 11434/11612/10749 11371/11549/10686 +f 11373/11551/10688 11435/11613/10750 11372/11550/10687 +f 11374/11552/10689 11436/11614/10751 11373/11551/10688 +f 11375/11553/10690 11437/11615/10752 11374/11552/10689 +f 11376/11554/10691 11438/11616/10753 11375/11553/10690 +f 11377/11555/10692 11439/11617/10754 11376/11554/10691 +f 11378/11556/10693 11440/11618/10755 11377/11555/10692 +f 11379/11557/10694 11441/11619/10756 11378/11556/10693 +f 11380/11558/10695 11442/11620/10757 11379/11557/10694 +f 11381/11559/10696 11443/11621/10758 11380/11558/10695 +f 11382/11560/10697 11444/11622/10759 11381/11559/10696 +f 11383/11561/10698 11445/11623/10760 11382/11560/10697 +f 11384/11562/10699 11446/11624/10761 11383/11561/10698 +f 11385/11563/10700 11447/11625/10762 11384/11562/10699 +f 11386/11564/10701 11448/11626/10763 11385/11563/10700 +f 11387/11565/10702 11449/11627/10764 11386/11564/10701 +f 11388/11566/10703 11450/11628/10765 11387/11565/10702 +f 11389/11567/10704 11451/11629/10766 11388/11566/10703 +f 11390/11568/10705 11452/11630/10767 11389/11567/10704 +f 11391/11569/10706 11453/11631/10768 11390/11568/10705 +f 11392/11570/10707 11454/11632/10769 11391/11569/10706 +f 11393/11571/10708 11455/11633/10770 11392/11570/10707 +f 11394/11572/10709 11456/11634/10771 11393/11571/10708 +f 11395/11573/10710 11457/11635/10772 11394/11572/10709 +f 11396/11574/10711 11458/11636/10773 11395/11573/10710 +f 11397/11575/10712 11459/11637/10774 11396/11574/10711 +f 11398/11576/10713 11460/11638/10775 11397/11575/10712 +f 11399/11577/10714 11461/11639/10776 11398/11576/10713 +f 11400/11578/10715 11462/11640/10777 11399/11577/10714 +f 11401/11579/10716 11463/11641/10778 11400/11578/10715 +f 11402/11580/10717 11464/11642/10779 11401/11579/10716 +f 11403/11581/10718 11465/11643/10780 11402/11580/10717 +f 11404/11582/10719 11466/11644/10781 11403/11581/10718 +f 11405/11583/10720 11467/11645/10782 11404/11582/10719 +f 11406/11584/10721 11468/11646/10783 11405/11583/10720 +f 11407/11585/10722 11469/11647/10784 11406/11584/10721 +f 11408/11586/10723 11470/11648/10785 11407/11585/10722 +f 11409/11587/10724 11471/11649/10786 11408/11586/10723 +f 11410/11588/10725 11472/11650/10787 11409/11587/10724 +f 11411/11589/10726 11473/11651/10788 11410/11588/10725 +f 11412/11590/10727 11474/11652/10789 11411/11589/10726 +f 11413/11591/10728 11475/11653/10790 11412/11590/10727 +f 11414/11592/10729 11476/11654/10791 11413/11591/10728 +f 11415/11593/10730 11477/11655/10792 11414/11592/10729 +f 11416/11595/10732 11478/11656/10793 11415/11593/10730 +f 11417/11657/10794 11479/11658/10795 11416/11595/10732 +f 11419/11597/10734 11481/11659/10796 11418/11596/10733 +f 11420/11598/10735 11482/11660/10797 11419/11597/10734 +f 11421/11599/10736 11483/11661/10798 11420/11598/10735 +f 11422/11600/10737 11484/11662/10799 11421/11599/10736 +f 11423/11601/10738 11485/11663/10800 11422/11600/10737 +f 11424/11602/10739 11486/11664/10801 11423/11601/10738 +f 11425/11603/10740 11487/11665/10802 11424/11602/10739 +f 11426/11604/10741 11488/11666/10803 11425/11603/10740 +f 11427/11605/10742 11489/11667/10804 11426/11604/10741 +f 11428/11606/10743 11490/11668/10805 11427/11605/10742 +f 11429/11607/10744 11491/11669/10806 11428/11606/10743 +f 11430/11608/10745 11492/11670/10807 11429/11607/10744 +f 11431/11609/10746 11493/11671/10808 11430/11608/10745 +f 11432/11610/10747 11494/11672/10809 11431/11609/10746 +f 11433/11611/10748 11495/11673/10810 11432/11610/10747 +f 11434/11612/10749 11496/11674/10811 11433/11611/10748 +f 11435/11613/10750 11497/11675/10812 11434/11612/10749 +f 11436/11614/10751 11498/11676/10813 11435/11613/10750 +f 11437/11615/10752 11499/11677/10814 11436/11614/10751 +f 11438/11616/10753 11500/11678/10815 11437/11615/10752 +f 11439/11617/10754 11501/11679/10816 11438/11616/10753 +f 11440/11618/10755 11502/11680/10817 11439/11617/10754 +f 11441/11619/10756 11503/11681/10818 11440/11618/10755 +f 11442/11620/10757 11504/11682/10819 11441/11619/10756 +f 11443/11621/10758 11505/11683/10820 11442/11620/10757 +f 11444/11622/10759 11506/11684/10821 11443/11621/10758 +f 11445/11623/10760 11507/11685/10822 11444/11622/10759 +f 11446/11624/10761 11508/11686/10823 11445/11623/10760 +f 11447/11625/10762 11509/11687/10824 11446/11624/10761 +f 11448/11626/10763 11510/11688/10825 11447/11625/10762 +f 11449/11627/10764 11511/11689/10826 11448/11626/10763 +f 11450/11628/10765 11512/11690/10827 11449/11627/10764 +f 11451/11629/10766 11513/11691/10828 11450/11628/10765 +f 11452/11630/10767 11514/11692/10829 11451/11629/10766 +f 11453/11631/10768 11515/11693/10830 11452/11630/10767 +f 11454/11632/10769 11516/11694/10831 11453/11631/10768 +f 11455/11633/10770 11517/11695/10832 11454/11632/10769 +f 11456/11634/10771 11518/11696/10833 11455/11633/10770 +f 11457/11635/10772 11519/11697/10834 11456/11634/10771 +f 11458/11636/10773 11520/11698/10835 11457/11635/10772 +f 11459/11637/10774 11521/11699/10836 11458/11636/10773 +f 11460/11638/10775 11522/11700/10837 11459/11637/10774 +f 11461/11639/10776 11523/11701/10838 11460/11638/10775 +f 11462/11640/10777 11524/11702/10839 11461/11639/10776 +f 11463/11641/10778 11525/11703/10840 11462/11640/10777 +f 11464/11642/10779 11526/11704/10841 11463/11641/10778 +f 11465/11643/10780 11527/11705/10842 11464/11642/10779 +f 11466/11644/10781 11528/11706/10843 11465/11643/10780 +f 11467/11645/10782 11529/11707/10844 11466/11644/10781 +f 11468/11646/10783 11530/11708/10845 11467/11645/10782 +f 11469/11647/10784 11531/11709/10846 11468/11646/10783 +f 11469/11647/10784 11533/11710/10847 11532/11711/10848 +f 11471/11649/10786 11533/11710/10847 11470/11648/10785 +f 11472/11650/10787 11534/11712/10849 11471/11649/10786 +f 11473/11651/10788 11535/11713/10850 11472/11650/10787 +f 11474/11652/10789 11536/11714/10851 11473/11651/10788 +f 11475/11653/10790 11537/11715/10852 11474/11652/10789 +f 11476/11654/10791 11538/11716/10853 11475/11653/10790 +f 11477/11655/10792 11539/11717/10854 11476/11654/10791 +f 11478/11656/10793 11540/11718/10855 11477/11655/10792 +f 11479/11658/10795 11541/11719/10856 11478/11656/10793 +f 11480/11720/10857 11542/11721/10858 11479/11658/10795 +f 11482/11660/10797 11544/11722/10859 11481/11659/10796 +f 11483/11661/10798 11545/11723/10860 11482/11660/10797 +f 11484/11662/10799 11546/11724/10861 11483/11661/10798 +f 11485/11663/10800 11547/11725/10862 11484/11662/10799 +f 11486/11664/10801 11548/11726/10863 11485/11663/10800 +f 11487/11665/10802 11549/11727/10864 11486/11664/10801 +f 11488/11666/10803 11550/11728/10865 11487/11665/10802 +f 11489/11667/10804 11551/11729/10866 11488/11666/10803 +f 11490/11668/10805 11552/11730/10867 11489/11667/10804 +f 11491/11669/10806 11553/11731/10868 11490/11668/10805 +f 11492/11670/10807 11554/11732/10869 11491/11669/10806 +f 11493/11671/10808 11555/11733/10870 11492/11670/10807 +f 11494/11672/10809 11556/11734/10871 11493/11671/10808 +f 11495/11673/10810 11557/11735/10872 11494/11672/10809 +f 11496/11674/10811 11558/11736/10873 11495/11673/10810 +f 11497/11675/10812 11559/11737/10874 11496/11674/10811 +f 11498/11676/10813 11560/11738/10875 11497/11675/10812 +f 11499/11677/10814 11561/11739/10876 11498/11676/10813 +f 11500/11678/10815 11562/11740/10877 11499/11677/10814 +f 11501/11679/10816 11563/11741/10878 11500/11678/10815 +f 11502/11680/10817 11564/11742/10879 11501/11679/10816 +f 11503/11681/10818 11565/11743/10880 11502/11680/10817 +f 11504/11682/10819 11566/11744/10881 11503/11681/10818 +f 11505/11683/10820 11567/11745/10882 11504/11682/10819 +f 11506/11684/10821 11568/11746/10883 11505/11683/10820 +f 11507/11685/10822 11569/11747/10884 11506/11684/10821 +f 11508/11686/10823 11570/11748/10885 11507/11685/10822 +f 11509/11687/10824 11571/11749/10886 11508/11686/10823 +f 11510/11688/10825 11572/11750/10887 11509/11687/10824 +f 11511/11689/10826 11573/11751/10888 11510/11688/10825 +f 11512/11690/10827 11574/11752/10889 11511/11689/10826 +f 11513/11691/10828 11575/11753/10890 11512/11690/10827 +f 11514/11692/10829 11576/11754/10891 11513/11691/10828 +f 11515/11693/10830 11577/11755/10892 11514/11692/10829 +f 11516/11694/10831 11578/11756/10893 11515/11693/10830 +f 11517/11695/10832 11579/11757/10894 11516/11694/10831 +f 11518/11696/10833 11580/11758/10895 11517/11695/10832 +f 11519/11697/10834 11581/11759/10896 11518/11696/10833 +f 11520/11698/10835 11582/11760/10897 11519/11697/10834 +f 11521/11699/10836 11583/11761/10898 11520/11698/10835 +f 11522/11700/10837 11584/11762/10899 11521/11699/10836 +f 11523/11701/10838 11585/11763/10900 11522/11700/10837 +f 11524/11702/10839 11586/11764/10901 11523/11701/10838 +f 11525/11703/10840 11587/11765/10902 11524/11702/10839 +f 11526/11704/10841 11588/11766/10903 11525/11703/10840 +f 11527/11705/10842 11589/11767/10904 11526/11704/10841 +f 11528/11706/10843 11590/11768/10905 11527/11705/10842 +f 11529/11707/10844 11591/11769/10906 11528/11706/10843 +f 11530/11708/10845 11592/11770/10907 11529/11707/10844 +f 11531/11709/10846 11593/11771/10908 11530/11708/10845 +f 11532/11711/10848 11594/11772/10909 11531/11709/10846 +f 11533/11710/10847 11595/11773/10910 11532/11711/10848 +f 11534/11712/10849 11596/11774/10911 11533/11710/10847 +f 11535/11713/10850 11597/11775/10912 11534/11712/10849 +f 11536/11714/10851 11598/11776/10913 11535/11713/10850 +f 11537/11715/10852 11599/11777/10914 11536/11714/10851 +f 11538/11716/10853 11600/11778/10915 11537/11715/10852 +f 11539/11717/10854 11601/11779/10916 11538/11716/10853 +f 11540/11718/10855 11602/11780/10917 11539/11717/10854 +f 11541/11719/10856 11603/11781/10918 11540/11718/10855 +f 11542/11721/10858 11604/11782/10919 11541/11719/10856 +f 11543/11783/10920 11605/11784/10921 11542/11721/10858 +f 11545/11723/10860 11607/11785/10922 11544/11722/10859 +f 11546/11724/10861 11608/11786/10923 11545/11723/10860 +f 11547/11725/10862 11609/11787/10924 11546/11724/10861 +f 11548/11726/10863 11610/11788/10925 11547/11725/10862 +f 11549/11727/10864 11611/11789/10926 11548/11726/10863 +f 11550/11728/10865 11612/11790/10927 11549/11727/10864 +f 11551/11729/10866 11613/11791/10928 11550/11728/10865 +f 11552/11730/10867 11614/11792/10929 11551/11729/10866 +f 11553/11731/10868 11615/11793/10930 11552/11730/10867 +f 11554/11732/10869 11616/11794/10931 11553/11731/10868 +f 11555/11733/10870 11617/11795/10932 11554/11732/10869 +f 11556/11734/10871 11618/11796/10933 11555/11733/10870 +f 11557/11735/10872 11619/11797/8490 11556/11734/10871 +f 11558/11736/10873 11620/11798/10934 11557/11735/10872 +f 11559/11737/10874 11621/11799/10935 11558/11736/10873 +f 11560/11738/10875 11622/11800/10936 11559/11737/10874 +f 11561/11739/10876 11623/11801/10937 11560/11738/10875 +f 11562/11740/10877 11624/11802/10938 11561/11739/10876 +f 11563/11741/10878 11625/11803/10939 11562/11740/10877 +f 11564/11742/10879 11626/11804/10940 11563/11741/10878 +f 11565/11743/10880 11627/11805/10941 11564/11742/10879 +f 11566/11744/10881 11628/11806/10942 11565/11743/10880 +f 11567/11745/10882 11629/11807/10943 11566/11744/10881 +f 11568/11746/10883 11630/11808/10944 11567/11745/10882 +f 11569/11747/10884 11631/11809/10945 11568/11746/10883 +f 11570/11748/10885 11632/11810/10946 11569/11747/10884 +f 11571/11749/10886 11633/11811/10947 11570/11748/10885 +f 11572/11750/10887 11634/11812/10948 11571/11749/10886 +f 11573/11751/10888 11635/11813/10949 11572/11750/10887 +f 11574/11752/10889 11636/11814/10950 11573/11751/10888 +f 11575/11753/10890 11637/11815/10951 11574/11752/10889 +f 11576/11754/10891 11638/11816/10952 11575/11753/10890 +f 11577/11755/10892 11639/11817/10953 11576/11754/10891 +f 11578/11756/10893 11640/11818/10954 11577/11755/10892 +f 11579/11757/10894 11641/11819/10955 11578/11756/10893 +f 11580/11758/10895 11642/11820/10956 11579/11757/10894 +f 11581/11759/10896 11643/11821/10957 11580/11758/10895 +f 11582/11760/10897 11644/11822/10958 11581/11759/10896 +f 11583/11761/10898 11645/11823/10959 11582/11760/10897 +f 11584/11762/10899 11646/11824/10960 11583/11761/10898 +f 11585/11763/10900 11647/11825/10961 11584/11762/10899 +f 11586/11764/10901 11648/11826/10962 11585/11763/10900 +f 11587/11765/10902 11649/11827/10963 11586/11764/10901 +f 11588/11766/10903 11650/11828/10964 11587/11765/10902 +f 11589/11767/10904 11651/11829/10965 11588/11766/10903 +f 11590/11768/10905 11652/11830/10966 11589/11767/10904 +f 11591/11769/10906 11653/11831/10967 11590/11768/10905 +f 11592/11770/10907 11654/11832/10968 11591/11769/10906 +f 11593/11771/10908 11655/11833/10969 11592/11770/10907 +f 11594/11772/10909 11656/11834/10970 11593/11771/10908 +f 11595/11773/10910 11657/11835/10971 11594/11772/10909 +f 11596/11774/10911 11658/11836/10972 11595/11773/10910 +f 11597/11775/10912 11659/11837/10973 11596/11774/10911 +f 11598/11776/10913 11660/11838/10974 11597/11775/10912 +f 11599/11777/10914 11661/11839/10975 11598/11776/10913 +f 11600/11778/10915 11662/11840/10976 11599/11777/10914 +f 11601/11779/10916 11663/11841/10977 11600/11778/10915 +f 11602/11780/10917 11664/11842/10978 11601/11779/10916 +f 11603/11781/10918 11665/11843/10979 11602/11780/10917 +f 11604/11782/10919 11666/11844/10980 11603/11781/10918 +f 11605/11784/10921 11667/11845/10981 11604/11782/10919 +f 11606/11846/10982 11668/11847/10983 11605/11784/10921 +f 11608/11786/10923 11670/11848/10984 11607/11785/10922 +f 11609/11787/10924 11671/11849/10985 11608/11786/10923 +f 11610/11788/10925 11672/11850/10986 11609/11787/10924 +f 11611/11789/10926 11673/11851/10987 11610/11788/10925 +f 11612/11790/10927 11674/11852/10988 11611/11789/10926 +f 11613/11791/10928 11675/11853/10989 11612/11790/10927 +f 11614/11792/10929 11676/11854/10990 11613/11791/10928 +f 11615/11793/10930 11677/11855/10991 11614/11792/10929 +f 11616/11794/10931 11678/11856/10992 11615/11793/10930 +f 11617/11795/10932 11679/11857/10993 11616/11794/10931 +f 11618/11796/10933 11680/11858/10994 11617/11795/10932 +f 11619/11797/8490 11681/11859/10995 11618/11796/10933 +f 11620/11798/10934 11682/11860/10996 11619/11797/8490 +f 11621/11799/10935 11683/11861/10997 11620/11798/10934 +f 11622/11800/10936 11684/11862/10998 11621/11799/10935 +f 11623/11801/10937 11685/11863/10999 11622/11800/10936 +f 11624/11802/10938 11686/11864/11000 11623/11801/10937 +f 11625/11803/10939 11687/11865/11001 11624/11802/10938 +f 11626/11804/10940 11688/11866/11002 11625/11803/10939 +f 11627/11805/10941 11689/11867/11003 11626/11804/10940 +f 11628/11806/10942 11690/11868/11004 11627/11805/10941 +f 11629/11807/10943 11691/11869/11005 11628/11806/10942 +f 11630/11808/10944 11692/11870/11006 11629/11807/10943 +f 11631/11809/10945 11693/11871/11007 11630/11808/10944 +f 11632/11810/10946 11694/11872/11008 11631/11809/10945 +f 11633/11811/10947 11695/11873/11009 11632/11810/10946 +f 11634/11812/10948 11696/11874/11010 11633/11811/10947 +f 11635/11813/10949 11697/11875/11011 11634/11812/10948 +f 11636/11814/10950 11698/11876/11012 11635/11813/10949 +f 11637/11815/10951 11699/11877/11013 11636/11814/10950 +f 11638/11816/10952 11700/11878/11014 11637/11815/10951 +f 11639/11817/10953 11701/11879/11015 11638/11816/10952 +f 11640/11818/10954 11702/11880/11016 11639/11817/10953 +f 11641/11819/10955 11703/11881/11017 11640/11818/10954 +f 11642/11820/10956 11704/11882/11018 11641/11819/10955 +f 11643/11821/10957 11705/11883/11019 11642/11820/10956 +f 11644/11822/10958 11706/11884/11020 11643/11821/10957 +f 11645/11823/10959 11707/11885/11021 11644/11822/10958 +f 11646/11824/10960 11708/11886/11022 11645/11823/10959 +f 11647/11825/10961 11709/11887/11023 11646/11824/10960 +f 11648/11826/10962 11710/11888/11024 11647/11825/10961 +f 11649/11827/10963 11711/11889/11025 11648/11826/10962 +f 11650/11828/10964 11712/11890/11026 11649/11827/10963 +f 11651/11829/10965 11713/11891/11027 11650/11828/10964 +f 11652/11830/10966 11714/11892/11028 11651/11829/10965 +f 11653/11831/10967 11715/11893/11029 11652/11830/10966 +f 11654/11832/10968 11716/11894/11030 11653/11831/10967 +f 11655/11833/10969 11717/11895/11031 11654/11832/10968 +f 11656/11834/10970 11718/11896/11032 11655/11833/10969 +f 11657/11835/10971 11719/11897/11033 11656/11834/10970 +f 11658/11836/10972 11720/11898/11034 11657/11835/10971 +f 11659/11837/10973 11721/11899/11035 11658/11836/10972 +f 11660/11838/10974 11722/11900/11036 11659/11837/10973 +f 11661/11839/10975 11723/11901/11037 11660/11838/10974 +f 11662/11840/10976 11724/11902/11038 11661/11839/10975 +f 11663/11841/10977 11725/11903/11039 11662/11840/10976 +f 11664/11842/10978 11726/11904/11040 11663/11841/10977 +f 11665/11843/10979 11727/11905/11041 11664/11842/10978 +f 11666/11844/10980 11728/11906/11042 11665/11843/10979 +f 11667/11845/10981 11729/11907/11043 11666/11844/10980 +f 11668/11847/10983 11730/11908/11044 11667/11845/10981 +f 11669/11909/11045 11731/11910/11046 11668/11847/10983 +f 11671/11849/10985 11733/11911/11047 11670/11848/10984 +f 11672/11850/10986 11734/11912/11048 11671/11849/10985 +f 11673/11851/10987 11735/11913/11049 11672/11850/10986 +f 11674/11852/10988 11736/11914/11050 11673/11851/10987 +f 11675/11853/10989 11737/11915/11051 11674/11852/10988 +f 11676/11854/10990 11738/11916/11052 11675/11853/10989 +f 11677/11855/10991 11739/11917/11053 11676/11854/10990 +f 11678/11856/10992 11740/11918/11054 11677/11855/10991 +f 11679/11857/10993 11741/11919/11055 11678/11856/10992 +f 11680/11858/10994 11742/11920/11056 11679/11857/10993 +f 11681/11859/10995 11743/11921/11057 11680/11858/10994 +f 11682/11860/10996 11744/11922/11058 11681/11859/10995 +f 11683/11861/10997 11745/11923/11059 11682/11860/10996 +f 11684/11862/10998 11746/11924/11060 11683/11861/10997 +f 11685/11863/10999 11747/11925/11061 11684/11862/10998 +f 11686/11864/11000 11748/11926/11062 11685/11863/10999 +f 11687/11865/11001 11749/11927/11063 11686/11864/11000 +f 11688/11866/11002 11750/11928/11064 11687/11865/11001 +f 11689/11867/11003 11751/11929/11065 11688/11866/11002 +f 11690/11868/11004 11752/11930/11066 11689/11867/11003 +f 11691/11869/11005 11753/11931/11067 11690/11868/11004 +f 11692/11870/11006 11754/11932/11068 11691/11869/11005 +f 11693/11871/11007 11755/11933/11069 11692/11870/11006 +f 11694/11872/11008 11756/11934/11070 11693/11871/11007 +f 11695/11873/11009 11757/11935/11071 11694/11872/11008 +f 11696/11874/11010 11758/11936/11072 11695/11873/11009 +f 11697/11875/11011 11759/11937/11073 11696/11874/11010 +f 11698/11876/11012 11760/11938/11074 11697/11875/11011 +f 11699/11877/11013 11761/11939/11075 11698/11876/11012 +f 11700/11878/11014 11762/11940/11076 11699/11877/11013 +f 11701/11879/11015 11763/11941/11077 11700/11878/11014 +f 11702/11880/11016 11764/11942/11078 11701/11879/11015 +f 11703/11881/11017 11765/11943/11079 11702/11880/11016 +f 11704/11882/11018 11766/11944/11080 11703/11881/11017 +f 11705/11883/11019 11767/11945/11081 11704/11882/11018 +f 11706/11884/11020 11768/11946/11082 11705/11883/11019 +f 11707/11885/11021 11769/11947/11083 11706/11884/11020 +f 11708/11886/11022 11770/11948/11022 11707/11885/11021 +f 11709/11887/11023 11771/11949/11084 11708/11886/11022 +f 11710/11888/11024 11772/11950/11085 11709/11887/11023 +f 11711/11889/11025 11773/11951/11086 11710/11888/11024 +f 11712/11890/11026 11774/11952/11087 11711/11889/11025 +f 11713/11891/11027 11775/11953/11088 11712/11890/11026 +f 11714/11892/11028 11776/11954/11089 11713/11891/11027 +f 11715/11893/11029 11777/11955/11090 11714/11892/11028 +f 11716/11894/11030 11778/11956/11091 11715/11893/11029 +f 11717/11895/11031 11779/11957/11092 11716/11894/11030 +f 11718/11896/11032 11780/11958/11093 11717/11895/11031 +f 11719/11897/11033 11781/11959/11094 11718/11896/11032 +f 11720/11898/11034 11782/11960/11095 11719/11897/11033 +f 11721/11899/11035 11783/11961/11096 11720/11898/11034 +f 11722/11900/11036 11784/11962/11097 11721/11899/11035 +f 11723/11901/11037 11785/11963/11098 11722/11900/11036 +f 11724/11902/11038 11786/11964/11099 11723/11901/11037 +f 11725/11903/11039 11787/11965/11100 11724/11902/11038 +f 11726/11904/11040 11788/11966/11101 11725/11903/11039 +f 11727/11905/11041 11789/11967/11102 11726/11904/11040 +f 11728/11906/11042 11790/11968/11103 11727/11905/11041 +f 11729/11907/11043 11791/11969/11104 11728/11906/11042 +f 11730/11908/11044 11792/11970/11105 11729/11907/11043 +f 11731/11910/11046 11793/11971/11106 11730/11908/11044 +f 11732/11972/11107 11794/11973/11108 11731/11910/11046 +f 11734/11912/11048 11796/11974/11109 11733/11911/11047 +f 11735/11913/11049 11797/11975/11110 11734/11912/11048 +f 11736/11914/11050 11798/11976/11111 11735/11913/11049 +f 11737/11915/11051 11799/11977/11112 11736/11914/11050 +f 11738/11916/11052 11800/11978/11113 11737/11915/11051 +f 11739/11917/11053 11801/11979/11114 11738/11916/11052 +f 11740/11918/11054 11802/11980/11115 11739/11917/11053 +f 11741/11919/11055 11803/11981/11116 11740/11918/11054 +f 11742/11920/11056 11804/11982/11117 11741/11919/11055 +f 11743/11921/11057 11805/11983/11118 11742/11920/11056 +f 11744/11922/11058 11806/11984/11119 11743/11921/11057 +f 11745/11923/11059 11807/11985/11120 11744/11922/11058 +f 11746/11924/11060 11808/11986/11121 11745/11923/11059 +f 11747/11925/11061 11809/11987/11122 11746/11924/11060 +f 11748/11926/11062 11810/11988/11123 11747/11925/11061 +f 11749/11927/11063 11811/11989/11124 11748/11926/11062 +f 11750/11928/11064 11812/11990/11125 11749/11927/11063 +f 11751/11929/11065 11813/11991/11126 11750/11928/11064 +f 11752/11930/11066 11814/11992/11127 11751/11929/11065 +f 11753/11931/11067 11815/11993/11128 11752/11930/11066 +f 11754/11932/11068 11816/11994/11129 11753/11931/11067 +f 11755/11933/11069 11817/11995/11130 11754/11932/11068 +f 11756/11934/11070 11818/11996/11131 11755/11933/11069 +f 11757/11935/11071 11819/11997/11132 11756/11934/11070 +f 11758/11936/11072 11820/11998/11133 11757/11935/11071 +f 11759/11937/11073 11821/11999/11134 11758/11936/11072 +f 11760/11938/11074 11822/12000/11135 11759/11937/11073 +f 11761/11939/11075 11823/12001/11136 11760/11938/11074 +f 11762/11940/11076 11824/12002/11137 11761/11939/11075 +f 11763/11941/11077 11825/12003/11138 11762/11940/11076 +f 11764/11942/11078 11826/12004/11139 11763/11941/11077 +f 11765/11943/11079 11827/12005/11140 11764/11942/11078 +f 11766/11944/11080 11828/12006/11141 11765/11943/11079 +f 11767/11945/11081 11829/12007/11142 11766/11944/11080 +f 11768/11946/11082 11830/12008/11143 11767/11945/11081 +f 11769/11947/11083 11831/12009/11144 11768/11946/11082 +f 11770/11948/11022 11832/12010/11145 11769/11947/11083 +f 11771/11949/11084 11833/12011/11146 11770/11948/11022 +f 11772/11950/11085 11834/12012/11147 11771/11949/11084 +f 11773/11951/11086 11835/12013/11148 11772/11950/11085 +f 11774/11952/11087 11836/12014/11149 11773/11951/11086 +f 11775/11953/11088 11837/12015/11150 11774/11952/11087 +f 11776/11954/11089 11838/12016/11151 11775/11953/11088 +f 11777/11955/11090 11839/12017/11152 11776/11954/11089 +f 11778/11956/11091 11840/12018/10536 11777/11955/11090 +f 11779/11957/11092 11841/12019/11153 11778/11956/11091 +f 11780/11958/11093 11842/12020/11154 11779/11957/11092 +f 11781/11959/11094 11843/12021/11155 11780/11958/11093 +f 11782/11960/11095 11844/12022/11156 11781/11959/11094 +f 11783/11961/11096 11845/12023/11157 11782/11960/11095 +f 11784/11962/11097 11846/12024/11158 11783/11961/11096 +f 11785/11963/11098 11847/12025/11159 11784/11962/11097 +f 11786/11964/11099 11848/12026/11160 11785/11963/11098 +f 11787/11965/11100 11849/12027/11161 11786/11964/11099 +f 11788/11966/11101 11850/12028/11162 11787/11965/11100 +f 11789/11967/11102 11851/12029/11163 11788/11966/11101 +f 11790/11968/11103 11852/12030/11164 11789/11967/11102 +f 11791/11969/11104 11853/12031/11165 11790/11968/11103 +f 11792/11970/11105 11854/12032/11166 11791/11969/11104 +f 11793/11971/11106 11855/12033/11167 11792/11970/11105 +f 11794/11973/11108 11856/12034/11168 11793/11971/11106 +f 11795/12035/11169 11857/12036/11170 11794/11973/11108 +f 11797/11975/11110 11859/12037/11171 11796/11974/11109 +f 11798/11976/11111 11860/12038/11172 11797/11975/11110 +f 11799/11977/11112 11861/12039/11173 11798/11976/11111 +f 11800/11978/11113 11862/12040/11174 11799/11977/11112 +f 11801/11979/11114 11863/12041/11175 11800/11978/11113 +f 11802/11980/11115 11864/12042/11176 11801/11979/11114 +f 11803/11981/11116 11865/12043/11177 11802/11980/11115 +f 11804/11982/11117 11866/12044/11178 11803/11981/11116 +f 11805/11983/11118 11867/12045/11179 11804/11982/11117 +f 11806/11984/11119 11868/12046/11180 11805/11983/11118 +f 11807/11985/11120 11869/12047/11181 11806/11984/11119 +f 11808/11986/11121 11870/12048/11182 11807/11985/11120 +f 11809/11987/11122 11871/12049/11183 11808/11986/11121 +f 11810/11988/11123 11872/12050/11184 11809/11987/11122 +f 11811/11989/11124 11873/12051/11185 11810/11988/11123 +f 11812/11990/11125 11874/12052/11186 11811/11989/11124 +f 11813/11991/11126 11875/12053/11187 11812/11990/11125 +f 11814/11992/11127 11876/12054/11188 11813/11991/11126 +f 11815/11993/11128 11877/12055/11189 11814/11992/11127 +f 11816/11994/11129 11878/12056/11190 11815/11993/11128 +f 11817/11995/11130 11879/12057/11191 11816/11994/11129 +f 11818/11996/11131 11880/12058/11192 11817/11995/11130 +f 11819/11997/11132 11881/12059/11193 11818/11996/11131 +f 11820/11998/11133 11882/12060/11194 11819/11997/11132 +f 11821/11999/11134 11883/12061/11195 11820/11998/11133 +f 11822/12000/11135 11884/12062/11196 11821/11999/11134 +f 11823/12001/11136 11885/12063/11197 11822/12000/11135 +f 11824/12002/11137 11886/12064/11198 11823/12001/11136 +f 11825/12003/11138 11887/12065/11199 11824/12002/11137 +f 11826/12004/11139 11888/12066/11200 11825/12003/11138 +f 11827/12005/11140 11889/12067/11201 11826/12004/11139 +f 11828/12006/11141 11890/12068/11202 11827/12005/11140 +f 11829/12007/11142 11891/12069/11203 11828/12006/11141 +f 11830/12008/11143 11892/12070/11204 11829/12007/11142 +f 11831/12009/11144 11893/12071/11205 11830/12008/11143 +f 11832/12010/11145 11894/12072/11206 11831/12009/11144 +f 11833/12011/11146 11895/12073/11207 11832/12010/11145 +f 11834/12012/11147 11896/12074/11208 11833/12011/11146 +f 11835/12013/11148 11897/12075/11209 11834/12012/11147 +f 11836/12014/11149 11898/12076/11210 11835/12013/11148 +f 11837/12015/11150 11899/12077/11211 11836/12014/11149 +f 11838/12016/11151 11900/12078/11212 11837/12015/11150 +f 11839/12017/11152 11901/12079/11213 11838/12016/11151 +f 11840/12018/10536 11902/12080/11214 11839/12017/11152 +f 11841/12019/11153 11903/12081/11215 11840/12018/10536 +f 11842/12020/11154 11904/12082/11216 11841/12019/11153 +f 11843/12021/11155 11905/12083/11217 11842/12020/11154 +f 11844/12022/11156 11906/12084/11218 11843/12021/11155 +f 11845/12023/11157 11907/12085/11219 11844/12022/11156 +f 11846/12024/11158 11908/12086/11220 11845/12023/11157 +f 11847/12025/11159 11909/12087/11221 11846/12024/11158 +f 11848/12026/11160 11910/12088/11222 11847/12025/11159 +f 11849/12027/11161 11911/12089/11223 11848/12026/11160 +f 11850/12028/11162 11912/12090/11224 11849/12027/11161 +f 11851/12029/11163 11913/12091/11225 11850/12028/11162 +f 11852/12030/11164 11914/12092/11226 11851/12029/11163 +f 11853/12031/11165 11915/12093/11227 11852/12030/11164 +f 11854/12032/11166 11916/12094/11228 11853/12031/11165 +f 11855/12033/11167 11917/12095/11229 11854/12032/11166 +f 11856/12034/11168 11918/12096/11230 11855/12033/11167 +f 11857/12036/11170 11919/12097/11231 11856/12034/11168 +f 11858/12098/11232 11920/12099/11233 11857/12036/11170 +f 7764/12100/11234 7763/12101/11235 7697/12102/11236 +f 7765/12103/11237 7953/8134/7288 7764/12100/11234 +f 7766/12104/11238 7954/8132/7286 7765/12103/11237 +f 7767/12105/11239 7955/8135/7289 7766/12104/11238 +f 7768/12106/11240 7956/8137/7291 7767/12105/11239 +f 7769/12107/11241 7957/8139/7293 7768/12106/11240 +f 7770/12108/11242 7958/8141/7295 7769/12107/11241 +f 7771/12109/11243 7959/8143/7297 7770/12108/11242 +f 7772/12110/11244 7960/8145/7299 7771/12109/11243 +f 7773/12111/11245 7961/8147/7301 7772/12110/11244 +f 7774/12112/11246 7962/8149/7303 7773/12111/11245 +f 7775/12113/11247 7963/8151/7305 7774/12112/11246 +f 7776/12114/11248 7964/8153/7307 7775/12113/11247 +f 7777/12115/11249 7965/8155/7309 7776/12114/11248 +f 7778/12116/11250 7966/8157/7311 7777/12115/11249 +f 7779/12117/11251 7967/8159/7313 7778/12116/11250 +f 7780/12118/11252 7968/8161/7315 7779/12117/11251 +f 7781/12119/11253 7969/8163/7317 7780/12118/11252 +f 7782/12120/11254 7970/8165/7319 7781/12119/11253 +f 7783/12121/11255 7971/8167/7321 7782/12120/11254 +f 7784/12122/11256 7972/8169/7323 7783/12121/11255 +f 7785/12123/11257 7973/8171/7325 7784/12122/11256 +f 7786/12124/11258 7974/8173/7327 7785/12123/11257 +f 7787/12125/11259 7975/8175/7329 7786/12124/11258 +f 7788/12126/11260 7976/8177/7331 7787/12125/11259 +f 7789/12127/11261 7977/8179/7333 7788/12126/11260 +f 7790/12128/11262 7978/8181/7335 7789/12127/11261 +f 7791/12129/11263 7979/8183/7337 7790/12128/11262 +f 7792/12130/11264 7980/8185/7339 7791/12129/11263 +f 7793/12131/11265 7981/8187/7341 7792/12130/11264 +f 7794/12132/11266 7982/8189/7343 7793/12131/11265 +f 7795/12133/11267 7983/8191/7345 7794/12132/11266 +f 7796/12134/11268 7984/8193/7347 7795/12133/11267 +f 7797/12135/11269 7985/8195/7349 7796/12134/11268 +f 7798/12136/11270 7986/8197/7351 7797/12135/11269 +f 7799/12137/11271 7987/8199/7353 7798/12136/11270 +f 7800/12138/11272 7988/8201/7355 7799/12137/11271 +f 7801/12139/11273 7989/8203/7357 7800/12138/11272 +f 7802/12140/11274 7990/8205/7359 7801/12139/11273 +f 7803/12141/11275 7991/8207/7361 7802/12140/11274 +f 7804/12142/11276 7992/8209/7363 7803/12141/11275 +f 7805/12143/11277 7993/8211/7365 7804/12142/11276 +f 7806/12144/11278 7994/8213/7367 7805/12143/11277 +f 7807/12145/11279 7995/8215/7369 7806/12144/11278 +f 7808/12146/11280 7996/8217/7371 7807/12145/11279 +f 7809/12147/11281 7997/8219/7373 7808/12146/11280 +f 7810/12148/11282 7998/8221/7375 7809/12147/11281 +f 7811/12149/11283 7999/8223/7377 7810/12148/11282 +f 7812/12150/11284 8000/8225/7379 7811/12149/11283 +f 7813/12151/11285 8001/8227/7381 7812/12150/11284 +f 7814/12152/11286 8002/8229/7383 7813/12151/11285 +f 7815/12153/11287 8003/8231/7385 7814/12152/11286 +f 7816/12154/11288 8004/8233/7387 7815/12153/11287 +f 7817/12155/11289 8005/8235/7389 7816/12154/11288 +f 7818/12156/11290 8006/8237/7391 7817/12155/11289 +f 7819/12157/11291 8007/8239/7393 7818/12156/11290 +f 7820/12158/11292 8008/8241/7395 7819/12157/11291 +f 7821/12159/11293 8009/8243/7397 7820/12158/11292 +f 7822/12160/11294 8010/8245/7399 7821/12159/11293 +f 7823/12161/11295 8011/8247/7401 7822/12160/11294 +f 7824/12162/11296 8012/8249/7403 7823/12161/11295 +f 7825/12163/11297 8013/8251/7405 7824/12162/11296 +f 7826/12164/11298 8014/8253/7407 7825/12163/11297 +f 7698/12165/11299 8015/8255/7409 7826/12164/11298 +f 7827/12166/11300 8078/8318/7472 8015/8255/7409 +f 7828/12167/11301 8141/8381/7535 8078/8318/7472 +f 7829/12168/11302 8204/8444/7598 8141/8381/7535 +f 7830/12169/11303 8267/8507/7661 8204/8444/7598 +f 7831/12170/11304 8330/8570/7724 8267/8507/7661 +f 7832/12171/11305 8393/8633/7787 8330/8570/7724 +f 7833/12172/11306 8456/8696/7850 8393/8633/7787 +f 7834/12173/11307 8519/8759/7913 8456/8696/7850 +f 7835/12174/11308 8582/8822/7976 8519/8759/7913 +f 7836/12175/11269 8645/8885/8039 8582/8822/7976 +f 7837/12176/11309 8708/8948/8102 8645/8885/8039 +f 7838/12177/11310 8771/9011/8165 8708/8948/8102 +f 7839/12178/11311 8834/9074/8227 8771/9011/8165 +f 7840/12179/11312 8897/9137/8289 8834/9074/8227 +f 7841/12180/11313 8960/9200/8351 8897/9137/8289 +f 7842/12181/11314 9023/9263/8414 8960/9200/8351 +f 7843/12182/11315 9086/9326/8477 9023/9263/8414 +f 7844/12183/11316 9149/9389/8539 9086/9326/8477 +f 7845/12184/11317 9212/9452/8602 9149/9389/8539 +f 7846/12185/11318 9275/9515/8665 9212/9452/8602 +f 7847/12186/11319 9338/9578/8728 9275/9515/8665 +f 7848/12187/11320 9401/9641/8790 9338/9578/8728 +f 7849/12188/11321 9464/9704/8852 9401/9641/8790 +f 7850/12189/11322 9527/9767/8915 9464/9704/8852 +f 7851/12190/11323 9590/9830/8978 9527/9767/8915 +f 7852/12191/11324 9653/9893/9040 9590/9830/8978 +f 7853/12192/11325 9716/9956/9102 9653/9893/9040 +f 7854/12193/11326 9779/10019/9165 9716/9956/9102 +f 7855/12194/11327 9842/10082/9228 9779/10019/9165 +f 7856/12195/11328 9905/10145/9291 9842/10082/9228 +f 7857/12196/10750 9968/10208/9354 9905/10145/9291 +f 7858/12197/11329 10031/10271/9417 9968/10208/9354 +f 7859/12198/11330 10094/10334/9480 10031/10271/9417 +f 7860/12199/11331 10157/10397/9543 10094/10334/9480 +f 7861/12200/11332 10220/10460/9606 10157/10397/9543 +f 7862/12201/11333 10283/10523/9669 10220/10460/9606 +f 7863/12202/11334 10346/10586/9732 10283/10523/9669 +f 7864/12203/11335 10409/10649/9793 10346/10586/9732 +f 7865/12204/11336 10472/10712/9856 10409/10649/9793 +f 7866/12205/11337 10535/10775/9919 10472/10712/9856 +f 7867/12206/11338 10598/10838/9982 10535/10775/9919 +f 7868/12207/11339 10661/10901/10043 10598/10838/9982 +f 7869/12208/11340 10724/10964/10105 10661/10901/10043 +f 7870/12209/11341 10787/11027/10168 10724/10964/10105 +f 7871/12210/11342 10850/11090/10231 10787/11027/10168 +f 7872/12211/11343 10913/11153/10294 10850/11090/10231 +f 7873/12212/11344 10976/11216/10356 10913/11153/10294 +f 7874/12213/11345 11039/11279/10418 10976/11216/10356 +f 7875/12214/11346 11102/11342/10480 11039/11279/10418 +f 7876/12215/11347 11165/11405/10543 11102/11342/10480 +f 7877/12216/11348 11228/11468/10605 11165/11405/10543 +f 7878/12217/11349 11291/11531/10668 11228/11468/10605 +f 7879/12218/11350 11354/11594/10731 11291/11531/10668 +f 7880/12219/11351 11417/11657/10794 11354/11594/10731 +f 7881/12220/10087 11480/11720/10857 11417/11657/10794 +f 7882/12221/11352 11543/11783/10920 11480/11720/10857 +f 7883/12222/11353 11606/11846/10982 11543/11783/10920 +f 7884/12223/11354 11669/11909/11045 11606/11846/10982 +f 7885/12224/11355 11732/11972/11107 11669/11909/11045 +f 7886/12225/11356 11795/12035/11169 11732/11972/11107 +f 7887/12226/11357 11858/12098/11232 11795/12035/11169 +f 7888/12227/11358 11921/12228/11359 11858/12098/11232 +f 7889/12229/11360 7890/12230/11361 11921/12228/11359 +f 11921/12228/11359 7891/12231/11362 11920/12099/11233 +f 11920/12099/11233 7892/12232/11363 11919/12097/11231 +f 11919/12097/11231 7893/12233/11364 11918/12096/11230 +f 11918/12096/11230 7894/12234/11365 11917/12095/11229 +f 11917/12095/11229 7895/12235/11366 11916/12094/11228 +f 11916/12094/11228 7896/12236/11367 11915/12093/11227 +f 11915/12093/11227 7897/12237/11368 11914/12092/11226 +f 11914/12092/11226 7898/12238/11369 11913/12091/11225 +f 11913/12091/11225 7899/12239/11370 11912/12090/11224 +f 11912/12090/11224 7900/12240/11371 11911/12089/11223 +f 11911/12089/11223 7901/12241/11372 11910/12088/11222 +f 11910/12088/11222 7902/12242/11373 11909/12087/11221 +f 11909/12087/11221 7903/12243/11374 11908/12086/11220 +f 11908/12086/11220 7904/12244/11375 11907/12085/11219 +f 11907/12085/11219 7905/12245/11376 11906/12084/11218 +f 11906/12084/11218 7906/12246/11377 11905/12083/11217 +f 11905/12083/11217 7907/12247/11378 11904/12082/11216 +f 11904/12082/11216 7908/12248/11379 11903/12081/11215 +f 11903/12081/11215 7909/12249/11380 11902/12080/11214 +f 11902/12080/11214 7910/12250/11381 11901/12079/11213 +f 11901/12079/11213 7911/12251/11382 11900/12078/11212 +f 11900/12078/11212 7912/12252/11383 11899/12077/11211 +f 11899/12077/11211 7913/12253/11384 11898/12076/11210 +f 11898/12076/11210 7914/12254/11385 11897/12075/11209 +f 11897/12075/11209 7915/12255/11386 11896/12074/11208 +f 11896/12074/11208 7916/12256/11387 11895/12073/11207 +f 11895/12073/11207 7917/12257/11388 11894/12072/11206 +f 11894/12072/11206 7918/12258/11389 11893/12071/11205 +f 11893/12071/11205 7919/12259/11390 11892/12070/11204 +f 11892/12070/11204 7920/12260/11391 11891/12069/11203 +f 11891/12069/11203 7921/12261/11392 11890/12068/11202 +f 11890/12068/11202 7922/12262/11393 11889/12067/11201 +f 11889/12067/11201 7923/12263/11394 11888/12066/11200 +f 11888/12066/11200 7924/12264/11395 11887/12065/11199 +f 11887/12065/11199 7925/12265/11396 11886/12064/11198 +f 11886/12064/11198 7926/12266/11397 11885/12063/11197 +f 11885/12063/11197 7927/12267/11398 11884/12062/11196 +f 11884/12062/11196 7928/12268/11399 11883/12061/11195 +f 11883/12061/11195 7929/12269/11400 11882/12060/11194 +f 11882/12060/11194 7930/12270/11401 11881/12059/11193 +f 11881/12059/11193 7931/12271/11402 11880/12058/11192 +f 11880/12058/11192 7932/12272/11403 11879/12057/11191 +f 11879/12057/11191 7933/12273/11404 11878/12056/11190 +f 11878/12056/11190 7934/12274/11405 11877/12055/11189 +f 11877/12055/11189 7935/12275/11406 11876/12054/11188 +f 11876/12054/11188 7936/12276/11407 11875/12053/11187 +f 11875/12053/11187 7937/12277/11408 11874/12052/11186 +f 11874/12052/11186 7938/12278/11409 11873/12051/11185 +f 11873/12051/11185 7939/12279/11410 11872/12050/11184 +f 11872/12050/11184 7940/12280/11411 11871/12049/11183 +f 11871/12049/11183 7941/12281/11412 11870/12048/11182 +f 11870/12048/11182 7942/12282/11413 11869/12047/11181 +f 11869/12047/11181 7943/12283/11414 11868/12046/11180 +f 11868/12046/11180 7944/12284/11415 11867/12045/11179 +f 11867/12045/11179 7945/12285/11416 11866/12044/11178 +f 11866/12044/11178 7946/12286/11417 11865/12043/11177 +f 11865/12043/11177 7947/12287/11418 11864/12042/11176 +f 11864/12042/11176 7948/12288/11419 11863/12041/11175 +f 11863/12041/11175 7949/12289/11420 11862/12040/11174 +f 11862/12040/11174 7950/12290/11421 11861/12039/11173 +f 11861/12039/11173 7951/12291/11422 11860/12038/11172 +f 11860/12038/11172 7952/12292/11423 11859/12037/11171 +f 11859/12037/11171 7699/12293/11424 7701/12294/11425 +f 11796/11974/11109 7701/12294/11425 7702/12295/11426 +f 11733/11911/11047 7702/12295/11426 7703/12296/11427 +f 11670/11848/10984 7703/12296/11427 7704/12297/11428 +f 11607/11785/10922 7704/12297/11428 7705/12298/11429 +f 11544/11722/10859 7705/12298/11429 7706/12299/11430 +f 11481/11659/10796 7706/12299/11430 7707/12300/11431 +f 11418/11596/10733 7707/12300/11431 7708/12301/11432 +f 11355/11533/10670 7708/12301/11432 7709/12302/11433 +f 11292/11470/10607 7709/12302/11433 7710/12303/11434 +f 11229/11407/10545 7710/12303/11434 7711/12304/11435 +f 11166/11344/10482 7711/12304/11435 7712/12305/11436 +f 11103/11281/10420 7712/12305/11436 7713/12306/11437 +f 11040/11218/10358 7713/12306/11437 7714/12307/11438 +f 10977/11155/10296 7714/12307/11438 7715/12308/11439 +f 10914/11092/10233 7715/12308/11439 7716/12309/11440 +f 10851/11029/10170 7716/12309/11440 7717/12310/11441 +f 10788/10966/10107 7717/12310/11441 7718/12311/11442 +f 10725/10903/10045 7718/12311/11442 7719/12312/11443 +f 10662/10840/9838 7719/12312/11443 7720/12313/11444 +f 10599/10777/9921 7720/12313/11444 7721/12314/11445 +f 10536/10714/9858 7721/12314/11445 7722/12315/11446 +f 10473/10651/9795 7722/12315/11446 7723/12316/11447 +f 10410/10588/9734 7723/12316/11447 7724/12317/11448 +f 10347/10525/9671 7724/12317/11448 7725/12318/11449 +f 10284/10462/9608 7725/12318/11449 7726/12319/11450 +f 10221/10399/9545 7726/12319/11450 7727/12320/11451 +f 10158/10336/9482 7727/12320/11451 7728/12321/11452 +f 10095/10273/9419 7728/12321/11452 7729/12322/11453 +f 10032/10210/9356 7729/12322/11453 7730/12323/11454 +f 9969/10147/9293 7730/12323/11454 7731/12324/11455 +f 9906/10084/9230 7731/12324/11455 7732/12325/11456 +f 9843/10021/9167 7732/12325/11456 7733/12326/11457 +f 9780/9958/9104 7733/12326/11457 7734/12327/11458 +f 9717/9895/9042 7734/12327/11458 7735/12328/11459 +f 9654/9832/8980 7735/12328/11459 7736/12329/11460 +f 9591/9769/8917 7736/12329/11460 7737/12330/11461 +f 9528/9706/8854 7737/12330/11461 7738/12331/11462 +f 9465/9643/8792 7738/12331/11462 7739/12332/11463 +f 9402/9580/8730 7739/12332/11463 7740/12333/11464 +f 9339/9517/8667 7740/12333/11464 7741/12334/11465 +f 9276/9454/8604 7741/12334/11465 7742/12335/11466 +f 9213/9391/8541 7742/12335/11466 7743/12336/11467 +f 9150/9328/8479 7743/12336/11467 7744/12337/11468 +f 9087/9265/8416 7744/12337/11468 7745/12338/11469 +f 9024/9202/8353 7745/12338/11469 7746/12339/11470 +f 8961/9139/8291 7746/12339/11470 7747/12340/11471 +f 8898/9076/8229 7747/12340/11471 7748/12341/11472 +f 8835/9013/8167 7748/12341/11472 7749/12342/11473 +f 8772/8950/8104 7749/12342/11473 7750/12343/11474 +f 8709/8887/8041 7750/12343/11474 7751/12344/11475 +f 8646/8824/7978 7751/12344/11475 7752/12345/11476 +f 8583/8761/7915 7752/12345/11476 7753/12346/11477 +f 8520/8698/7852 7753/12346/11477 7754/12347/11478 +f 8457/8635/7789 7754/12347/11478 7755/12348/11479 +f 8394/8572/7726 7755/12348/11479 7756/12349/11480 +f 8331/8509/7663 7756/12349/11480 7757/12350/11481 +f 8268/8446/7600 7757/12350/11481 7758/12351/11482 +f 8205/8383/7537 7758/12351/11482 7759/12352/11483 +f 8142/8320/7474 7759/12352/11483 7760/12353/11484 +f 8079/8257/7411 7760/12353/11484 7761/12354/11485 +f 8016/8133/7287 7761/12354/11485 7762/12355/11486 +f 7953/8134/7288 7762/12355/11486 7763/12101/11235 +f 7954/8132/7286 8017/8136/7290 8016/8133/7287 +f 7955/8135/7289 8018/8138/7292 8017/8136/7290 +f 7956/8137/7291 8019/8140/7294 8018/8138/7292 +f 7957/8139/7293 8020/8142/7296 8019/8140/7294 +f 7958/8141/7295 8021/8144/7298 8020/8142/7296 +f 7959/8143/7297 8022/8146/7300 8021/8144/7298 +f 7960/8145/7299 8023/8148/7302 8022/8146/7300 +f 7961/8147/7301 8024/8150/7304 8023/8148/7302 +f 7962/8149/7303 8025/8152/7306 8024/8150/7304 +f 7963/8151/7305 8026/8154/7308 8025/8152/7306 +f 7964/8153/7307 8027/8156/7310 8026/8154/7308 +f 7965/8155/7309 8028/8158/7312 8027/8156/7310 +f 7966/8157/7311 8029/8160/7314 8028/8158/7312 +f 7967/8159/7313 8030/8162/7316 8029/8160/7314 +f 7968/8161/7315 8031/8164/7318 8030/8162/7316 +f 7969/8163/7317 8032/8166/7320 8031/8164/7318 +f 7970/8165/7319 8033/8168/7322 8032/8166/7320 +f 7971/8167/7321 8034/8170/7324 8033/8168/7322 +f 7972/8169/7323 8035/8172/7326 8034/8170/7324 +f 7973/8171/7325 8036/8174/7328 8035/8172/7326 +f 7974/8173/7327 8037/8176/7330 8036/8174/7328 +f 7975/8175/7329 8038/8178/7332 8037/8176/7330 +f 7976/8177/7331 8039/8180/7334 8038/8178/7332 +f 7977/8179/7333 8040/8182/7336 8039/8180/7334 +f 7978/8181/7335 8041/8184/7338 8040/8182/7336 +f 7979/8183/7337 8042/8186/7340 8041/8184/7338 +f 7980/8185/7339 8043/8188/7342 8042/8186/7340 +f 7981/8187/7341 8044/8190/7344 8043/8188/7342 +f 7982/8189/7343 8045/8192/7346 8044/8190/7344 +f 7983/8191/7345 8046/8194/7348 8045/8192/7346 +f 7984/8193/7347 8047/8196/7350 8046/8194/7348 +f 7985/8195/7349 8048/8198/7352 8047/8196/7350 +f 7986/8197/7351 8049/8200/7354 8048/8198/7352 +f 7987/8199/7353 8050/8202/7356 8049/8200/7354 +f 7988/8201/7355 8051/8204/7358 8050/8202/7356 +f 7989/8203/7357 8052/8206/7360 8051/8204/7358 +f 7990/8205/7359 8053/8208/7362 8052/8206/7360 +f 7991/8207/7361 8054/8210/7364 8053/8208/7362 +f 7992/8209/7363 8055/8212/7366 8054/8210/7364 +f 7993/8211/7365 8056/8214/7368 8055/8212/7366 +f 7994/8213/7367 8057/8216/7370 8056/8214/7368 +f 7995/8215/7369 8058/8218/7372 8057/8216/7370 +f 7996/8217/7371 8059/8220/7374 8058/8218/7372 +f 7997/8219/7373 8060/8222/7376 8059/8220/7374 +f 7998/8221/7375 8061/8224/7378 8060/8222/7376 +f 7999/8223/7377 8062/8226/7380 8061/8224/7378 +f 8000/8225/7379 8063/8228/7382 8062/8226/7380 +f 8001/8227/7381 8064/8230/7384 8063/8228/7382 +f 8002/8229/7383 8065/8232/7386 8064/8230/7384 +f 8003/8231/7385 8066/8234/7388 8065/8232/7386 +f 8004/8233/7387 8067/8236/7390 8066/8234/7388 +f 8005/8235/7389 8068/8238/7392 8067/8236/7390 +f 8006/8237/7391 8069/8240/7394 8068/8238/7392 +f 8007/8239/7393 8070/8242/7396 8069/8240/7394 +f 8008/8241/7395 8071/8244/7398 8070/8242/7396 +f 8009/8243/7397 8072/8246/7400 8071/8244/7398 +f 8010/8245/7399 8073/8248/7402 8072/8246/7400 +f 8011/8247/7401 8074/8250/7404 8073/8248/7402 +f 8012/8249/7403 8075/8252/7406 8074/8250/7404 +f 8013/8251/7405 8076/8254/7408 8075/8252/7406 +f 8014/8253/7407 8077/8256/7410 8076/8254/7408 +f 8015/8255/7409 8078/8318/7472 8077/8256/7410 +f 8017/8136/7290 8080/8258/7412 8079/8257/7411 +f 8018/8138/7292 8081/8259/7413 8080/8258/7412 +f 8019/8140/7294 8082/8260/7414 8081/8259/7413 +f 8020/8142/7296 8083/8261/7415 8082/8260/7414 +f 8021/8144/7298 8084/8262/7416 8083/8261/7415 +f 8022/8146/7300 8085/8263/7417 8084/8262/7416 +f 8023/8148/7302 8086/8264/7418 8085/8263/7417 +f 8024/8150/7304 8087/8265/7419 8086/8264/7418 +f 8025/8152/7306 8088/8266/7420 8087/8265/7419 +f 8026/8154/7308 8089/8267/7421 8088/8266/7420 +f 8027/8156/7310 8090/8268/7422 8089/8267/7421 +f 8028/8158/7312 8091/8269/7423 8090/8268/7422 +f 8029/8160/7314 8092/8270/7424 8091/8269/7423 +f 8030/8162/7316 8093/8271/7425 8092/8270/7424 +f 8031/8164/7318 8094/8272/7426 8093/8271/7425 +f 8032/8166/7320 8095/8273/7427 8094/8272/7426 +f 8033/8168/7322 8096/8274/7428 8095/8273/7427 +f 8034/8170/7324 8097/8275/7429 8096/8274/7428 +f 8035/8172/7326 8098/8276/7430 8097/8275/7429 +f 8036/8174/7328 8099/8277/7431 8098/8276/7430 +f 8037/8176/7330 8100/8278/7432 8099/8277/7431 +f 8038/8178/7332 8101/8279/7433 8100/8278/7432 +f 8039/8180/7334 8102/8280/7434 8101/8279/7433 +f 8040/8182/7336 8103/8281/7435 8102/8280/7434 +f 8041/8184/7338 8104/8282/7436 8103/8281/7435 +f 8042/8186/7340 8105/8283/7437 8104/8282/7436 +f 8043/8188/7342 8106/8284/7438 8105/8283/7437 +f 8044/8190/7344 8107/8285/7439 8106/8284/7438 +f 8045/8192/7346 8108/8286/7440 8107/8285/7439 +f 8046/8194/7348 8109/8287/7441 8108/8286/7440 +f 8047/8196/7350 8110/8288/7442 8109/8287/7441 +f 8048/8198/7352 8111/8289/7443 8110/8288/7442 +f 8049/8200/7354 8112/8290/7444 8111/8289/7443 +f 8050/8202/7356 8113/8291/7445 8112/8290/7444 +f 8051/8204/7358 8114/8292/7446 8113/8291/7445 +f 8052/8206/7360 8115/8293/7447 8114/8292/7446 +f 8053/8208/7362 8116/8294/7448 8115/8293/7447 +f 8054/8210/7364 8117/8295/7449 8116/8294/7448 +f 8055/8212/7366 8118/8296/7450 8117/8295/7449 +f 8056/8214/7368 8119/8297/7451 8118/8296/7450 +f 8057/8216/7370 8120/8298/7452 8119/8297/7451 +f 8058/8218/7372 8121/8299/7453 8120/8298/7452 +f 8059/8220/7374 8122/8300/7454 8121/8299/7453 +f 8060/8222/7376 8123/8301/7455 8122/8300/7454 +f 8061/8224/7378 8124/8302/7456 8123/8301/7455 +f 8062/8226/7380 8125/8303/7457 8124/8302/7456 +f 8063/8228/7382 8126/8304/7458 8125/8303/7457 +f 8064/8230/7384 8127/8305/7459 8126/8304/7458 +f 8065/8232/7386 8128/8306/7460 8127/8305/7459 +f 8066/8234/7388 8129/8307/7461 8128/8306/7460 +f 8067/8236/7390 8130/8308/7462 8129/8307/7461 +f 8068/8238/7392 8131/8309/7463 8130/8308/7462 +f 8069/8240/7394 8132/8310/7464 8131/8309/7463 +f 8070/8242/7396 8133/8311/7465 8132/8310/7464 +f 8071/8244/7398 8134/8312/7466 8133/8311/7465 +f 8072/8246/7400 8135/8313/7467 8134/8312/7466 +f 8073/8248/7402 8136/8314/7468 8135/8313/7467 +f 8074/8250/7404 8137/8315/7469 8136/8314/7468 +f 8075/8252/7406 8138/8316/7470 8137/8315/7469 +f 8076/8254/7408 8139/8317/7471 8138/8316/7470 +f 8077/8256/7410 8140/8319/7473 8139/8317/7471 +f 8078/8318/7472 8141/8381/7535 8140/8319/7473 +f 8080/8258/7412 8143/8321/7475 8142/8320/7474 +f 8081/8259/7413 8144/8322/7476 8143/8321/7475 +f 8082/8260/7414 8145/8323/7477 8144/8322/7476 +f 8083/8261/7415 8146/8324/7478 8145/8323/7477 +f 8084/8262/7416 8147/8325/7479 8146/8324/7478 +f 8085/8263/7417 8148/8326/7480 8147/8325/7479 +f 8086/8264/7418 8149/8327/7481 8148/8326/7480 +f 8087/8265/7419 8150/8328/7482 8149/8327/7481 +f 8088/8266/7420 8151/8329/7483 8150/8328/7482 +f 8089/8267/7421 8152/8330/7484 8151/8329/7483 +f 8090/8268/7422 8153/8331/7485 8152/8330/7484 +f 8091/8269/7423 8154/8332/7486 8153/8331/7485 +f 8092/8270/7424 8155/8333/7487 8154/8332/7486 +f 8093/8271/7425 8156/8334/7488 8155/8333/7487 +f 8094/8272/7426 8157/8335/7489 8156/8334/7488 +f 8095/8273/7427 8158/8336/7490 8157/8335/7489 +f 8096/8274/7428 8159/8337/7491 8158/8336/7490 +f 8097/8275/7429 8160/8338/7492 8159/8337/7491 +f 8098/8276/7430 8161/8339/7493 8160/8338/7492 +f 8099/8277/7431 8162/8340/7494 8161/8339/7493 +f 8100/8278/7432 8163/8341/7495 8162/8340/7494 +f 8101/8279/7433 8164/8342/7496 8163/8341/7495 +f 8102/8280/7434 8165/8343/7497 8164/8342/7496 +f 8103/8281/7435 8166/8344/7498 8165/8343/7497 +f 8104/8282/7436 8167/8345/7499 8166/8344/7498 +f 8105/8283/7437 8168/8346/7500 8167/8345/7499 +f 8106/8284/7438 8169/8347/7501 8168/8346/7500 +f 8107/8285/7439 8170/8348/7502 8169/8347/7501 +f 8108/8286/7440 8171/8349/7503 8170/8348/7502 +f 8109/8287/7441 8172/8350/7504 8171/8349/7503 +f 8110/8288/7442 8173/8351/7505 8172/8350/7504 +f 8111/8289/7443 8174/8352/7506 8173/8351/7505 +f 8112/8290/7444 8175/8353/7507 8174/8352/7506 +f 8113/8291/7445 8176/8354/7508 8175/8353/7507 +f 8114/8292/7446 8177/8355/7509 8176/8354/7508 +f 8115/8293/7447 8178/8356/7510 8177/8355/7509 +f 8116/8294/7448 8179/8357/7511 8178/8356/7510 +f 8117/8295/7449 8180/8358/7512 8179/8357/7511 +f 8118/8296/7450 8181/8359/7513 8180/8358/7512 +f 8119/8297/7451 8182/8360/7514 8181/8359/7513 +f 8120/8298/7452 8183/8361/7515 8182/8360/7514 +f 8121/8299/7453 8184/8362/7516 8183/8361/7515 +f 8122/8300/7454 8185/8363/7517 8184/8362/7516 +f 8123/8301/7455 8186/8364/7518 8185/8363/7517 +f 8124/8302/7456 8187/8365/7519 8186/8364/7518 +f 8125/8303/7457 8188/8366/7520 8187/8365/7519 +f 8126/8304/7458 8189/8367/7521 8188/8366/7520 +f 8127/8305/7459 8190/8368/7522 8189/8367/7521 +f 8128/8306/7460 8191/8369/7523 8190/8368/7522 +f 8129/8307/7461 8192/8370/7524 8191/8369/7523 +f 8130/8308/7462 8193/8371/7525 8192/8370/7524 +f 8131/8309/7463 8194/8372/7526 8193/8371/7525 +f 8132/8310/7464 8195/8373/7527 8194/8372/7526 +f 8133/8311/7465 8196/8374/7528 8195/8373/7527 +f 8134/8312/7466 8197/8375/7529 8196/8374/7528 +f 8135/8313/7467 8198/8376/7530 8197/8375/7529 +f 8136/8314/7468 8199/8377/7531 8198/8376/7530 +f 8137/8315/7469 8200/8378/7532 8199/8377/7531 +f 8138/8316/7470 8201/8379/7533 8200/8378/7532 +f 8139/8317/7471 8202/8380/7534 8201/8379/7533 +f 8140/8319/7473 8203/8382/7536 8202/8380/7534 +f 8141/8381/7535 8204/8444/7598 8203/8382/7536 +f 8143/8321/7475 8206/8384/7538 8205/8383/7537 +f 8144/8322/7476 8207/8385/7539 8206/8384/7538 +f 8145/8323/7477 8208/8386/7540 8207/8385/7539 +f 8146/8324/7478 8209/8387/7541 8208/8386/7540 +f 8147/8325/7479 8210/8388/7542 8209/8387/7541 +f 8148/8326/7480 8211/8389/7543 8210/8388/7542 +f 8149/8327/7481 8212/8390/7544 8211/8389/7543 +f 8150/8328/7482 8213/8391/7545 8212/8390/7544 +f 8151/8329/7483 8214/8392/7546 8213/8391/7545 +f 8152/8330/7484 8215/8393/7547 8214/8392/7546 +f 8153/8331/7485 8216/8394/7548 8215/8393/7547 +f 8154/8332/7486 8217/8395/7549 8216/8394/7548 +f 8155/8333/7487 8218/8396/7550 8217/8395/7549 +f 8156/8334/7488 8219/8397/7551 8218/8396/7550 +f 8157/8335/7489 8220/8398/7552 8219/8397/7551 +f 8158/8336/7490 8221/8399/7553 8220/8398/7552 +f 8159/8337/7491 8222/8400/7554 8221/8399/7553 +f 8160/8338/7492 8223/8401/7555 8222/8400/7554 +f 8161/8339/7493 8224/8402/7556 8223/8401/7555 +f 8162/8340/7494 8225/8403/7557 8224/8402/7556 +f 8163/8341/7495 8226/8404/7558 8225/8403/7557 +f 8164/8342/7496 8227/8405/7559 8226/8404/7558 +f 8165/8343/7497 8228/8406/7560 8227/8405/7559 +f 8166/8344/7498 8229/8407/7561 8228/8406/7560 +f 8167/8345/7499 8230/8408/7562 8229/8407/7561 +f 8168/8346/7500 8231/8409/7563 8230/8408/7562 +f 8169/8347/7501 8232/8410/7564 8231/8409/7563 +f 8170/8348/7502 8233/8411/7565 8232/8410/7564 +f 8171/8349/7503 8234/8412/7566 8233/8411/7565 +f 8172/8350/7504 8235/8413/7567 8234/8412/7566 +f 8173/8351/7505 8236/8414/7568 8235/8413/7567 +f 8174/8352/7506 8237/8415/7569 8236/8414/7568 +f 8175/8353/7507 8238/8416/7570 8237/8415/7569 +f 8176/8354/7508 8239/8417/7571 8238/8416/7570 +f 8177/8355/7509 8240/8418/7572 8239/8417/7571 +f 8178/8356/7510 8241/8419/7573 8240/8418/7572 +f 8179/8357/7511 8242/8420/7574 8241/8419/7573 +f 8180/8358/7512 8243/8421/7575 8242/8420/7574 +f 8181/8359/7513 8244/8422/7576 8243/8421/7575 +f 8182/8360/7514 8245/8423/7577 8244/8422/7576 +f 8183/8361/7515 8246/8424/7578 8245/8423/7577 +f 8184/8362/7516 8247/8425/7579 8246/8424/7578 +f 8185/8363/7517 8248/8426/7580 8247/8425/7579 +f 8186/8364/7518 8249/8427/7581 8248/8426/7580 +f 8187/8365/7519 8250/8428/7582 8249/8427/7581 +f 8188/8366/7520 8251/8429/7583 8250/8428/7582 +f 8189/8367/7521 8252/8430/7584 8251/8429/7583 +f 8190/8368/7522 8253/8431/7585 8252/8430/7584 +f 8191/8369/7523 8254/8432/7586 8253/8431/7585 +f 8192/8370/7524 8255/8433/7587 8254/8432/7586 +f 8193/8371/7525 8256/8434/7588 8255/8433/7587 +f 8194/8372/7526 8257/8435/7589 8256/8434/7588 +f 8195/8373/7527 8258/8436/7590 8257/8435/7589 +f 8196/8374/7528 8259/8437/7591 8258/8436/7590 +f 8197/8375/7529 8260/8438/7592 8259/8437/7591 +f 8198/8376/7530 8261/8439/7593 8260/8438/7592 +f 8199/8377/7531 8262/8440/7594 8261/8439/7593 +f 8200/8378/7532 8263/8441/7595 8262/8440/7594 +f 8201/8379/7533 8264/8442/7596 8263/8441/7595 +f 8202/8380/7534 8265/8443/7597 8264/8442/7596 +f 8203/8382/7536 8266/8445/7599 8265/8443/7597 +f 8204/8444/7598 8267/8507/7661 8266/8445/7599 +f 8206/8384/7538 8269/8447/7601 8268/8446/7600 +f 8207/8385/7539 8270/8448/7602 8269/8447/7601 +f 8208/8386/7540 8271/8449/7603 8270/8448/7602 +f 8209/8387/7541 8272/8450/7604 8271/8449/7603 +f 8210/8388/7542 8273/8451/7605 8272/8450/7604 +f 8211/8389/7543 8274/8452/7606 8273/8451/7605 +f 8212/8390/7544 8275/8453/7607 8274/8452/7606 +f 8213/8391/7545 8276/8454/7608 8275/8453/7607 +f 8214/8392/7546 8277/8455/7609 8276/8454/7608 +f 8215/8393/7547 8278/8456/7610 8277/8455/7609 +f 8216/8394/7548 8279/8457/7611 8278/8456/7610 +f 8217/8395/7549 8280/8458/7612 8279/8457/7611 +f 8218/8396/7550 8281/8459/7613 8280/8458/7612 +f 8219/8397/7551 8282/8460/7614 8281/8459/7613 +f 8220/8398/7552 8283/8461/7615 8282/8460/7614 +f 8221/8399/7553 8284/8462/7616 8283/8461/7615 +f 8222/8400/7554 8285/8463/7617 8284/8462/7616 +f 8223/8401/7555 8286/8464/7618 8285/8463/7617 +f 8224/8402/7556 8287/8465/7619 8286/8464/7618 +f 8225/8403/7557 8288/8466/7620 8287/8465/7619 +f 8226/8404/7558 8289/8467/7621 8288/8466/7620 +f 8227/8405/7559 8290/8468/7622 8289/8467/7621 +f 8228/8406/7560 8291/8469/7623 8290/8468/7622 +f 8229/8407/7561 8292/8470/7624 8291/8469/7623 +f 8230/8408/7562 8293/8471/7625 8292/8470/7624 +f 8231/8409/7563 8294/8472/7626 8293/8471/7625 +f 8232/8410/7564 8295/8473/7627 8294/8472/7626 +f 8233/8411/7565 8296/8474/7628 8295/8473/7627 +f 8234/8412/7566 8297/8475/7629 8296/8474/7628 +f 8235/8413/7567 8298/8476/7630 8297/8475/7629 +f 8236/8414/7568 8299/8477/7631 8298/8476/7630 +f 8237/8415/7569 8300/8478/7632 8299/8477/7631 +f 8238/8416/7570 8301/8479/7633 8300/8478/7632 +f 8239/8417/7571 8302/8480/7634 8301/8479/7633 +f 8240/8418/7572 8303/8481/7635 8302/8480/7634 +f 8241/8419/7573 8304/8482/7636 8303/8481/7635 +f 8242/8420/7574 8305/8483/7637 8304/8482/7636 +f 8243/8421/7575 8306/8484/7638 8305/8483/7637 +f 8244/8422/7576 8307/8485/7639 8306/8484/7638 +f 8245/8423/7577 8308/8486/7640 8307/8485/7639 +f 8246/8424/7578 8309/8487/7641 8308/8486/7640 +f 8247/8425/7579 8310/8488/7642 8309/8487/7641 +f 8248/8426/7580 8311/8489/7643 8310/8488/7642 +f 8249/8427/7581 8312/8490/7644 8311/8489/7643 +f 8250/8428/7582 8313/8491/7645 8312/8490/7644 +f 8251/8429/7583 8314/8492/7646 8313/8491/7645 +f 8252/8430/7584 8315/8493/7647 8314/8492/7646 +f 8253/8431/7585 8316/8494/7648 8315/8493/7647 +f 8254/8432/7586 8317/8495/7649 8316/8494/7648 +f 8255/8433/7587 8318/8496/7650 8317/8495/7649 +f 8256/8434/7588 8319/8497/7651 8318/8496/7650 +f 8257/8435/7589 8320/8498/7652 8319/8497/7651 +f 8258/8436/7590 8321/8499/7653 8320/8498/7652 +f 8259/8437/7591 8322/8500/7654 8321/8499/7653 +f 8260/8438/7592 8323/8501/7655 8322/8500/7654 +f 8261/8439/7593 8324/8502/7656 8323/8501/7655 +f 8262/8440/7594 8325/8503/7657 8324/8502/7656 +f 8263/8441/7595 8326/8504/7658 8325/8503/7657 +f 8264/8442/7596 8327/8505/7659 8326/8504/7658 +f 8265/8443/7597 8328/8506/7660 8327/8505/7659 +f 8266/8445/7599 8329/8508/7662 8328/8506/7660 +f 8267/8507/7661 8330/8570/7724 8329/8508/7662 +f 8269/8447/7601 8332/8510/7664 8331/8509/7663 +f 8270/8448/7602 8333/8511/7665 8332/8510/7664 +f 8271/8449/7603 8334/8512/7666 8333/8511/7665 +f 8272/8450/7604 8335/8513/7667 8334/8512/7666 +f 8273/8451/7605 8336/8514/7668 8335/8513/7667 +f 8274/8452/7606 8337/8515/7669 8336/8514/7668 +f 8275/8453/7607 8338/8516/7670 8337/8515/7669 +f 8276/8454/7608 8339/8517/7671 8338/8516/7670 +f 8277/8455/7609 8340/8518/7672 8339/8517/7671 +f 8278/8456/7610 8341/8519/7673 8340/8518/7672 +f 8279/8457/7611 8342/8520/7674 8341/8519/7673 +f 8280/8458/7612 8343/8521/7675 8342/8520/7674 +f 8281/8459/7613 8344/8522/7676 8343/8521/7675 +f 8282/8460/7614 8345/8523/7677 8344/8522/7676 +f 8283/8461/7615 8346/8524/7678 8345/8523/7677 +f 8284/8462/7616 8347/8525/7679 8346/8524/7678 +f 8285/8463/7617 8348/8526/7680 8347/8525/7679 +f 8286/8464/7618 8349/8527/7681 8348/8526/7680 +f 8287/8465/7619 8350/8528/7682 8349/8527/7681 +f 8288/8466/7620 8351/8529/7683 8350/8528/7682 +f 8289/8467/7621 8352/8530/7684 8351/8529/7683 +f 8290/8468/7622 8353/8531/7685 8352/8530/7684 +f 8291/8469/7623 8354/8532/7686 8353/8531/7685 +f 8292/8470/7624 8355/8533/7687 8354/8532/7686 +f 8293/8471/7625 8356/8534/7688 8355/8533/7687 +f 8294/8472/7626 8357/8535/7689 8356/8534/7688 +f 8295/8473/7627 8358/8536/7690 8357/8535/7689 +f 8296/8474/7628 8359/8537/7691 8358/8536/7690 +f 8297/8475/7629 8360/8538/7692 8359/8537/7691 +f 8298/8476/7630 8361/8539/7693 8360/8538/7692 +f 8299/8477/7631 8362/8540/7694 8361/8539/7693 +f 8300/8478/7632 8363/8541/7695 8362/8540/7694 +f 8301/8479/7633 8364/8542/7696 8363/8541/7695 +f 8302/8480/7634 8365/8543/7697 8364/8542/7696 +f 8303/8481/7635 8366/8544/7698 8365/8543/7697 +f 8304/8482/7636 8367/8545/7699 8366/8544/7698 +f 8305/8483/7637 8368/8546/7700 8367/8545/7699 +f 8306/8484/7638 8369/8547/7701 8368/8546/7700 +f 8307/8485/7639 8370/8548/7702 8369/8547/7701 +f 8308/8486/7640 8371/8549/7703 8370/8548/7702 +f 8309/8487/7641 8372/8550/7704 8371/8549/7703 +f 8310/8488/7642 8373/8551/7705 8372/8550/7704 +f 8311/8489/7643 8374/8552/7706 8373/8551/7705 +f 8312/8490/7644 8375/8553/7707 8374/8552/7706 +f 8313/8491/7645 8376/8554/7708 8375/8553/7707 +f 8314/8492/7646 8377/8555/7709 8376/8554/7708 +f 8315/8493/7647 8378/8556/7710 8377/8555/7709 +f 8316/8494/7648 8379/8557/7711 8378/8556/7710 +f 8317/8495/7649 8380/8558/7712 8379/8557/7711 +f 8318/8496/7650 8381/8559/7713 8380/8558/7712 +f 8319/8497/7651 8382/8560/7714 8381/8559/7713 +f 8320/8498/7652 8383/8561/7715 8382/8560/7714 +f 8321/8499/7653 8384/8562/7716 8383/8561/7715 +f 8322/8500/7654 8385/8563/7717 8384/8562/7716 +f 8323/8501/7655 8386/8564/7718 8385/8563/7717 +f 8324/8502/7656 8387/8565/7719 8386/8564/7718 +f 8325/8503/7657 8388/8566/7720 8387/8565/7719 +f 8326/8504/7658 8389/8567/7721 8388/8566/7720 +f 8327/8505/7659 8390/8568/7722 8389/8567/7721 +f 8328/8506/7660 8391/8569/7723 8390/8568/7722 +f 8329/8508/7662 8392/8571/7725 8391/8569/7723 +f 8330/8570/7724 8393/8633/7787 8392/8571/7725 +f 8332/8510/7664 8395/8573/7727 8394/8572/7726 +f 8333/8511/7665 8396/8574/7728 8395/8573/7727 +f 8334/8512/7666 8397/8575/7729 8396/8574/7728 +f 8335/8513/7667 8398/8576/7730 8397/8575/7729 +f 8336/8514/7668 8399/8577/7731 8398/8576/7730 +f 8337/8515/7669 8400/8578/7732 8399/8577/7731 +f 8338/8516/7670 8401/8579/7733 8400/8578/7732 +f 8339/8517/7671 8402/8580/7734 8401/8579/7733 +f 8340/8518/7672 8403/8581/7735 8402/8580/7734 +f 8341/8519/7673 8404/8582/7736 8403/8581/7735 +f 8342/8520/7674 8405/8583/7737 8404/8582/7736 +f 8343/8521/7675 8406/8584/7738 8405/8583/7737 +f 8344/8522/7676 8407/8585/7739 8406/8584/7738 +f 8345/8523/7677 8408/8586/7740 8407/8585/7739 +f 8346/8524/7678 8409/8587/7741 8408/8586/7740 +f 8347/8525/7679 8410/8588/7742 8409/8587/7741 +f 8348/8526/7680 8411/8589/7743 8410/8588/7742 +f 8349/8527/7681 8412/8590/7744 8411/8589/7743 +f 8350/8528/7682 8413/8591/7745 8412/8590/7744 +f 8351/8529/7683 8414/8592/7746 8413/8591/7745 +f 8352/8530/7684 8415/8593/7747 8414/8592/7746 +f 8353/8531/7685 8416/8594/7748 8415/8593/7747 +f 8354/8532/7686 8417/8595/7749 8416/8594/7748 +f 8355/8533/7687 8418/8596/7750 8417/8595/7749 +f 8356/8534/7688 8419/8597/7751 8418/8596/7750 +f 8357/8535/7689 8420/8598/7752 8419/8597/7751 +f 8358/8536/7690 8421/8599/7753 8420/8598/7752 +f 8359/8537/7691 8422/8600/7754 8421/8599/7753 +f 8360/8538/7692 8423/8601/7755 8422/8600/7754 +f 8361/8539/7693 8424/8602/7756 8423/8601/7755 +f 8362/8540/7694 8425/8603/7757 8424/8602/7756 +f 8363/8541/7695 8426/8604/7758 8425/8603/7757 +f 8364/8542/7696 8427/8605/7759 8426/8604/7758 +f 8365/8543/7697 8428/8606/7760 8427/8605/7759 +f 8366/8544/7698 8429/8607/7761 8428/8606/7760 +f 8367/8545/7699 8430/8608/7762 8429/8607/7761 +f 8368/8546/7700 8431/8609/7763 8430/8608/7762 +f 8369/8547/7701 8432/8610/7764 8431/8609/7763 +f 8370/8548/7702 8433/8611/7765 8432/8610/7764 +f 8371/8549/7703 8434/8612/7766 8433/8611/7765 +f 8372/8550/7704 8435/8613/7767 8434/8612/7766 +f 8373/8551/7705 8436/8614/7768 8435/8613/7767 +f 8374/8552/7706 8437/8615/7769 8436/8614/7768 +f 8375/8553/7707 8438/8616/7770 8437/8615/7769 +f 8376/8554/7708 8439/8617/7771 8438/8616/7770 +f 8377/8555/7709 8440/8618/7772 8439/8617/7771 +f 8378/8556/7710 8441/8619/7773 8440/8618/7772 +f 8379/8557/7711 8442/8620/7774 8441/8619/7773 +f 8380/8558/7712 8443/8621/7775 8442/8620/7774 +f 8381/8559/7713 8444/8622/7776 8443/8621/7775 +f 8382/8560/7714 8445/8623/7777 8444/8622/7776 +f 8383/8561/7715 8446/8624/7778 8445/8623/7777 +f 8384/8562/7716 8447/8625/7779 8446/8624/7778 +f 8385/8563/7717 8448/8626/7780 8447/8625/7779 +f 8386/8564/7718 8449/8627/7781 8448/8626/7780 +f 8387/8565/7719 8450/8628/7782 8449/8627/7781 +f 8388/8566/7720 8451/8629/7783 8450/8628/7782 +f 8389/8567/7721 8452/8630/7784 8451/8629/7783 +f 8390/8568/7722 8453/8631/7785 8452/8630/7784 +f 8391/8569/7723 8454/8632/7786 8453/8631/7785 +f 8392/8571/7725 8455/8634/7788 8454/8632/7786 +f 8393/8633/7787 8456/8696/7850 8455/8634/7788 +f 8395/8573/7727 8458/8636/7790 8457/8635/7789 +f 8396/8574/7728 8459/8637/7791 8458/8636/7790 +f 8397/8575/7729 8460/8638/7792 8459/8637/7791 +f 8398/8576/7730 8461/8639/7793 8460/8638/7792 +f 8399/8577/7731 8462/8640/7794 8461/8639/7793 +f 8400/8578/7732 8463/8641/7795 8462/8640/7794 +f 8401/8579/7733 8464/8642/7796 8463/8641/7795 +f 8402/8580/7734 8465/8643/7797 8464/8642/7796 +f 8403/8581/7735 8466/8644/7798 8465/8643/7797 +f 8404/8582/7736 8467/8645/7799 8466/8644/7798 +f 8405/8583/7737 8468/8646/7800 8467/8645/7799 +f 8406/8584/7738 8469/8647/7801 8468/8646/7800 +f 8407/8585/7739 8470/8648/7802 8469/8647/7801 +f 8408/8586/7740 8471/8649/7803 8470/8648/7802 +f 8409/8587/7741 8472/8650/7804 8471/8649/7803 +f 8410/8588/7742 8473/8651/7805 8472/8650/7804 +f 8411/8589/7743 8474/8652/7806 8473/8651/7805 +f 8412/8590/7744 8475/8653/7807 8474/8652/7806 +f 8413/8591/7745 8476/8654/7808 8475/8653/7807 +f 8414/8592/7746 8477/8655/7809 8476/8654/7808 +f 8415/8593/7747 8478/8656/7810 8477/8655/7809 +f 8416/8594/7748 8479/8657/7811 8478/8656/7810 +f 8417/8595/7749 8480/8658/7812 8479/8657/7811 +f 8418/8596/7750 8481/8659/7813 8480/8658/7812 +f 8419/8597/7751 8482/8660/7814 8481/8659/7813 +f 8420/8598/7752 8483/8661/7815 8482/8660/7814 +f 8421/8599/7753 8484/8662/7816 8483/8661/7815 +f 8422/8600/7754 8485/8663/7817 8484/8662/7816 +f 8423/8601/7755 8486/8664/7818 8485/8663/7817 +f 8424/8602/7756 8487/8665/7819 8486/8664/7818 +f 8425/8603/7757 8488/8666/7820 8487/8665/7819 +f 8426/8604/7758 8489/8667/7821 8488/8666/7820 +f 8427/8605/7759 8490/8668/7822 8489/8667/7821 +f 8428/8606/7760 8491/8669/7823 8490/8668/7822 +f 8429/8607/7761 8492/8670/7824 8491/8669/7823 +f 8430/8608/7762 8493/8671/7825 8492/8670/7824 +f 8431/8609/7763 8494/8672/7826 8493/8671/7825 +f 8432/8610/7764 8495/8673/7827 8494/8672/7826 +f 8433/8611/7765 8496/8674/7828 8495/8673/7827 +f 8434/8612/7766 8497/8675/7829 8496/8674/7828 +f 8435/8613/7767 8498/8676/7830 8497/8675/7829 +f 8436/8614/7768 8499/8677/7831 8498/8676/7830 +f 8437/8615/7769 8500/8678/7832 8499/8677/7831 +f 8438/8616/7770 8501/8679/7833 8500/8678/7832 +f 8439/8617/7771 8502/8680/7834 8501/8679/7833 +f 8440/8618/7772 8503/8681/7835 8502/8680/7834 +f 8441/8619/7773 8504/8682/7836 8503/8681/7835 +f 8442/8620/7774 8505/8683/7837 8504/8682/7836 +f 8443/8621/7775 8506/8684/7838 8505/8683/7837 +f 8444/8622/7776 8507/8685/7839 8506/8684/7838 +f 8445/8623/7777 8508/8686/7840 8507/8685/7839 +f 8446/8624/7778 8509/8687/7841 8508/8686/7840 +f 8447/8625/7779 8510/8688/7842 8509/8687/7841 +f 8448/8626/7780 8511/8689/7843 8510/8688/7842 +f 8449/8627/7781 8512/8690/7844 8511/8689/7843 +f 8450/8628/7782 8513/8691/7845 8512/8690/7844 +f 8451/8629/7783 8514/8692/7846 8513/8691/7845 +f 8452/8630/7784 8515/8693/7847 8514/8692/7846 +f 8453/8631/7785 8516/8694/7848 8515/8693/7847 +f 8454/8632/7786 8517/8695/7849 8516/8694/7848 +f 8455/8634/7788 8518/8697/7851 8517/8695/7849 +f 8456/8696/7850 8519/8759/7913 8518/8697/7851 +f 8458/8636/7790 8521/8699/7853 8520/8698/7852 +f 8459/8637/7791 8522/8700/7854 8521/8699/7853 +f 8460/8638/7792 8523/8701/7855 8522/8700/7854 +f 8461/8639/7793 8524/8702/7856 8523/8701/7855 +f 8462/8640/7794 8525/8703/7857 8524/8702/7856 +f 8463/8641/7795 8526/8704/7858 8525/8703/7857 +f 8464/8642/7796 8527/8705/7859 8526/8704/7858 +f 8465/8643/7797 8528/8706/7860 8527/8705/7859 +f 8466/8644/7798 8529/8707/7861 8528/8706/7860 +f 8467/8645/7799 8530/8708/7862 8529/8707/7861 +f 8468/8646/7800 8531/8709/7863 8530/8708/7862 +f 8469/8647/7801 8532/8710/7864 8531/8709/7863 +f 8470/8648/7802 8533/8711/7865 8532/8710/7864 +f 8471/8649/7803 8534/8712/7866 8533/8711/7865 +f 8472/8650/7804 8535/8713/7867 8534/8712/7866 +f 8473/8651/7805 8536/8714/7868 8535/8713/7867 +f 8474/8652/7806 8537/8715/7869 8536/8714/7868 +f 8475/8653/7807 8538/8716/7870 8537/8715/7869 +f 8476/8654/7808 8539/8717/7871 8538/8716/7870 +f 8477/8655/7809 8540/8718/7872 8539/8717/7871 +f 8478/8656/7810 8541/8719/7873 8540/8718/7872 +f 8479/8657/7811 8542/8720/7874 8541/8719/7873 +f 8480/8658/7812 8543/8721/7875 8542/8720/7874 +f 8481/8659/7813 8544/8722/7876 8543/8721/7875 +f 8482/8660/7814 8545/8723/7877 8544/8722/7876 +f 8483/8661/7815 8546/8724/7878 8545/8723/7877 +f 8484/8662/7816 8547/8725/7879 8546/8724/7878 +f 8485/8663/7817 8548/8726/7880 8547/8725/7879 +f 8486/8664/7818 8549/8727/7881 8548/8726/7880 +f 8487/8665/7819 8550/8728/7882 8549/8727/7881 +f 8488/8666/7820 8551/8729/7883 8550/8728/7882 +f 8489/8667/7821 8552/8730/7884 8551/8729/7883 +f 8490/8668/7822 8553/8731/7885 8552/8730/7884 +f 8491/8669/7823 8554/8732/7886 8553/8731/7885 +f 8492/8670/7824 8555/8733/7887 8554/8732/7886 +f 8493/8671/7825 8556/8734/7888 8555/8733/7887 +f 8494/8672/7826 8557/8735/7889 8556/8734/7888 +f 8495/8673/7827 8558/8736/7890 8557/8735/7889 +f 8496/8674/7828 8559/8737/7891 8558/8736/7890 +f 8497/8675/7829 8560/8738/7892 8559/8737/7891 +f 8498/8676/7830 8561/8739/7893 8560/8738/7892 +f 8499/8677/7831 8562/8740/7894 8561/8739/7893 +f 8500/8678/7832 8563/8741/7895 8562/8740/7894 +f 8501/8679/7833 8564/8742/7896 8563/8741/7895 +f 8502/8680/7834 8565/8743/7897 8564/8742/7896 +f 8503/8681/7835 8566/8744/7898 8565/8743/7897 +f 8504/8682/7836 8567/8745/7899 8566/8744/7898 +f 8505/8683/7837 8568/8746/7900 8567/8745/7899 +f 8506/8684/7838 8569/8747/7901 8568/8746/7900 +f 8507/8685/7839 8570/8748/7902 8569/8747/7901 +f 8508/8686/7840 8571/8749/7903 8570/8748/7902 +f 8509/8687/7841 8572/8750/7904 8571/8749/7903 +f 8510/8688/7842 8573/8751/7905 8572/8750/7904 +f 8511/8689/7843 8574/8752/7906 8573/8751/7905 +f 8512/8690/7844 8575/8753/7907 8574/8752/7906 +f 8513/8691/7845 8576/8754/7908 8575/8753/7907 +f 8514/8692/7846 8577/8755/7909 8576/8754/7908 +f 8515/8693/7847 8578/8756/7910 8577/8755/7909 +f 8516/8694/7848 8579/8757/7911 8578/8756/7910 +f 8517/8695/7849 8580/8758/7912 8579/8757/7911 +f 8518/8697/7851 8581/8760/7914 8580/8758/7912 +f 8519/8759/7913 8582/8822/7976 8581/8760/7914 +f 8521/8699/7853 8584/8762/7916 8583/8761/7915 +f 8522/8700/7854 8585/8763/7917 8584/8762/7916 +f 8523/8701/7855 8586/8764/7918 8585/8763/7917 +f 8524/8702/7856 8587/8765/7919 8586/8764/7918 +f 8525/8703/7857 8588/8766/7920 8587/8765/7919 +f 8526/8704/7858 8589/8767/7921 8588/8766/7920 +f 8527/8705/7859 8590/8768/7922 8589/8767/7921 +f 8528/8706/7860 8591/8769/7923 8590/8768/7922 +f 8529/8707/7861 8592/8770/7924 8591/8769/7923 +f 8530/8708/7862 8593/8771/7925 8592/8770/7924 +f 8531/8709/7863 8594/8772/7926 8593/8771/7925 +f 8532/8710/7864 8595/8773/7927 8594/8772/7926 +f 8533/8711/7865 8596/8774/7928 8595/8773/7927 +f 8534/8712/7866 8597/8775/7929 8596/8774/7928 +f 8535/8713/7867 8598/8776/7930 8597/8775/7929 +f 8536/8714/7868 8599/8777/7931 8598/8776/7930 +f 8537/8715/7869 8600/8778/7932 8599/8777/7931 +f 8538/8716/7870 8601/8779/7933 8600/8778/7932 +f 8539/8717/7871 8602/8780/7934 8601/8779/7933 +f 8540/8718/7872 8603/8781/7935 8602/8780/7934 +f 8541/8719/7873 8604/8782/7936 8603/8781/7935 +f 8542/8720/7874 8605/8783/7937 8604/8782/7936 +f 8543/8721/7875 8606/8784/7938 8605/8783/7937 +f 8544/8722/7876 8607/8785/7939 8606/8784/7938 +f 8545/8723/7877 8608/8786/7940 8607/8785/7939 +f 8546/8724/7878 8609/8787/7941 8608/8786/7940 +f 8547/8725/7879 8610/8788/7942 8609/8787/7941 +f 8548/8726/7880 8611/8789/7943 8610/8788/7942 +f 8549/8727/7881 8612/8790/7944 8611/8789/7943 +f 8550/8728/7882 8613/8791/7945 8612/8790/7944 +f 8551/8729/7883 8614/8792/7946 8613/8791/7945 +f 8552/8730/7884 8615/8793/7947 8614/8792/7946 +f 8553/8731/7885 8616/8794/7948 8615/8793/7947 +f 8554/8732/7886 8617/8795/7949 8616/8794/7948 +f 8555/8733/7887 8618/8796/7950 8617/8795/7949 +f 8556/8734/7888 8619/8797/7951 8618/8796/7950 +f 8557/8735/7889 8620/8798/7952 8619/8797/7951 +f 8558/8736/7890 8621/8799/7953 8620/8798/7952 +f 8559/8737/7891 8622/8800/7954 8621/8799/7953 +f 8560/8738/7892 8623/8801/7955 8622/8800/7954 +f 8561/8739/7893 8624/8802/7956 8623/8801/7955 +f 8562/8740/7894 8625/8803/7957 8624/8802/7956 +f 8563/8741/7895 8626/8804/7958 8625/8803/7957 +f 8564/8742/7896 8627/8805/7959 8626/8804/7958 +f 8565/8743/7897 8628/8806/7960 8627/8805/7959 +f 8566/8744/7898 8629/8807/7961 8628/8806/7960 +f 8567/8745/7899 8630/8808/7962 8629/8807/7961 +f 8568/8746/7900 8631/8809/7963 8630/8808/7962 +f 8569/8747/7901 8632/8810/7964 8631/8809/7963 +f 8570/8748/7902 8633/8811/7965 8632/8810/7964 +f 8571/8749/7903 8634/8812/7966 8633/8811/7965 +f 8572/8750/7904 8635/8813/7967 8634/8812/7966 +f 8573/8751/7905 8636/8814/7968 8635/8813/7967 +f 8574/8752/7906 8637/8815/7969 8636/8814/7968 +f 8575/8753/7907 8638/8816/7970 8637/8815/7969 +f 8576/8754/7908 8639/8817/7971 8638/8816/7970 +f 8577/8755/7909 8640/8818/7972 8639/8817/7971 +f 8578/8756/7910 8641/8819/7973 8640/8818/7972 +f 8579/8757/7911 8642/8820/7974 8641/8819/7973 +f 8580/8758/7912 8643/8821/7975 8642/8820/7974 +f 8581/8760/7914 8644/8823/7977 8643/8821/7975 +f 8582/8822/7976 8645/8885/8039 8644/8823/7977 +f 8584/8762/7916 8647/8825/7979 8646/8824/7978 +f 8585/8763/7917 8648/8826/7980 8647/8825/7979 +f 8586/8764/7918 8649/8827/7981 8648/8826/7980 +f 8587/8765/7919 8650/8828/7982 8649/8827/7981 +f 8588/8766/7920 8651/8829/7983 8650/8828/7982 +f 8589/8767/7921 8652/8830/7984 8651/8829/7983 +f 8590/8768/7922 8653/8831/7985 8652/8830/7984 +f 8591/8769/7923 8654/8832/7986 8653/8831/7985 +f 8592/8770/7924 8655/8833/7987 8654/8832/7986 +f 8593/8771/7925 8656/8834/7988 8655/8833/7987 +f 8594/8772/7926 8657/8835/7989 8656/8834/7988 +f 8595/8773/7927 8658/8836/7990 8657/8835/7989 +f 8596/8774/7928 8659/8837/7991 8658/8836/7990 +f 8597/8775/7929 8660/8838/7992 8659/8837/7991 +f 8598/8776/7930 8661/8839/7993 8660/8838/7992 +f 8599/8777/7931 8662/8840/7994 8661/8839/7993 +f 8600/8778/7932 8663/8841/7995 8662/8840/7994 +f 8601/8779/7933 8664/8842/7996 8663/8841/7995 +f 8602/8780/7934 8665/8843/7997 8664/8842/7996 +f 8603/8781/7935 8666/8844/7998 8665/8843/7997 +f 8604/8782/7936 8667/8845/7999 8666/8844/7998 +f 8605/8783/7937 8668/8846/8000 8667/8845/7999 +f 8606/8784/7938 8669/8847/8001 8668/8846/8000 +f 8607/8785/7939 8670/8848/8002 8669/8847/8001 +f 8608/8786/7940 8671/8849/8003 8670/8848/8002 +f 8609/8787/7941 8672/8850/8004 8671/8849/8003 +f 8610/8788/7942 8673/8851/8005 8672/8850/8004 +f 8611/8789/7943 8674/8852/8006 8673/8851/8005 +f 8612/8790/7944 8675/8853/8007 8674/8852/8006 +f 8613/8791/7945 8676/8854/8008 8675/8853/8007 +f 8614/8792/7946 8677/8855/8009 8676/8854/8008 +f 8615/8793/7947 8678/8856/8010 8677/8855/8009 +f 8616/8794/7948 8679/8857/8011 8678/8856/8010 +f 8617/8795/7949 8680/8858/8012 8679/8857/8011 +f 8618/8796/7950 8681/8859/8013 8680/8858/8012 +f 8619/8797/7951 8682/8860/8014 8681/8859/8013 +f 8620/8798/7952 8683/8861/8015 8682/8860/8014 +f 8621/8799/7953 8684/8862/8016 8683/8861/8015 +f 8622/8800/7954 8685/8863/8017 8684/8862/8016 +f 8623/8801/7955 8686/8864/8018 8685/8863/8017 +f 8624/8802/7956 8687/8865/8019 8686/8864/8018 +f 8625/8803/7957 8688/8866/8020 8687/8865/8019 +f 8626/8804/7958 8689/8867/8021 8688/8866/8020 +f 8627/8805/7959 8690/8868/8022 8689/8867/8021 +f 8628/8806/7960 8691/8869/8023 8690/8868/8022 +f 8629/8807/7961 8692/8870/8024 8691/8869/8023 +f 8630/8808/7962 8693/8871/8025 8692/8870/8024 +f 8631/8809/7963 8694/8872/8026 8693/8871/8025 +f 8632/8810/7964 8695/8873/8027 8694/8872/8026 +f 8633/8811/7965 8696/8874/8028 8695/8873/8027 +f 8634/8812/7966 8697/8875/8029 8696/8874/8028 +f 8635/8813/7967 8698/8876/8030 8697/8875/8029 +f 8636/8814/7968 8699/8877/8031 8698/8876/8030 +f 8637/8815/7969 8700/8878/8032 8699/8877/8031 +f 8638/8816/7970 8701/8879/8033 8700/8878/8032 +f 8639/8817/7971 8702/8880/8034 8701/8879/8033 +f 8640/8818/7972 8703/8881/8035 8702/8880/8034 +f 8641/8819/7973 8704/8882/8036 8703/8881/8035 +f 8642/8820/7974 8705/8883/8037 8704/8882/8036 +f 8643/8821/7975 8706/8884/8038 8705/8883/8037 +f 8644/8823/7977 8707/8886/8040 8706/8884/8038 +f 8645/8885/8039 8708/8948/8102 8707/8886/8040 +f 8647/8825/7979 8710/8888/8042 8709/8887/8041 +f 8648/8826/7980 8711/8889/8043 8710/8888/8042 +f 8649/8827/7981 8712/8890/8044 8711/8889/8043 +f 8650/8828/7982 8713/8891/8045 8712/8890/8044 +f 8651/8829/7983 8714/8892/8046 8713/8891/8045 +f 8652/8830/7984 8715/8893/8047 8714/8892/8046 +f 8653/8831/7985 8716/8894/8048 8715/8893/8047 +f 8654/8832/7986 8717/8895/8049 8716/8894/8048 +f 8655/8833/7987 8718/8896/8050 8717/8895/8049 +f 8656/8834/7988 8719/8897/8051 8718/8896/8050 +f 8657/8835/7989 8720/8898/8052 8719/8897/8051 +f 8658/8836/7990 8721/8899/8053 8720/8898/8052 +f 8659/8837/7991 8722/8900/8054 8721/8899/8053 +f 8660/8838/7992 8723/8901/8055 8722/8900/8054 +f 8661/8839/7993 8724/8902/8056 8723/8901/8055 +f 8662/8840/7994 8725/8903/8057 8724/8902/8056 +f 8663/8841/7995 8726/8904/8058 8725/8903/8057 +f 8664/8842/7996 8727/8905/8059 8726/8904/8058 +f 8665/8843/7997 8728/8906/8060 8727/8905/8059 +f 8666/8844/7998 8729/8907/8061 8728/8906/8060 +f 8667/8845/7999 8730/8908/8062 8729/8907/8061 +f 8668/8846/8000 8731/8909/8063 8730/8908/8062 +f 8669/8847/8001 8732/8910/8064 8731/8909/8063 +f 8670/8848/8002 8733/8911/8065 8732/8910/8064 +f 8671/8849/8003 8734/8912/8066 8733/8911/8065 +f 8672/8850/8004 8735/8913/8067 8734/8912/8066 +f 8673/8851/8005 8736/8914/8068 8735/8913/8067 +f 8674/8852/8006 8737/8915/8069 8736/8914/8068 +f 8675/8853/8007 8738/8916/8070 8737/8915/8069 +f 8676/8854/8008 8739/8917/8071 8738/8916/8070 +f 8677/8855/8009 8740/8918/8072 8739/8917/8071 +f 8678/8856/8010 8741/8919/8073 8740/8918/8072 +f 8679/8857/8011 8742/8920/8074 8741/8919/8073 +f 8680/8858/8012 8743/8921/8075 8742/8920/8074 +f 8681/8859/8013 8744/8922/8076 8743/8921/8075 +f 8682/8860/8014 8745/8923/8077 8744/8922/8076 +f 8683/8861/8015 8746/8924/8078 8745/8923/8077 +f 8684/8862/8016 8747/8925/8079 8746/8924/8078 +f 8685/8863/8017 8748/8926/8080 8747/8925/8079 +f 8686/8864/8018 8749/8927/8081 8748/8926/8080 +f 8687/8865/8019 8750/8928/8082 8749/8927/8081 +f 8688/8866/8020 8751/8929/8083 8750/8928/8082 +f 8689/8867/8021 8752/8930/8084 8751/8929/8083 +f 8690/8868/8022 8753/8931/8085 8752/8930/8084 +f 8691/8869/8023 8754/8932/8086 8753/8931/8085 +f 8692/8870/8024 8755/8933/8087 8754/8932/8086 +f 8693/8871/8025 8756/8934/8088 8755/8933/8087 +f 8694/8872/8026 8757/8935/8089 8756/8934/8088 +f 8695/8873/8027 8758/8936/8090 8757/8935/8089 +f 8696/8874/8028 8759/8937/8091 8758/8936/8090 +f 8697/8875/8029 8760/8938/8092 8759/8937/8091 +f 8698/8876/8030 8761/8939/8093 8760/8938/8092 +f 8699/8877/8031 8762/8940/8094 8761/8939/8093 +f 8700/8878/8032 8763/8941/8095 8762/8940/8094 +f 8701/8879/8033 8764/8942/8096 8763/8941/8095 +f 8702/8880/8034 8765/8943/8097 8764/8942/8096 +f 8703/8881/8035 8766/8944/8098 8765/8943/8097 +f 8704/8882/8036 8767/8945/8099 8766/8944/8098 +f 8705/8883/8037 8768/8946/8100 8767/8945/8099 +f 8706/8884/8038 8769/8947/8101 8768/8946/8100 +f 8707/8886/8040 8770/8949/8103 8769/8947/8101 +f 8708/8948/8102 8771/9011/8165 8770/8949/8103 +f 8710/8888/8042 8773/8951/8105 8772/8950/8104 +f 8711/8889/8043 8774/8952/8106 8773/8951/8105 +f 8712/8890/8044 8775/8953/8107 8774/8952/8106 +f 8713/8891/8045 8776/8954/8108 8775/8953/8107 +f 8714/8892/8046 8777/8955/8109 8776/8954/8108 +f 8715/8893/8047 8778/8956/8110 8777/8955/8109 +f 8716/8894/8048 8779/8957/8111 8778/8956/8110 +f 8717/8895/8049 8780/8958/8112 8779/8957/8111 +f 8718/8896/8050 8781/8959/8113 8780/8958/8112 +f 8719/8897/8051 8782/8960/8114 8781/8959/8113 +f 8720/8898/8052 8783/8961/8115 8782/8960/8114 +f 8721/8899/8053 8784/8962/8116 8783/8961/8115 +f 8722/8900/8054 8785/8963/8117 8784/8962/8116 +f 8723/8901/8055 8786/8964/8118 8785/8963/8117 +f 8724/8902/8056 8787/8965/8119 8786/8964/8118 +f 8725/8903/8057 8788/8966/8120 8787/8965/8119 +f 8726/8904/8058 8789/8967/8121 8788/8966/8120 +f 8727/8905/8059 8790/8968/8122 8789/8967/8121 +f 8728/8906/8060 8791/8969/8123 8790/8968/8122 +f 8729/8907/8061 8792/8970/8124 8791/8969/8123 +f 8730/8908/8062 8793/8971/8125 8792/8970/8124 +f 8731/8909/8063 8794/8972/8126 8793/8971/8125 +f 8732/8910/8064 8795/8973/8127 8794/8972/8126 +f 8733/8911/8065 8796/8974/8128 8795/8973/8127 +f 8734/8912/8066 8797/8975/8129 8796/8974/8128 +f 8735/8913/8067 8798/8976/8130 8797/8975/8129 +f 8736/8914/8068 8799/8977/8131 8798/8976/8130 +f 8737/8915/8069 8800/8978/8132 8799/8977/8131 +f 8738/8916/8070 8801/8979/8133 8800/8978/8132 +f 8739/8917/8071 8802/8980/8134 8801/8979/8133 +f 8740/8918/8072 8803/8981/8135 8802/8980/8134 +f 8741/8919/8073 8804/8982/8136 8803/8981/8135 +f 8742/8920/8074 8805/8983/8137 8804/8982/8136 +f 8743/8921/8075 8806/8984/8138 8805/8983/8137 +f 8744/8922/8076 8807/8985/8139 8806/8984/8138 +f 8745/8923/8077 8808/8986/8140 8807/8985/8139 +f 8746/8924/8078 8809/8987/8141 8808/8986/8140 +f 8747/8925/8079 8810/8988/8142 8809/8987/8141 +f 8748/8926/8080 8811/8989/8143 8810/8988/8142 +f 8749/8927/8081 8812/8990/8144 8811/8989/8143 +f 8750/8928/8082 8813/8991/8145 8812/8990/8144 +f 8751/8929/8083 8814/8992/8146 8813/8991/8145 +f 8752/8930/8084 8815/8993/8147 8814/8992/8146 +f 8753/8931/8085 8816/8994/8148 8815/8993/8147 +f 8754/8932/8086 8817/8995/8149 8816/8994/8148 +f 8755/8933/8087 8818/8996/8150 8817/8995/8149 +f 8756/8934/8088 8819/8997/8151 8818/8996/8150 +f 8757/8935/8089 8820/8998/8152 8819/8997/8151 +f 8758/8936/8090 8821/8999/8153 8820/8998/8152 +f 8759/8937/8091 8822/9000/8154 8821/8999/8153 +f 8760/8938/8092 8823/9001/8155 8822/9000/8154 +f 8761/8939/8093 8824/9002/8156 8823/9001/8155 +f 8762/8940/8094 8825/9003/8157 8824/9002/8156 +f 8763/8941/8095 8826/9004/8158 8825/9003/8157 +f 8764/8942/8096 8827/9005/8159 8826/9004/8158 +f 8765/8943/8097 8828/9006/8160 8827/9005/8159 +f 8766/8944/8098 8829/9007/8161 8828/9006/8160 +f 8767/8945/8099 8830/9008/8162 8829/9007/8161 +f 8768/8946/8100 8831/9009/8163 8830/9008/8162 +f 8769/8947/8101 8832/9010/8164 8831/9009/8163 +f 8770/8949/8103 8833/9012/8166 8832/9010/8164 +f 8771/9011/8165 8834/9074/8227 8833/9012/8166 +f 8773/8951/8105 8836/9014/8168 8835/9013/8167 +f 8774/8952/8106 8837/9015/8169 8836/9014/8168 +f 8775/8953/8107 8838/9016/8170 8837/9015/8169 +f 8776/8954/8108 8839/9017/8171 8838/9016/8170 +f 8777/8955/8109 8840/9018/8172 8839/9017/8171 +f 8778/8956/8110 8841/9019/8173 8840/9018/8172 +f 8779/8957/8111 8842/9020/8174 8841/9019/8173 +f 8780/8958/8112 8843/9021/8175 8842/9020/8174 +f 8781/8959/8113 8844/9022/8176 8843/9021/8175 +f 8782/8960/8114 8845/9023/8177 8844/9022/8176 +f 8783/8961/8115 8846/9024/8178 8845/9023/8177 +f 8784/8962/8116 8847/9025/8179 8846/9024/8178 +f 8785/8963/8117 8848/9026/8180 8847/9025/8179 +f 8786/8964/8118 8849/9027/8181 8848/9026/8180 +f 8787/8965/8119 8850/9028/8182 8849/9027/8181 +f 8788/8966/8120 8851/9029/8183 8850/9028/8182 +f 8789/8967/8121 8852/9030/8184 8851/9029/8183 +f 8790/8968/8122 8853/9031/8185 8852/9030/8184 +f 8791/8969/8123 8854/9032/8186 8853/9031/8185 +f 8792/8970/8124 8855/9033/8187 8854/9032/8186 +f 8793/8971/8125 8856/9034/8188 8855/9033/8187 +f 8794/8972/8126 8857/9035/8189 8856/9034/8188 +f 8795/8973/8127 8858/9036/8190 8857/9035/8189 +f 8796/8974/8128 8859/9037/8191 8858/9036/8190 +f 8797/8975/8129 8860/9038/8192 8859/9037/8191 +f 8798/8976/8130 8861/9039/8193 8860/9038/8192 +f 8799/8977/8131 8862/9040/8194 8861/9039/8193 +f 8800/8978/8132 8863/9041/8195 8862/9040/8194 +f 8801/8979/8133 8864/9042/8196 8863/9041/8195 +f 8802/8980/8134 8865/9043/8197 8864/9042/8196 +f 8803/8981/8135 8866/9044/8198 8865/9043/8197 +f 8804/8982/8136 8867/9045/8199 8866/9044/8198 +f 8805/8983/8137 8868/9046/8014 8867/9045/8199 +f 8806/8984/8138 8869/9047/8200 8868/9046/8014 +f 8807/8985/8139 8870/9048/8201 8869/9047/8200 +f 8808/8986/8140 8871/9049/8202 8870/9048/8201 +f 8809/8987/8141 8872/9050/8203 8871/9049/8202 +f 8810/8988/8142 8873/9051/8204 8872/9050/8203 +f 8811/8989/8143 8874/9052/8205 8873/9051/8204 +f 8812/8990/8144 8875/9053/8206 8874/9052/8205 +f 8813/8991/8145 8876/9054/8207 8875/9053/8206 +f 8814/8992/8146 8877/9055/8208 8876/9054/8207 +f 8815/8993/8147 8878/9056/8209 8877/9055/8208 +f 8816/8994/8148 8879/9057/8210 8878/9056/8209 +f 8817/8995/8149 8880/9058/8211 8879/9057/8210 +f 8818/8996/8150 8881/9059/8212 8880/9058/8211 +f 8819/8997/8151 8882/9060/8213 8881/9059/8212 +f 8820/8998/8152 8883/9061/8214 8882/9060/8213 +f 8821/8999/8153 8884/9062/8215 8883/9061/8214 +f 8822/9000/8154 8885/9063/8216 8884/9062/8215 +f 8823/9001/8155 8886/9064/8217 8885/9063/8216 +f 8824/9002/8156 8887/9065/8218 8886/9064/8217 +f 8825/9003/8157 8888/9066/8219 8887/9065/8218 +f 8826/9004/8158 8889/9067/8220 8888/9066/8219 +f 8827/9005/8159 8890/9068/8221 8889/9067/8220 +f 8828/9006/8160 8891/9069/8222 8890/9068/8221 +f 8829/9007/8161 8892/9070/8223 8891/9069/8222 +f 8830/9008/8162 8893/9071/8224 8892/9070/8223 +f 8831/9009/8163 8894/9072/8225 8893/9071/8224 +f 8832/9010/8164 8895/9073/8226 8894/9072/8225 +f 8833/9012/8166 8896/9075/8228 8895/9073/8226 +f 8834/9074/8227 8897/9137/8289 8896/9075/8228 +f 8836/9014/8168 8899/9077/8230 8898/9076/8229 +f 8837/9015/8169 8900/9078/8231 8899/9077/8230 +f 8838/9016/8170 8901/9079/8232 8900/9078/8231 +f 8839/9017/8171 8902/9080/8233 8901/9079/8232 +f 8840/9018/8172 8903/9081/8234 8902/9080/8233 +f 8841/9019/8173 8904/9082/8235 8903/9081/8234 +f 8842/9020/8174 8905/9083/8236 8904/9082/8235 +f 8843/9021/8175 8906/9084/8237 8905/9083/8236 +f 8844/9022/8176 8907/9085/8238 8906/9084/8237 +f 8845/9023/8177 8908/9086/8239 8907/9085/8238 +f 8846/9024/8178 8909/9087/8240 8908/9086/8239 +f 8847/9025/8179 8910/9088/8241 8909/9087/8240 +f 8848/9026/8180 8911/9089/8242 8910/9088/8241 +f 8849/9027/8181 8912/9090/8243 8911/9089/8242 +f 8850/9028/8182 8913/9091/8244 8912/9090/8243 +f 8851/9029/8183 8914/9092/8245 8913/9091/8244 +f 8852/9030/8184 8915/9093/8246 8914/9092/8245 +f 8853/9031/8185 8916/9094/8247 8915/9093/8246 +f 8854/9032/8186 8917/9095/8248 8916/9094/8247 +f 8855/9033/8187 8918/9096/8249 8917/9095/8248 +f 8856/9034/8188 8919/9097/8250 8918/9096/8249 +f 8857/9035/8189 8920/9098/8251 8919/9097/8250 +f 8858/9036/8190 8921/9099/8252 8920/9098/8251 +f 8859/9037/8191 8922/9100/8253 8921/9099/8252 +f 8860/9038/8192 8923/9101/8254 8922/9100/8253 +f 8861/9039/8193 8924/9102/8255 8923/9101/8254 +f 8862/9040/8194 8925/9103/8256 8924/9102/8255 +f 8863/9041/8195 8926/9104/8069 8925/9103/8256 +f 8864/9042/8196 8927/9105/8257 8926/9104/8069 +f 8865/9043/8197 8928/9106/8258 8927/9105/8257 +f 8866/9044/8198 8929/9107/8259 8928/9106/8258 +f 8867/9045/8199 8930/9108/8260 8929/9107/8259 +f 8868/9046/8014 8931/9109/8261 8930/9108/8260 +f 8869/9047/8200 8932/9110/8262 8931/9109/8261 +f 8870/9048/8201 8933/9111/8263 8932/9110/8262 +f 8871/9049/8202 8934/9112/8264 8933/9111/8263 +f 8872/9050/8203 8935/9113/8265 8934/9112/8264 +f 8873/9051/8204 8936/9114/8266 8935/9113/8265 +f 8874/9052/8205 8937/9115/8267 8936/9114/8266 +f 8875/9053/8206 8938/9116/8268 8937/9115/8267 +f 8876/9054/8207 8939/9117/8269 8938/9116/8268 +f 8877/9055/8208 8940/9118/8270 8939/9117/8269 +f 8878/9056/8209 8941/9119/8271 8940/9118/8270 +f 8879/9057/8210 8942/9120/8272 8941/9119/8271 +f 8880/9058/8211 8943/9121/8273 8942/9120/8272 +f 8881/9059/8212 8944/9122/8274 8943/9121/8273 +f 8882/9060/8213 8945/9123/8275 8944/9122/8274 +f 8883/9061/8214 8946/9124/8276 8945/9123/8275 +f 8884/9062/8215 8947/9125/8277 8946/9124/8276 +f 8885/9063/8216 8948/9126/8278 8947/9125/8277 +f 8886/9064/8217 8949/9127/8279 8948/9126/8278 +f 8887/9065/8218 8950/9128/8280 8949/9127/8279 +f 8888/9066/8219 8951/9129/8281 8950/9128/8280 +f 8889/9067/8220 8952/9130/8282 8951/9129/8281 +f 8890/9068/8221 8953/9131/8283 8952/9130/8282 +f 8891/9069/8222 8954/9132/8284 8953/9131/8283 +f 8892/9070/8223 8955/9133/8285 8954/9132/8284 +f 8893/9071/8224 8956/9134/8286 8955/9133/8285 +f 8894/9072/8225 8957/9135/8287 8956/9134/8286 +f 8895/9073/8226 8958/9136/8288 8957/9135/8287 +f 8896/9075/8228 8959/9138/8290 8958/9136/8288 +f 8897/9137/8289 8960/9200/8351 8959/9138/8290 +f 8899/9077/8230 8962/9140/8292 8961/9139/8291 +f 8900/9078/8231 8963/9141/8293 8962/9140/8292 +f 8901/9079/8232 8964/9142/8294 8963/9141/8293 +f 8902/9080/8233 8965/9143/8295 8964/9142/8294 +f 8903/9081/8234 8966/9144/8296 8965/9143/8295 +f 8904/9082/8235 8967/9145/8297 8966/9144/8296 +f 8905/9083/8236 8968/9146/8298 8967/9145/8297 +f 8906/9084/8237 8969/9147/8299 8968/9146/8298 +f 8907/9085/8238 8970/9148/8300 8969/9147/8299 +f 8908/9086/8239 8971/9149/8301 8970/9148/8300 +f 8909/9087/8240 8972/9150/8302 8971/9149/8301 +f 8910/9088/8241 8973/9151/8303 8972/9150/8302 +f 8911/9089/8242 8974/9152/8304 8973/9151/8303 +f 8912/9090/8243 8975/9153/8305 8974/9152/8304 +f 8913/9091/8244 8976/9154/8306 8975/9153/8305 +f 8914/9092/8245 8977/9155/8307 8976/9154/8306 +f 8915/9093/8246 8978/9156/7628 8977/9155/8307 +f 8916/9094/8247 8979/9157/8308 8978/9156/7628 +f 8917/9095/8248 8980/9158/8309 8979/9157/8308 +f 8918/9096/8249 8981/9159/8310 8980/9158/8309 +f 8919/9097/8250 8982/9160/8311 8981/9159/8310 +f 8920/9098/8251 8983/9161/8312 8982/9160/8311 +f 8921/9099/8252 8984/9162/8313 8983/9161/8312 +f 8922/9100/8253 8985/9163/8314 8984/9162/8313 +f 8923/9101/8254 8986/9164/8315 8985/9163/8314 +f 8924/9102/8255 8987/9165/8316 8986/9164/8315 +f 8925/9103/8256 8988/9166/8317 8987/9165/8316 +f 8926/9104/8069 8989/9167/8318 8988/9166/8317 +f 8927/9105/8257 8990/9168/8319 8989/9167/8318 +f 8928/9106/8258 8991/9169/8320 8990/9168/8319 +f 8929/9107/8259 8992/9170/8321 8991/9169/8320 +f 8930/9108/8260 8993/9171/8322 8992/9170/8321 +f 8931/9109/8261 8994/9172/8323 8993/9171/8322 +f 8932/9110/8262 8995/9173/8324 8994/9172/8323 +f 8933/9111/8263 8996/9174/8325 8995/9173/8324 +f 8934/9112/8264 8997/9175/8326 8996/9174/8325 +f 8935/9113/8265 8998/9176/8327 8997/9175/8326 +f 8936/9114/8266 8999/9177/8328 8998/9176/8327 +f 8937/9115/8267 9000/9178/8329 8999/9177/8328 +f 8938/9116/8268 9001/9179/8330 9000/9178/8329 +f 8939/9117/8269 9002/9180/8331 9001/9179/8330 +f 8940/9118/8270 9003/9181/8332 9002/9180/8331 +f 8941/9119/8271 9004/9182/8333 9003/9181/8332 +f 8942/9120/8272 9005/9183/8334 9004/9182/8333 +f 8943/9121/8273 9006/9184/8335 9005/9183/8334 +f 8944/9122/8274 9007/9185/8336 9006/9184/8335 +f 8945/9123/8275 9008/9186/8337 9007/9185/8336 +f 8946/9124/8276 9009/9187/8338 9008/9186/8337 +f 8947/9125/8277 9010/9188/8339 9009/9187/8338 +f 8948/9126/8278 9011/9189/8340 9010/9188/8339 +f 8949/9127/8279 9012/9190/8341 9011/9189/8340 +f 8950/9128/8280 9013/9191/8342 9012/9190/8341 +f 8951/9129/8281 9014/9192/8343 9013/9191/8342 +f 8952/9130/8282 9015/9193/8344 9014/9192/8343 +f 8953/9131/8283 9016/9194/8345 9015/9193/8344 +f 8954/9132/8284 9017/9195/8346 9016/9194/8345 +f 8955/9133/8285 9018/9196/8347 9017/9195/8346 +f 8956/9134/8286 9019/9197/8348 9018/9196/8347 +f 8957/9135/8287 9020/9198/8349 9019/9197/8348 +f 8958/9136/8288 9021/9199/8350 9020/9198/8349 +f 8959/9138/8290 9022/9201/8352 9021/9199/8350 +f 8960/9200/8351 9023/9263/8414 9022/9201/8352 +f 8962/9140/8292 9025/9203/8354 9024/9202/8353 +f 8963/9141/8293 9026/9204/8355 9025/9203/8354 +f 8964/9142/8294 9027/9205/8356 9026/9204/8355 +f 8965/9143/8295 9028/9206/8357 9027/9205/8356 +f 8966/9144/8296 9029/9207/8358 9028/9206/8357 +f 8967/9145/8297 9030/9208/8359 9029/9207/8358 +f 8968/9146/8298 9031/9209/8360 9030/9208/8359 +f 8969/9147/8299 9032/9210/8361 9031/9209/8360 +f 8970/9148/8300 9033/9211/8362 9032/9210/8361 +f 8971/9149/8301 9034/9212/8363 9033/9211/8362 +f 8972/9150/8302 9035/9213/8364 9034/9212/8363 +f 8973/9151/8303 9036/9214/8365 9035/9213/8364 +f 8974/9152/8304 9037/9215/8366 9036/9214/8365 +f 8975/9153/8305 9038/9216/8367 9037/9215/8366 +f 8976/9154/8306 9039/9217/8368 9038/9216/8367 +f 8977/9155/8307 9040/9218/8369 9039/9217/8368 +f 8978/9156/7628 9041/9219/8370 9040/9218/8369 +f 8979/9157/8308 9042/9220/8371 9041/9219/8370 +f 8980/9158/8309 9043/9221/8372 9042/9220/8371 +f 8981/9159/8310 9044/9222/8373 9043/9221/8372 +f 8982/9160/8311 9045/9223/8374 9044/9222/8373 +f 8983/9161/8312 9046/9224/8375 9045/9223/8374 +f 8984/9162/8313 9047/9225/8376 9046/9224/8375 +f 8985/9163/8314 9048/9226/8377 9047/9225/8376 +f 8986/9164/8315 9049/9227/8378 9048/9226/8377 +f 8987/9165/8316 9050/9228/8379 9049/9227/8378 +f 8988/9166/8317 9051/9229/8380 9050/9228/8379 +f 8989/9167/8318 9052/9230/8381 9051/9229/8380 +f 8990/9168/8319 9053/9231/8382 9052/9230/8381 +f 8991/9169/8320 9054/9232/8383 9053/9231/8382 +f 8992/9170/8321 9055/9233/8384 9054/9232/8383 +f 8993/9171/8322 9056/9234/8385 9055/9233/8384 +f 8994/9172/8323 9057/9235/8386 9056/9234/8385 +f 8995/9173/8324 9058/9236/8387 9057/9235/8386 +f 8996/9174/8325 9059/9237/8388 9058/9236/8387 +f 8997/9175/8326 9060/9238/8389 9059/9237/8388 +f 8998/9176/8327 9061/9239/8390 9060/9238/8389 +f 8999/9177/8328 9062/9240/8391 9061/9239/8390 +f 9000/9178/8329 9063/9241/8392 9062/9240/8391 +f 9001/9179/8330 9064/9242/8393 9063/9241/8392 +f 9002/9180/8331 9065/9243/8394 9064/9242/8393 +f 9003/9181/8332 9066/9244/8395 9065/9243/8394 +f 9004/9182/8333 9067/9245/8396 9066/9244/8395 +f 9005/9183/8334 9068/9246/8397 9067/9245/8396 +f 9006/9184/8335 9069/9247/8398 9068/9246/8397 +f 9007/9185/8336 9070/9248/8399 9069/9247/8398 +f 9008/9186/8337 9071/9249/8400 9070/9248/8399 +f 9009/9187/8338 9072/9250/8401 9071/9249/8400 +f 9010/9188/8339 9073/9251/8402 9072/9250/8401 +f 9011/9189/8340 9074/9252/8403 9073/9251/8402 +f 9012/9190/8341 9075/9253/8404 9074/9252/8403 +f 9013/9191/8342 9076/9254/8405 9075/9253/8404 +f 9014/9192/8343 9077/9255/8406 9076/9254/8405 +f 9015/9193/8344 9078/9256/8407 9077/9255/8406 +f 9016/9194/8345 9079/9257/8408 9078/9256/8407 +f 9017/9195/8346 9080/9258/8409 9079/9257/8408 +f 9018/9196/8347 9081/9259/8410 9080/9258/8409 +f 9019/9197/8348 9082/9260/8411 9081/9259/8410 +f 9020/9198/8349 9083/9261/8412 9082/9260/8411 +f 9021/9199/8350 9084/9262/8413 9083/9261/8412 +f 9022/9201/8352 9085/9264/8415 9084/9262/8413 +f 9023/9263/8414 9086/9326/8477 9085/9264/8415 +f 9025/9203/8354 9088/9266/8417 9087/9265/8416 +f 9026/9204/8355 9089/9267/8418 9088/9266/8417 +f 9027/9205/8356 9090/9268/8419 9089/9267/8418 +f 9028/9206/8357 9091/9269/8420 9090/9268/8419 +f 9029/9207/8358 9092/9270/8421 9091/9269/8420 +f 9030/9208/8359 9093/9271/8422 9092/9270/8421 +f 9031/9209/8360 9094/9272/8423 9093/9271/8422 +f 9032/9210/8361 9095/9273/8424 9094/9272/8423 +f 9033/9211/8362 9096/9274/8425 9095/9273/8424 +f 9034/9212/8363 9097/9275/8426 9096/9274/8425 +f 9035/9213/8364 9098/9276/8427 9097/9275/8426 +f 9036/9214/8365 9099/9277/8428 9098/9276/8427 +f 9037/9215/8366 9100/9278/8429 9099/9277/8428 +f 9038/9216/8367 9101/9279/8430 9100/9278/8429 +f 9039/9217/8368 9102/9280/8431 9101/9279/8430 +f 9040/9218/8369 9103/9281/8432 9102/9280/8431 +f 9041/9219/8370 9104/9282/8433 9103/9281/8432 +f 9042/9220/8371 9105/9283/8434 9104/9282/8433 +f 9043/9221/8372 9106/9284/8435 9105/9283/8434 +f 9044/9222/8373 9107/9285/8436 9106/9284/8435 +f 9045/9223/8374 9108/9286/8437 9107/9285/8436 +f 9046/9224/8375 9109/9287/8438 9108/9286/8437 +f 9047/9225/8376 9110/9288/8439 9109/9287/8438 +f 9048/9226/8377 9111/9289/8440 9110/9288/8439 +f 9049/9227/8378 9112/9290/8441 9111/9289/8440 +f 9050/9228/8379 9113/9291/8442 9112/9290/8441 +f 9051/9229/8380 9114/9292/8443 9113/9291/8442 +f 9052/9230/8381 9115/9293/8444 9114/9292/8443 +f 9053/9231/8382 9116/9294/8445 9115/9293/8444 +f 9054/9232/8383 9117/9295/8446 9116/9294/8445 +f 9055/9233/8384 9118/9296/8447 9117/9295/8446 +f 9056/9234/8385 9119/9297/8448 9118/9296/8447 +f 9057/9235/8386 9120/9298/8449 9119/9297/8448 +f 9058/9236/8387 9121/9299/8450 9120/9298/8449 +f 9059/9237/8388 9122/9300/8451 9121/9299/8450 +f 9060/9238/8389 9123/9301/8452 9122/9300/8451 +f 9061/9239/8390 9124/9302/8453 9123/9301/8452 +f 9062/9240/8391 9125/9303/8454 9124/9302/8453 +f 9063/9241/8392 9126/9304/8455 9125/9303/8454 +f 9064/9242/8393 9127/9305/8456 9126/9304/8455 +f 9065/9243/8394 9128/9306/8457 9127/9305/8456 +f 9066/9244/8395 9129/9307/8458 9128/9306/8457 +f 9067/9245/8396 9130/9308/8459 9129/9307/8458 +f 9068/9246/8397 9131/9309/8460 9130/9308/8459 +f 9069/9247/8398 9132/9310/8461 9131/9309/8460 +f 9070/9248/8399 9133/9311/8462 9132/9310/8461 +f 9071/9249/8400 9134/9312/8463 9133/9311/8462 +f 9072/9250/8401 9135/9313/8464 9134/9312/8463 +f 9073/9251/8402 9136/9314/8465 9135/9313/8464 +f 9074/9252/8403 9137/9315/8466 9136/9314/8465 +f 9075/9253/8404 9138/9316/8467 9137/9315/8466 +f 9076/9254/8405 9139/9317/8468 9138/9316/8467 +f 9077/9255/8406 9140/9318/8469 9139/9317/8468 +f 9078/9256/8407 9141/9319/8470 9140/9318/8469 +f 9079/9257/8408 9142/9320/8471 9141/9319/8470 +f 9080/9258/8409 9143/9321/8472 9142/9320/8471 +f 9081/9259/8410 9144/9322/8473 9143/9321/8472 +f 9082/9260/8411 9145/9323/8474 9144/9322/8473 +f 9083/9261/8412 9146/9324/8475 9145/9323/8474 +f 9084/9262/8413 9147/9325/8476 9146/9324/8475 +f 9085/9264/8415 9148/9327/8478 9147/9325/8476 +f 9086/9326/8477 9149/9389/8539 9148/9327/8478 +f 9088/9266/8417 9151/9329/8480 9150/9328/8479 +f 9089/9267/8418 9152/9330/8481 9151/9329/8480 +f 9090/9268/8419 9153/9331/8482 9152/9330/8481 +f 9091/9269/8420 9154/9332/8483 9153/9331/8482 +f 9092/9270/8421 9155/9333/8484 9154/9332/8483 +f 9093/9271/8422 9156/9334/8485 9155/9333/8484 +f 9094/9272/8423 9157/9335/8486 9156/9334/8485 +f 9095/9273/8424 9158/9336/8487 9157/9335/8486 +f 9096/9274/8425 9159/9337/8488 9158/9336/8487 +f 9097/9275/8426 9160/9338/8489 9159/9337/8488 +f 9098/9276/8427 9161/9339/8490 9160/9338/8489 +f 9099/9277/8428 9162/9340/8491 9161/9339/8490 +f 9100/9278/8429 9163/9341/8492 9162/9340/8491 +f 9101/9279/8430 9164/9342/8493 9163/9341/8492 +f 9102/9280/8431 9165/9343/8494 9164/9342/8493 +f 9103/9281/8432 9166/9344/8495 9165/9343/8494 +f 9104/9282/8433 9167/9345/8496 9166/9344/8495 +f 9105/9283/8434 9168/9346/8497 9167/9345/8496 +f 9106/9284/8435 9169/9347/8498 9168/9346/8497 +f 9107/9285/8436 9170/9348/8499 9169/9347/8498 +f 9108/9286/8437 9171/9349/8500 9170/9348/8499 +f 9109/9287/8438 9172/9350/8501 9171/9349/8500 +f 9110/9288/8439 9173/9351/8502 9172/9350/8501 +f 9111/9289/8440 9174/9352/8503 9173/9351/8502 +f 9112/9290/8441 9175/9353/8504 9174/9352/8503 +f 9113/9291/8442 9176/9354/8505 9175/9353/8504 +f 9114/9292/8443 9177/9355/8506 9176/9354/8505 +f 9115/9293/8444 9178/9356/7318 9177/9355/8506 +f 9116/9294/8445 9179/9357/8507 9178/9356/7318 +f 9117/9295/8446 9180/9358/8508 9179/9357/8507 +f 9118/9296/8447 9181/9359/8509 9180/9358/8508 +f 9119/9297/8448 9182/9360/8510 9181/9359/8509 +f 9120/9298/8449 9183/9361/8511 9182/9360/8510 +f 9121/9299/8450 9184/9362/8512 9183/9361/8511 +f 9122/9300/8451 9185/9363/8513 9184/9362/8512 +f 9123/9301/8452 9186/9364/8514 9185/9363/8513 +f 9124/9302/8453 9187/9365/8515 9186/9364/8514 +f 9125/9303/8454 9188/9366/8516 9187/9365/8515 +f 9126/9304/8455 9189/9367/8517 9188/9366/8516 +f 9127/9305/8456 9190/9368/8518 9189/9367/8517 +f 9128/9306/8457 9191/9369/8519 9190/9368/8518 +f 9129/9307/8458 9192/9370/8520 9191/9369/8519 +f 9130/9308/8459 9193/9371/8521 9192/9370/8520 +f 9131/9309/8460 9194/9372/8522 9193/9371/8521 +f 9132/9310/8461 9195/9373/8523 9194/9372/8522 +f 9133/9311/8462 9196/9374/8524 9195/9373/8523 +f 9134/9312/8463 9197/9375/8525 9196/9374/8524 +f 9135/9313/8464 9198/9376/8526 9197/9375/8525 +f 9136/9314/8465 9199/9377/8527 9198/9376/8526 +f 9137/9315/8466 9200/9378/8528 9199/9377/8527 +f 9138/9316/8467 9201/9379/8529 9200/9378/8528 +f 9139/9317/8468 9202/9380/8530 9201/9379/8529 +f 9140/9318/8469 9203/9381/8531 9202/9380/8530 +f 9141/9319/8470 9204/9382/8532 9203/9381/8531 +f 9142/9320/8471 9205/9383/8533 9204/9382/8532 +f 9143/9321/8472 9206/9384/8534 9205/9383/8533 +f 9144/9322/8473 9207/9385/8535 9206/9384/8534 +f 9145/9323/8474 9208/9386/8536 9207/9385/8535 +f 9146/9324/8475 9209/9387/8537 9208/9386/8536 +f 9147/9325/8476 9210/9388/8538 9209/9387/8537 +f 9148/9327/8478 9211/9390/8540 9210/9388/8538 +f 9149/9389/8539 9212/9452/8602 9211/9390/8540 +f 9151/9329/8480 9214/9392/8542 9213/9391/8541 +f 9152/9330/8481 9215/9393/8543 9214/9392/8542 +f 9153/9331/8482 9216/9394/8544 9215/9393/8543 +f 9154/9332/8483 9217/9395/8545 9216/9394/8544 +f 9155/9333/8484 9218/9396/8546 9217/9395/8545 +f 9156/9334/8485 9219/9397/8547 9218/9396/8546 +f 9157/9335/8486 9220/9398/8548 9219/9397/8547 +f 9158/9336/8487 9221/9399/8549 9220/9398/8548 +f 9159/9337/8488 9222/9400/8550 9221/9399/8549 +f 9160/9338/8489 9223/9401/8551 9222/9400/8550 +f 9161/9339/8490 9224/9402/8552 9223/9401/8551 +f 9162/9340/8491 9225/9403/8553 9224/9402/8552 +f 9163/9341/8492 9226/9404/8554 9225/9403/8553 +f 9164/9342/8493 9227/9405/8555 9226/9404/8554 +f 9165/9343/8494 9228/9406/8556 9227/9405/8555 +f 9166/9344/8495 9229/9407/8557 9228/9406/8556 +f 9167/9345/8496 9230/9408/8558 9229/9407/8557 +f 9168/9346/8497 9231/9409/8559 9230/9408/8558 +f 9169/9347/8498 9232/9410/8560 9231/9409/8559 +f 9170/9348/8499 9233/9411/8561 9232/9410/8560 +f 9171/9349/8500 9234/9412/8562 9233/9411/8561 +f 9172/9350/8501 9235/9413/8563 9234/9412/8562 +f 9173/9351/8502 9236/9414/8564 9235/9413/8563 +f 9174/9352/8503 9237/9415/8565 9236/9414/8564 +f 9175/9353/8504 9238/9416/8566 9237/9415/8565 +f 9176/9354/8505 9239/9417/8567 9238/9416/8566 +f 9177/9355/8506 9240/9418/8568 9239/9417/8567 +f 9178/9356/7318 9241/9419/8569 9240/9418/8568 +f 9179/9357/8507 9242/9420/8570 9241/9419/8569 +f 9180/9358/8508 9243/9421/8571 9242/9420/8570 +f 9181/9359/8509 9244/9422/8572 9243/9421/8571 +f 9182/9360/8510 9245/9423/8573 9244/9422/8572 +f 9183/9361/8511 9246/9424/8574 9245/9423/8573 +f 9184/9362/8512 9247/9425/8575 9246/9424/8574 +f 9185/9363/8513 9248/9426/8576 9247/9425/8575 +f 9186/9364/8514 9249/9427/8577 9248/9426/8576 +f 9187/9365/8515 9250/9428/8578 9249/9427/8577 +f 9188/9366/8516 9251/9429/8579 9250/9428/8578 +f 9189/9367/8517 9252/9430/8580 9251/9429/8579 +f 9190/9368/8518 9253/9431/8581 9252/9430/8580 +f 9191/9369/8519 9254/9432/8582 9253/9431/8581 +f 9192/9370/8520 9255/9433/8583 9254/9432/8582 +f 9193/9371/8521 9256/9434/8584 9255/9433/8583 +f 9194/9372/8522 9257/9435/8585 9256/9434/8584 +f 9195/9373/8523 9258/9436/8586 9257/9435/8585 +f 9196/9374/8524 9259/9437/8587 9258/9436/8586 +f 9197/9375/8525 9260/9438/8588 9259/9437/8587 +f 9198/9376/8526 9261/9439/8589 9260/9438/8588 +f 9199/9377/8527 9262/9440/8590 9261/9439/8589 +f 9200/9378/8528 9263/9441/8591 9262/9440/8590 +f 9201/9379/8529 9264/9442/8592 9263/9441/8591 +f 9202/9380/8530 9265/9443/8593 9264/9442/8592 +f 9203/9381/8531 9266/9444/8594 9265/9443/8593 +f 9204/9382/8532 9267/9445/8595 9266/9444/8594 +f 9205/9383/8533 9268/9446/8596 9267/9445/8595 +f 9206/9384/8534 9269/9447/8597 9268/9446/8596 +f 9207/9385/8535 9270/9448/8598 9269/9447/8597 +f 9208/9386/8536 9271/9449/8599 9270/9448/8598 +f 9209/9387/8537 9272/9450/8600 9271/9449/8599 +f 9210/9388/8538 9273/9451/8601 9272/9450/8600 +f 9211/9390/8540 9274/9453/8603 9273/9451/8601 +f 9212/9452/8602 9275/9515/8665 9274/9453/8603 +f 9214/9392/8542 9277/9455/8605 9276/9454/8604 +f 9215/9393/8543 9278/9456/8606 9277/9455/8605 +f 9216/9394/8544 9279/9457/8607 9278/9456/8606 +f 9217/9395/8545 9280/9458/8608 9279/9457/8607 +f 9218/9396/8546 9281/9459/8609 9280/9458/8608 +f 9219/9397/8547 9282/9460/8610 9281/9459/8609 +f 9220/9398/8548 9283/9461/8611 9282/9460/8610 +f 9221/9399/8549 9284/9462/8612 9283/9461/8611 +f 9222/9400/8550 9285/9463/8613 9284/9462/8612 +f 9223/9401/8551 9286/9464/8614 9285/9463/8613 +f 9224/9402/8552 9287/9465/8615 9286/9464/8614 +f 9225/9403/8553 9288/9466/8616 9287/9465/8615 +f 9226/9404/8554 9289/9467/8617 9288/9466/8616 +f 9227/9405/8555 9290/9468/8618 9289/9467/8617 +f 9228/9406/8556 9291/9469/8619 9290/9468/8618 +f 9229/9407/8557 9292/9470/8620 9291/9469/8619 +f 9230/9408/8558 9293/9471/8621 9292/9470/8620 +f 9231/9409/8559 9294/9472/8622 9293/9471/8621 +f 9232/9410/8560 9295/9473/8623 9294/9472/8622 +f 9233/9411/8561 9296/9474/8624 9295/9473/8623 +f 9234/9412/8562 9297/9475/8625 9296/9474/8624 +f 9235/9413/8563 9298/9476/8626 9297/9475/8625 +f 9236/9414/8564 9299/9477/8627 9298/9476/8626 +f 9237/9415/8565 9300/9478/8628 9299/9477/8627 +f 9238/9416/8566 9301/9479/8629 9300/9478/8628 +f 9239/9417/8567 9302/9480/8630 9301/9479/8629 +f 9240/9418/8568 9303/9481/8631 9302/9480/8630 +f 9241/9419/8569 9304/9482/8632 9303/9481/8631 +f 9242/9420/8570 9305/9483/8633 9304/9482/8632 +f 9243/9421/8571 9306/9484/8634 9305/9483/8633 +f 9244/9422/8572 9307/9485/8635 9306/9484/8634 +f 9245/9423/8573 9308/9486/8636 9307/9485/8635 +f 9246/9424/8574 9309/9487/8637 9308/9486/8636 +f 9247/9425/8575 9310/9488/8638 9309/9487/8637 +f 9248/9426/8576 9311/9489/8639 9310/9488/8638 +f 9249/9427/8577 9312/9490/8640 9311/9489/8639 +f 9250/9428/8578 9313/9491/8641 9312/9490/8640 +f 9251/9429/8579 9314/9492/8642 9313/9491/8641 +f 9252/9430/8580 9315/9493/8643 9314/9492/8642 +f 9253/9431/8581 9316/9494/8644 9315/9493/8643 +f 9254/9432/8582 9317/9495/8645 9316/9494/8644 +f 9255/9433/8583 9318/9496/8646 9317/9495/8645 +f 9256/9434/8584 9319/9497/8647 9318/9496/8646 +f 9257/9435/8585 9320/9498/8648 9319/9497/8647 +f 9258/9436/8586 9321/9499/8649 9320/9498/8648 +f 9259/9437/8587 9322/9500/8650 9321/9499/8649 +f 9260/9438/8588 9323/9501/8651 9322/9500/8650 +f 9261/9439/8589 9324/9502/8652 9323/9501/8651 +f 9262/9440/8590 9325/9503/8653 9324/9502/8652 +f 9263/9441/8591 9326/9504/8654 9325/9503/8653 +f 9264/9442/8592 9327/9505/8655 9326/9504/8654 +f 9265/9443/8593 9328/9506/8656 9327/9505/8655 +f 9266/9444/8594 9329/9507/8657 9328/9506/8656 +f 9267/9445/8595 9330/9508/8658 9329/9507/8657 +f 9268/9446/8596 9331/9509/8659 9330/9508/8658 +f 9269/9447/8597 9332/9510/8660 9331/9509/8659 +f 9270/9448/8598 9333/9511/8661 9332/9510/8660 +f 9271/9449/8599 9334/9512/8662 9333/9511/8661 +f 9272/9450/8600 9335/9513/8663 9334/9512/8662 +f 9273/9451/8601 9336/9514/8664 9335/9513/8663 +f 9274/9453/8603 9337/9516/8666 9336/9514/8664 +f 9275/9515/8665 9338/9578/8728 9337/9516/8666 +f 9277/9455/8605 9340/9518/8668 9339/9517/8667 +f 9278/9456/8606 9341/9519/8669 9340/9518/8668 +f 9279/9457/8607 9342/9520/8670 9341/9519/8669 +f 9280/9458/8608 9343/9521/8671 9342/9520/8670 +f 9281/9459/8609 9344/9522/8672 9343/9521/8671 +f 9282/9460/8610 9345/9523/8673 9344/9522/8672 +f 9283/9461/8611 9346/9524/8674 9345/9523/8673 +f 9284/9462/8612 9347/9525/8675 9346/9524/8674 +f 9285/9463/8613 9348/9526/8676 9347/9525/8675 +f 9286/9464/8614 9349/9527/8677 9348/9526/8676 +f 9287/9465/8615 9350/9528/8678 9349/9527/8677 +f 9288/9466/8616 9351/9529/8679 9350/9528/8678 +f 9289/9467/8617 9352/9530/8680 9351/9529/8679 +f 9290/9468/8618 9353/9531/8681 9352/9530/8680 +f 9291/9469/8619 9354/9532/8682 9353/9531/8681 +f 9292/9470/8620 9355/9533/8683 9354/9532/8682 +f 9293/9471/8621 9356/9534/8684 9355/9533/8683 +f 9294/9472/8622 9357/9535/8685 9356/9534/8684 +f 9295/9473/8623 9358/9536/8686 9357/9535/8685 +f 9296/9474/8624 9359/9537/8687 9358/9536/8686 +f 9297/9475/8625 9360/9538/8688 9359/9537/8687 +f 9298/9476/8626 9361/9539/8689 9360/9538/8688 +f 9299/9477/8627 9362/9540/8690 9361/9539/8689 +f 9300/9478/8628 9363/9541/8691 9362/9540/8690 +f 9301/9479/8629 9364/9542/8692 9363/9541/8691 +f 9302/9480/8630 9365/9543/8693 9364/9542/8692 +f 9303/9481/8631 9366/9544/8694 9365/9543/8693 +f 9304/9482/8632 9367/9545/8695 9366/9544/8694 +f 9305/9483/8633 9368/9546/8696 9367/9545/8695 +f 9306/9484/8634 9369/9547/8697 9368/9546/8696 +f 9307/9485/8635 9370/9548/8698 9369/9547/8697 +f 9308/9486/8636 9371/9549/8699 9370/9548/8698 +f 9309/9487/8637 9372/9550/8700 9371/9549/8699 +f 9310/9488/8638 9373/9551/8701 9372/9550/8700 +f 9311/9489/8639 9374/9552/8702 9373/9551/8701 +f 9312/9490/8640 9375/9553/8703 9374/9552/8702 +f 9313/9491/8641 9376/9554/8704 9375/9553/8703 +f 9314/9492/8642 9377/9555/8705 9376/9554/8704 +f 9315/9493/8643 9378/9556/8706 9377/9555/8705 +f 9316/9494/8644 9379/9557/8707 9378/9556/8706 +f 9317/9495/8645 9380/9558/8708 9379/9557/8707 +f 9318/9496/8646 9381/9559/8709 9380/9558/8708 +f 9319/9497/8647 9382/9560/8710 9381/9559/8709 +f 9320/9498/8648 9383/9561/8711 9382/9560/8710 +f 9321/9499/8649 9384/9562/8712 9383/9561/8711 +f 9322/9500/8650 9385/9563/8713 9384/9562/8712 +f 9323/9501/8651 9386/9564/8714 9385/9563/8713 +f 9324/9502/8652 9387/9565/8715 9386/9564/8714 +f 9325/9503/8653 9388/9566/8716 9387/9565/8715 +f 9326/9504/8654 9389/9567/8717 9388/9566/8716 +f 9327/9505/8655 9390/9568/8718 9389/9567/8717 +f 9328/9506/8656 9391/9569/8719 9390/9568/8718 +f 9329/9507/8657 9392/9570/8720 9391/9569/8719 +f 9330/9508/8658 9393/9571/8721 9392/9570/8720 +f 9331/9509/8659 9394/9572/8722 9393/9571/8721 +f 9332/9510/8660 9395/9573/8723 9394/9572/8722 +f 9333/9511/8661 9396/9574/8724 9395/9573/8723 +f 9334/9512/8662 9397/9575/8725 9396/9574/8724 +f 9335/9513/8663 9398/9576/8726 9397/9575/8725 +f 9336/9514/8664 9399/9577/8727 9398/9576/8726 +f 9337/9516/8666 9400/9579/8729 9399/9577/8727 +f 9338/9578/8728 9401/9641/8790 9400/9579/8729 +f 9340/9518/8668 9403/9581/8731 9402/9580/8730 +f 9341/9519/8669 9404/9582/8732 9403/9581/8731 +f 9342/9520/8670 9405/9583/8733 9404/9582/8732 +f 9343/9521/8671 9406/9584/8734 9405/9583/8733 +f 9344/9522/8672 9407/9585/8735 9406/9584/8734 +f 9345/9523/8673 9408/9586/8736 9407/9585/8735 +f 9346/9524/8674 9409/9587/8737 9408/9586/8736 +f 9347/9525/8675 9410/9588/8738 9409/9587/8737 +f 9348/9526/8676 9411/9589/8739 9410/9588/8738 +f 9349/9527/8677 9412/9590/8740 9411/9589/8739 +f 9350/9528/8678 9413/9591/8741 9412/9590/8740 +f 9351/9529/8679 9414/9592/8742 9413/9591/8741 +f 9352/9530/8680 9415/9593/8743 9414/9592/8742 +f 9353/9531/8681 9416/9594/8744 9415/9593/8743 +f 9354/9532/8682 9417/9595/8745 9416/9594/8744 +f 9355/9533/8683 9418/9596/8746 9417/9595/8745 +f 9356/9534/8684 9419/9597/8747 9418/9596/8746 +f 9357/9535/8685 9420/9598/8748 9419/9597/8747 +f 9358/9536/8686 9421/9599/8749 9420/9598/8748 +f 9359/9537/8687 9422/9600/8750 9421/9599/8749 +f 9360/9538/8688 9423/9601/8751 9422/9600/8750 +f 9361/9539/8689 9424/9602/8752 9423/9601/8751 +f 9362/9540/8690 9425/9603/8753 9424/9602/8752 +f 9363/9541/8691 9426/9604/8754 9425/9603/8753 +f 9364/9542/8692 9427/9605/8755 9426/9604/8754 +f 9365/9543/8693 9428/9606/8756 9427/9605/8755 +f 9366/9544/8694 9429/9607/8757 9428/9606/8756 +f 9367/9545/8695 9430/9608/8758 9429/9607/8757 +f 9368/9546/8696 9431/9609/8759 9430/9608/8758 +f 9369/9547/8697 9432/9610/8760 9431/9609/8759 +f 9370/9548/8698 9433/9611/8761 9432/9610/8760 +f 9371/9549/8699 9434/9612/8762 9433/9611/8761 +f 9372/9550/8700 9435/9613/8763 9434/9612/8762 +f 9373/9551/8701 9436/9614/8764 9435/9613/8763 +f 9374/9552/8702 9437/9615/8765 9436/9614/8764 +f 9375/9553/8703 9438/9616/8766 9437/9615/8765 +f 9376/9554/8704 9439/9617/8767 9438/9616/8766 +f 9377/9555/8705 9440/9618/8768 9439/9617/8767 +f 9378/9556/8706 9441/9619/8769 9440/9618/8768 +f 9379/9557/8707 9442/9620/8770 9441/9619/8769 +f 9380/9558/8708 9443/9621/8771 9442/9620/8770 +f 9381/9559/8709 9444/9622/8772 9443/9621/8771 +f 9382/9560/8710 9445/9623/8773 9444/9622/8772 +f 9383/9561/8711 9446/9624/8774 9445/9623/8773 +f 9384/9562/8712 9447/9625/8775 9446/9624/8774 +f 9385/9563/8713 9448/9626/8776 9447/9625/8775 +f 9386/9564/8714 9449/9627/7628 9448/9626/8776 +f 9387/9565/8715 9450/9628/8777 9449/9627/7628 +f 9388/9566/8716 9451/9629/8778 9450/9628/8777 +f 9389/9567/8717 9452/9630/8779 9451/9629/8778 +f 9390/9568/8718 9453/9631/8780 9452/9630/8779 +f 9391/9569/8719 9454/9632/8781 9453/9631/8780 +f 9392/9570/8720 9455/9633/8782 9454/9632/8781 +f 9393/9571/8721 9456/9634/8783 9455/9633/8782 +f 9394/9572/8722 9457/9635/8784 9456/9634/8783 +f 9395/9573/8723 9458/9636/8785 9457/9635/8784 +f 9396/9574/8724 9459/9637/8786 9458/9636/8785 +f 9397/9575/8725 9460/9638/8787 9459/9637/8786 +f 9398/9576/8726 9461/9639/8788 9460/9638/8787 +f 9399/9577/8727 9462/9640/8789 9461/9639/8788 +f 9400/9579/8729 9463/9642/8791 9462/9640/8789 +f 9401/9641/8790 9464/9704/8852 9463/9642/8791 +f 9403/9581/8731 9466/9644/8793 9465/9643/8792 +f 9404/9582/8732 9467/9645/8794 9466/9644/8793 +f 9405/9583/8733 9468/9646/8795 9467/9645/8794 +f 9406/9584/8734 9469/9647/8796 9468/9646/8795 +f 9407/9585/8735 9470/9648/8797 9469/9647/8796 +f 9408/9586/8736 9471/9649/8798 9470/9648/8797 +f 9409/9587/8737 9472/9650/8799 9471/9649/8798 +f 9410/9588/8738 9473/9651/8800 9472/9650/8799 +f 9411/9589/8739 9474/9652/8801 9473/9651/8800 +f 9412/9590/8740 9475/9653/8802 9474/9652/8801 +f 9413/9591/8741 9476/9654/8803 9475/9653/8802 +f 9414/9592/8742 9477/9655/8804 9476/9654/8803 +f 9415/9593/8743 9478/9656/8805 9477/9655/8804 +f 9416/9594/8744 9479/9657/8806 9478/9656/8805 +f 9417/9595/8745 9480/9658/8807 9479/9657/8806 +f 9418/9596/8746 9481/9659/8808 9480/9658/8807 +f 9419/9597/8747 9482/9660/8809 9481/9659/8808 +f 9420/9598/8748 9483/9661/8810 9482/9660/8809 +f 9421/9599/8749 9484/9662/8811 9483/9661/8810 +f 9422/9600/8750 9485/9663/8812 9484/9662/8811 +f 9423/9601/8751 9486/9664/8813 9485/9663/8812 +f 9424/9602/8752 9487/9665/8814 9486/9664/8813 +f 9425/9603/8753 9488/9666/7910 9487/9665/8814 +f 9426/9604/8754 9489/9667/8815 9488/9666/7910 +f 9427/9605/8755 9490/9668/8816 9489/9667/8815 +f 9428/9606/8756 9491/9669/8817 9490/9668/8816 +f 9429/9607/8757 9492/9670/8818 9491/9669/8817 +f 9430/9608/8758 9493/9671/8819 9492/9670/8818 +f 9431/9609/8759 9494/9672/8820 9493/9671/8819 +f 9432/9610/8760 9495/9673/8821 9494/9672/8820 +f 9433/9611/8761 9496/9674/8822 9495/9673/8821 +f 9434/9612/8762 9497/9675/8823 9496/9674/8822 +f 9435/9613/8763 9498/9676/8824 9497/9675/8823 +f 9436/9614/8764 9499/9677/8825 9498/9676/8824 +f 9437/9615/8765 9500/9678/8826 9499/9677/8825 +f 9438/9616/8766 9501/9679/8827 9500/9678/8826 +f 9439/9617/8767 9502/9680/8828 9501/9679/8827 +f 9440/9618/8768 9503/9681/8829 9502/9680/8828 +f 9441/9619/8769 9504/9682/8830 9503/9681/8829 +f 9442/9620/8770 9505/9683/8831 9504/9682/8830 +f 9443/9621/8771 9506/9684/8832 9505/9683/8831 +f 9444/9622/8772 9507/9685/8833 9506/9684/8832 +f 9445/9623/8773 9508/9686/8834 9507/9685/8833 +f 9446/9624/8774 9509/9687/8835 9508/9686/8834 +f 9447/9625/8775 9510/9688/8836 9509/9687/8835 +f 9448/9626/8776 9511/9689/8837 9510/9688/8836 +f 9449/9627/7628 9512/9690/8838 9511/9689/8837 +f 9450/9628/8777 9513/9691/8839 9512/9690/8838 +f 9451/9629/8778 9514/9692/8840 9513/9691/8839 +f 9452/9630/8779 9515/9693/8841 9514/9692/8840 +f 9453/9631/8780 9516/9694/8842 9515/9693/8841 +f 9454/9632/8781 9517/9695/8843 9516/9694/8842 +f 9455/9633/8782 9518/9696/8844 9517/9695/8843 +f 9456/9634/8783 9519/9697/8845 9518/9696/8844 +f 9457/9635/8784 9520/9698/8846 9519/9697/8845 +f 9458/9636/8785 9521/9699/8847 9520/9698/8846 +f 9459/9637/8786 9522/9700/8848 9521/9699/8847 +f 9460/9638/8787 9523/9701/8849 9522/9700/8848 +f 9461/9639/8788 9524/9702/8850 9523/9701/8849 +f 9462/9640/8789 9525/9703/8851 9524/9702/8850 +f 9463/9642/8791 9526/9705/8853 9525/9703/8851 +f 9464/9704/8852 9527/9767/8915 9526/9705/8853 +f 9466/9644/8793 9529/9707/8855 9528/9706/8854 +f 9467/9645/8794 9530/9708/8856 9529/9707/8855 +f 9468/9646/8795 9531/9709/8857 9530/9708/8856 +f 9469/9647/8796 9532/9710/8858 9531/9709/8857 +f 9470/9648/8797 9533/9711/8859 9532/9710/8858 +f 9471/9649/8798 9534/9712/8860 9533/9711/8859 +f 9472/9650/8799 9535/9713/8861 9534/9712/8860 +f 9473/9651/8800 9536/9714/8862 9535/9713/8861 +f 9474/9652/8801 9537/9715/8863 9536/9714/8862 +f 9475/9653/8802 9538/9716/8864 9537/9715/8863 +f 9476/9654/8803 9539/9717/8865 9538/9716/8864 +f 9477/9655/8804 9540/9718/8866 9539/9717/8865 +f 9478/9656/8805 9541/9719/8867 9540/9718/8866 +f 9479/9657/8806 9542/9720/8868 9541/9719/8867 +f 9480/9658/8807 9543/9721/8869 9542/9720/8868 +f 9481/9659/8808 9544/9722/8870 9543/9721/8869 +f 9482/9660/8809 9545/9723/8871 9544/9722/8870 +f 9483/9661/8810 9546/9724/8872 9545/9723/8871 +f 9484/9662/8811 9547/9725/8873 9546/9724/8872 +f 9485/9663/8812 9548/9726/8874 9547/9725/8873 +f 9486/9664/8813 9549/9727/8875 9548/9726/8874 +f 9487/9665/8814 9550/9728/8876 9549/9727/8875 +f 9488/9666/7910 9551/9729/8877 9550/9728/8876 +f 9489/9667/8815 9552/9730/8878 9551/9729/8877 +f 9490/9668/8816 9553/9731/8879 9552/9730/8878 +f 9491/9669/8817 9554/9732/8880 9553/9731/8879 +f 9492/9670/8818 9555/9733/8881 9554/9732/8880 +f 9493/9671/8819 9556/9734/8882 9555/9733/8881 +f 9494/9672/8820 9557/9735/8883 9556/9734/8882 +f 9495/9673/8821 9558/9736/8884 9557/9735/8883 +f 9496/9674/8822 9559/9737/8885 9558/9736/8884 +f 9497/9675/8823 9560/9738/8886 9559/9737/8885 +f 9498/9676/8824 9561/9739/8887 9560/9738/8886 +f 9499/9677/8825 9562/9740/8888 9561/9739/8887 +f 9500/9678/8826 9563/9741/8889 9562/9740/8888 +f 9501/9679/8827 9564/9742/8890 9563/9741/8889 +f 9502/9680/8828 9565/9743/8891 9564/9742/8890 +f 9503/9681/8829 9566/9744/8892 9565/9743/8891 +f 9504/9682/8830 9567/9745/8893 9566/9744/8892 +f 9505/9683/8831 9568/9746/8894 9567/9745/8893 +f 9506/9684/8832 9569/9747/8895 9568/9746/8894 +f 9507/9685/8833 9570/9748/8896 9569/9747/8895 +f 9508/9686/8834 9571/9749/8897 9570/9748/8896 +f 9509/9687/8835 9572/9750/8898 9571/9749/8897 +f 9510/9688/8836 9573/9751/8899 9572/9750/8898 +f 9511/9689/8837 9574/9752/8900 9573/9751/8899 +f 9512/9690/8838 9575/9753/8901 9574/9752/8900 +f 9513/9691/8839 9576/9754/8902 9575/9753/8901 +f 9514/9692/8840 9577/9755/8903 9576/9754/8902 +f 9515/9693/8841 9578/9756/8904 9577/9755/8903 +f 9516/9694/8842 9579/9757/8905 9578/9756/8904 +f 9517/9695/8843 9580/9758/8906 9579/9757/8905 +f 9518/9696/8844 9581/9759/8907 9580/9758/8906 +f 9519/9697/8845 9582/9760/8908 9581/9759/8907 +f 9520/9698/8846 9583/9761/8909 9582/9760/8908 +f 9521/9699/8847 9584/9762/8910 9583/9761/8909 +f 9522/9700/8848 9585/9763/8911 9584/9762/8910 +f 9523/9701/8849 9586/9764/8912 9585/9763/8911 +f 9524/9702/8850 9587/9765/8913 9586/9764/8912 +f 9525/9703/8851 9588/9766/8914 9587/9765/8913 +f 9526/9705/8853 9589/9768/8916 9588/9766/8914 +f 9527/9767/8915 9590/9830/8978 9589/9768/8916 +f 9529/9707/8855 9592/9770/8918 9591/9769/8917 +f 9530/9708/8856 9593/9771/8919 9592/9770/8918 +f 9531/9709/8857 9594/9772/8920 9593/9771/8919 +f 9532/9710/8858 9595/9773/8921 9594/9772/8920 +f 9533/9711/8859 9596/9774/8922 9595/9773/8921 +f 9534/9712/8860 9597/9775/8923 9596/9774/8922 +f 9535/9713/8861 9598/9776/8924 9597/9775/8923 +f 9536/9714/8862 9599/9777/8925 9598/9776/8924 +f 9537/9715/8863 9600/9778/8926 9599/9777/8925 +f 9538/9716/8864 9601/9779/8927 9600/9778/8926 +f 9539/9717/8865 9602/9780/8928 9601/9779/8927 +f 9540/9718/8866 9603/9781/8929 9602/9780/8928 +f 9541/9719/8867 9604/9782/8930 9603/9781/8929 +f 9542/9720/8868 9605/9783/8931 9604/9782/8930 +f 9543/9721/8869 9606/9784/8932 9605/9783/8931 +f 9544/9722/8870 9607/9785/8933 9606/9784/8932 +f 9545/9723/8871 9608/9786/8934 9607/9785/8933 +f 9546/9724/8872 9609/9787/8935 9608/9786/8934 +f 9547/9725/8873 9610/9788/8936 9609/9787/8935 +f 9548/9726/8874 9611/9789/8937 9610/9788/8936 +f 9549/9727/8875 9612/9790/8938 9611/9789/8937 +f 9550/9728/8876 9613/9791/8939 9612/9790/8938 +f 9551/9729/8877 9614/9792/8940 9613/9791/8939 +f 9552/9730/8878 9615/9793/8941 9614/9792/8940 +f 9553/9731/8879 9616/9794/8942 9615/9793/8941 +f 9554/9732/8880 9617/9795/8943 9616/9794/8942 +f 9555/9733/8881 9618/9796/8944 9617/9795/8943 +f 9556/9734/8882 9619/9797/8945 9618/9796/8944 +f 9557/9735/8883 9620/9798/8946 9619/9797/8945 +f 9558/9736/8884 9621/9799/8947 9620/9798/8946 +f 9559/9737/8885 9622/9800/8948 9621/9799/8947 +f 9560/9738/8886 9623/9801/8949 9622/9800/8948 +f 9561/9739/8887 9624/9802/8950 9623/9801/8949 +f 9562/9740/8888 9625/9803/8951 9624/9802/8950 +f 9563/9741/8889 9626/9804/8952 9625/9803/8951 +f 9564/9742/8890 9627/9805/8953 9626/9804/8952 +f 9565/9743/8891 9628/9806/8954 9627/9805/8953 +f 9566/9744/8892 9629/9807/8955 9628/9806/8954 +f 9567/9745/8893 9630/9808/8956 9629/9807/8955 +f 9568/9746/8894 9631/9809/8957 9630/9808/8956 +f 9569/9747/8895 9632/9810/8958 9631/9809/8957 +f 9570/9748/8896 9633/9811/8959 9632/9810/8958 +f 9571/9749/8897 9634/9812/8960 9633/9811/8959 +f 9572/9750/8898 9635/9813/8961 9634/9812/8960 +f 9573/9751/8899 9636/9814/8962 9635/9813/8961 +f 9574/9752/8900 9637/9815/8963 9636/9814/8962 +f 9575/9753/8901 9638/9816/8964 9637/9815/8963 +f 9576/9754/8902 9639/9817/8965 9638/9816/8964 +f 9577/9755/8903 9640/9818/8966 9639/9817/8965 +f 9578/9756/8904 9641/9819/8967 9640/9818/8966 +f 9579/9757/8905 9642/9820/8968 9641/9819/8967 +f 9580/9758/8906 9643/9821/8969 9642/9820/8968 +f 9581/9759/8907 9644/9822/8970 9643/9821/8969 +f 9582/9760/8908 9645/9823/8971 9644/9822/8970 +f 9583/9761/8909 9646/9824/8972 9645/9823/8971 +f 9584/9762/8910 9647/9825/8973 9646/9824/8972 +f 9585/9763/8911 9648/9826/8974 9647/9825/8973 +f 9586/9764/8912 9649/9827/8975 9648/9826/8974 +f 9587/9765/8913 9650/9828/8976 9649/9827/8975 +f 9588/9766/8914 9651/9829/8977 9650/9828/8976 +f 9589/9768/8916 9652/9831/8979 9651/9829/8977 +f 9590/9830/8978 9653/9893/9040 9652/9831/8979 +f 9592/9770/8918 9655/9833/8981 9654/9832/8980 +f 9593/9771/8919 9656/9834/8982 9655/9833/8981 +f 9594/9772/8920 9657/9835/8983 9656/9834/8982 +f 9595/9773/8921 9658/9836/8984 9657/9835/8983 +f 9596/9774/8922 9659/9837/8985 9658/9836/8984 +f 9597/9775/8923 9660/9838/8986 9659/9837/8985 +f 9598/9776/8924 9661/9839/7877 9660/9838/8986 +f 9599/9777/8925 9662/9840/8987 9661/9839/7877 +f 9600/9778/8926 9663/9841/8988 9662/9840/8987 +f 9601/9779/8927 9664/9842/8989 9663/9841/8988 +f 9602/9780/8928 9665/9843/8990 9664/9842/8989 +f 9603/9781/8929 9666/9844/8991 9665/9843/8990 +f 9604/9782/8930 9667/9845/8992 9666/9844/8991 +f 9605/9783/8931 9668/9846/8993 9667/9845/8992 +f 9606/9784/8932 9669/9847/8994 9668/9846/8993 +f 9607/9785/8933 9670/9848/8995 9669/9847/8994 +f 9608/9786/8934 9671/9849/8996 9670/9848/8995 +f 9609/9787/8935 9672/9850/8997 9671/9849/8996 +f 9610/9788/8936 9673/9851/8998 9672/9850/8997 +f 9611/9789/8937 9674/9852/8999 9673/9851/8998 +f 9612/9790/8938 9675/9853/9000 9674/9852/8999 +f 9613/9791/8939 9676/9854/9001 9675/9853/9000 +f 9614/9792/8940 9677/9855/9002 9676/9854/9001 +f 9615/9793/8941 9678/9856/9003 9677/9855/9002 +f 9616/9794/8942 9679/9857/9004 9678/9856/9003 +f 9617/9795/8943 9680/9858/9005 9679/9857/9004 +f 9618/9796/8944 9681/9859/9006 9680/9858/9005 +f 9619/9797/8945 9682/9860/9007 9681/9859/9006 +f 9620/9798/8946 9683/9861/9008 9682/9860/9007 +f 9621/9799/8947 9684/9862/9009 9683/9861/9008 +f 9622/9800/8948 9685/9863/9010 9684/9862/9009 +f 9623/9801/8949 9686/9864/9011 9685/9863/9010 +f 9624/9802/8950 9687/9865/9012 9686/9864/9011 +f 9625/9803/8951 9688/9866/9013 9687/9865/9012 +f 9626/9804/8952 9689/9867/9014 9688/9866/9013 +f 9627/9805/8953 9690/9868/9015 9689/9867/9014 +f 9628/9806/8954 9691/9869/9016 9690/9868/9015 +f 9629/9807/8955 9692/9870/9017 9691/9869/9016 +f 9630/9808/8956 9693/9871/9018 9692/9870/9017 +f 9631/9809/8957 9694/9872/9019 9693/9871/9018 +f 9632/9810/8958 9695/9873/9020 9694/9872/9019 +f 9633/9811/8959 9696/9874/9021 9695/9873/9020 +f 9634/9812/8960 9697/9875/9022 9696/9874/9021 +f 9635/9813/8961 9698/9876/9023 9697/9875/9022 +f 9636/9814/8962 9699/9877/9024 9698/9876/9023 +f 9637/9815/8963 9700/9878/9025 9699/9877/9024 +f 9638/9816/8964 9701/9879/9026 9700/9878/9025 +f 9639/9817/8965 9702/9880/9027 9701/9879/9026 +f 9640/9818/8966 9703/9881/9028 9702/9880/9027 +f 9641/9819/8967 9704/9882/9029 9703/9881/9028 +f 9642/9820/8968 9705/9883/9030 9704/9882/9029 +f 9643/9821/8969 9706/9884/9031 9705/9883/9030 +f 9644/9822/8970 9707/9885/9032 9706/9884/9031 +f 9645/9823/8971 9708/9886/9033 9707/9885/9032 +f 9646/9824/8972 9709/9887/9034 9708/9886/9033 +f 9647/9825/8973 9710/9888/9035 9709/9887/9034 +f 9648/9826/8974 9711/9889/9036 9710/9888/9035 +f 9649/9827/8975 9712/9890/9037 9711/9889/9036 +f 9650/9828/8976 9713/9891/9038 9712/9890/9037 +f 9651/9829/8977 9714/9892/9039 9713/9891/9038 +f 9652/9831/8979 9715/9894/9041 9714/9892/9039 +f 9653/9893/9040 9716/9956/9102 9715/9894/9041 +f 9655/9833/8981 9718/9896/9043 9717/9895/9042 +f 9656/9834/8982 9719/9897/9044 9718/9896/9043 +f 9657/9835/8983 9720/9898/9045 9719/9897/9044 +f 9658/9836/8984 9721/9899/9046 9720/9898/9045 +f 9659/9837/8985 9722/9900/9047 9721/9899/9046 +f 9660/9838/8986 9723/9901/9043 9722/9900/9047 +f 9661/9839/7877 9724/9902/9048 9723/9901/9043 +f 9662/9840/8987 9725/9903/9049 9724/9902/9048 +f 9663/9841/8988 9726/9904/9050 9725/9903/9049 +f 9664/9842/8989 9727/9905/9051 9726/9904/9050 +f 9665/9843/8990 9728/9906/9052 9727/9905/9051 +f 9666/9844/8991 9729/9907/9053 9728/9906/9052 +f 9667/9845/8992 9730/9908/9054 9729/9907/9053 +f 9668/9846/8993 9731/9909/9055 9730/9908/9054 +f 9669/9847/8994 9732/9910/9056 9731/9909/9055 +f 9670/9848/8995 9733/9911/9057 9732/9910/9056 +f 9671/9849/8996 9734/9912/9058 9733/9911/9057 +f 9672/9850/8997 9735/9913/9059 9734/9912/9058 +f 9673/9851/8998 9736/9914/9060 9735/9913/9059 +f 9674/9852/8999 9737/9915/9061 9736/9914/9060 +f 9675/9853/9000 9738/9916/9062 9737/9915/9061 +f 9676/9854/9001 9739/9917/9063 9738/9916/9062 +f 9677/9855/9002 9740/9918/9064 9739/9917/9063 +f 9678/9856/9003 9741/9919/9065 9740/9918/9064 +f 9679/9857/9004 9742/9920/9066 9741/9919/9065 +f 9680/9858/9005 9743/9921/9067 9742/9920/9066 +f 9681/9859/9006 9744/9922/9068 9743/9921/9067 +f 9682/9860/9007 9745/9923/9069 9744/9922/9068 +f 9683/9861/9008 9746/9924/9070 9745/9923/9069 +f 9684/9862/9009 9747/9925/9071 9746/9924/9070 +f 9685/9863/9010 9748/9926/9072 9747/9925/9071 +f 9686/9864/9011 9749/9927/9073 9748/9926/9072 +f 9687/9865/9012 9750/9928/9074 9749/9927/9073 +f 9688/9866/9013 9751/9929/9075 9750/9928/9074 +f 9689/9867/9014 9752/9930/9076 9751/9929/9075 +f 9690/9868/9015 9753/9931/9077 9752/9930/9076 +f 9691/9869/9016 9754/9932/9078 9753/9931/9077 +f 9692/9870/9017 9755/9933/9079 9754/9932/9078 +f 9693/9871/9018 9756/9934/9080 9755/9933/9079 +f 9694/9872/9019 9757/9935/9081 9756/9934/9080 +f 9695/9873/9020 9758/9936/9082 9757/9935/9081 +f 9696/9874/9021 9759/9937/9083 9758/9936/9082 +f 9697/9875/9022 9760/9938/9084 9759/9937/9083 +f 9698/9876/9023 9761/9939/9085 9760/9938/9084 +f 9699/9877/9024 9762/9940/9086 9761/9939/9085 +f 9700/9878/9025 9763/9941/9087 9762/9940/9086 +f 9701/9879/9026 9764/9942/9088 9763/9941/9087 +f 9702/9880/9027 9765/9943/9089 9764/9942/9088 +f 9703/9881/9028 9766/9944/9090 9765/9943/9089 +f 9704/9882/9029 9767/9945/9091 9766/9944/9090 +f 9705/9883/9030 9768/9946/9092 9767/9945/9091 +f 9706/9884/9031 9769/9947/9093 9768/9946/9092 +f 9707/9885/9032 9770/9948/9094 9769/9947/9093 +f 9708/9886/9033 9771/9949/9095 9770/9948/9094 +f 9709/9887/9034 9772/9950/9096 9771/9949/9095 +f 9710/9888/9035 9773/9951/9097 9772/9950/9096 +f 9711/9889/9036 9774/9952/9098 9773/9951/9097 +f 9712/9890/9037 9775/9953/9099 9774/9952/9098 +f 9713/9891/9038 9776/9954/9100 9775/9953/9099 +f 9714/9892/9039 9777/9955/9101 9776/9954/9100 +f 9715/9894/9041 9778/9957/9103 9777/9955/9101 +f 9716/9956/9102 9779/10019/9165 9778/9957/9103 +f 9718/9896/9043 9781/9959/9105 9780/9958/9104 +f 9719/9897/9044 9782/9960/9106 9781/9959/9105 +f 9720/9898/9045 9783/9961/9107 9782/9960/9106 +f 9721/9899/9046 9784/9962/9108 9783/9961/9107 +f 9722/9900/9047 9785/9963/9109 9784/9962/9108 +f 9723/9901/9043 9786/9964/9110 9785/9963/9109 +f 9724/9902/9048 9787/9965/9111 9786/9964/9110 +f 9725/9903/9049 9788/9966/9112 9787/9965/9111 +f 9726/9904/9050 9789/9967/9113 9788/9966/9112 +f 9727/9905/9051 9790/9968/9114 9789/9967/9113 +f 9728/9906/9052 9791/9969/9115 9790/9968/9114 +f 9729/9907/9053 9792/9970/9116 9791/9969/9115 +f 9730/9908/9054 9793/9971/9117 9792/9970/9116 +f 9731/9909/9055 9794/9972/9118 9793/9971/9117 +f 9732/9910/9056 9795/9973/9119 9794/9972/9118 +f 9733/9911/9057 9796/9974/9120 9795/9973/9119 +f 9734/9912/9058 9797/9975/9121 9796/9974/9120 +f 9735/9913/9059 9798/9976/9122 9797/9975/9121 +f 9736/9914/9060 9799/9977/9123 9798/9976/9122 +f 9737/9915/9061 9800/9978/9124 9799/9977/9123 +f 9738/9916/9062 9801/9979/9125 9800/9978/9124 +f 9739/9917/9063 9802/9980/9126 9801/9979/9125 +f 9740/9918/9064 9803/9981/9127 9802/9980/9126 +f 9741/9919/9065 9804/9982/9128 9803/9981/9127 +f 9742/9920/9066 9805/9983/9129 9804/9982/9128 +f 9743/9921/9067 9806/9984/9130 9805/9983/9129 +f 9744/9922/9068 9807/9985/9131 9806/9984/9130 +f 9745/9923/9069 9808/9986/9132 9807/9985/9131 +f 9746/9924/9070 9809/9987/9133 9808/9986/9132 +f 9747/9925/9071 9810/9988/9134 9809/9987/9133 +f 9748/9926/9072 9811/9989/9135 9810/9988/9134 +f 9749/9927/9073 9812/9990/9136 9811/9989/9135 +f 9750/9928/9074 9813/9991/9137 9812/9990/9136 +f 9751/9929/9075 9814/9992/9138 9813/9991/9137 +f 9752/9930/9076 9815/9993/9139 9814/9992/9138 +f 9753/9931/9077 9816/9994/9140 9815/9993/9139 +f 9754/9932/9078 9817/9995/9141 9816/9994/9140 +f 9755/9933/9079 9818/9996/9142 9817/9995/9141 +f 9756/9934/9080 9819/9997/9143 9818/9996/9142 +f 9757/9935/9081 9820/9998/9144 9819/9997/9143 +f 9758/9936/9082 9821/9999/9145 9820/9998/9144 +f 9759/9937/9083 9822/10000/9146 9821/9999/9145 +f 9760/9938/9084 9823/10001/9147 9822/10000/9146 +f 9761/9939/9085 9824/10002/9148 9823/10001/9147 +f 9762/9940/9086 9825/10003/9149 9824/10002/9148 +f 9763/9941/9087 9826/10004/9150 9825/10003/9149 +f 9764/9942/9088 9827/10005/9151 9826/10004/9150 +f 9765/9943/9089 9828/10006/9152 9827/10005/9151 +f 9766/9944/9090 9829/10007/9153 9828/10006/9152 +f 9767/9945/9091 9830/10008/9154 9829/10007/9153 +f 9768/9946/9092 9831/10009/9155 9830/10008/9154 +f 9769/9947/9093 9832/10010/9156 9831/10009/9155 +f 9770/9948/9094 9833/10011/9157 9832/10010/9156 +f 9771/9949/9095 9834/10012/9158 9833/10011/9157 +f 9772/9950/9096 9835/10013/9159 9834/10012/9158 +f 9773/9951/9097 9836/10014/9160 9835/10013/9159 +f 9774/9952/9098 9837/10015/9161 9836/10014/9160 +f 9775/9953/9099 9838/10016/9162 9837/10015/9161 +f 9776/9954/9100 9839/10017/9163 9838/10016/9162 +f 9777/9955/9101 9840/10018/9164 9839/10017/9163 +f 9778/9957/9103 9841/10020/9166 9840/10018/9164 +f 9779/10019/9165 9842/10082/9228 9841/10020/9166 +f 9781/9959/9105 9844/10022/9168 9843/10021/9167 +f 9782/9960/9106 9845/10023/9169 9844/10022/9168 +f 9783/9961/9107 9846/10024/9170 9845/10023/9169 +f 9784/9962/9108 9847/10025/9171 9846/10024/9170 +f 9785/9963/9109 9848/10026/9172 9847/10025/9171 +f 9786/9964/9110 9849/10027/9173 9848/10026/9172 +f 9787/9965/9111 9850/10028/9174 9849/10027/9173 +f 9788/9966/9112 9851/10029/9175 9850/10028/9174 +f 9789/9967/9113 9852/10030/9176 9851/10029/9175 +f 9790/9968/9114 9853/10031/9177 9852/10030/9176 +f 9791/9969/9115 9854/10032/9178 9853/10031/9177 +f 9792/9970/9116 9855/10033/9179 9854/10032/9178 +f 9793/9971/9117 9856/10034/9180 9855/10033/9179 +f 9794/9972/9118 9857/10035/9181 9856/10034/9180 +f 9795/9973/9119 9858/10036/9182 9857/10035/9181 +f 9796/9974/9120 9859/10037/9183 9858/10036/9182 +f 9797/9975/9121 9860/10038/9184 9859/10037/9183 +f 9798/9976/9122 9861/10039/9185 9860/10038/9184 +f 9799/9977/9123 9862/10040/9186 9861/10039/9185 +f 9800/9978/9124 9863/10041/9187 9862/10040/9186 +f 9801/9979/9125 9864/10042/9188 9863/10041/9187 +f 9802/9980/9126 9865/10043/9189 9864/10042/9188 +f 9803/9981/9127 9866/10044/9190 9865/10043/9189 +f 9804/9982/9128 9867/10045/9191 9866/10044/9190 +f 9805/9983/9129 9868/10046/9192 9867/10045/9191 +f 9806/9984/9130 9869/10047/9193 9868/10046/9192 +f 9807/9985/9131 9870/10048/9194 9869/10047/9193 +f 9808/9986/9132 9871/10049/9195 9870/10048/9194 +f 9809/9987/9133 9872/10050/9196 9871/10049/9195 +f 9810/9988/9134 9873/10051/9197 9872/10050/9196 +f 9811/9989/9135 9874/10052/9198 9873/10051/9197 +f 9812/9990/9136 9875/10053/9199 9874/10052/9198 +f 9813/9991/9137 9876/10054/9200 9875/10053/9199 +f 9814/9992/9138 9877/10055/9201 9876/10054/9200 +f 9815/9993/9139 9878/10056/9202 9877/10055/9201 +f 9816/9994/9140 9879/10057/9203 9878/10056/9202 +f 9817/9995/9141 9880/10058/9204 9879/10057/9203 +f 9818/9996/9142 9881/10059/9205 9880/10058/9204 +f 9819/9997/9143 9882/10060/9206 9881/10059/9205 +f 9820/9998/9144 9883/10061/9207 9882/10060/9206 +f 9821/9999/9145 9884/10062/9208 9883/10061/9207 +f 9822/10000/9146 9885/10063/9209 9884/10062/9208 +f 9823/10001/9147 9886/10064/9210 9885/10063/9209 +f 9824/10002/9148 9887/10065/9211 9886/10064/9210 +f 9825/10003/9149 9888/10066/9212 9887/10065/9211 +f 9826/10004/9150 9889/10067/9213 9888/10066/9212 +f 9827/10005/9151 9890/10068/9214 9889/10067/9213 +f 9828/10006/9152 9891/10069/9215 9890/10068/9214 +f 9829/10007/9153 9892/10070/9216 9891/10069/9215 +f 9830/10008/9154 9893/10071/9217 9892/10070/9216 +f 9831/10009/9155 9894/10072/9218 9893/10071/9217 +f 9832/10010/9156 9895/10073/9219 9894/10072/9218 +f 9833/10011/9157 9896/10074/9220 9895/10073/9219 +f 9834/10012/9158 9897/10075/9221 9896/10074/9220 +f 9835/10013/9159 9898/10076/9222 9897/10075/9221 +f 9836/10014/9160 9899/10077/9223 9898/10076/9222 +f 9837/10015/9161 9900/10078/9224 9899/10077/9223 +f 9838/10016/9162 9901/10079/9225 9900/10078/9224 +f 9839/10017/9163 9902/10080/9226 9901/10079/9225 +f 9840/10018/9164 9903/10081/9227 9902/10080/9226 +f 9841/10020/9166 9904/10083/9229 9903/10081/9227 +f 9842/10082/9228 9905/10145/9291 9904/10083/9229 +f 9844/10022/9168 9907/10085/9231 9906/10084/9230 +f 9845/10023/9169 9908/10086/9232 9907/10085/9231 +f 9846/10024/9170 9909/10087/9233 9908/10086/9232 +f 9847/10025/9171 9910/10088/9234 9909/10087/9233 +f 9848/10026/9172 9911/10089/9235 9910/10088/9234 +f 9849/10027/9173 9912/10090/9236 9911/10089/9235 +f 9850/10028/9174 9913/10091/9237 9912/10090/9236 +f 9851/10029/9175 9914/10092/9238 9913/10091/9237 +f 9852/10030/9176 9915/10093/9239 9914/10092/9238 +f 9853/10031/9177 9916/10094/9240 9915/10093/9239 +f 9854/10032/9178 9917/10095/9241 9916/10094/9240 +f 9855/10033/9179 9918/10096/9242 9917/10095/9241 +f 9856/10034/9180 9919/10097/9243 9918/10096/9242 +f 9857/10035/9181 9920/10098/9244 9919/10097/9243 +f 9858/10036/9182 9921/10099/9245 9920/10098/9244 +f 9859/10037/9183 9922/10100/9246 9921/10099/9245 +f 9860/10038/9184 9923/10101/9247 9922/10100/9246 +f 9861/10039/9185 9924/10102/9248 9923/10101/9247 +f 9862/10040/9186 9925/10103/9249 9924/10102/9248 +f 9863/10041/9187 9926/10104/9250 9925/10103/9249 +f 9864/10042/9188 9927/10105/9251 9926/10104/9250 +f 9865/10043/9189 9928/10106/9252 9927/10105/9251 +f 9866/10044/9190 9929/10107/9253 9928/10106/9252 +f 9867/10045/9191 9930/10108/9254 9929/10107/9253 +f 9868/10046/9192 9931/10109/9255 9930/10108/9254 +f 9869/10047/9193 9932/10110/9256 9931/10109/9255 +f 9870/10048/9194 9933/10111/9257 9932/10110/9256 +f 9871/10049/9195 9934/10112/9258 9933/10111/9257 +f 9872/10050/9196 9935/10113/9259 9934/10112/9258 +f 9873/10051/9197 9936/10114/9260 9935/10113/9259 +f 9874/10052/9198 9937/10115/9261 9936/10114/9260 +f 9875/10053/9199 9938/10116/9262 9937/10115/9261 +f 9876/10054/9200 9939/10117/9263 9938/10116/9262 +f 9877/10055/9201 9940/10118/9264 9939/10117/9263 +f 9878/10056/9202 9941/10119/9265 9940/10118/9264 +f 9879/10057/9203 9942/10120/9266 9941/10119/9265 +f 9880/10058/9204 9943/10121/9267 9942/10120/9266 +f 9881/10059/9205 9944/10122/9268 9943/10121/9267 +f 9882/10060/9206 9945/10123/9269 9944/10122/9268 +f 9883/10061/9207 9946/10124/9270 9945/10123/9269 +f 9884/10062/9208 9947/10125/9271 9946/10124/9270 +f 9885/10063/9209 9948/10126/9272 9947/10125/9271 +f 9886/10064/9210 9949/10127/9273 9948/10126/9272 +f 9887/10065/9211 9950/10128/9274 9949/10127/9273 +f 9888/10066/9212 9951/10129/9275 9950/10128/9274 +f 9889/10067/9213 9952/10130/9276 9951/10129/9275 +f 9890/10068/9214 9953/10131/9277 9952/10130/9276 +f 9891/10069/9215 9954/10132/9278 9953/10131/9277 +f 9892/10070/9216 9955/10133/9279 9954/10132/9278 +f 9893/10071/9217 9956/10134/9280 9955/10133/9279 +f 9894/10072/9218 9957/10135/9281 9956/10134/9280 +f 9895/10073/9219 9958/10136/9282 9957/10135/9281 +f 9896/10074/9220 9959/10137/9283 9958/10136/9282 +f 9897/10075/9221 9960/10138/9284 9959/10137/9283 +f 9898/10076/9222 9961/10139/9285 9960/10138/9284 +f 9899/10077/9223 9962/10140/9286 9961/10139/9285 +f 9900/10078/9224 9963/10141/9287 9962/10140/9286 +f 9901/10079/9225 9964/10142/9288 9963/10141/9287 +f 9902/10080/9226 9965/10143/9289 9964/10142/9288 +f 9903/10081/9227 9966/10144/9290 9965/10143/9289 +f 9904/10083/9229 9967/10146/9292 9966/10144/9290 +f 9905/10145/9291 9968/10208/9354 9967/10146/9292 +f 9907/10085/9231 9970/10148/9294 9969/10147/9293 +f 9908/10086/9232 9971/10149/9295 9970/10148/9294 +f 9909/10087/9233 9972/10150/9296 9971/10149/9295 +f 9910/10088/9234 9973/10151/9297 9972/10150/9296 +f 9911/10089/9235 9974/10152/9298 9973/10151/9297 +f 9912/10090/9236 9975/10153/9299 9974/10152/9298 +f 9913/10091/9237 9976/10154/9300 9975/10153/9299 +f 9914/10092/9238 9977/10155/9301 9976/10154/9300 +f 9915/10093/9239 9978/10156/9302 9977/10155/9301 +f 9916/10094/9240 9979/10157/9303 9978/10156/9302 +f 9917/10095/9241 9980/10158/9304 9979/10157/9303 +f 9918/10096/9242 9981/10159/9305 9980/10158/9304 +f 9919/10097/9243 9982/10160/9306 9981/10159/9305 +f 9920/10098/9244 9983/10161/9307 9982/10160/9306 +f 9921/10099/9245 9984/10162/9308 9983/10161/9307 +f 9922/10100/9246 9985/10163/9309 9984/10162/9308 +f 9923/10101/9247 9986/10164/9310 9985/10163/9309 +f 9924/10102/9248 9987/10165/9311 9986/10164/9310 +f 9925/10103/9249 9988/10166/9312 9987/10165/9311 +f 9926/10104/9250 9989/10167/9313 9988/10166/9312 +f 9927/10105/9251 9990/10168/9314 9989/10167/9313 +f 9928/10106/9252 9991/10169/9315 9990/10168/9314 +f 9929/10107/9253 9992/10170/9316 9991/10169/9315 +f 9930/10108/9254 9993/10171/9317 9992/10170/9316 +f 9931/10109/9255 9994/10172/9318 9993/10171/9317 +f 9932/10110/9256 9995/10173/9319 9994/10172/9318 +f 9933/10111/9257 9996/10174/9320 9995/10173/9319 +f 9934/10112/9258 9997/10175/9321 9996/10174/9320 +f 9935/10113/9259 9998/10176/9322 9997/10175/9321 +f 9936/10114/9260 9999/10177/9323 9998/10176/9322 +f 9937/10115/9261 10000/10178/9324 9999/10177/9323 +f 9938/10116/9262 10001/10179/9325 10000/10178/9324 +f 9939/10117/9263 10002/10180/9326 10001/10179/9325 +f 9940/10118/9264 10003/10181/9327 10002/10180/9326 +f 9941/10119/9265 10004/10182/9328 10003/10181/9327 +f 9942/10120/9266 10005/10183/9329 10004/10182/9328 +f 9943/10121/9267 10006/10184/9330 10005/10183/9329 +f 9944/10122/9268 10007/10185/9331 10006/10184/9330 +f 9945/10123/9269 10008/10186/9332 10007/10185/9331 +f 9946/10124/9270 10009/10187/9333 10008/10186/9332 +f 9947/10125/9271 10010/10188/9334 10009/10187/9333 +f 9948/10126/9272 10011/10189/9335 10010/10188/9334 +f 9949/10127/9273 10012/10190/9336 10011/10189/9335 +f 9950/10128/9274 10013/10191/9337 10012/10190/9336 +f 9951/10129/9275 10014/10192/9338 10013/10191/9337 +f 9952/10130/9276 10015/10193/9339 10014/10192/9338 +f 9953/10131/9277 10016/10194/9340 10015/10193/9339 +f 9954/10132/9278 10017/10195/9341 10016/10194/9340 +f 9955/10133/9279 10018/10196/9342 10017/10195/9341 +f 9956/10134/9280 10019/10197/9343 10018/10196/9342 +f 9957/10135/9281 10020/10198/9344 10019/10197/9343 +f 9958/10136/9282 10021/10199/9345 10020/10198/9344 +f 9959/10137/9283 10022/10200/9346 10021/10199/9345 +f 9960/10138/9284 10023/10201/9347 10022/10200/9346 +f 9961/10139/9285 10024/10202/9348 10023/10201/9347 +f 9962/10140/9286 10025/10203/9349 10024/10202/9348 +f 9963/10141/9287 10026/10204/9350 10025/10203/9349 +f 9964/10142/9288 10027/10205/9351 10026/10204/9350 +f 9965/10143/9289 10028/10206/9352 10027/10205/9351 +f 9966/10144/9290 10029/10207/9353 10028/10206/9352 +f 9967/10146/9292 10030/10209/9355 10029/10207/9353 +f 9968/10208/9354 10031/10271/9417 10030/10209/9355 +f 9970/10148/9294 10033/10211/9357 10032/10210/9356 +f 9971/10149/9295 10034/10212/9358 10033/10211/9357 +f 9972/10150/9296 10035/10213/9359 10034/10212/9358 +f 9973/10151/9297 10036/10214/9360 10035/10213/9359 +f 9974/10152/9298 10037/10215/9361 10036/10214/9360 +f 9975/10153/9299 10038/10216/9362 10037/10215/9361 +f 9976/10154/9300 10039/10217/9363 10038/10216/9362 +f 9977/10155/9301 10040/10218/9364 10039/10217/9363 +f 9978/10156/9302 10041/10219/9365 10040/10218/9364 +f 9979/10157/9303 10042/10220/9366 10041/10219/9365 +f 9980/10158/9304 10043/10221/9367 10042/10220/9366 +f 9981/10159/9305 10044/10222/9368 10043/10221/9367 +f 9982/10160/9306 10045/10223/9369 10044/10222/9368 +f 9983/10161/9307 10046/10224/9370 10045/10223/9369 +f 9984/10162/9308 10047/10225/9371 10046/10224/9370 +f 9985/10163/9309 10048/10226/9372 10047/10225/9371 +f 9986/10164/9310 10049/10227/9373 10048/10226/9372 +f 9987/10165/9311 10050/10228/9374 10049/10227/9373 +f 9988/10166/9312 10051/10229/9375 10050/10228/9374 +f 9989/10167/9313 10052/10230/9376 10051/10229/9375 +f 9990/10168/9314 10053/10231/9377 10052/10230/9376 +f 9991/10169/9315 10054/10232/9378 10053/10231/9377 +f 9992/10170/9316 10055/10233/9379 10054/10232/9378 +f 9993/10171/9317 10056/10234/9380 10055/10233/9379 +f 9994/10172/9318 10057/10235/9381 10056/10234/9380 +f 9995/10173/9319 10058/10236/9382 10057/10235/9381 +f 9996/10174/9320 10059/10237/9383 10058/10236/9382 +f 9997/10175/9321 10060/10238/9384 10059/10237/9383 +f 9998/10176/9322 10061/10239/9385 10060/10238/9384 +f 9999/10177/9323 10062/10240/9386 10061/10239/9385 +f 10000/10178/9324 10063/10241/9387 10062/10240/9386 +f 10001/10179/9325 10064/10242/9388 10063/10241/9387 +f 10002/10180/9326 10065/10243/9389 10064/10242/9388 +f 10003/10181/9327 10066/10244/9390 10065/10243/9389 +f 10004/10182/9328 10067/10245/9391 10066/10244/9390 +f 10005/10183/9329 10068/10246/9392 10067/10245/9391 +f 10006/10184/9330 10069/10247/9393 10068/10246/9392 +f 10007/10185/9331 10070/10248/9394 10069/10247/9393 +f 10008/10186/9332 10071/10249/9395 10070/10248/9394 +f 10009/10187/9333 10072/10250/9396 10071/10249/9395 +f 10010/10188/9334 10073/10251/9397 10072/10250/9396 +f 10011/10189/9335 10074/10252/9398 10073/10251/9397 +f 10012/10190/9336 10075/10253/9399 10074/10252/9398 +f 10013/10191/9337 10076/10254/9400 10075/10253/9399 +f 10014/10192/9338 10077/10255/9401 10076/10254/9400 +f 10015/10193/9339 10078/10256/9402 10077/10255/9401 +f 10016/10194/9340 10079/10257/9403 10078/10256/9402 +f 10017/10195/9341 10080/10258/9404 10079/10257/9403 +f 10018/10196/9342 10081/10259/9405 10080/10258/9404 +f 10019/10197/9343 10082/10260/9406 10081/10259/9405 +f 10020/10198/9344 10083/10261/9407 10082/10260/9406 +f 10021/10199/9345 10084/10262/9408 10083/10261/9407 +f 10022/10200/9346 10085/10263/9409 10084/10262/9408 +f 10023/10201/9347 10086/10264/9410 10085/10263/9409 +f 10024/10202/9348 10087/10265/9411 10086/10264/9410 +f 10025/10203/9349 10088/10266/9412 10087/10265/9411 +f 10026/10204/9350 10089/10267/9413 10088/10266/9412 +f 10027/10205/9351 10090/10268/9414 10089/10267/9413 +f 10028/10206/9352 10091/10269/9415 10090/10268/9414 +f 10029/10207/9353 10092/10270/9416 10091/10269/9415 +f 10030/10209/9355 10093/10272/9418 10092/10270/9416 +f 10031/10271/9417 10094/10334/9480 10093/10272/9418 +f 10033/10211/9357 10096/10274/9420 10095/10273/9419 +f 10034/10212/9358 10097/10275/9421 10096/10274/9420 +f 10035/10213/9359 10098/10276/9422 10097/10275/9421 +f 10036/10214/9360 10099/10277/9423 10098/10276/9422 +f 10037/10215/9361 10100/10278/9424 10099/10277/9423 +f 10038/10216/9362 10101/10279/9425 10100/10278/9424 +f 10039/10217/9363 10102/10280/9426 10101/10279/9425 +f 10040/10218/9364 10103/10281/9427 10102/10280/9426 +f 10041/10219/9365 10104/10282/9428 10103/10281/9427 +f 10042/10220/9366 10105/10283/9429 10104/10282/9428 +f 10043/10221/9367 10106/10284/9430 10105/10283/9429 +f 10044/10222/9368 10107/10285/9431 10106/10284/9430 +f 10045/10223/9369 10108/10286/9432 10107/10285/9431 +f 10046/10224/9370 10109/10287/9433 10108/10286/9432 +f 10047/10225/9371 10110/10288/9434 10109/10287/9433 +f 10048/10226/9372 10111/10289/9435 10110/10288/9434 +f 10049/10227/9373 10112/10290/9436 10111/10289/9435 +f 10050/10228/9374 10113/10291/9437 10112/10290/9436 +f 10051/10229/9375 10114/10292/9438 10113/10291/9437 +f 10052/10230/9376 10115/10293/9439 10114/10292/9438 +f 10053/10231/9377 10116/10294/9440 10115/10293/9439 +f 10054/10232/9378 10117/10295/9441 10116/10294/9440 +f 10055/10233/9379 10118/10296/9442 10117/10295/9441 +f 10056/10234/9380 10119/10297/9443 10118/10296/9442 +f 10057/10235/9381 10120/10298/9444 10119/10297/9443 +f 10058/10236/9382 10121/10299/9445 10120/10298/9444 +f 10059/10237/9383 10122/10300/9446 10121/10299/9445 +f 10060/10238/9384 10123/10301/9447 10122/10300/9446 +f 10061/10239/9385 10124/10302/9448 10123/10301/9447 +f 10062/10240/9386 10125/10303/9449 10124/10302/9448 +f 10063/10241/9387 10126/10304/9450 10125/10303/9449 +f 10064/10242/9388 10127/10305/9451 10126/10304/9450 +f 10065/10243/9389 10128/10306/9452 10127/10305/9451 +f 10066/10244/9390 10129/10307/9453 10128/10306/9452 +f 10067/10245/9391 10130/10308/9454 10129/10307/9453 +f 10068/10246/9392 10131/10309/9455 10130/10308/9454 +f 10069/10247/9393 10132/10310/9456 10131/10309/9455 +f 10070/10248/9394 10133/10311/9457 10132/10310/9456 +f 10071/10249/9395 10134/10312/9458 10133/10311/9457 +f 10072/10250/9396 10135/10313/9459 10134/10312/9458 +f 10073/10251/9397 10136/10314/9460 10135/10313/9459 +f 10074/10252/9398 10137/10315/9461 10136/10314/9460 +f 10075/10253/9399 10138/10316/9462 10137/10315/9461 +f 10076/10254/9400 10139/10317/9463 10138/10316/9462 +f 10077/10255/9401 10140/10318/9464 10139/10317/9463 +f 10078/10256/9402 10141/10319/9465 10140/10318/9464 +f 10079/10257/9403 10142/10320/9466 10141/10319/9465 +f 10080/10258/9404 10143/10321/9467 10142/10320/9466 +f 10081/10259/9405 10144/10322/9468 10143/10321/9467 +f 10082/10260/9406 10145/10323/9469 10144/10322/9468 +f 10083/10261/9407 10146/10324/9470 10145/10323/9469 +f 10084/10262/9408 10147/10325/9471 10146/10324/9470 +f 10085/10263/9409 10148/10326/9472 10147/10325/9471 +f 10086/10264/9410 10149/10327/9473 10148/10326/9472 +f 10087/10265/9411 10150/10328/9474 10149/10327/9473 +f 10088/10266/9412 10151/10329/9475 10150/10328/9474 +f 10089/10267/9413 10152/10330/9476 10151/10329/9475 +f 10090/10268/9414 10153/10331/9477 10152/10330/9476 +f 10091/10269/9415 10154/10332/9478 10153/10331/9477 +f 10092/10270/9416 10155/10333/9479 10154/10332/9478 +f 10093/10272/9418 10156/10335/9481 10155/10333/9479 +f 10094/10334/9480 10157/10397/9543 10156/10335/9481 +f 10096/10274/9420 10159/10337/9483 10158/10336/9482 +f 10097/10275/9421 10160/10338/9484 10159/10337/9483 +f 10098/10276/9422 10161/10339/9485 10160/10338/9484 +f 10099/10277/9423 10162/10340/9486 10161/10339/9485 +f 10100/10278/9424 10163/10341/9487 10162/10340/9486 +f 10101/10279/9425 10164/10342/9488 10163/10341/9487 +f 10102/10280/9426 10165/10343/9489 10164/10342/9488 +f 10103/10281/9427 10166/10344/9490 10165/10343/9489 +f 10104/10282/9428 10167/10345/9491 10166/10344/9490 +f 10105/10283/9429 10168/10346/9492 10167/10345/9491 +f 10106/10284/9430 10169/10347/9493 10168/10346/9492 +f 10107/10285/9431 10170/10348/9494 10169/10347/9493 +f 10108/10286/9432 10171/10349/9495 10170/10348/9494 +f 10109/10287/9433 10172/10350/9496 10171/10349/9495 +f 10110/10288/9434 10173/10351/9497 10172/10350/9496 +f 10111/10289/9435 10174/10352/9498 10173/10351/9497 +f 10112/10290/9436 10175/10353/9499 10174/10352/9498 +f 10113/10291/9437 10176/10354/9500 10175/10353/9499 +f 10114/10292/9438 10177/10355/9501 10176/10354/9500 +f 10115/10293/9439 10178/10356/9502 10177/10355/9501 +f 10116/10294/9440 10179/10357/9503 10178/10356/9502 +f 10117/10295/9441 10180/10358/9504 10179/10357/9503 +f 10118/10296/9442 10181/10359/9505 10180/10358/9504 +f 10119/10297/9443 10182/10360/9506 10181/10359/9505 +f 10120/10298/9444 10183/10361/9507 10182/10360/9506 +f 10121/10299/9445 10184/10362/9508 10183/10361/9507 +f 10122/10300/9446 10185/10363/9509 10184/10362/9508 +f 10123/10301/9447 10186/10364/9510 10185/10363/9509 +f 10124/10302/9448 10187/10365/9511 10186/10364/9510 +f 10125/10303/9449 10188/10366/9512 10187/10365/9511 +f 10126/10304/9450 10189/10367/9513 10188/10366/9512 +f 10127/10305/9451 10190/10368/9514 10189/10367/9513 +f 10128/10306/9452 10191/10369/9515 10190/10368/9514 +f 10129/10307/9453 10192/10370/9516 10191/10369/9515 +f 10130/10308/9454 10193/10371/9517 10192/10370/9516 +f 10131/10309/9455 10194/10372/9518 10193/10371/9517 +f 10132/10310/9456 10195/10373/9519 10194/10372/9518 +f 10133/10311/9457 10196/10374/9520 10195/10373/9519 +f 10134/10312/9458 10197/10375/9521 10196/10374/9520 +f 10135/10313/9459 10198/10376/9522 10197/10375/9521 +f 10136/10314/9460 10199/10377/9523 10198/10376/9522 +f 10137/10315/9461 10200/10378/9524 10199/10377/9523 +f 10138/10316/9462 10201/10379/9525 10200/10378/9524 +f 10139/10317/9463 10202/10380/9526 10201/10379/9525 +f 10140/10318/9464 10203/10381/9527 10202/10380/9526 +f 10141/10319/9465 10204/10382/9528 10203/10381/9527 +f 10142/10320/9466 10205/10383/9529 10204/10382/9528 +f 10143/10321/9467 10206/10384/9530 10205/10383/9529 +f 10144/10322/9468 10207/10385/9531 10206/10384/9530 +f 10145/10323/9469 10208/10386/9532 10207/10385/9531 +f 10146/10324/9470 10209/10387/9533 10208/10386/9532 +f 10147/10325/9471 10210/10388/9534 10209/10387/9533 +f 10148/10326/9472 10211/10389/9535 10210/10388/9534 +f 10149/10327/9473 10212/10390/9536 10211/10389/9535 +f 10150/10328/9474 10213/10391/9537 10212/10390/9536 +f 10151/10329/9475 10214/10392/9538 10213/10391/9537 +f 10152/10330/9476 10215/10393/9539 10214/10392/9538 +f 10153/10331/9477 10216/10394/9540 10215/10393/9539 +f 10154/10332/9478 10217/10395/9541 10216/10394/9540 +f 10155/10333/9479 10218/10396/9542 10217/10395/9541 +f 10156/10335/9481 10219/10398/9544 10218/10396/9542 +f 10157/10397/9543 10220/10460/9606 10219/10398/9544 +f 10159/10337/9483 10222/10400/9546 10221/10399/9545 +f 10160/10338/9484 10223/10401/9547 10222/10400/9546 +f 10161/10339/9485 10224/10402/9548 10223/10401/9547 +f 10162/10340/9486 10225/10403/9549 10224/10402/9548 +f 10163/10341/9487 10226/10404/9550 10225/10403/9549 +f 10164/10342/9488 10227/10405/9551 10226/10404/9550 +f 10165/10343/9489 10228/10406/9552 10227/10405/9551 +f 10166/10344/9490 10229/10407/9553 10228/10406/9552 +f 10167/10345/9491 10230/10408/9554 10229/10407/9553 +f 10168/10346/9492 10231/10409/9555 10230/10408/9554 +f 10169/10347/9493 10232/10410/9556 10231/10409/9555 +f 10170/10348/9494 10233/10411/9557 10232/10410/9556 +f 10171/10349/9495 10234/10412/9558 10233/10411/9557 +f 10172/10350/9496 10235/10413/9559 10234/10412/9558 +f 10173/10351/9497 10236/10414/9560 10235/10413/9559 +f 10174/10352/9498 10237/10415/9561 10236/10414/9560 +f 10175/10353/9499 10238/10416/9562 10237/10415/9561 +f 10176/10354/9500 10239/10417/9563 10238/10416/9562 +f 10177/10355/9501 10240/10418/9564 10239/10417/9563 +f 10178/10356/9502 10241/10419/9565 10240/10418/9564 +f 10179/10357/9503 10242/10420/9566 10241/10419/9565 +f 10180/10358/9504 10243/10421/9567 10242/10420/9566 +f 10181/10359/9505 10244/10422/9568 10243/10421/9567 +f 10182/10360/9506 10245/10423/9569 10244/10422/9568 +f 10183/10361/9507 10246/10424/9570 10245/10423/9569 +f 10184/10362/9508 10247/10425/9571 10246/10424/9570 +f 10185/10363/9509 10248/10426/9572 10247/10425/9571 +f 10186/10364/9510 10249/10427/9573 10248/10426/9572 +f 10187/10365/9511 10250/10428/9574 10249/10427/9573 +f 10188/10366/9512 10251/10429/9575 10250/10428/9574 +f 10189/10367/9513 10252/10430/9576 10251/10429/9575 +f 10190/10368/9514 10253/10431/9577 10252/10430/9576 +f 10191/10369/9515 10254/10432/9578 10253/10431/9577 +f 10192/10370/9516 10255/10433/9579 10254/10432/9578 +f 10193/10371/9517 10256/10434/9580 10255/10433/9579 +f 10194/10372/9518 10257/10435/9581 10256/10434/9580 +f 10195/10373/9519 10258/10436/9582 10257/10435/9581 +f 10196/10374/9520 10259/10437/9583 10258/10436/9582 +f 10197/10375/9521 10260/10438/9584 10259/10437/9583 +f 10198/10376/9522 10261/10439/9585 10260/10438/9584 +f 10199/10377/9523 10262/10440/9586 10261/10439/9585 +f 10200/10378/9524 10263/10441/9587 10262/10440/9586 +f 10201/10379/9525 10264/10442/9588 10263/10441/9587 +f 10202/10380/9526 10265/10443/9589 10264/10442/9588 +f 10203/10381/9527 10266/10444/9590 10265/10443/9589 +f 10204/10382/9528 10267/10445/9591 10266/10444/9590 +f 10205/10383/9529 10268/10446/9592 10267/10445/9591 +f 10206/10384/9530 10269/10447/9593 10268/10446/9592 +f 10207/10385/9531 10270/10448/9594 10269/10447/9593 +f 10208/10386/9532 10271/10449/9595 10270/10448/9594 +f 10209/10387/9533 10272/10450/9596 10271/10449/9595 +f 10210/10388/9534 10273/10451/9597 10272/10450/9596 +f 10211/10389/9535 10274/10452/9598 10273/10451/9597 +f 10212/10390/9536 10275/10453/9599 10274/10452/9598 +f 10213/10391/9537 10276/10454/9600 10275/10453/9599 +f 10214/10392/9538 10277/10455/9601 10276/10454/9600 +f 10215/10393/9539 10278/10456/9602 10277/10455/9601 +f 10216/10394/9540 10279/10457/9603 10278/10456/9602 +f 10217/10395/9541 10280/10458/9604 10279/10457/9603 +f 10218/10396/9542 10281/10459/9605 10280/10458/9604 +f 10219/10398/9544 10282/10461/9607 10281/10459/9605 +f 10220/10460/9606 10283/10523/9669 10282/10461/9607 +f 10222/10400/9546 10285/10463/9609 10284/10462/9608 +f 10223/10401/9547 10286/10464/9610 10285/10463/9609 +f 10224/10402/9548 10287/10465/9611 10286/10464/9610 +f 10225/10403/9549 10288/10466/9612 10287/10465/9611 +f 10226/10404/9550 10289/10467/9613 10288/10466/9612 +f 10227/10405/9551 10290/10468/9614 10289/10467/9613 +f 10228/10406/9552 10291/10469/9615 10290/10468/9614 +f 10229/10407/9553 10292/10470/9616 10291/10469/9615 +f 10230/10408/9554 10293/10471/9617 10292/10470/9616 +f 10231/10409/9555 10294/10472/9618 10293/10471/9617 +f 10232/10410/9556 10295/10473/9619 10294/10472/9618 +f 10233/10411/9557 10296/10474/9620 10295/10473/9619 +f 10234/10412/9558 10297/10475/9621 10296/10474/9620 +f 10235/10413/9559 10298/10476/9622 10297/10475/9621 +f 10236/10414/9560 10299/10477/9623 10298/10476/9622 +f 10237/10415/9561 10300/10478/9624 10299/10477/9623 +f 10238/10416/9562 10301/10479/9625 10300/10478/9624 +f 10239/10417/9563 10302/10480/9626 10301/10479/9625 +f 10240/10418/9564 10303/10481/9627 10302/10480/9626 +f 10241/10419/9565 10304/10482/9628 10303/10481/9627 +f 10242/10420/9566 10305/10483/9629 10304/10482/9628 +f 10243/10421/9567 10306/10484/9630 10305/10483/9629 +f 10244/10422/9568 10307/10485/9631 10306/10484/9630 +f 10245/10423/9569 10308/10486/9632 10307/10485/9631 +f 10246/10424/9570 10309/10487/9633 10308/10486/9632 +f 10247/10425/9571 10310/10488/9634 10309/10487/9633 +f 10248/10426/9572 10311/10489/9635 10310/10488/9634 +f 10249/10427/9573 10312/10490/9636 10311/10489/9635 +f 10250/10428/9574 10313/10491/9637 10312/10490/9636 +f 10251/10429/9575 10314/10492/9638 10313/10491/9637 +f 10252/10430/9576 10315/10493/9639 10314/10492/9638 +f 10253/10431/9577 10316/10494/9640 10315/10493/9639 +f 10254/10432/9578 10317/10495/9641 10316/10494/9640 +f 10255/10433/9579 10318/10496/9642 10317/10495/9641 +f 10256/10434/9580 10319/10497/9643 10318/10496/9642 +f 10257/10435/9581 10320/10498/9644 10319/10497/9643 +f 10258/10436/9582 10321/10499/9645 10320/10498/9644 +f 10259/10437/9583 10322/10500/9646 10321/10499/9645 +f 10260/10438/9584 10323/10501/9647 10322/10500/9646 +f 10261/10439/9585 10324/10502/9648 10323/10501/9647 +f 10262/10440/9586 10325/10503/9649 10324/10502/9648 +f 10263/10441/9587 10326/10504/9650 10325/10503/9649 +f 10264/10442/9588 10327/10505/9651 10326/10504/9650 +f 10265/10443/9589 10328/10506/9652 10327/10505/9651 +f 10266/10444/9590 10329/10507/9653 10328/10506/9652 +f 10267/10445/9591 10330/10508/9654 10329/10507/9653 +f 10268/10446/9592 10331/10509/9655 10330/10508/9654 +f 10269/10447/9593 10332/10510/9656 10331/10509/9655 +f 10270/10448/9594 10333/10511/9657 10332/10510/9656 +f 10271/10449/9595 10334/10512/9658 10333/10511/9657 +f 10272/10450/9596 10335/10513/9659 10334/10512/9658 +f 10273/10451/9597 10336/10514/9660 10335/10513/9659 +f 10274/10452/9598 10337/10515/9661 10336/10514/9660 +f 10275/10453/9599 10338/10516/9662 10337/10515/9661 +f 10276/10454/9600 10339/10517/9663 10338/10516/9662 +f 10277/10455/9601 10340/10518/9664 10339/10517/9663 +f 10278/10456/9602 10341/10519/9665 10340/10518/9664 +f 10279/10457/9603 10342/10520/9666 10341/10519/9665 +f 10280/10458/9604 10343/10521/9667 10342/10520/9666 +f 10281/10459/9605 10344/10522/9668 10343/10521/9667 +f 10282/10461/9607 10345/10524/9670 10344/10522/9668 +f 10283/10523/9669 10346/10586/9732 10345/10524/9670 +f 10285/10463/9609 10348/10526/9672 10347/10525/9671 +f 10286/10464/9610 10349/10527/9673 10348/10526/9672 +f 10287/10465/9611 10350/10528/9674 10349/10527/9673 +f 10288/10466/9612 10351/10529/9675 10350/10528/9674 +f 10289/10467/9613 10352/10530/9676 10351/10529/9675 +f 10290/10468/9614 10353/10531/9677 10352/10530/9676 +f 10291/10469/9615 10354/10532/9678 10353/10531/9677 +f 10292/10470/9616 10355/10533/9679 10354/10532/9678 +f 10293/10471/9617 10356/10534/9680 10355/10533/9679 +f 10294/10472/9618 10357/10535/9681 10356/10534/9680 +f 10295/10473/9619 10358/10536/9682 10357/10535/9681 +f 10296/10474/9620 10359/10537/9683 10358/10536/9682 +f 10297/10475/9621 10360/10538/9684 10359/10537/9683 +f 10298/10476/9622 10361/10539/9685 10360/10538/9684 +f 10299/10477/9623 10362/10540/9686 10361/10539/9685 +f 10300/10478/9624 10363/10541/9687 10362/10540/9686 +f 10301/10479/9625 10364/10542/9688 10363/10541/9687 +f 10302/10480/9626 10365/10543/9689 10364/10542/9688 +f 10303/10481/9627 10366/10544/9690 10365/10543/9689 +f 10304/10482/9628 10367/10545/9691 10366/10544/9690 +f 10305/10483/9629 10368/10546/9692 10367/10545/9691 +f 10306/10484/9630 10369/10547/9693 10368/10546/9692 +f 10307/10485/9631 10370/10548/9694 10369/10547/9693 +f 10308/10486/9632 10371/10549/9695 10370/10548/9694 +f 10309/10487/9633 10372/10550/9696 10371/10549/9695 +f 10310/10488/9634 10373/10551/9697 10372/10550/9696 +f 10311/10489/9635 10374/10552/9698 10373/10551/9697 +f 10312/10490/9636 10375/10553/9699 10374/10552/9698 +f 10313/10491/9637 10376/10554/9700 10375/10553/9699 +f 10314/10492/9638 10377/10555/9701 10376/10554/9700 +f 10315/10493/9639 10378/10556/9702 10377/10555/9701 +f 10316/10494/9640 10379/10557/9703 10378/10556/9702 +f 10317/10495/9641 10380/10558/9704 10379/10557/9703 +f 10318/10496/9642 10381/10559/9705 10380/10558/9704 +f 10319/10497/9643 10382/10560/9706 10381/10559/9705 +f 10320/10498/9644 10383/10561/9707 10382/10560/9706 +f 10321/10499/9645 10384/10562/9708 10383/10561/9707 +f 10322/10500/9646 10385/10563/9709 10384/10562/9708 +f 10323/10501/9647 10386/10564/9710 10385/10563/9709 +f 10324/10502/9648 10387/10565/9711 10386/10564/9710 +f 10325/10503/9649 10388/10566/9712 10387/10565/9711 +f 10326/10504/9650 10389/10567/9713 10388/10566/9712 +f 10327/10505/9651 10390/10568/9714 10389/10567/9713 +f 10328/10506/9652 10391/10569/9715 10390/10568/9714 +f 10329/10507/9653 10392/10570/9716 10391/10569/9715 +f 10330/10508/9654 10393/10571/9717 10392/10570/9716 +f 10331/10509/9655 10394/10572/9718 10393/10571/9717 +f 10332/10510/9656 10395/10573/9719 10394/10572/9718 +f 10333/10511/9657 10396/10574/9720 10395/10573/9719 +f 10334/10512/9658 10397/10575/9721 10396/10574/9720 +f 10335/10513/9659 10398/10576/9722 10397/10575/9721 +f 10336/10514/9660 10399/10577/9723 10398/10576/9722 +f 10337/10515/9661 10400/10578/9724 10399/10577/9723 +f 10338/10516/9662 10401/10579/9725 10400/10578/9724 +f 10339/10517/9663 10402/10580/9726 10401/10579/9725 +f 10340/10518/9664 10403/10581/9727 10402/10580/9726 +f 10341/10519/9665 10404/10582/9728 10403/10581/9727 +f 10342/10520/9666 10405/10583/9729 10404/10582/9728 +f 10343/10521/9667 10406/10584/9730 10405/10583/9729 +f 10344/10522/9668 10407/10585/9731 10406/10584/9730 +f 10345/10524/9670 10408/10587/9733 10407/10585/9731 +f 10346/10586/9732 10409/10649/9793 10408/10587/9733 +f 10348/10526/9672 10411/10589/9735 10410/10588/9734 +f 10349/10527/9673 10412/10590/9736 10411/10589/9735 +f 10350/10528/9674 10413/10591/9737 10412/10590/9736 +f 10351/10529/9675 10414/10592/9738 10413/10591/9737 +f 10352/10530/9676 10415/10593/9739 10414/10592/9738 +f 10353/10531/9677 10416/10594/9740 10415/10593/9739 +f 10354/10532/9678 10417/10595/9741 10416/10594/9740 +f 10355/10533/9679 10418/10596/9742 10417/10595/9741 +f 10356/10534/9680 10419/10597/9743 10418/10596/9742 +f 10357/10535/9681 10420/10598/9744 10419/10597/9743 +f 10358/10536/9682 10421/10599/9745 10420/10598/9744 +f 10359/10537/9683 10422/10600/9746 10421/10599/9745 +f 10360/10538/9684 10423/10601/9747 10422/10600/9746 +f 10361/10539/9685 10424/10602/9748 10423/10601/9747 +f 10362/10540/9686 10425/10603/9749 10424/10602/9748 +f 10363/10541/9687 10426/10604/9750 10425/10603/9749 +f 10364/10542/9688 10427/10605/9751 10426/10604/9750 +f 10365/10543/9689 10428/10606/8455 10427/10605/9751 +f 10366/10544/9690 10429/10607/9752 10428/10606/8455 +f 10367/10545/9691 10430/10608/9753 10429/10607/9752 +f 10368/10546/9692 10431/10609/9754 10430/10608/9753 +f 10369/10547/9693 10432/10610/9755 10431/10609/9754 +f 10370/10548/9694 10433/10611/9756 10432/10610/9755 +f 10371/10549/9695 10434/10612/9757 10433/10611/9756 +f 10372/10550/9696 10435/10613/9758 10434/10612/9757 +f 10373/10551/9697 10436/10614/9759 10435/10613/9758 +f 10374/10552/9698 10437/10615/9760 10436/10614/9759 +f 10375/10553/9699 10438/10616/9761 10437/10615/9760 +f 10376/10554/9700 10439/10617/9762 10438/10616/9761 +f 10377/10555/9701 10440/10618/9763 10439/10617/9762 +f 10378/10556/9702 10441/10619/9764 10440/10618/9763 +f 10379/10557/9703 10442/10620/9765 10441/10619/9764 +f 10380/10558/9704 10443/10621/9766 10442/10620/9765 +f 10381/10559/9705 10444/10622/9767 10443/10621/9766 +f 10382/10560/9706 10445/10623/9768 10444/10622/9767 +f 10383/10561/9707 10446/10624/9769 10445/10623/9768 +f 10384/10562/9708 10447/10625/9770 10446/10624/9769 +f 10385/10563/9709 10448/10626/9771 10447/10625/9770 +f 10386/10564/9710 10449/10627/9711 10448/10626/9771 +f 10387/10565/9711 10450/10628/9772 10449/10627/9711 +f 10388/10566/9712 10451/10629/9773 10450/10628/9772 +f 10389/10567/9713 10452/10630/9774 10451/10629/9773 +f 10390/10568/9714 10453/10631/9775 10452/10630/9774 +f 10391/10569/9715 10454/10632/9776 10453/10631/9775 +f 10392/10570/9716 10455/10633/9777 10454/10632/9776 +f 10393/10571/9717 10456/10634/9778 10455/10633/9777 +f 10394/10572/9718 10457/10635/9779 10456/10634/9778 +f 10395/10573/9719 10458/10636/9780 10457/10635/9779 +f 10396/10574/9720 10459/10637/9781 10458/10636/9780 +f 10397/10575/9721 10460/10638/9782 10459/10637/9781 +f 10398/10576/9722 10461/10639/9783 10460/10638/9782 +f 10399/10577/9723 10462/10640/9784 10461/10639/9783 +f 10400/10578/9724 10463/10641/9785 10462/10640/9784 +f 10401/10579/9725 10464/10642/9786 10463/10641/9785 +f 10402/10580/9726 10465/10643/9787 10464/10642/9786 +f 10403/10581/9727 10466/10644/9788 10465/10643/9787 +f 10404/10582/9728 10467/10645/9789 10466/10644/9788 +f 10405/10583/9729 10468/10646/9790 10467/10645/9789 +f 10406/10584/9730 10469/10647/9791 10468/10646/9790 +f 10407/10585/9731 10470/10648/9792 10469/10647/9791 +f 10408/10587/9733 10471/10650/9794 10470/10648/9792 +f 10409/10649/9793 10472/10712/9856 10471/10650/9794 +f 10411/10589/9735 10474/10652/9796 10473/10651/9795 +f 10412/10590/9736 10475/10653/9797 10474/10652/9796 +f 10413/10591/9737 10476/10654/9798 10475/10653/9797 +f 10414/10592/9738 10477/10655/9799 10476/10654/9798 +f 10415/10593/9739 10478/10656/9800 10477/10655/9799 +f 10416/10594/9740 10479/10657/9801 10478/10656/9800 +f 10417/10595/9741 10480/10658/9802 10479/10657/9801 +f 10418/10596/9742 10481/10659/9803 10480/10658/9802 +f 10419/10597/9743 10482/10660/9804 10481/10659/9803 +f 10420/10598/9744 10483/10661/9805 10482/10660/9804 +f 10421/10599/9745 10484/10662/9806 10483/10661/9805 +f 10422/10600/9746 10485/10663/9807 10484/10662/9806 +f 10423/10601/9747 10486/10664/9808 10485/10663/9807 +f 10424/10602/9748 10487/10665/9809 10486/10664/9808 +f 10425/10603/9749 10488/10666/9810 10487/10665/9809 +f 10426/10604/9750 10489/10667/9811 10488/10666/9810 +f 10427/10605/9751 10490/10668/9812 10489/10667/9811 +f 10428/10606/8455 10491/10669/9813 10490/10668/9812 +f 10429/10607/9752 10492/10670/9814 10491/10669/9813 +f 10430/10608/9753 10493/10671/9815 10492/10670/9814 +f 10431/10609/9754 10494/10672/9816 10493/10671/9815 +f 10432/10610/9755 10495/10673/9817 10494/10672/9816 +f 10433/10611/9756 10496/10674/9818 10495/10673/9817 +f 10434/10612/9757 10497/10675/9819 10496/10674/9818 +f 10435/10613/9758 10498/10676/9820 10497/10675/9819 +f 10436/10614/9759 10499/10677/9821 10498/10676/9820 +f 10437/10615/9760 10500/10678/9822 10499/10677/9821 +f 10438/10616/9761 10501/10679/9823 10500/10678/9822 +f 10439/10617/9762 10502/10680/9824 10501/10679/9823 +f 10440/10618/9763 10503/10681/9825 10502/10680/9824 +f 10441/10619/9764 10504/10682/9826 10503/10681/9825 +f 10442/10620/9765 10505/10683/9827 10504/10682/9826 +f 10443/10621/9766 10506/10684/9828 10505/10683/9827 +f 10444/10622/9767 10507/10685/9829 10506/10684/9828 +f 10445/10623/9768 10508/10686/9830 10507/10685/9829 +f 10446/10624/9769 10509/10687/9831 10508/10686/9830 +f 10447/10625/9770 10510/10688/9832 10509/10687/9831 +f 10448/10626/9771 10511/10689/9833 10510/10688/9832 +f 10449/10627/9711 10512/10690/9834 10511/10689/9833 +f 10450/10628/9772 10513/10691/9835 10512/10690/9834 +f 10451/10629/9773 10514/10692/9836 10513/10691/9835 +f 10452/10630/9774 10515/10693/9837 10514/10692/9836 +f 10453/10631/9775 10516/10694/9838 10515/10693/9837 +f 10454/10632/9776 10517/10695/9839 10516/10694/9838 +f 10455/10633/9777 10518/10696/9840 10517/10695/9839 +f 10456/10634/9778 10519/10697/9841 10518/10696/9840 +f 10457/10635/9779 10520/10698/9842 10519/10697/9841 +f 10458/10636/9780 10521/10699/9843 10520/10698/9842 +f 10459/10637/9781 10522/10700/9844 10521/10699/9843 +f 10460/10638/9782 10523/10701/9845 10522/10700/9844 +f 10461/10639/9783 10524/10702/9846 10523/10701/9845 +f 10462/10640/9784 10525/10703/9847 10524/10702/9846 +f 10463/10641/9785 10526/10704/9848 10525/10703/9847 +f 10464/10642/9786 10527/10705/9849 10526/10704/9848 +f 10465/10643/9787 10528/10706/9850 10527/10705/9849 +f 10466/10644/9788 10529/10707/9851 10528/10706/9850 +f 10467/10645/9789 10530/10708/9852 10529/10707/9851 +f 10468/10646/9790 10531/10709/9853 10530/10708/9852 +f 10469/10647/9791 10532/10710/9854 10531/10709/9853 +f 10470/10648/9792 10533/10711/9855 10532/10710/9854 +f 10471/10650/9794 10534/10713/9857 10533/10711/9855 +f 10472/10712/9856 10535/10775/9919 10534/10713/9857 +f 10474/10652/9796 10537/10715/9859 10536/10714/9858 +f 10475/10653/9797 10538/10716/9860 10537/10715/9859 +f 10476/10654/9798 10539/10717/9861 10538/10716/9860 +f 10477/10655/9799 10540/10718/9862 10539/10717/9861 +f 10478/10656/9800 10541/10719/9863 10540/10718/9862 +f 10479/10657/9801 10542/10720/9864 10541/10719/9863 +f 10480/10658/9802 10543/10721/9865 10542/10720/9864 +f 10481/10659/9803 10544/10722/9866 10543/10721/9865 +f 10482/10660/9804 10545/10723/9867 10544/10722/9866 +f 10483/10661/9805 10546/10724/9868 10545/10723/9867 +f 10484/10662/9806 10547/10725/9869 10546/10724/9868 +f 10485/10663/9807 10548/10726/9870 10547/10725/9869 +f 10486/10664/9808 10549/10727/9871 10548/10726/9870 +f 10487/10665/9809 10550/10728/9872 10549/10727/9871 +f 10488/10666/9810 10551/10729/9873 10550/10728/9872 +f 10489/10667/9811 10552/10730/9874 10551/10729/9873 +f 10490/10668/9812 10553/10731/9875 10552/10730/9874 +f 10491/10669/9813 10554/10732/9876 10553/10731/9875 +f 10492/10670/9814 10555/10733/9877 10554/10732/9876 +f 10493/10671/9815 10556/10734/9878 10555/10733/9877 +f 10494/10672/9816 10557/10735/9879 10556/10734/9878 +f 10495/10673/9817 10558/10736/9880 10557/10735/9879 +f 10496/10674/9818 10559/10737/9881 10558/10736/9880 +f 10497/10675/9819 10560/10738/9882 10559/10737/9881 +f 10498/10676/9820 10561/10739/9883 10560/10738/9882 +f 10499/10677/9821 10562/10740/9884 10561/10739/9883 +f 10500/10678/9822 10563/10741/9885 10562/10740/9884 +f 10501/10679/9823 10564/10742/9886 10563/10741/9885 +f 10502/10680/9824 10565/10743/9887 10564/10742/9886 +f 10503/10681/9825 10566/10744/9888 10565/10743/9887 +f 10504/10682/9826 10567/10745/9889 10566/10744/9888 +f 10505/10683/9827 10568/10746/9890 10567/10745/9889 +f 10506/10684/9828 10569/10747/9891 10568/10746/9890 +f 10507/10685/9829 10570/10748/9892 10569/10747/9891 +f 10508/10686/9830 10571/10749/9893 10570/10748/9892 +f 10509/10687/9831 10572/10750/9894 10571/10749/9893 +f 10510/10688/9832 10573/10751/9895 10572/10750/9894 +f 10511/10689/9833 10574/10752/9896 10573/10751/9895 +f 10512/10690/9834 10575/10753/9897 10574/10752/9896 +f 10513/10691/9835 10576/10754/9898 10575/10753/9897 +f 10514/10692/9836 10577/10755/9899 10576/10754/9898 +f 10515/10693/9837 10578/10756/9900 10577/10755/9899 +f 10516/10694/9838 10579/10757/9901 10578/10756/9900 +f 10517/10695/9839 10580/10758/9902 10579/10757/9901 +f 10518/10696/9840 10581/10759/9903 10580/10758/9902 +f 10519/10697/9841 10582/10760/9904 10581/10759/9903 +f 10520/10698/9842 10583/10761/9905 10582/10760/9904 +f 10521/10699/9843 10584/10762/9906 10583/10761/9905 +f 10522/10700/9844 10585/10763/9907 10584/10762/9906 +f 10523/10701/9845 10586/10764/9908 10585/10763/9907 +f 10524/10702/9846 10587/10765/9909 10586/10764/9908 +f 10525/10703/9847 10588/10766/9910 10587/10765/9909 +f 10526/10704/9848 10589/10767/9911 10588/10766/9910 +f 10527/10705/9849 10590/10768/9912 10589/10767/9911 +f 10528/10706/9850 10591/10769/9913 10590/10768/9912 +f 10529/10707/9851 10592/10771/9915 10591/10769/9913 +f 10529/10707/9851 10530/10708/9852 10593/10770/9914 +f 10531/10709/9853 10594/10772/9916 10593/10770/9914 +f 10532/10710/9854 10595/10773/9917 10594/10772/9916 +f 10533/10711/9855 10596/10774/9918 10595/10773/9917 +f 10534/10713/9857 10597/10776/9920 10596/10774/9918 +f 10535/10775/9919 10598/10838/9982 10597/10776/9920 +f 10537/10715/9859 10600/10778/9922 10599/10777/9921 +f 10538/10716/9860 10601/10779/9923 10600/10778/9922 +f 10539/10717/9861 10602/10780/9924 10601/10779/9923 +f 10540/10718/9862 10603/10781/9925 10602/10780/9924 +f 10541/10719/9863 10604/10782/9926 10603/10781/9925 +f 10542/10720/9864 10605/10783/9927 10604/10782/9926 +f 10543/10721/9865 10606/10784/9928 10605/10783/9927 +f 10544/10722/9866 10607/10785/9929 10606/10784/9928 +f 10545/10723/9867 10608/10786/9930 10607/10785/9929 +f 10546/10724/9868 10609/10787/9931 10608/10786/9930 +f 10547/10725/9869 10610/10788/9932 10609/10787/9931 +f 10548/10726/9870 10611/10789/9933 10610/10788/9932 +f 10549/10727/9871 10612/10790/9934 10611/10789/9933 +f 10550/10728/9872 10613/10791/9935 10612/10790/9934 +f 10551/10729/9873 10614/10792/9936 10613/10791/9935 +f 10552/10730/9874 10615/10793/9937 10614/10792/9936 +f 10553/10731/9875 10616/10794/9938 10615/10793/9937 +f 10554/10732/9876 10617/10795/9939 10616/10794/9938 +f 10555/10733/9877 10618/10796/9940 10617/10795/9939 +f 10556/10734/9878 10619/10797/9941 10618/10796/9940 +f 10557/10735/9879 10620/10798/9942 10619/10797/9941 +f 10558/10736/9880 10621/10799/9943 10620/10798/9942 +f 10559/10737/9881 10622/10800/9944 10621/10799/9943 +f 10560/10738/9882 10623/10801/9945 10622/10800/9944 +f 10561/10739/9883 10624/10802/9946 10623/10801/9945 +f 10562/10740/9884 10625/10803/9947 10624/10802/9946 +f 10563/10741/9885 10626/10804/9948 10625/10803/9947 +f 10564/10742/9886 10627/10805/9949 10626/10804/9948 +f 10565/10743/9887 10628/10806/9950 10627/10805/9949 +f 10566/10744/9888 10629/10807/9951 10628/10806/9950 +f 10567/10745/9889 10630/10808/9952 10629/10807/9951 +f 10568/10746/9890 10631/10809/9953 10630/10808/9952 +f 10569/10747/9891 10632/10810/9954 10631/10809/9953 +f 10570/10748/9892 10633/10811/9955 10632/10810/9954 +f 10571/10749/9893 10634/10812/9956 10633/10811/9955 +f 10572/10750/9894 10635/10813/9957 10634/10812/9956 +f 10573/10751/9895 10636/10814/9958 10635/10813/9957 +f 10574/10752/9896 10637/10815/9959 10636/10814/9958 +f 10575/10753/9897 10638/10816/9960 10637/10815/9959 +f 10576/10754/9898 10639/10817/9961 10638/10816/9960 +f 10577/10755/9899 10640/10818/9962 10639/10817/9961 +f 10578/10756/9900 10641/10819/9963 10640/10818/9962 +f 10579/10757/9901 10642/10820/9964 10641/10819/9963 +f 10580/10758/9902 10643/10821/9965 10642/10820/9964 +f 10581/10759/9903 10644/10822/9966 10643/10821/9965 +f 10582/10760/9904 10645/10823/9967 10644/10822/9966 +f 10583/10761/9905 10646/10824/9968 10645/10823/9967 +f 10584/10762/9906 10647/10825/9969 10646/10824/9968 +f 10585/10763/9907 10648/10826/9970 10647/10825/9969 +f 10586/10764/9908 10649/10827/9971 10648/10826/9970 +f 10587/10765/9909 10650/10828/9972 10649/10827/9971 +f 10588/10766/9910 10651/10829/9973 10650/10828/9972 +f 10589/10767/9911 10652/10830/9974 10651/10829/9973 +f 10590/10768/9912 10653/10831/9975 10652/10830/9974 +f 10591/10769/9913 10654/10832/9976 10653/10831/9975 +f 10592/10771/9915 10655/10833/9977 10654/10832/9976 +f 10593/10770/9914 10656/10834/9978 10655/10833/9977 +f 10594/10772/9916 10657/10835/9979 10656/10834/9978 +f 10595/10773/9917 10658/10836/9980 10657/10835/9979 +f 10596/10774/9918 10659/10837/9981 10658/10836/9980 +f 10597/10776/9920 10660/10839/9983 10659/10837/9981 +f 10598/10838/9982 10661/10901/10043 10660/10839/9983 +f 10600/10778/9922 10663/10841/9984 10662/10840/9838 +f 10601/10779/9923 10664/10842/9985 10663/10841/9984 +f 10602/10780/9924 10665/10843/9986 10664/10842/9985 +f 10603/10781/9925 10666/10844/9987 10665/10843/9986 +f 10604/10782/9926 10667/10845/9988 10666/10844/9987 +f 10605/10783/9927 10668/10846/9989 10667/10845/9988 +f 10606/10784/9928 10669/10847/9990 10668/10846/9989 +f 10607/10785/9929 10670/10848/9991 10669/10847/9990 +f 10608/10786/9930 10671/10849/9992 10670/10848/9991 +f 10609/10787/9931 10672/10850/9993 10671/10849/9992 +f 10610/10788/9932 10673/10851/9994 10672/10850/9993 +f 10611/10789/9933 10674/10852/9995 10673/10851/9994 +f 10612/10790/9934 10675/10853/9996 10674/10852/9995 +f 10613/10791/9935 10676/10854/9997 10675/10853/9996 +f 10614/10792/9936 10677/10855/9998 10676/10854/9997 +f 10615/10793/9937 10678/10856/9999 10677/10855/9998 +f 10616/10794/9938 10679/10857/10000 10678/10856/9999 +f 10617/10795/9939 10680/10858/10001 10679/10857/10000 +f 10618/10796/9940 10681/10859/10002 10680/10858/10001 +f 10619/10797/9941 10682/10860/10003 10681/10859/10002 +f 10620/10798/9942 10683/10861/10004 10682/10860/10003 +f 10621/10799/9943 10684/10862/10005 10683/10861/10004 +f 10622/10800/9944 10685/10863/10006 10684/10862/10005 +f 10623/10801/9945 10686/10864/10007 10685/10863/10006 +f 10624/10802/9946 10687/10865/10008 10686/10864/10007 +f 10625/10803/9947 10688/10866/10009 10687/10865/10008 +f 10626/10804/9948 10689/10867/10010 10688/10866/10009 +f 10627/10805/9949 10690/10868/10011 10689/10867/10010 +f 10628/10806/9950 10691/10869/10012 10690/10868/10011 +f 10629/10807/9951 10692/10870/10013 10691/10869/10012 +f 10630/10808/9952 10693/10871/10014 10692/10870/10013 +f 10631/10809/9953 10694/10872/10015 10693/10871/10014 +f 10632/10810/9954 10695/10873/10016 10694/10872/10015 +f 10633/10811/9955 10696/10874/9648 10695/10873/10016 +f 10634/10812/9956 10697/10875/10017 10696/10874/9648 +f 10635/10813/9957 10698/10876/10018 10697/10875/10017 +f 10636/10814/9958 10699/10877/10019 10698/10876/10018 +f 10637/10815/9959 10700/10878/10020 10699/10877/10019 +f 10638/10816/9960 10701/10879/10021 10700/10878/10020 +f 10639/10817/9961 10702/10880/10022 10701/10879/10021 +f 10640/10818/9962 10703/10881/10023 10702/10880/10022 +f 10641/10819/9963 10704/10882/10024 10703/10881/10023 +f 10642/10820/9964 10705/10883/10025 10704/10882/10024 +f 10643/10821/9965 10706/10884/10026 10705/10883/10025 +f 10644/10822/9966 10707/10885/10027 10706/10884/10026 +f 10645/10823/9967 10708/10886/10028 10707/10885/10027 +f 10646/10824/9968 10709/10887/10029 10708/10886/10028 +f 10647/10825/9969 10710/10888/10030 10709/10887/10029 +f 10648/10826/9970 10711/10889/10031 10710/10888/10030 +f 10649/10827/9971 10712/10890/10032 10711/10889/10031 +f 10650/10828/9972 10713/10891/10033 10712/10890/10032 +f 10651/10829/9973 10714/10892/10034 10713/10891/10033 +f 10652/10830/9974 10715/10893/10035 10714/10892/10034 +f 10653/10831/9975 10716/10894/10036 10715/10893/10035 +f 10654/10832/9976 10717/10895/10037 10716/10894/10036 +f 10655/10833/9977 10718/10896/10038 10717/10895/10037 +f 10656/10834/9978 10719/10897/10039 10718/10896/10038 +f 10657/10835/9979 10720/10898/10040 10719/10897/10039 +f 10658/10836/9980 10721/10899/10041 10720/10898/10040 +f 10659/10837/9981 10722/10900/10042 10721/10899/10041 +f 10660/10839/9983 10723/10902/10044 10722/10900/10042 +f 10661/10901/10043 10724/10964/10105 10723/10902/10044 +f 10663/10841/9984 10726/10904/10046 10725/10903/10045 +f 10664/10842/9985 10727/10905/10047 10726/10904/10046 +f 10665/10843/9986 10728/10906/10048 10727/10905/10047 +f 10666/10844/9987 10729/10907/10049 10728/10906/10048 +f 10667/10845/9988 10730/10908/10050 10729/10907/10049 +f 10668/10846/9989 10731/10909/10051 10730/10908/10050 +f 10669/10847/9990 10732/10910/10052 10731/10909/10051 +f 10670/10848/9991 10733/10911/10053 10732/10910/10052 +f 10671/10849/9992 10734/10912/10054 10733/10911/10053 +f 10672/10850/9993 10735/10913/10055 10734/10912/10054 +f 10673/10851/9994 10736/10914/10056 10735/10913/10055 +f 10674/10852/9995 10737/10915/10057 10736/10914/10056 +f 10675/10853/9996 10738/10916/10058 10737/10915/10057 +f 10676/10854/9997 10739/10917/10059 10738/10916/10058 +f 10677/10855/9998 10740/10918/10060 10739/10917/10059 +f 10678/10856/9999 10741/10919/10061 10740/10918/10060 +f 10679/10857/10000 10742/10920/10062 10741/10919/10061 +f 10680/10858/10001 10743/10921/10063 10742/10920/10062 +f 10681/10859/10002 10744/10922/10064 10743/10921/10063 +f 10682/10860/10003 10745/10923/10065 10744/10922/10064 +f 10683/10861/10004 10746/10924/8710 10745/10923/10065 +f 10684/10862/10005 10747/10925/10066 10746/10924/8710 +f 10685/10863/10006 10748/10926/10067 10747/10925/10066 +f 10686/10864/10007 10749/10927/10068 10748/10926/10067 +f 10687/10865/10008 10750/10928/10069 10749/10927/10068 +f 10688/10866/10009 10751/10929/10070 10750/10928/10069 +f 10689/10867/10010 10752/10930/10071 10751/10929/10070 +f 10690/10868/10011 10753/10931/10072 10752/10930/10071 +f 10691/10869/10012 10754/10932/10073 10753/10931/10072 +f 10692/10870/10013 10755/10933/10074 10754/10932/10073 +f 10693/10871/10014 10756/10934/10075 10755/10933/10074 +f 10694/10872/10015 10757/10935/10076 10756/10934/10075 +f 10695/10873/10016 10758/10936/10077 10757/10935/10076 +f 10696/10874/9648 10759/10937/10078 10758/10936/10077 +f 10697/10875/10017 10760/10938/10079 10759/10937/10078 +f 10698/10876/10018 10761/10939/10080 10760/10938/10079 +f 10699/10877/10019 10762/10940/10081 10761/10939/10080 +f 10700/10878/10020 10763/10941/10082 10762/10940/10081 +f 10701/10879/10021 10764/10942/10083 10763/10941/10082 +f 10702/10880/10022 10765/10943/10084 10764/10942/10083 +f 10703/10881/10023 10766/10944/10085 10765/10943/10084 +f 10704/10882/10024 10767/10945/10086 10766/10944/10085 +f 10705/10883/10025 10768/10946/10087 10767/10945/10086 +f 10706/10884/10026 10769/10947/10088 10768/10946/10087 +f 10707/10885/10027 10770/10948/10089 10769/10947/10088 +f 10708/10886/10028 10771/10949/10090 10770/10948/10089 +f 10709/10887/10029 10772/10950/10091 10771/10949/10090 +f 10710/10888/10030 10773/10951/10092 10772/10950/10091 +f 10711/10889/10031 10774/10952/10093 10773/10951/10092 +f 10712/10890/10032 10775/10953/10094 10774/10952/10093 +f 10713/10891/10033 10776/10954/10095 10775/10953/10094 +f 10714/10892/10034 10777/10955/10096 10776/10954/10095 +f 10715/10893/10035 10778/10956/10097 10777/10955/10096 +f 10716/10894/10036 10779/10957/10098 10778/10956/10097 +f 10717/10895/10037 10780/10958/10099 10779/10957/10098 +f 10718/10896/10038 10781/10959/10100 10780/10958/10099 +f 10719/10897/10039 10782/10960/10101 10781/10959/10100 +f 10720/10898/10040 10783/10961/10102 10782/10960/10101 +f 10721/10899/10041 10784/10962/10103 10783/10961/10102 +f 10722/10900/10042 10785/10963/10104 10784/10962/10103 +f 10723/10902/10044 10786/10965/10106 10785/10963/10104 +f 10724/10964/10105 10787/11027/10168 10786/10965/10106 +f 10726/10904/10046 10789/10967/10108 10788/10966/10107 +f 10727/10905/10047 10790/10968/10109 10789/10967/10108 +f 10728/10906/10048 10791/10969/10110 10790/10968/10109 +f 10729/10907/10049 10792/10970/10111 10791/10969/10110 +f 10730/10908/10050 10793/10971/10112 10792/10970/10111 +f 10731/10909/10051 10794/10972/10113 10793/10971/10112 +f 10732/10910/10052 10795/10973/10114 10794/10972/10113 +f 10733/10911/10053 10796/10974/10115 10795/10973/10114 +f 10734/10912/10054 10797/10975/10116 10796/10974/10115 +f 10735/10913/10055 10798/10976/10117 10797/10975/10116 +f 10736/10914/10056 10799/10977/10118 10798/10976/10117 +f 10737/10915/10057 10800/10978/10119 10799/10977/10118 +f 10738/10916/10058 10801/10979/10120 10800/10978/10119 +f 10739/10917/10059 10802/10980/10121 10801/10979/10120 +f 10740/10918/10060 10803/10981/10122 10802/10980/10121 +f 10741/10919/10061 10804/10982/10123 10803/10981/10122 +f 10742/10920/10062 10805/10983/10124 10804/10982/10123 +f 10743/10921/10063 10806/10984/10125 10805/10983/10124 +f 10744/10922/10064 10807/10985/10126 10806/10984/10125 +f 10745/10923/10065 10808/10986/10127 10807/10985/10126 +f 10746/10924/8710 10809/10987/10128 10808/10986/10127 +f 10747/10925/10066 10810/10988/10129 10809/10987/10128 +f 10748/10926/10067 10811/10989/10130 10810/10988/10129 +f 10749/10927/10068 10812/10990/10131 10811/10989/10130 +f 10750/10928/10069 10813/10991/10132 10812/10990/10131 +f 10751/10929/10070 10814/10992/10133 10813/10991/10132 +f 10752/10930/10071 10815/10993/10134 10814/10992/10133 +f 10753/10931/10072 10816/10994/10135 10815/10993/10134 +f 10754/10932/10073 10817/10995/10136 10816/10994/10135 +f 10755/10933/10074 10818/10996/10137 10817/10995/10136 +f 10756/10934/10075 10819/10997/10138 10818/10996/10137 +f 10757/10935/10076 10820/10998/10139 10819/10997/10138 +f 10758/10936/10077 10821/10999/10140 10820/10998/10139 +f 10759/10937/10078 10822/11000/10141 10821/10999/10140 +f 10760/10938/10079 10823/11001/10142 10822/11000/10141 +f 10761/10939/10080 10824/11002/10143 10823/11001/10142 +f 10762/10940/10081 10825/11003/10144 10824/11002/10143 +f 10763/10941/10082 10826/11004/10145 10825/11003/10144 +f 10764/10942/10083 10827/11005/10146 10826/11004/10145 +f 10765/10943/10084 10828/11006/10147 10827/11005/10146 +f 10766/10944/10085 10829/11007/10148 10828/11006/10147 +f 10767/10945/10086 10830/11008/10149 10829/11007/10148 +f 10768/10946/10087 10831/11009/10150 10830/11008/10149 +f 10769/10947/10088 10832/11010/10151 10831/11009/10150 +f 10770/10948/10089 10833/11011/10152 10832/11010/10151 +f 10771/10949/10090 10834/11012/10153 10833/11011/10152 +f 10772/10950/10091 10835/11013/10154 10834/11012/10153 +f 10773/10951/10092 10836/11014/10155 10835/11013/10154 +f 10774/10952/10093 10837/11015/10156 10836/11014/10155 +f 10775/10953/10094 10838/11016/10157 10837/11015/10156 +f 10776/10954/10095 10839/11017/10158 10838/11016/10157 +f 10777/10955/10096 10840/11019/10160 10839/11017/10158 +f 10777/10955/10096 10778/10956/10097 10841/11018/10159 +f 10779/10957/10098 10842/11020/10161 10841/11018/10159 +f 10780/10958/10099 10843/11021/10162 10842/11020/10161 +f 10781/10959/10100 10844/11022/10163 10843/11021/10162 +f 10782/10960/10101 10845/11023/10164 10844/11022/10163 +f 10783/10961/10102 10846/11024/10165 10845/11023/10164 +f 10784/10962/10103 10847/11025/10166 10846/11024/10165 +f 10785/10963/10104 10848/11026/10167 10847/11025/10166 +f 10786/10965/10106 10849/11028/10169 10848/11026/10167 +f 10787/11027/10168 10850/11090/10231 10849/11028/10169 +f 10789/10967/10108 10852/11030/10171 10851/11029/10170 +f 10790/10968/10109 10853/11031/10172 10852/11030/10171 +f 10791/10969/10110 10854/11032/10173 10853/11031/10172 +f 10792/10970/10111 10855/11033/10174 10854/11032/10173 +f 10793/10971/10112 10856/11034/10175 10855/11033/10174 +f 10794/10972/10113 10857/11035/10176 10856/11034/10175 +f 10795/10973/10114 10858/11036/10177 10857/11035/10176 +f 10796/10974/10115 10859/11037/10178 10858/11036/10177 +f 10797/10975/10116 10860/11038/10179 10859/11037/10178 +f 10798/10976/10117 10861/11039/10180 10860/11038/10179 +f 10799/10977/10118 10862/11040/10181 10861/11039/10180 +f 10800/10978/10119 10863/11041/10182 10862/11040/10181 +f 10801/10979/10120 10864/11042/10183 10863/11041/10182 +f 10802/10980/10121 10865/11043/10184 10864/11042/10183 +f 10803/10981/10122 10866/11044/10185 10865/11043/10184 +f 10804/10982/10123 10867/11045/10186 10866/11044/10185 +f 10805/10983/10124 10868/11046/10187 10867/11045/10186 +f 10806/10984/10125 10869/11047/10188 10868/11046/10187 +f 10807/10985/10126 10870/11048/10189 10869/11047/10188 +f 10808/10986/10127 10871/11049/10190 10870/11048/10189 +f 10809/10987/10128 10872/11050/10191 10871/11049/10190 +f 10810/10988/10129 10873/11051/10192 10872/11050/10191 +f 10811/10989/10130 10874/11052/10193 10873/11051/10192 +f 10812/10990/10131 10875/11053/10194 10874/11052/10193 +f 10813/10991/10132 10876/11054/10195 10875/11053/10194 +f 10814/10992/10133 10877/11055/10196 10876/11054/10195 +f 10815/10993/10134 10878/11056/10197 10877/11055/10196 +f 10816/10994/10135 10879/11057/10198 10878/11056/10197 +f 10817/10995/10136 10880/11058/10199 10879/11057/10198 +f 10818/10996/10137 10881/11059/10200 10880/11058/10199 +f 10819/10997/10138 10882/11060/10201 10881/11059/10200 +f 10820/10998/10139 10883/11061/10202 10882/11060/10201 +f 10821/10999/10140 10884/11062/10203 10883/11061/10202 +f 10822/11000/10141 10885/11063/10204 10884/11062/10203 +f 10823/11001/10142 10886/11064/10205 10885/11063/10204 +f 10824/11002/10143 10887/11065/10206 10886/11064/10205 +f 10825/11003/10144 10888/11066/10207 10887/11065/10206 +f 10826/11004/10145 10889/11067/10208 10888/11066/10207 +f 10827/11005/10146 10890/11068/10209 10889/11067/10208 +f 10828/11006/10147 10891/11069/10210 10890/11068/10209 +f 10829/11007/10148 10892/11070/10211 10891/11069/10210 +f 10830/11008/10149 10893/11071/10212 10892/11070/10211 +f 10831/11009/10150 10894/11072/10213 10893/11071/10212 +f 10832/11010/10151 10895/11073/10214 10894/11072/10213 +f 10833/11011/10152 10896/11074/10215 10895/11073/10214 +f 10834/11012/10153 10897/11075/10216 10896/11074/10215 +f 10835/11013/10154 10898/11076/10217 10897/11075/10216 +f 10836/11014/10155 10899/11077/10218 10898/11076/10217 +f 10837/11015/10156 10900/11078/10219 10899/11077/10218 +f 10838/11016/10157 10901/11079/10220 10900/11078/10219 +f 10839/11017/10158 10902/11080/10221 10901/11079/10220 +f 10840/11019/10160 10903/11081/10222 10902/11080/10221 +f 10841/11018/10159 10904/11082/10223 10903/11081/10222 +f 10842/11020/10161 10905/11083/10224 10904/11082/10223 +f 10843/11021/10162 10906/11084/10225 10905/11083/10224 +f 10844/11022/10163 10907/11085/10226 10906/11084/10225 +f 10845/11023/10164 10908/11086/10227 10907/11085/10226 +f 10846/11024/10165 10909/11087/10228 10908/11086/10227 +f 10847/11025/10166 10910/11088/10229 10909/11087/10228 +f 10848/11026/10167 10911/11089/10230 10910/11088/10229 +f 10849/11028/10169 10912/11091/10232 10911/11089/10230 +f 10850/11090/10231 10913/11153/10294 10912/11091/10232 +f 10852/11030/10171 10915/11093/10234 10914/11092/10233 +f 10853/11031/10172 10916/11094/10235 10915/11093/10234 +f 10854/11032/10173 10917/11095/10236 10916/11094/10235 +f 10855/11033/10174 10918/11096/10237 10917/11095/10236 +f 10856/11034/10175 10919/11097/10238 10918/11096/10237 +f 10857/11035/10176 10920/11098/10239 10919/11097/10238 +f 10858/11036/10177 10921/11099/10240 10920/11098/10239 +f 10859/11037/10178 10922/11100/10241 10921/11099/10240 +f 10860/11038/10179 10923/11101/10242 10922/11100/10241 +f 10861/11039/10180 10924/11102/10243 10923/11101/10242 +f 10862/11040/10181 10925/11103/10244 10924/11102/10243 +f 10863/11041/10182 10926/11104/10245 10925/11103/10244 +f 10864/11042/10183 10927/11105/10246 10926/11104/10245 +f 10865/11043/10184 10928/11106/10247 10927/11105/10246 +f 10866/11044/10185 10929/11107/10248 10928/11106/10247 +f 10867/11045/10186 10930/11108/10249 10929/11107/10248 +f 10868/11046/10187 10931/11109/10250 10930/11108/10249 +f 10869/11047/10188 10932/11110/10251 10931/11109/10250 +f 10870/11048/10189 10933/11111/10252 10932/11110/10251 +f 10871/11049/10190 10934/11112/10253 10933/11111/10252 +f 10872/11050/10191 10935/11113/10254 10934/11112/10253 +f 10873/11051/10192 10936/11114/10255 10935/11113/10254 +f 10874/11052/10193 10937/11115/10256 10936/11114/10255 +f 10875/11053/10194 10938/11116/10257 10937/11115/10256 +f 10876/11054/10195 10939/11117/10258 10938/11116/10257 +f 10877/11055/10196 10940/11118/10259 10939/11117/10258 +f 10878/11056/10197 10941/11119/10260 10940/11118/10259 +f 10879/11057/10198 10942/11120/10261 10941/11119/10260 +f 10880/11058/10199 10943/11121/10262 10942/11120/10261 +f 10881/11059/10200 10944/11122/10263 10943/11121/10262 +f 10882/11060/10201 10945/11123/10264 10944/11122/10263 +f 10883/11061/10202 10946/11124/10265 10945/11123/10264 +f 10884/11062/10203 10947/11125/10266 10946/11124/10265 +f 10885/11063/10204 10948/11126/10267 10947/11125/10266 +f 10886/11064/10205 10949/11127/10268 10948/11126/10267 +f 10887/11065/10206 10950/11128/10269 10949/11127/10268 +f 10888/11066/10207 10951/11129/10270 10950/11128/10269 +f 10889/11067/10208 10952/11130/10271 10951/11129/10270 +f 10890/11068/10209 10953/11131/10272 10952/11130/10271 +f 10891/11069/10210 10954/11132/10273 10953/11131/10272 +f 10892/11070/10211 10955/11133/10274 10954/11132/10273 +f 10893/11071/10212 10956/11134/10275 10955/11133/10274 +f 10894/11072/10213 10957/11135/10276 10956/11134/10275 +f 10895/11073/10214 10958/11136/10277 10957/11135/10276 +f 10896/11074/10215 10959/11137/10278 10958/11136/10277 +f 10897/11075/10216 10960/11138/10279 10959/11137/10278 +f 10898/11076/10217 10961/11139/10280 10960/11138/10279 +f 10899/11077/10218 10962/11140/10281 10961/11139/10280 +f 10900/11078/10219 10963/11141/10282 10962/11140/10281 +f 10901/11079/10220 10964/11142/10283 10963/11141/10282 +f 10902/11080/10221 10965/11143/10284 10964/11142/10283 +f 10903/11081/10222 10966/11144/10285 10965/11143/10284 +f 10904/11082/10223 10967/11145/10286 10966/11144/10285 +f 10905/11083/10224 10968/11146/10287 10967/11145/10286 +f 10906/11084/10225 10969/11147/10288 10968/11146/10287 +f 10907/11085/10226 10970/11148/10289 10969/11147/10288 +f 10908/11086/10227 10971/11149/10290 10970/11148/10289 +f 10909/11087/10228 10972/11150/10291 10971/11149/10290 +f 10910/11088/10229 10973/11151/10292 10972/11150/10291 +f 10911/11089/10230 10974/11152/10293 10973/11151/10292 +f 10912/11091/10232 10975/11154/10295 10974/11152/10293 +f 10913/11153/10294 10976/11216/10356 10975/11154/10295 +f 10915/11093/10234 10978/11156/10297 10977/11155/10296 +f 10916/11094/10235 10979/11157/10298 10978/11156/10297 +f 10917/11095/10236 10980/11158/10299 10979/11157/10298 +f 10918/11096/10237 10981/11159/10300 10980/11158/10299 +f 10919/11097/10238 10982/11160/10301 10981/11159/10300 +f 10920/11098/10239 10983/11161/10302 10982/11160/10301 +f 10921/11099/10240 10984/11162/10303 10983/11161/10302 +f 10922/11100/10241 10985/11163/10304 10984/11162/10303 +f 10923/11101/10242 10986/11164/10305 10985/11163/10304 +f 10924/11102/10243 10987/11165/10306 10986/11164/10305 +f 10925/11103/10244 10988/11166/10307 10987/11165/10306 +f 10926/11104/10245 10989/11167/10308 10988/11166/10307 +f 10927/11105/10246 10990/11168/10309 10989/11167/10308 +f 10928/11106/10247 10991/11169/10310 10990/11168/10309 +f 10929/11107/10248 10992/11170/10311 10991/11169/10310 +f 10930/11108/10249 10993/11171/10312 10992/11170/10311 +f 10931/11109/10250 10994/11172/10313 10993/11171/10312 +f 10932/11110/10251 10995/11173/10314 10994/11172/10313 +f 10933/11111/10252 10996/11174/7560 10995/11173/10314 +f 10934/11112/10253 10997/11175/10315 10996/11174/7560 +f 10935/11113/10254 10998/11176/10316 10997/11175/10315 +f 10936/11114/10255 10999/11177/10317 10998/11176/10316 +f 10937/11115/10256 11000/11178/10318 10999/11177/10317 +f 10938/11116/10257 11001/11179/10319 11000/11178/10318 +f 10939/11117/10258 11002/11180/10320 11001/11179/10319 +f 10940/11118/10259 11003/11181/10321 11002/11180/10320 +f 10941/11119/10260 11004/11182/10322 11003/11181/10321 +f 10942/11120/10261 11005/11183/10323 11004/11182/10322 +f 10943/11121/10262 11006/11184/10324 11005/11183/10323 +f 10944/11122/10263 11007/11185/10325 11006/11184/10324 +f 10945/11123/10264 11008/11186/10326 11007/11185/10325 +f 10946/11124/10265 11009/11187/10327 11008/11186/10326 +f 10947/11125/10266 11010/11188/10328 11009/11187/10327 +f 10948/11126/10267 11011/11189/10329 11010/11188/10328 +f 10949/11127/10268 11012/11190/10330 11011/11189/10329 +f 10950/11128/10269 11013/11191/10331 11012/11190/10330 +f 10951/11129/10270 11014/11192/10332 11013/11191/10331 +f 10952/11130/10271 11015/11193/10333 11014/11192/10332 +f 10953/11131/10272 11016/11194/10334 11015/11193/10333 +f 10954/11132/10273 11017/11195/10335 11016/11194/10334 +f 10955/11133/10274 11018/11196/10336 11017/11195/10335 +f 10956/11134/10275 11019/11197/10337 11018/11196/10336 +f 10957/11135/10276 11020/11198/10338 11019/11197/10337 +f 10958/11136/10277 11021/11199/10339 11020/11198/10338 +f 10959/11137/10278 11022/11200/10340 11021/11199/10339 +f 10960/11138/10279 11023/11201/10341 11022/11200/10340 +f 10961/11139/10280 11024/11202/10342 11023/11201/10341 +f 10962/11140/10281 11025/11203/10343 11024/11202/10342 +f 10963/11141/10282 11026/11204/10344 11025/11203/10343 +f 10964/11142/10283 11027/11205/10345 11026/11204/10344 +f 10965/11143/10284 11028/11206/10346 11027/11205/10345 +f 10966/11144/10285 11029/11207/10347 11028/11206/10346 +f 10967/11145/10286 11030/11208/10348 11029/11207/10347 +f 10968/11146/10287 11031/11209/10349 11030/11208/10348 +f 10969/11147/10288 11032/11210/10350 11031/11209/10349 +f 10970/11148/10289 11033/11211/10351 11032/11210/10350 +f 10971/11149/10290 11034/11212/10352 11033/11211/10351 +f 10972/11150/10291 11035/11213/10353 11034/11212/10352 +f 10973/11151/10292 11036/11214/10354 11035/11213/10353 +f 10974/11152/10293 11037/11215/10355 11036/11214/10354 +f 10975/11154/10295 11038/11217/10357 11037/11215/10355 +f 10976/11216/10356 11039/11279/10418 11038/11217/10357 +f 10978/11156/10297 11041/11219/10359 11040/11218/10358 +f 10979/11157/10298 11042/11220/10360 11041/11219/10359 +f 10980/11158/10299 11043/11221/10361 11042/11220/10360 +f 10981/11159/10300 11044/11222/10362 11043/11221/10361 +f 10982/11160/10301 11045/11223/10363 11044/11222/10362 +f 10983/11161/10302 11046/11224/10364 11045/11223/10363 +f 10984/11162/10303 11047/11225/10365 11046/11224/10364 +f 10985/11163/10304 11048/11226/10366 11047/11225/10365 +f 10986/11164/10305 11049/11227/10367 11048/11226/10366 +f 10987/11165/10306 11050/11228/10368 11049/11227/10367 +f 10988/11166/10307 11051/11229/10369 11050/11228/10368 +f 10989/11167/10308 11052/11230/10370 11051/11229/10369 +f 10990/11168/10309 11053/11231/10371 11052/11230/10370 +f 10991/11169/10310 11054/11232/10372 11053/11231/10371 +f 10992/11170/10311 11055/11233/10373 11054/11232/10372 +f 10993/11171/10312 11056/11234/10374 11055/11233/10373 +f 10994/11172/10313 11057/11235/7559 11056/11234/10374 +f 10995/11173/10314 11058/11236/10375 11057/11235/7559 +f 10996/11174/7560 11059/11237/10376 11058/11236/10375 +f 10997/11175/10315 11060/11238/10377 11059/11237/10376 +f 10998/11176/10316 11061/11239/10378 11060/11238/10377 +f 10999/11177/10317 11062/11240/10379 11061/11239/10378 +f 11000/11178/10318 11063/11241/10380 11062/11240/10379 +f 11001/11179/10319 11064/11242/10381 11063/11241/10380 +f 11002/11180/10320 11065/11243/10382 11064/11242/10381 +f 11003/11181/10321 11066/11244/10383 11065/11243/10382 +f 11004/11182/10322 11067/11245/10384 11066/11244/10383 +f 11005/11183/10323 11068/11246/10385 11067/11245/10384 +f 11006/11184/10324 11069/11247/10386 11068/11246/10385 +f 11007/11185/10325 11070/11248/10387 11069/11247/10386 +f 11008/11186/10326 11071/11249/10388 11070/11248/10387 +f 11009/11187/10327 11072/11250/10389 11071/11249/10388 +f 11010/11188/10328 11073/11251/10390 11072/11250/10389 +f 11011/11189/10329 11074/11252/10391 11073/11251/10390 +f 11012/11190/10330 11075/11253/10392 11074/11252/10391 +f 11013/11191/10331 11076/11254/10393 11075/11253/10392 +f 11014/11192/10332 11077/11255/10394 11076/11254/10393 +f 11015/11193/10333 11078/11256/10395 11077/11255/10394 +f 11016/11194/10334 11079/11257/10396 11078/11256/10395 +f 11017/11195/10335 11080/11258/10397 11079/11257/10396 +f 11018/11196/10336 11081/11259/10398 11080/11258/10397 +f 11019/11197/10337 11082/11260/10399 11081/11259/10398 +f 11020/11198/10338 11083/11261/10400 11082/11260/10399 +f 11021/11199/10339 11084/11262/10401 11083/11261/10400 +f 11022/11200/10340 11085/11263/10402 11084/11262/10401 +f 11023/11201/10341 11086/11264/10403 11085/11263/10402 +f 11024/11202/10342 11087/11265/10404 11086/11264/10403 +f 11025/11203/10343 11088/11266/10405 11087/11265/10404 +f 11026/11204/10344 11089/11267/10406 11088/11266/10405 +f 11027/11205/10345 11090/11268/10407 11089/11267/10406 +f 11028/11206/10346 11091/11269/10408 11090/11268/10407 +f 11029/11207/10347 11092/11270/10409 11091/11269/10408 +f 11030/11208/10348 11093/11271/10410 11092/11270/10409 +f 11031/11209/10349 11094/11272/10411 11093/11271/10410 +f 11032/11210/10350 11095/11273/10412 11094/11272/10411 +f 11033/11211/10351 11096/11274/10413 11095/11273/10412 +f 11034/11212/10352 11097/11275/10414 11096/11274/10413 +f 11035/11213/10353 11098/11276/10415 11097/11275/10414 +f 11036/11214/10354 11099/11277/10416 11098/11276/10415 +f 11037/11215/10355 11100/11278/10417 11099/11277/10416 +f 11038/11217/10357 11101/11280/10419 11100/11278/10417 +f 11039/11279/10418 11102/11342/10480 11101/11280/10419 +f 11041/11219/10359 11104/11282/10421 11103/11281/10420 +f 11042/11220/10360 11105/11283/10422 11104/11282/10421 +f 11043/11221/10361 11106/11284/10423 11105/11283/10422 +f 11044/11222/10362 11107/11285/10424 11106/11284/10423 +f 11045/11223/10363 11108/11286/10425 11107/11285/10424 +f 11046/11224/10364 11109/11287/10426 11108/11286/10425 +f 11047/11225/10365 11110/11288/10427 11109/11287/10426 +f 11048/11226/10366 11111/11289/10428 11110/11288/10427 +f 11049/11227/10367 11112/11290/10429 11111/11289/10428 +f 11050/11228/10368 11113/11291/10430 11112/11290/10429 +f 11051/11229/10369 11114/11292/10431 11113/11291/10430 +f 11052/11230/10370 11115/11293/10432 11114/11292/10431 +f 11053/11231/10371 11116/11294/10433 11115/11293/10432 +f 11054/11232/10372 11117/11295/10434 11116/11294/10433 +f 11055/11233/10373 11118/11296/10435 11117/11295/10434 +f 11056/11234/10374 11119/11297/10436 11118/11296/10435 +f 11057/11235/7559 11120/11298/10437 11119/11297/10436 +f 11058/11236/10375 11121/11299/10438 11120/11298/10437 +f 11059/11237/10376 11122/11300/10439 11121/11299/10438 +f 11060/11238/10377 11123/11301/10440 11122/11300/10439 +f 11061/11239/10378 11124/11302/10441 11123/11301/10440 +f 11062/11240/10379 11125/11303/10442 11124/11302/10441 +f 11063/11241/10380 11126/11304/10443 11125/11303/10442 +f 11064/11242/10381 11127/11305/10444 11126/11304/10443 +f 11065/11243/10382 11128/11306/10445 11127/11305/10444 +f 11066/11244/10383 11129/11307/10446 11128/11306/10445 +f 11067/11245/10384 11130/11308/10447 11129/11307/10446 +f 11068/11246/10385 11131/11309/10448 11130/11308/10447 +f 11069/11247/10386 11132/11310/10449 11131/11309/10448 +f 11070/11248/10387 11133/11311/10450 11132/11310/10449 +f 11071/11249/10388 11134/11312/10451 11133/11311/10450 +f 11072/11250/10389 11135/11313/10452 11134/11312/10451 +f 11073/11251/10390 11136/11314/10453 11135/11313/10452 +f 11074/11252/10391 11137/11315/10454 11136/11314/10453 +f 11075/11253/10392 11138/11316/10455 11137/11315/10454 +f 11076/11254/10393 11139/11317/10169 11138/11316/10455 +f 11077/11255/10394 11140/11318/10456 11139/11317/10169 +f 11078/11256/10395 11141/11319/10457 11140/11318/10456 +f 11079/11257/10396 11142/11320/10458 11141/11319/10457 +f 11080/11258/10397 11143/11321/10459 11142/11320/10458 +f 11081/11259/10398 11144/11322/10460 11143/11321/10459 +f 11082/11260/10399 11145/11323/10461 11144/11322/10460 +f 11083/11261/10400 11146/11324/10462 11145/11323/10461 +f 11084/11262/10401 11147/11325/10463 11146/11324/10462 +f 11085/11263/10402 11148/11326/10464 11147/11325/10463 +f 11086/11264/10403 11149/11327/10465 11148/11326/10464 +f 11087/11265/10404 11150/11328/10466 11149/11327/10465 +f 11088/11266/10405 11151/11329/10467 11150/11328/10466 +f 11089/11267/10406 11152/11330/10468 11151/11329/10467 +f 11090/11268/10407 11153/11331/10469 11152/11330/10468 +f 11091/11269/10408 11154/11332/10470 11153/11331/10469 +f 11092/11270/10409 11155/11333/10471 11154/11332/10470 +f 11093/11271/10410 11156/11334/10472 11155/11333/10471 +f 11094/11272/10411 11157/11335/10473 11156/11334/10472 +f 11095/11273/10412 11158/11336/10474 11157/11335/10473 +f 11096/11274/10413 11159/11337/10475 11158/11336/10474 +f 11097/11275/10414 11160/11338/10476 11159/11337/10475 +f 11098/11276/10415 11161/11339/10477 11160/11338/10476 +f 11099/11277/10416 11162/11340/10478 11161/11339/10477 +f 11100/11278/10417 11163/11341/10479 11162/11340/10478 +f 11101/11280/10419 11164/11343/10481 11163/11341/10479 +f 11102/11342/10480 11165/11405/10543 11164/11343/10481 +f 11104/11282/10421 11167/11345/10483 11166/11344/10482 +f 11105/11283/10422 11168/11346/10484 11167/11345/10483 +f 11106/11284/10423 11169/11347/10485 11168/11346/10484 +f 11107/11285/10424 11170/11348/10486 11169/11347/10485 +f 11108/11286/10425 11171/11349/10487 11170/11348/10486 +f 11109/11287/10426 11172/11350/10488 11171/11349/10487 +f 11110/11288/10427 11173/11351/10489 11172/11350/10488 +f 11111/11289/10428 11174/11352/10490 11173/11351/10489 +f 11112/11290/10429 11175/11353/10491 11174/11352/10490 +f 11113/11291/10430 11176/11354/10492 11175/11353/10491 +f 11114/11292/10431 11177/11355/10493 11176/11354/10492 +f 11115/11293/10432 11178/11356/10494 11177/11355/10493 +f 11116/11294/10433 11179/11357/10495 11178/11356/10494 +f 11117/11295/10434 11180/11358/10496 11179/11357/10495 +f 11118/11296/10435 11181/11359/10497 11180/11358/10496 +f 11119/11297/10436 11182/11360/10498 11181/11359/10497 +f 11120/11298/10437 11183/11361/10499 11182/11360/10498 +f 11121/11299/10438 11184/11362/10500 11183/11361/10499 +f 11122/11300/10439 11185/11363/10501 11184/11362/10500 +f 11123/11301/10440 11186/11364/10502 11185/11363/10501 +f 11124/11302/10441 11187/11365/10503 11186/11364/10502 +f 11125/11303/10442 11188/11366/10504 11187/11365/10503 +f 11126/11304/10443 11189/11367/10505 11188/11366/10504 +f 11127/11305/10444 11190/11368/10506 11189/11367/10505 +f 11128/11306/10445 11191/11369/10507 11190/11368/10506 +f 11129/11307/10446 11192/11370/10508 11191/11369/10507 +f 11130/11308/10447 11193/11371/10509 11192/11370/10508 +f 11131/11309/10448 11194/11372/10510 11193/11371/10509 +f 11132/11310/10449 11195/11373/10511 11194/11372/10510 +f 11133/11311/10450 11196/11374/10512 11195/11373/10511 +f 11134/11312/10451 11197/11375/10513 11196/11374/10512 +f 11135/11313/10452 11198/11376/10514 11197/11375/10513 +f 11136/11314/10453 11199/11377/10515 11198/11376/10514 +f 11137/11315/10454 11200/11378/10516 11199/11377/10515 +f 11138/11316/10455 11201/11379/10517 11200/11378/10516 +f 11139/11317/10169 11202/11380/10518 11201/11379/10517 +f 11140/11318/10456 11203/11381/10519 11202/11380/10518 +f 11141/11319/10457 11204/11382/10520 11203/11381/10519 +f 11142/11320/10458 11205/11383/10521 11204/11382/10520 +f 11143/11321/10459 11206/11384/10522 11205/11383/10521 +f 11144/11322/10460 11207/11385/10523 11206/11384/10522 +f 11145/11323/10461 11208/11386/10524 11207/11385/10523 +f 11146/11324/10462 11209/11387/10525 11208/11386/10524 +f 11147/11325/10463 11210/11388/10526 11209/11387/10525 +f 11148/11326/10464 11211/11389/10527 11210/11388/10526 +f 11149/11327/10465 11212/11390/10528 11211/11389/10527 +f 11150/11328/10466 11213/11391/10529 11212/11390/10528 +f 11151/11329/10467 11214/11392/10530 11213/11391/10529 +f 11152/11330/10468 11215/11393/10531 11214/11392/10530 +f 11153/11331/10469 11216/11394/10532 11215/11393/10531 +f 11154/11332/10470 11217/11395/10533 11216/11394/10532 +f 11155/11333/10471 11218/11396/10534 11217/11395/10533 +f 11156/11334/10472 11219/11397/10535 11218/11396/10534 +f 11157/11335/10473 11220/11398/10536 11219/11397/10535 +f 11158/11336/10474 11221/11399/10537 11220/11398/10536 +f 11159/11337/10475 11222/11400/10538 11221/11399/10537 +f 11160/11338/10476 11223/11401/10539 11222/11400/10538 +f 11161/11339/10477 11224/11402/10540 11223/11401/10539 +f 11162/11340/10478 11225/11403/10541 11224/11402/10540 +f 11163/11341/10479 11226/11404/10542 11225/11403/10541 +f 11164/11343/10481 11227/11406/10544 11226/11404/10542 +f 11165/11405/10543 11228/11468/10605 11227/11406/10544 +f 11167/11345/10483 11230/11408/10546 11229/11407/10545 +f 11168/11346/10484 11231/11409/10547 11230/11408/10546 +f 11169/11347/10485 11232/11410/10548 11231/11409/10547 +f 11170/11348/10486 11233/11411/10549 11232/11410/10548 +f 11171/11349/10487 11234/11412/10550 11233/11411/10549 +f 11172/11350/10488 11235/11413/10551 11234/11412/10550 +f 11173/11351/10489 11236/11414/10552 11235/11413/10551 +f 11174/11352/10490 11237/11415/10553 11236/11414/10552 +f 11175/11353/10491 11238/11416/10554 11237/11415/10553 +f 11176/11354/10492 11239/11417/10555 11238/11416/10554 +f 11177/11355/10493 11240/11418/10556 11239/11417/10555 +f 11178/11356/10494 11241/11419/10557 11240/11418/10556 +f 11179/11357/10495 11242/11420/10558 11241/11419/10557 +f 11180/11358/10496 11243/11421/10559 11242/11420/10558 +f 11181/11359/10497 11244/11422/10560 11243/11421/10559 +f 11182/11360/10498 11245/11423/10561 11244/11422/10560 +f 11183/11361/10499 11246/11424/10562 11245/11423/10561 +f 11184/11362/10500 11247/11425/10563 11246/11424/10562 +f 11185/11363/10501 11248/11426/10564 11247/11425/10563 +f 11186/11364/10502 11249/11427/10565 11248/11426/10564 +f 11187/11365/10503 11250/11428/10566 11249/11427/10565 +f 11188/11366/10504 11251/11429/10567 11250/11428/10566 +f 11189/11367/10505 11252/11430/10568 11251/11429/10567 +f 11190/11368/10506 11253/11431/10569 11252/11430/10568 +f 11191/11369/10507 11254/11432/10488 11253/11431/10569 +f 11192/11370/10508 11255/11433/10570 11254/11432/10488 +f 11193/11371/10509 11256/11434/10571 11255/11433/10570 +f 11194/11372/10510 11257/11435/10572 11256/11434/10571 +f 11195/11373/10511 11258/11436/10573 11257/11435/10572 +f 11196/11374/10512 11259/11437/10574 11258/11436/10573 +f 11197/11375/10513 11260/11438/10575 11259/11437/10574 +f 11198/11376/10514 11261/11439/10576 11260/11438/10575 +f 11199/11377/10515 11262/11440/10577 11261/11439/10576 +f 11200/11378/10516 11263/11441/10578 11262/11440/10577 +f 11201/11379/10517 11264/11442/10579 11263/11441/10578 +f 11202/11380/10518 11265/11443/10580 11264/11442/10579 +f 11203/11381/10519 11266/11444/10581 11265/11443/10580 +f 11204/11382/10520 11267/11445/10582 11266/11444/10581 +f 11205/11383/10521 11268/11446/10583 11267/11445/10582 +f 11206/11384/10522 11269/11447/10584 11268/11446/10583 +f 11207/11385/10523 11270/11448/10585 11269/11447/10584 +f 11208/11386/10524 11271/11449/10586 11270/11448/10585 +f 11209/11387/10525 11272/11450/10587 11271/11449/10586 +f 11210/11388/10526 11273/11451/10588 11272/11450/10587 +f 11211/11389/10527 11274/11452/10589 11273/11451/10588 +f 11212/11390/10528 11275/11453/10590 11274/11452/10589 +f 11213/11391/10529 11276/11454/10591 11275/11453/10590 +f 11214/11392/10530 11277/11455/10592 11276/11454/10591 +f 11215/11393/10531 11278/11456/10593 11277/11455/10592 +f 11216/11394/10532 11279/11457/10594 11278/11456/10593 +f 11217/11395/10533 11280/11458/10595 11279/11457/10594 +f 11218/11396/10534 11281/11459/10596 11280/11458/10595 +f 11219/11397/10535 11282/11460/10597 11281/11459/10596 +f 11220/11398/10536 11283/11461/10598 11282/11460/10597 +f 11221/11399/10537 11284/11462/10599 11283/11461/10598 +f 11222/11400/10538 11285/11463/10600 11284/11462/10599 +f 11223/11401/10539 11286/11464/10601 11285/11463/10600 +f 11224/11402/10540 11287/11465/10602 11286/11464/10601 +f 11225/11403/10541 11288/11466/10603 11287/11465/10602 +f 11226/11404/10542 11289/11467/10604 11288/11466/10603 +f 11227/11406/10544 11290/11469/10606 11289/11467/10604 +f 11228/11468/10605 11291/11531/10668 11290/11469/10606 +f 11230/11408/10546 11293/11471/10608 11292/11470/10607 +f 11231/11409/10547 11294/11472/10609 11293/11471/10608 +f 11232/11410/10548 11295/11473/10610 11294/11472/10609 +f 11233/11411/10549 11296/11474/10611 11295/11473/10610 +f 11234/11412/10550 11297/11475/10612 11296/11474/10611 +f 11235/11413/10551 11298/11476/10613 11297/11475/10612 +f 11236/11414/10552 11299/11477/10614 11298/11476/10613 +f 11237/11415/10553 11300/11478/10615 11299/11477/10614 +f 11238/11416/10554 11301/11479/10616 11300/11478/10615 +f 11239/11417/10555 11302/11480/10617 11301/11479/10616 +f 11240/11418/10556 11303/11481/10618 11302/11480/10617 +f 11241/11419/10557 11304/11482/10619 11303/11481/10618 +f 11242/11420/10558 11305/11483/10620 11304/11482/10619 +f 11243/11421/10559 11306/11484/10621 11305/11483/10620 +f 11244/11422/10560 11307/11485/10622 11306/11484/10621 +f 11245/11423/10561 11308/11486/10623 11307/11485/10622 +f 11246/11424/10562 11309/11487/10624 11308/11486/10623 +f 11247/11425/10563 11310/11488/10625 11309/11487/10624 +f 11248/11426/10564 11311/11489/10626 11310/11488/10625 +f 11249/11427/10565 11312/11490/10627 11311/11489/10626 +f 11250/11428/10566 11313/11491/10628 11312/11490/10627 +f 11251/11429/10567 11314/11492/10629 11313/11491/10628 +f 11252/11430/10568 11315/11493/10630 11314/11492/10629 +f 11253/11431/10569 11316/11494/10631 11315/11493/10630 +f 11254/11432/10488 11317/11495/10632 11316/11494/10631 +f 11255/11433/10570 11318/11496/10633 11317/11495/10632 +f 11256/11434/10571 11319/11497/10634 11318/11496/10633 +f 11257/11435/10572 11320/11498/10635 11319/11497/10634 +f 11258/11436/10573 11321/11499/10636 11320/11498/10635 +f 11259/11437/10574 11322/11500/10637 11321/11499/10636 +f 11260/11438/10575 11323/11501/10638 11322/11500/10637 +f 11261/11439/10576 11324/11502/10639 11323/11501/10638 +f 11262/11440/10577 11325/11503/10640 11324/11502/10639 +f 11263/11441/10578 11326/11504/10641 11325/11503/10640 +f 11264/11442/10579 11327/11505/10642 11326/11504/10641 +f 11265/11443/10580 11328/11506/10643 11327/11505/10642 +f 11266/11444/10581 11329/11507/10644 11328/11506/10643 +f 11267/11445/10582 11330/11508/10645 11329/11507/10644 +f 11268/11446/10583 11331/11509/10646 11330/11508/10645 +f 11269/11447/10584 11332/11510/10647 11331/11509/10646 +f 11270/11448/10585 11333/11511/10648 11332/11510/10647 +f 11271/11449/10586 11334/11512/10649 11333/11511/10648 +f 11272/11450/10587 11335/11513/10650 11334/11512/10649 +f 11273/11451/10588 11336/11514/10651 11335/11513/10650 +f 11274/11452/10589 11337/11515/10652 11336/11514/10651 +f 11275/11453/10590 11338/11516/10653 11337/11515/10652 +f 11276/11454/10591 11339/11517/10654 11338/11516/10653 +f 11277/11455/10592 11340/11518/10655 11339/11517/10654 +f 11278/11456/10593 11341/11519/10656 11340/11518/10655 +f 11279/11457/10594 11342/11520/10657 11341/11519/10656 +f 11280/11458/10595 11343/11521/10658 11342/11520/10657 +f 11281/11459/10596 11344/11522/10659 11343/11521/10658 +f 11282/11460/10597 11345/11523/10660 11344/11522/10659 +f 11283/11461/10598 11346/11524/10661 11345/11523/10660 +f 11284/11462/10599 11347/11525/10662 11346/11524/10661 +f 11285/11463/10600 11348/11526/10663 11347/11525/10662 +f 11286/11464/10601 11349/11527/10664 11348/11526/10663 +f 11287/11465/10602 11350/11528/10665 11349/11527/10664 +f 11288/11466/10603 11351/11529/10666 11350/11528/10665 +f 11289/11467/10604 11352/11530/10667 11351/11529/10666 +f 11290/11469/10606 11353/11532/10669 11352/11530/10667 +f 11291/11531/10668 11354/11594/10731 11353/11532/10669 +f 11293/11471/10608 11356/11534/10671 11355/11533/10670 +f 11294/11472/10609 11357/11535/10672 11356/11534/10671 +f 11295/11473/10610 11358/11536/10673 11357/11535/10672 +f 11296/11474/10611 11359/11537/10674 11358/11536/10673 +f 11297/11475/10612 11360/11538/10675 11359/11537/10674 +f 11298/11476/10613 11361/11539/10676 11360/11538/10675 +f 11299/11477/10614 11362/11540/10677 11361/11539/10676 +f 11300/11478/10615 11363/11541/10678 11362/11540/10677 +f 11301/11479/10616 11364/11542/10679 11363/11541/10678 +f 11302/11480/10617 11365/11543/10680 11364/11542/10679 +f 11303/11481/10618 11366/11544/10681 11365/11543/10680 +f 11304/11482/10619 11367/11545/10682 11366/11544/10681 +f 11305/11483/10620 11368/11546/10683 11367/11545/10682 +f 11306/11484/10621 11369/11547/10684 11368/11546/10683 +f 11307/11485/10622 11370/11548/10685 11369/11547/10684 +f 11308/11486/10623 11371/11549/10686 11370/11548/10685 +f 11309/11487/10624 11372/11550/10687 11371/11549/10686 +f 11310/11488/10625 11373/11551/10688 11372/11550/10687 +f 11311/11489/10626 11374/11552/10689 11373/11551/10688 +f 11312/11490/10627 11375/11553/10690 11374/11552/10689 +f 11313/11491/10628 11376/11554/10691 11375/11553/10690 +f 11314/11492/10629 11377/11555/10692 11376/11554/10691 +f 11315/11493/10630 11378/11556/10693 11377/11555/10692 +f 11316/11494/10631 11379/11557/10694 11378/11556/10693 +f 11317/11495/10632 11380/11558/10695 11379/11557/10694 +f 11318/11496/10633 11381/11559/10696 11380/11558/10695 +f 11319/11497/10634 11382/11560/10697 11381/11559/10696 +f 11320/11498/10635 11383/11561/10698 11382/11560/10697 +f 11321/11499/10636 11384/11562/10699 11383/11561/10698 +f 11322/11500/10637 11385/11563/10700 11384/11562/10699 +f 11323/11501/10638 11386/11564/10701 11385/11563/10700 +f 11324/11502/10639 11387/11565/10702 11386/11564/10701 +f 11325/11503/10640 11388/11566/10703 11387/11565/10702 +f 11326/11504/10641 11389/11567/10704 11388/11566/10703 +f 11327/11505/10642 11390/11568/10705 11389/11567/10704 +f 11328/11506/10643 11391/11569/10706 11390/11568/10705 +f 11329/11507/10644 11392/11570/10707 11391/11569/10706 +f 11330/11508/10645 11393/11571/10708 11392/11570/10707 +f 11331/11509/10646 11394/11572/10709 11393/11571/10708 +f 11332/11510/10647 11395/11573/10710 11394/11572/10709 +f 11333/11511/10648 11396/11574/10711 11395/11573/10710 +f 11334/11512/10649 11397/11575/10712 11396/11574/10711 +f 11335/11513/10650 11398/11576/10713 11397/11575/10712 +f 11336/11514/10651 11399/11577/10714 11398/11576/10713 +f 11337/11515/10652 11400/11578/10715 11399/11577/10714 +f 11338/11516/10653 11401/11579/10716 11400/11578/10715 +f 11339/11517/10654 11402/11580/10717 11401/11579/10716 +f 11340/11518/10655 11403/11581/10718 11402/11580/10717 +f 11341/11519/10656 11404/11582/10719 11403/11581/10718 +f 11342/11520/10657 11405/11583/10720 11404/11582/10719 +f 11343/11521/10658 11406/11584/10721 11405/11583/10720 +f 11344/11522/10659 11407/11585/10722 11406/11584/10721 +f 11345/11523/10660 11408/11586/10723 11407/11585/10722 +f 11346/11524/10661 11409/11587/10724 11408/11586/10723 +f 11347/11525/10662 11410/11588/10725 11409/11587/10724 +f 11348/11526/10663 11411/11589/10726 11410/11588/10725 +f 11349/11527/10664 11412/11590/10727 11411/11589/10726 +f 11350/11528/10665 11413/11591/10728 11412/11590/10727 +f 11351/11529/10666 11414/11592/10729 11413/11591/10728 +f 11352/11530/10667 11415/11593/10730 11414/11592/10729 +f 11353/11532/10669 11416/11595/10732 11415/11593/10730 +f 11354/11594/10731 11417/11657/10794 11416/11595/10732 +f 11356/11534/10671 11419/11597/10734 11418/11596/10733 +f 11357/11535/10672 11420/11598/10735 11419/11597/10734 +f 11358/11536/10673 11421/11599/10736 11420/11598/10735 +f 11359/11537/10674 11422/11600/10737 11421/11599/10736 +f 11360/11538/10675 11423/11601/10738 11422/11600/10737 +f 11361/11539/10676 11424/11602/10739 11423/11601/10738 +f 11362/11540/10677 11425/11603/10740 11424/11602/10739 +f 11363/11541/10678 11426/11604/10741 11425/11603/10740 +f 11364/11542/10679 11427/11605/10742 11426/11604/10741 +f 11365/11543/10680 11428/11606/10743 11427/11605/10742 +f 11366/11544/10681 11429/11607/10744 11428/11606/10743 +f 11367/11545/10682 11430/11608/10745 11429/11607/10744 +f 11368/11546/10683 11431/11609/10746 11430/11608/10745 +f 11369/11547/10684 11432/11610/10747 11431/11609/10746 +f 11370/11548/10685 11433/11611/10748 11432/11610/10747 +f 11371/11549/10686 11434/11612/10749 11433/11611/10748 +f 11372/11550/10687 11435/11613/10750 11434/11612/10749 +f 11373/11551/10688 11436/11614/10751 11435/11613/10750 +f 11374/11552/10689 11437/11615/10752 11436/11614/10751 +f 11375/11553/10690 11438/11616/10753 11437/11615/10752 +f 11376/11554/10691 11439/11617/10754 11438/11616/10753 +f 11377/11555/10692 11440/11618/10755 11439/11617/10754 +f 11378/11556/10693 11441/11619/10756 11440/11618/10755 +f 11379/11557/10694 11442/11620/10757 11441/11619/10756 +f 11380/11558/10695 11443/11621/10758 11442/11620/10757 +f 11381/11559/10696 11444/11622/10759 11443/11621/10758 +f 11382/11560/10697 11445/11623/10760 11444/11622/10759 +f 11383/11561/10698 11446/11624/10761 11445/11623/10760 +f 11384/11562/10699 11447/11625/10762 11446/11624/10761 +f 11385/11563/10700 11448/11626/10763 11447/11625/10762 +f 11386/11564/10701 11449/11627/10764 11448/11626/10763 +f 11387/11565/10702 11450/11628/10765 11449/11627/10764 +f 11388/11566/10703 11451/11629/10766 11450/11628/10765 +f 11389/11567/10704 11452/11630/10767 11451/11629/10766 +f 11390/11568/10705 11453/11631/10768 11452/11630/10767 +f 11391/11569/10706 11454/11632/10769 11453/11631/10768 +f 11392/11570/10707 11455/11633/10770 11454/11632/10769 +f 11393/11571/10708 11456/11634/10771 11455/11633/10770 +f 11394/11572/10709 11457/11635/10772 11456/11634/10771 +f 11395/11573/10710 11458/11636/10773 11457/11635/10772 +f 11396/11574/10711 11459/11637/10774 11458/11636/10773 +f 11397/11575/10712 11460/11638/10775 11459/11637/10774 +f 11398/11576/10713 11461/11639/10776 11460/11638/10775 +f 11399/11577/10714 11462/11640/10777 11461/11639/10776 +f 11400/11578/10715 11463/11641/10778 11462/11640/10777 +f 11401/11579/10716 11464/11642/10779 11463/11641/10778 +f 11402/11580/10717 11465/11643/10780 11464/11642/10779 +f 11403/11581/10718 11466/11644/10781 11465/11643/10780 +f 11404/11582/10719 11467/11645/10782 11466/11644/10781 +f 11405/11583/10720 11468/11646/10783 11467/11645/10782 +f 11406/11584/10721 11469/11647/10784 11468/11646/10783 +f 11407/11585/10722 11470/11648/10785 11469/11647/10784 +f 11408/11586/10723 11471/11649/10786 11470/11648/10785 +f 11409/11587/10724 11472/11650/10787 11471/11649/10786 +f 11410/11588/10725 11473/11651/10788 11472/11650/10787 +f 11411/11589/10726 11474/11652/10789 11473/11651/10788 +f 11412/11590/10727 11475/11653/10790 11474/11652/10789 +f 11413/11591/10728 11476/11654/10791 11475/11653/10790 +f 11414/11592/10729 11477/11655/10792 11476/11654/10791 +f 11415/11593/10730 11478/11656/10793 11477/11655/10792 +f 11416/11595/10732 11479/11658/10795 11478/11656/10793 +f 11417/11657/10794 11480/11720/10857 11479/11658/10795 +f 11419/11597/10734 11482/11660/10797 11481/11659/10796 +f 11420/11598/10735 11483/11661/10798 11482/11660/10797 +f 11421/11599/10736 11484/11662/10799 11483/11661/10798 +f 11422/11600/10737 11485/11663/10800 11484/11662/10799 +f 11423/11601/10738 11486/11664/10801 11485/11663/10800 +f 11424/11602/10739 11487/11665/10802 11486/11664/10801 +f 11425/11603/10740 11488/11666/10803 11487/11665/10802 +f 11426/11604/10741 11489/11667/10804 11488/11666/10803 +f 11427/11605/10742 11490/11668/10805 11489/11667/10804 +f 11428/11606/10743 11491/11669/10806 11490/11668/10805 +f 11429/11607/10744 11492/11670/10807 11491/11669/10806 +f 11430/11608/10745 11493/11671/10808 11492/11670/10807 +f 11431/11609/10746 11494/11672/10809 11493/11671/10808 +f 11432/11610/10747 11495/11673/10810 11494/11672/10809 +f 11433/11611/10748 11496/11674/10811 11495/11673/10810 +f 11434/11612/10749 11497/11675/10812 11496/11674/10811 +f 11435/11613/10750 11498/11676/10813 11497/11675/10812 +f 11436/11614/10751 11499/11677/10814 11498/11676/10813 +f 11437/11615/10752 11500/11678/10815 11499/11677/10814 +f 11438/11616/10753 11501/11679/10816 11500/11678/10815 +f 11439/11617/10754 11502/11680/10817 11501/11679/10816 +f 11440/11618/10755 11503/11681/10818 11502/11680/10817 +f 11441/11619/10756 11504/11682/10819 11503/11681/10818 +f 11442/11620/10757 11505/11683/10820 11504/11682/10819 +f 11443/11621/10758 11506/11684/10821 11505/11683/10820 +f 11444/11622/10759 11507/11685/10822 11506/11684/10821 +f 11445/11623/10760 11508/11686/10823 11507/11685/10822 +f 11446/11624/10761 11509/11687/10824 11508/11686/10823 +f 11447/11625/10762 11510/11688/10825 11509/11687/10824 +f 11448/11626/10763 11511/11689/10826 11510/11688/10825 +f 11449/11627/10764 11512/11690/10827 11511/11689/10826 +f 11450/11628/10765 11513/11691/10828 11512/11690/10827 +f 11451/11629/10766 11514/11692/10829 11513/11691/10828 +f 11452/11630/10767 11515/11693/10830 11514/11692/10829 +f 11453/11631/10768 11516/11694/10831 11515/11693/10830 +f 11454/11632/10769 11517/11695/10832 11516/11694/10831 +f 11455/11633/10770 11518/11696/10833 11517/11695/10832 +f 11456/11634/10771 11519/11697/10834 11518/11696/10833 +f 11457/11635/10772 11520/11698/10835 11519/11697/10834 +f 11458/11636/10773 11521/11699/10836 11520/11698/10835 +f 11459/11637/10774 11522/11700/10837 11521/11699/10836 +f 11460/11638/10775 11523/11701/10838 11522/11700/10837 +f 11461/11639/10776 11524/11702/10839 11523/11701/10838 +f 11462/11640/10777 11525/11703/10840 11524/11702/10839 +f 11463/11641/10778 11526/11704/10841 11525/11703/10840 +f 11464/11642/10779 11527/11705/10842 11526/11704/10841 +f 11465/11643/10780 11528/11706/10843 11527/11705/10842 +f 11466/11644/10781 11529/11707/10844 11528/11706/10843 +f 11467/11645/10782 11530/11708/10845 11529/11707/10844 +f 11468/11646/10783 11531/11709/10846 11530/11708/10845 +f 11469/11647/10784 11532/11711/10848 11531/11709/10846 +f 11469/11647/10784 11470/11648/10785 11533/11710/10847 +f 11471/11649/10786 11534/11712/10849 11533/11710/10847 +f 11472/11650/10787 11535/11713/10850 11534/11712/10849 +f 11473/11651/10788 11536/11714/10851 11535/11713/10850 +f 11474/11652/10789 11537/11715/10852 11536/11714/10851 +f 11475/11653/10790 11538/11716/10853 11537/11715/10852 +f 11476/11654/10791 11539/11717/10854 11538/11716/10853 +f 11477/11655/10792 11540/11718/10855 11539/11717/10854 +f 11478/11656/10793 11541/11719/10856 11540/11718/10855 +f 11479/11658/10795 11542/11721/10858 11541/11719/10856 +f 11480/11720/10857 11543/11783/10920 11542/11721/10858 +f 11482/11660/10797 11545/11723/10860 11544/11722/10859 +f 11483/11661/10798 11546/11724/10861 11545/11723/10860 +f 11484/11662/10799 11547/11725/10862 11546/11724/10861 +f 11485/11663/10800 11548/11726/10863 11547/11725/10862 +f 11486/11664/10801 11549/11727/10864 11548/11726/10863 +f 11487/11665/10802 11550/11728/10865 11549/11727/10864 +f 11488/11666/10803 11551/11729/10866 11550/11728/10865 +f 11489/11667/10804 11552/11730/10867 11551/11729/10866 +f 11490/11668/10805 11553/11731/10868 11552/11730/10867 +f 11491/11669/10806 11554/11732/10869 11553/11731/10868 +f 11492/11670/10807 11555/11733/10870 11554/11732/10869 +f 11493/11671/10808 11556/11734/10871 11555/11733/10870 +f 11494/11672/10809 11557/11735/10872 11556/11734/10871 +f 11495/11673/10810 11558/11736/10873 11557/11735/10872 +f 11496/11674/10811 11559/11737/10874 11558/11736/10873 +f 11497/11675/10812 11560/11738/10875 11559/11737/10874 +f 11498/11676/10813 11561/11739/10876 11560/11738/10875 +f 11499/11677/10814 11562/11740/10877 11561/11739/10876 +f 11500/11678/10815 11563/11741/10878 11562/11740/10877 +f 11501/11679/10816 11564/11742/10879 11563/11741/10878 +f 11502/11680/10817 11565/11743/10880 11564/11742/10879 +f 11503/11681/10818 11566/11744/10881 11565/11743/10880 +f 11504/11682/10819 11567/11745/10882 11566/11744/10881 +f 11505/11683/10820 11568/11746/10883 11567/11745/10882 +f 11506/11684/10821 11569/11747/10884 11568/11746/10883 +f 11507/11685/10822 11570/11748/10885 11569/11747/10884 +f 11508/11686/10823 11571/11749/10886 11570/11748/10885 +f 11509/11687/10824 11572/11750/10887 11571/11749/10886 +f 11510/11688/10825 11573/11751/10888 11572/11750/10887 +f 11511/11689/10826 11574/11752/10889 11573/11751/10888 +f 11512/11690/10827 11575/11753/10890 11574/11752/10889 +f 11513/11691/10828 11576/11754/10891 11575/11753/10890 +f 11514/11692/10829 11577/11755/10892 11576/11754/10891 +f 11515/11693/10830 11578/11756/10893 11577/11755/10892 +f 11516/11694/10831 11579/11757/10894 11578/11756/10893 +f 11517/11695/10832 11580/11758/10895 11579/11757/10894 +f 11518/11696/10833 11581/11759/10896 11580/11758/10895 +f 11519/11697/10834 11582/11760/10897 11581/11759/10896 +f 11520/11698/10835 11583/11761/10898 11582/11760/10897 +f 11521/11699/10836 11584/11762/10899 11583/11761/10898 +f 11522/11700/10837 11585/11763/10900 11584/11762/10899 +f 11523/11701/10838 11586/11764/10901 11585/11763/10900 +f 11524/11702/10839 11587/11765/10902 11586/11764/10901 +f 11525/11703/10840 11588/11766/10903 11587/11765/10902 +f 11526/11704/10841 11589/11767/10904 11588/11766/10903 +f 11527/11705/10842 11590/11768/10905 11589/11767/10904 +f 11528/11706/10843 11591/11769/10906 11590/11768/10905 +f 11529/11707/10844 11592/11770/10907 11591/11769/10906 +f 11530/11708/10845 11593/11771/10908 11592/11770/10907 +f 11531/11709/10846 11594/11772/10909 11593/11771/10908 +f 11532/11711/10848 11595/11773/10910 11594/11772/10909 +f 11533/11710/10847 11596/11774/10911 11595/11773/10910 +f 11534/11712/10849 11597/11775/10912 11596/11774/10911 +f 11535/11713/10850 11598/11776/10913 11597/11775/10912 +f 11536/11714/10851 11599/11777/10914 11598/11776/10913 +f 11537/11715/10852 11600/11778/10915 11599/11777/10914 +f 11538/11716/10853 11601/11779/10916 11600/11778/10915 +f 11539/11717/10854 11602/11780/10917 11601/11779/10916 +f 11540/11718/10855 11603/11781/10918 11602/11780/10917 +f 11541/11719/10856 11604/11782/10919 11603/11781/10918 +f 11542/11721/10858 11605/11784/10921 11604/11782/10919 +f 11543/11783/10920 11606/11846/10982 11605/11784/10921 +f 11545/11723/10860 11608/11786/10923 11607/11785/10922 +f 11546/11724/10861 11609/11787/10924 11608/11786/10923 +f 11547/11725/10862 11610/11788/10925 11609/11787/10924 +f 11548/11726/10863 11611/11789/10926 11610/11788/10925 +f 11549/11727/10864 11612/11790/10927 11611/11789/10926 +f 11550/11728/10865 11613/11791/10928 11612/11790/10927 +f 11551/11729/10866 11614/11792/10929 11613/11791/10928 +f 11552/11730/10867 11615/11793/10930 11614/11792/10929 +f 11553/11731/10868 11616/11794/10931 11615/11793/10930 +f 11554/11732/10869 11617/11795/10932 11616/11794/10931 +f 11555/11733/10870 11618/11796/10933 11617/11795/10932 +f 11556/11734/10871 11619/11797/8490 11618/11796/10933 +f 11557/11735/10872 11620/11798/10934 11619/11797/8490 +f 11558/11736/10873 11621/11799/10935 11620/11798/10934 +f 11559/11737/10874 11622/11800/10936 11621/11799/10935 +f 11560/11738/10875 11623/11801/10937 11622/11800/10936 +f 11561/11739/10876 11624/11802/10938 11623/11801/10937 +f 11562/11740/10877 11625/11803/10939 11624/11802/10938 +f 11563/11741/10878 11626/11804/10940 11625/11803/10939 +f 11564/11742/10879 11627/11805/10941 11626/11804/10940 +f 11565/11743/10880 11628/11806/10942 11627/11805/10941 +f 11566/11744/10881 11629/11807/10943 11628/11806/10942 +f 11567/11745/10882 11630/11808/10944 11629/11807/10943 +f 11568/11746/10883 11631/11809/10945 11630/11808/10944 +f 11569/11747/10884 11632/11810/10946 11631/11809/10945 +f 11570/11748/10885 11633/11811/10947 11632/11810/10946 +f 11571/11749/10886 11634/11812/10948 11633/11811/10947 +f 11572/11750/10887 11635/11813/10949 11634/11812/10948 +f 11573/11751/10888 11636/11814/10950 11635/11813/10949 +f 11574/11752/10889 11637/11815/10951 11636/11814/10950 +f 11575/11753/10890 11638/11816/10952 11637/11815/10951 +f 11576/11754/10891 11639/11817/10953 11638/11816/10952 +f 11577/11755/10892 11640/11818/10954 11639/11817/10953 +f 11578/11756/10893 11641/11819/10955 11640/11818/10954 +f 11579/11757/10894 11642/11820/10956 11641/11819/10955 +f 11580/11758/10895 11643/11821/10957 11642/11820/10956 +f 11581/11759/10896 11644/11822/10958 11643/11821/10957 +f 11582/11760/10897 11645/11823/10959 11644/11822/10958 +f 11583/11761/10898 11646/11824/10960 11645/11823/10959 +f 11584/11762/10899 11647/11825/10961 11646/11824/10960 +f 11585/11763/10900 11648/11826/10962 11647/11825/10961 +f 11586/11764/10901 11649/11827/10963 11648/11826/10962 +f 11587/11765/10902 11650/11828/10964 11649/11827/10963 +f 11588/11766/10903 11651/11829/10965 11650/11828/10964 +f 11589/11767/10904 11652/11830/10966 11651/11829/10965 +f 11590/11768/10905 11653/11831/10967 11652/11830/10966 +f 11591/11769/10906 11654/11832/10968 11653/11831/10967 +f 11592/11770/10907 11655/11833/10969 11654/11832/10968 +f 11593/11771/10908 11656/11834/10970 11655/11833/10969 +f 11594/11772/10909 11657/11835/10971 11656/11834/10970 +f 11595/11773/10910 11658/11836/10972 11657/11835/10971 +f 11596/11774/10911 11659/11837/10973 11658/11836/10972 +f 11597/11775/10912 11660/11838/10974 11659/11837/10973 +f 11598/11776/10913 11661/11839/10975 11660/11838/10974 +f 11599/11777/10914 11662/11840/10976 11661/11839/10975 +f 11600/11778/10915 11663/11841/10977 11662/11840/10976 +f 11601/11779/10916 11664/11842/10978 11663/11841/10977 +f 11602/11780/10917 11665/11843/10979 11664/11842/10978 +f 11603/11781/10918 11666/11844/10980 11665/11843/10979 +f 11604/11782/10919 11667/11845/10981 11666/11844/10980 +f 11605/11784/10921 11668/11847/10983 11667/11845/10981 +f 11606/11846/10982 11669/11909/11045 11668/11847/10983 +f 11608/11786/10923 11671/11849/10985 11670/11848/10984 +f 11609/11787/10924 11672/11850/10986 11671/11849/10985 +f 11610/11788/10925 11673/11851/10987 11672/11850/10986 +f 11611/11789/10926 11674/11852/10988 11673/11851/10987 +f 11612/11790/10927 11675/11853/10989 11674/11852/10988 +f 11613/11791/10928 11676/11854/10990 11675/11853/10989 +f 11614/11792/10929 11677/11855/10991 11676/11854/10990 +f 11615/11793/10930 11678/11856/10992 11677/11855/10991 +f 11616/11794/10931 11679/11857/10993 11678/11856/10992 +f 11617/11795/10932 11680/11858/10994 11679/11857/10993 +f 11618/11796/10933 11681/11859/10995 11680/11858/10994 +f 11619/11797/8490 11682/11860/10996 11681/11859/10995 +f 11620/11798/10934 11683/11861/10997 11682/11860/10996 +f 11621/11799/10935 11684/11862/10998 11683/11861/10997 +f 11622/11800/10936 11685/11863/10999 11684/11862/10998 +f 11623/11801/10937 11686/11864/11000 11685/11863/10999 +f 11624/11802/10938 11687/11865/11001 11686/11864/11000 +f 11625/11803/10939 11688/11866/11002 11687/11865/11001 +f 11626/11804/10940 11689/11867/11003 11688/11866/11002 +f 11627/11805/10941 11690/11868/11004 11689/11867/11003 +f 11628/11806/10942 11691/11869/11005 11690/11868/11004 +f 11629/11807/10943 11692/11870/11006 11691/11869/11005 +f 11630/11808/10944 11693/11871/11007 11692/11870/11006 +f 11631/11809/10945 11694/11872/11008 11693/11871/11007 +f 11632/11810/10946 11695/11873/11009 11694/11872/11008 +f 11633/11811/10947 11696/11874/11010 11695/11873/11009 +f 11634/11812/10948 11697/11875/11011 11696/11874/11010 +f 11635/11813/10949 11698/11876/11012 11697/11875/11011 +f 11636/11814/10950 11699/11877/11013 11698/11876/11012 +f 11637/11815/10951 11700/11878/11014 11699/11877/11013 +f 11638/11816/10952 11701/11879/11015 11700/11878/11014 +f 11639/11817/10953 11702/11880/11016 11701/11879/11015 +f 11640/11818/10954 11703/11881/11017 11702/11880/11016 +f 11641/11819/10955 11704/11882/11018 11703/11881/11017 +f 11642/11820/10956 11705/11883/11019 11704/11882/11018 +f 11643/11821/10957 11706/11884/11020 11705/11883/11019 +f 11644/11822/10958 11707/11885/11021 11706/11884/11020 +f 11645/11823/10959 11708/11886/11022 11707/11885/11021 +f 11646/11824/10960 11709/11887/11023 11708/11886/11022 +f 11647/11825/10961 11710/11888/11024 11709/11887/11023 +f 11648/11826/10962 11711/11889/11025 11710/11888/11024 +f 11649/11827/10963 11712/11890/11026 11711/11889/11025 +f 11650/11828/10964 11713/11891/11027 11712/11890/11026 +f 11651/11829/10965 11714/11892/11028 11713/11891/11027 +f 11652/11830/10966 11715/11893/11029 11714/11892/11028 +f 11653/11831/10967 11716/11894/11030 11715/11893/11029 +f 11654/11832/10968 11717/11895/11031 11716/11894/11030 +f 11655/11833/10969 11718/11896/11032 11717/11895/11031 +f 11656/11834/10970 11719/11897/11033 11718/11896/11032 +f 11657/11835/10971 11720/11898/11034 11719/11897/11033 +f 11658/11836/10972 11721/11899/11035 11720/11898/11034 +f 11659/11837/10973 11722/11900/11036 11721/11899/11035 +f 11660/11838/10974 11723/11901/11037 11722/11900/11036 +f 11661/11839/10975 11724/11902/11038 11723/11901/11037 +f 11662/11840/10976 11725/11903/11039 11724/11902/11038 +f 11663/11841/10977 11726/11904/11040 11725/11903/11039 +f 11664/11842/10978 11727/11905/11041 11726/11904/11040 +f 11665/11843/10979 11728/11906/11042 11727/11905/11041 +f 11666/11844/10980 11729/11907/11043 11728/11906/11042 +f 11667/11845/10981 11730/11908/11044 11729/11907/11043 +f 11668/11847/10983 11731/11910/11046 11730/11908/11044 +f 11669/11909/11045 11732/11972/11107 11731/11910/11046 +f 11671/11849/10985 11734/11912/11048 11733/11911/11047 +f 11672/11850/10986 11735/11913/11049 11734/11912/11048 +f 11673/11851/10987 11736/11914/11050 11735/11913/11049 +f 11674/11852/10988 11737/11915/11051 11736/11914/11050 +f 11675/11853/10989 11738/11916/11052 11737/11915/11051 +f 11676/11854/10990 11739/11917/11053 11738/11916/11052 +f 11677/11855/10991 11740/11918/11054 11739/11917/11053 +f 11678/11856/10992 11741/11919/11055 11740/11918/11054 +f 11679/11857/10993 11742/11920/11056 11741/11919/11055 +f 11680/11858/10994 11743/11921/11057 11742/11920/11056 +f 11681/11859/10995 11744/11922/11058 11743/11921/11057 +f 11682/11860/10996 11745/11923/11059 11744/11922/11058 +f 11683/11861/10997 11746/11924/11060 11745/11923/11059 +f 11684/11862/10998 11747/11925/11061 11746/11924/11060 +f 11685/11863/10999 11748/11926/11062 11747/11925/11061 +f 11686/11864/11000 11749/11927/11063 11748/11926/11062 +f 11687/11865/11001 11750/11928/11064 11749/11927/11063 +f 11688/11866/11002 11751/11929/11065 11750/11928/11064 +f 11689/11867/11003 11752/11930/11066 11751/11929/11065 +f 11690/11868/11004 11753/11931/11067 11752/11930/11066 +f 11691/11869/11005 11754/11932/11068 11753/11931/11067 +f 11692/11870/11006 11755/11933/11069 11754/11932/11068 +f 11693/11871/11007 11756/11934/11070 11755/11933/11069 +f 11694/11872/11008 11757/11935/11071 11756/11934/11070 +f 11695/11873/11009 11758/11936/11072 11757/11935/11071 +f 11696/11874/11010 11759/11937/11073 11758/11936/11072 +f 11697/11875/11011 11760/11938/11074 11759/11937/11073 +f 11698/11876/11012 11761/11939/11075 11760/11938/11074 +f 11699/11877/11013 11762/11940/11076 11761/11939/11075 +f 11700/11878/11014 11763/11941/11077 11762/11940/11076 +f 11701/11879/11015 11764/11942/11078 11763/11941/11077 +f 11702/11880/11016 11765/11943/11079 11764/11942/11078 +f 11703/11881/11017 11766/11944/11080 11765/11943/11079 +f 11704/11882/11018 11767/11945/11081 11766/11944/11080 +f 11705/11883/11019 11768/11946/11082 11767/11945/11081 +f 11706/11884/11020 11769/11947/11083 11768/11946/11082 +f 11707/11885/11021 11770/11948/11022 11769/11947/11083 +f 11708/11886/11022 11771/11949/11084 11770/11948/11022 +f 11709/11887/11023 11772/11950/11085 11771/11949/11084 +f 11710/11888/11024 11773/11951/11086 11772/11950/11085 +f 11711/11889/11025 11774/11952/11087 11773/11951/11086 +f 11712/11890/11026 11775/11953/11088 11774/11952/11087 +f 11713/11891/11027 11776/11954/11089 11775/11953/11088 +f 11714/11892/11028 11777/11955/11090 11776/11954/11089 +f 11715/11893/11029 11778/11956/11091 11777/11955/11090 +f 11716/11894/11030 11779/11957/11092 11778/11956/11091 +f 11717/11895/11031 11780/11958/11093 11779/11957/11092 +f 11718/11896/11032 11781/11959/11094 11780/11958/11093 +f 11719/11897/11033 11782/11960/11095 11781/11959/11094 +f 11720/11898/11034 11783/11961/11096 11782/11960/11095 +f 11721/11899/11035 11784/11962/11097 11783/11961/11096 +f 11722/11900/11036 11785/11963/11098 11784/11962/11097 +f 11723/11901/11037 11786/11964/11099 11785/11963/11098 +f 11724/11902/11038 11787/11965/11100 11786/11964/11099 +f 11725/11903/11039 11788/11966/11101 11787/11965/11100 +f 11726/11904/11040 11789/11967/11102 11788/11966/11101 +f 11727/11905/11041 11790/11968/11103 11789/11967/11102 +f 11728/11906/11042 11791/11969/11104 11790/11968/11103 +f 11729/11907/11043 11792/11970/11105 11791/11969/11104 +f 11730/11908/11044 11793/11971/11106 11792/11970/11105 +f 11731/11910/11046 11794/11973/11108 11793/11971/11106 +f 11732/11972/11107 11795/12035/11169 11794/11973/11108 +f 11734/11912/11048 11797/11975/11110 11796/11974/11109 +f 11735/11913/11049 11798/11976/11111 11797/11975/11110 +f 11736/11914/11050 11799/11977/11112 11798/11976/11111 +f 11737/11915/11051 11800/11978/11113 11799/11977/11112 +f 11738/11916/11052 11801/11979/11114 11800/11978/11113 +f 11739/11917/11053 11802/11980/11115 11801/11979/11114 +f 11740/11918/11054 11803/11981/11116 11802/11980/11115 +f 11741/11919/11055 11804/11982/11117 11803/11981/11116 +f 11742/11920/11056 11805/11983/11118 11804/11982/11117 +f 11743/11921/11057 11806/11984/11119 11805/11983/11118 +f 11744/11922/11058 11807/11985/11120 11806/11984/11119 +f 11745/11923/11059 11808/11986/11121 11807/11985/11120 +f 11746/11924/11060 11809/11987/11122 11808/11986/11121 +f 11747/11925/11061 11810/11988/11123 11809/11987/11122 +f 11748/11926/11062 11811/11989/11124 11810/11988/11123 +f 11749/11927/11063 11812/11990/11125 11811/11989/11124 +f 11750/11928/11064 11813/11991/11126 11812/11990/11125 +f 11751/11929/11065 11814/11992/11127 11813/11991/11126 +f 11752/11930/11066 11815/11993/11128 11814/11992/11127 +f 11753/11931/11067 11816/11994/11129 11815/11993/11128 +f 11754/11932/11068 11817/11995/11130 11816/11994/11129 +f 11755/11933/11069 11818/11996/11131 11817/11995/11130 +f 11756/11934/11070 11819/11997/11132 11818/11996/11131 +f 11757/11935/11071 11820/11998/11133 11819/11997/11132 +f 11758/11936/11072 11821/11999/11134 11820/11998/11133 +f 11759/11937/11073 11822/12000/11135 11821/11999/11134 +f 11760/11938/11074 11823/12001/11136 11822/12000/11135 +f 11761/11939/11075 11824/12002/11137 11823/12001/11136 +f 11762/11940/11076 11825/12003/11138 11824/12002/11137 +f 11763/11941/11077 11826/12004/11139 11825/12003/11138 +f 11764/11942/11078 11827/12005/11140 11826/12004/11139 +f 11765/11943/11079 11828/12006/11141 11827/12005/11140 +f 11766/11944/11080 11829/12007/11142 11828/12006/11141 +f 11767/11945/11081 11830/12008/11143 11829/12007/11142 +f 11768/11946/11082 11831/12009/11144 11830/12008/11143 +f 11769/11947/11083 11832/12010/11145 11831/12009/11144 +f 11770/11948/11022 11833/12011/11146 11832/12010/11145 +f 11771/11949/11084 11834/12012/11147 11833/12011/11146 +f 11772/11950/11085 11835/12013/11148 11834/12012/11147 +f 11773/11951/11086 11836/12014/11149 11835/12013/11148 +f 11774/11952/11087 11837/12015/11150 11836/12014/11149 +f 11775/11953/11088 11838/12016/11151 11837/12015/11150 +f 11776/11954/11089 11839/12017/11152 11838/12016/11151 +f 11777/11955/11090 11840/12018/10536 11839/12017/11152 +f 11778/11956/11091 11841/12019/11153 11840/12018/10536 +f 11779/11957/11092 11842/12020/11154 11841/12019/11153 +f 11780/11958/11093 11843/12021/11155 11842/12020/11154 +f 11781/11959/11094 11844/12022/11156 11843/12021/11155 +f 11782/11960/11095 11845/12023/11157 11844/12022/11156 +f 11783/11961/11096 11846/12024/11158 11845/12023/11157 +f 11784/11962/11097 11847/12025/11159 11846/12024/11158 +f 11785/11963/11098 11848/12026/11160 11847/12025/11159 +f 11786/11964/11099 11849/12027/11161 11848/12026/11160 +f 11787/11965/11100 11850/12028/11162 11849/12027/11161 +f 11788/11966/11101 11851/12029/11163 11850/12028/11162 +f 11789/11967/11102 11852/12030/11164 11851/12029/11163 +f 11790/11968/11103 11853/12031/11165 11852/12030/11164 +f 11791/11969/11104 11854/12032/11166 11853/12031/11165 +f 11792/11970/11105 11855/12033/11167 11854/12032/11166 +f 11793/11971/11106 11856/12034/11168 11855/12033/11167 +f 11794/11973/11108 11857/12036/11170 11856/12034/11168 +f 11795/12035/11169 11858/12098/11232 11857/12036/11170 +f 11797/11975/11110 11860/12038/11172 11859/12037/11171 +f 11798/11976/11111 11861/12039/11173 11860/12038/11172 +f 11799/11977/11112 11862/12040/11174 11861/12039/11173 +f 11800/11978/11113 11863/12041/11175 11862/12040/11174 +f 11801/11979/11114 11864/12042/11176 11863/12041/11175 +f 11802/11980/11115 11865/12043/11177 11864/12042/11176 +f 11803/11981/11116 11866/12044/11178 11865/12043/11177 +f 11804/11982/11117 11867/12045/11179 11866/12044/11178 +f 11805/11983/11118 11868/12046/11180 11867/12045/11179 +f 11806/11984/11119 11869/12047/11181 11868/12046/11180 +f 11807/11985/11120 11870/12048/11182 11869/12047/11181 +f 11808/11986/11121 11871/12049/11183 11870/12048/11182 +f 11809/11987/11122 11872/12050/11184 11871/12049/11183 +f 11810/11988/11123 11873/12051/11185 11872/12050/11184 +f 11811/11989/11124 11874/12052/11186 11873/12051/11185 +f 11812/11990/11125 11875/12053/11187 11874/12052/11186 +f 11813/11991/11126 11876/12054/11188 11875/12053/11187 +f 11814/11992/11127 11877/12055/11189 11876/12054/11188 +f 11815/11993/11128 11878/12056/11190 11877/12055/11189 +f 11816/11994/11129 11879/12057/11191 11878/12056/11190 +f 11817/11995/11130 11880/12058/11192 11879/12057/11191 +f 11818/11996/11131 11881/12059/11193 11880/12058/11192 +f 11819/11997/11132 11882/12060/11194 11881/12059/11193 +f 11820/11998/11133 11883/12061/11195 11882/12060/11194 +f 11821/11999/11134 11884/12062/11196 11883/12061/11195 +f 11822/12000/11135 11885/12063/11197 11884/12062/11196 +f 11823/12001/11136 11886/12064/11198 11885/12063/11197 +f 11824/12002/11137 11887/12065/11199 11886/12064/11198 +f 11825/12003/11138 11888/12066/11200 11887/12065/11199 +f 11826/12004/11139 11889/12067/11201 11888/12066/11200 +f 11827/12005/11140 11890/12068/11202 11889/12067/11201 +f 11828/12006/11141 11891/12069/11203 11890/12068/11202 +f 11829/12007/11142 11892/12070/11204 11891/12069/11203 +f 11830/12008/11143 11893/12071/11205 11892/12070/11204 +f 11831/12009/11144 11894/12072/11206 11893/12071/11205 +f 11832/12010/11145 11895/12073/11207 11894/12072/11206 +f 11833/12011/11146 11896/12074/11208 11895/12073/11207 +f 11834/12012/11147 11897/12075/11209 11896/12074/11208 +f 11835/12013/11148 11898/12076/11210 11897/12075/11209 +f 11836/12014/11149 11899/12077/11211 11898/12076/11210 +f 11837/12015/11150 11900/12078/11212 11899/12077/11211 +f 11838/12016/11151 11901/12079/11213 11900/12078/11212 +f 11839/12017/11152 11902/12080/11214 11901/12079/11213 +f 11840/12018/10536 11903/12081/11215 11902/12080/11214 +f 11841/12019/11153 11904/12082/11216 11903/12081/11215 +f 11842/12020/11154 11905/12083/11217 11904/12082/11216 +f 11843/12021/11155 11906/12084/11218 11905/12083/11217 +f 11844/12022/11156 11907/12085/11219 11906/12084/11218 +f 11845/12023/11157 11908/12086/11220 11907/12085/11219 +f 11846/12024/11158 11909/12087/11221 11908/12086/11220 +f 11847/12025/11159 11910/12088/11222 11909/12087/11221 +f 11848/12026/11160 11911/12089/11223 11910/12088/11222 +f 11849/12027/11161 11912/12090/11224 11911/12089/11223 +f 11850/12028/11162 11913/12091/11225 11912/12090/11224 +f 11851/12029/11163 11914/12092/11226 11913/12091/11225 +f 11852/12030/11164 11915/12093/11227 11914/12092/11226 +f 11853/12031/11165 11916/12094/11228 11915/12093/11227 +f 11854/12032/11166 11917/12095/11229 11916/12094/11228 +f 11855/12033/11167 11918/12096/11230 11917/12095/11229 +f 11856/12034/11168 11919/12097/11231 11918/12096/11230 +f 11857/12036/11170 11920/12099/11233 11919/12097/11231 +f 11858/12098/11232 11921/12228/11359 11920/12099/11233 +f 7764/12100/11234 7953/8134/7288 7763/12101/11235 +f 7765/12103/11237 7954/8132/7286 7953/8134/7288 +f 7766/12104/11238 7955/8135/7289 7954/8132/7286 +f 7767/12105/11239 7956/8137/7291 7955/8135/7289 +f 7768/12106/11240 7957/8139/7293 7956/8137/7291 +f 7769/12107/11241 7958/8141/7295 7957/8139/7293 +f 7770/12108/11242 7959/8143/7297 7958/8141/7295 +f 7771/12109/11243 7960/8145/7299 7959/8143/7297 +f 7772/12110/11244 7961/8147/7301 7960/8145/7299 +f 7773/12111/11245 7962/8149/7303 7961/8147/7301 +f 7774/12112/11246 7963/8151/7305 7962/8149/7303 +f 7775/12113/11247 7964/8153/7307 7963/8151/7305 +f 7776/12114/11248 7965/8155/7309 7964/8153/7307 +f 7777/12115/11249 7966/8157/7311 7965/8155/7309 +f 7778/12116/11250 7967/8159/7313 7966/8157/7311 +f 7779/12117/11251 7968/8161/7315 7967/8159/7313 +f 7780/12118/11252 7969/8163/7317 7968/8161/7315 +f 7781/12119/11253 7970/8165/7319 7969/8163/7317 +f 7782/12120/11254 7971/8167/7321 7970/8165/7319 +f 7783/12121/11255 7972/8169/7323 7971/8167/7321 +f 7784/12122/11256 7973/8171/7325 7972/8169/7323 +f 7785/12123/11257 7974/8173/7327 7973/8171/7325 +f 7786/12124/11258 7975/8175/7329 7974/8173/7327 +f 7787/12125/11259 7976/8177/7331 7975/8175/7329 +f 7788/12126/11260 7977/8179/7333 7976/8177/7331 +f 7789/12127/11261 7978/8181/7335 7977/8179/7333 +f 7790/12128/11262 7979/8183/7337 7978/8181/7335 +f 7791/12129/11263 7980/8185/7339 7979/8183/7337 +f 7792/12130/11264 7981/8187/7341 7980/8185/7339 +f 7793/12131/11265 7982/8189/7343 7981/8187/7341 +f 7794/12132/11266 7983/8191/7345 7982/8189/7343 +f 7795/12133/11267 7984/8193/7347 7983/8191/7345 +f 7796/12134/11268 7985/8195/7349 7984/8193/7347 +f 7797/12135/11269 7986/8197/7351 7985/8195/7349 +f 7798/12136/11270 7987/8199/7353 7986/8197/7351 +f 7799/12137/11271 7988/8201/7355 7987/8199/7353 +f 7800/12138/11272 7989/8203/7357 7988/8201/7355 +f 7801/12139/11273 7990/8205/7359 7989/8203/7357 +f 7802/12140/11274 7991/8207/7361 7990/8205/7359 +f 7803/12141/11275 7992/8209/7363 7991/8207/7361 +f 7804/12142/11276 7993/8211/7365 7992/8209/7363 +f 7805/12143/11277 7994/8213/7367 7993/8211/7365 +f 7806/12144/11278 7995/8215/7369 7994/8213/7367 +f 7807/12145/11279 7996/8217/7371 7995/8215/7369 +f 7808/12146/11280 7997/8219/7373 7996/8217/7371 +f 7809/12147/11281 7998/8221/7375 7997/8219/7373 +f 7810/12148/11282 7999/8223/7377 7998/8221/7375 +f 7811/12149/11283 8000/8225/7379 7999/8223/7377 +f 7812/12150/11284 8001/8227/7381 8000/8225/7379 +f 7813/12151/11285 8002/8229/7383 8001/8227/7381 +f 7814/12152/11286 8003/8231/7385 8002/8229/7383 +f 7815/12153/11287 8004/8233/7387 8003/8231/7385 +f 7816/12154/11288 8005/8235/7389 8004/8233/7387 +f 7817/12155/11289 8006/8237/7391 8005/8235/7389 +f 7818/12156/11290 8007/8239/7393 8006/8237/7391 +f 7819/12157/11291 8008/8241/7395 8007/8239/7393 +f 7820/12158/11292 8009/8243/7397 8008/8241/7395 +f 7821/12159/11293 8010/8245/7399 8009/8243/7397 +f 7822/12160/11294 8011/8247/7401 8010/8245/7399 +f 7823/12161/11295 8012/8249/7403 8011/8247/7401 +f 7824/12162/11296 8013/8251/7405 8012/8249/7403 +f 7825/12163/11297 8014/8253/7407 8013/8251/7405 +f 7826/12164/11298 8015/8255/7409 8014/8253/7407 +f 7698/12165/11299 7827/12166/11300 8015/8255/7409 +f 7827/12166/11300 7828/12167/11301 8078/8318/7472 +f 7828/12167/11301 7829/12168/11302 8141/8381/7535 +f 7829/12168/11302 7830/12169/11303 8204/8444/7598 +f 7830/12169/11303 7831/12170/11304 8267/8507/7661 +f 7831/12170/11304 7832/12171/11305 8330/8570/7724 +f 7832/12171/11305 7833/12172/11306 8393/8633/7787 +f 7833/12172/11306 7834/12173/11307 8456/8696/7850 +f 7834/12173/11307 7835/12174/11308 8519/8759/7913 +f 7835/12174/11308 7836/12175/11269 8582/8822/7976 +f 7836/12175/11269 7837/12176/11309 8645/8885/8039 +f 7837/12176/11309 7838/12177/11310 8708/8948/8102 +f 7838/12177/11310 7839/12178/11311 8771/9011/8165 +f 7839/12178/11311 7840/12179/11312 8834/9074/8227 +f 7840/12179/11312 7841/12180/11313 8897/9137/8289 +f 7841/12180/11313 7842/12181/11314 8960/9200/8351 +f 7842/12181/11314 7843/12182/11315 9023/9263/8414 +f 7843/12182/11315 7844/12183/11316 9086/9326/8477 +f 7844/12183/11316 7845/12184/11317 9149/9389/8539 +f 7845/12184/11317 7846/12185/11318 9212/9452/8602 +f 7846/12185/11318 7847/12186/11319 9275/9515/8665 +f 7847/12186/11319 7848/12187/11320 9338/9578/8728 +f 7848/12187/11320 7849/12188/11321 9401/9641/8790 +f 7849/12188/11321 7850/12189/11322 9464/9704/8852 +f 7850/12189/11322 7851/12190/11323 9527/9767/8915 +f 7851/12190/11323 7852/12191/11324 9590/9830/8978 +f 7852/12191/11324 7853/12192/11325 9653/9893/9040 +f 7853/12192/11325 7854/12193/11326 9716/9956/9102 +f 7854/12193/11326 7855/12194/11327 9779/10019/9165 +f 7855/12194/11327 7856/12195/11328 9842/10082/9228 +f 7856/12195/11328 7857/12196/10750 9905/10145/9291 +f 7857/12196/10750 7858/12197/11329 9968/10208/9354 +f 7858/12197/11329 7859/12198/11330 10031/10271/9417 +f 7859/12198/11330 7860/12199/11331 10094/10334/9480 +f 7860/12199/11331 7861/12200/11332 10157/10397/9543 +f 7861/12200/11332 7862/12201/11333 10220/10460/9606 +f 7862/12201/11333 7863/12202/11334 10283/10523/9669 +f 7863/12202/11334 7864/12203/11335 10346/10586/9732 +f 7864/12203/11335 7865/12204/11336 10409/10649/9793 +f 7865/12204/11336 7866/12205/11337 10472/10712/9856 +f 7866/12205/11337 7867/12206/11338 10535/10775/9919 +f 7867/12206/11338 7868/12207/11339 10598/10838/9982 +f 7868/12207/11339 7869/12208/11340 10661/10901/10043 +f 7869/12208/11340 7870/12209/11341 10724/10964/10105 +f 7870/12209/11341 7871/12210/11342 10787/11027/10168 +f 7871/12210/11342 7872/12211/11343 10850/11090/10231 +f 7872/12211/11343 7873/12212/11344 10913/11153/10294 +f 7873/12212/11344 7874/12213/11345 10976/11216/10356 +f 7874/12213/11345 7875/12214/11346 11039/11279/10418 +f 7875/12214/11346 7876/12215/11347 11102/11342/10480 +f 7876/12215/11347 7877/12216/11348 11165/11405/10543 +f 7877/12216/11348 7878/12217/11349 11228/11468/10605 +f 7878/12217/11349 7879/12218/11350 11291/11531/10668 +f 7879/12218/11350 7880/12219/11351 11354/11594/10731 +f 7880/12219/11351 7881/12220/10087 11417/11657/10794 +f 7881/12220/10087 7882/12221/11352 11480/11720/10857 +f 7882/12221/11352 7883/12222/11353 11543/11783/10920 +f 7883/12222/11353 7884/12223/11354 11606/11846/10982 +f 7884/12223/11354 7885/12224/11355 11669/11909/11045 +f 7885/12224/11355 7886/12225/11356 11732/11972/11107 +f 7886/12225/11356 7887/12226/11357 11795/12035/11169 +f 7887/12226/11357 7888/12227/11358 11858/12098/11232 +f 7888/12227/11358 7889/12229/11360 11921/12228/11359 +f 7889/12229/11360 7700/12356/11487 7890/12230/11361 +f 11921/12228/11359 7890/12230/11361 7891/12231/11362 +f 11920/12099/11233 7891/12231/11362 7892/12232/11363 +f 11919/12097/11231 7892/12232/11363 7893/12233/11364 +f 11918/12096/11230 7893/12233/11364 7894/12234/11365 +f 11917/12095/11229 7894/12234/11365 7895/12235/11366 +f 11916/12094/11228 7895/12235/11366 7896/12236/11367 +f 11915/12093/11227 7896/12236/11367 7897/12237/11368 +f 11914/12092/11226 7897/12237/11368 7898/12238/11369 +f 11913/12091/11225 7898/12238/11369 7899/12239/11370 +f 11912/12090/11224 7899/12239/11370 7900/12240/11371 +f 11911/12089/11223 7900/12240/11371 7901/12241/11372 +f 11910/12088/11222 7901/12241/11372 7902/12242/11373 +f 11909/12087/11221 7902/12242/11373 7903/12243/11374 +f 11908/12086/11220 7903/12243/11374 7904/12244/11375 +f 11907/12085/11219 7904/12244/11375 7905/12245/11376 +f 11906/12084/11218 7905/12245/11376 7906/12246/11377 +f 11905/12083/11217 7906/12246/11377 7907/12247/11378 +f 11904/12082/11216 7907/12247/11378 7908/12248/11379 +f 11903/12081/11215 7908/12248/11379 7909/12249/11380 +f 11902/12080/11214 7909/12249/11380 7910/12250/11381 +f 11901/12079/11213 7910/12250/11381 7911/12251/11382 +f 11900/12078/11212 7911/12251/11382 7912/12252/11383 +f 11899/12077/11211 7912/12252/11383 7913/12253/11384 +f 11898/12076/11210 7913/12253/11384 7914/12254/11385 +f 11897/12075/11209 7914/12254/11385 7915/12255/11386 +f 11896/12074/11208 7915/12255/11386 7916/12256/11387 +f 11895/12073/11207 7916/12256/11387 7917/12257/11388 +f 11894/12072/11206 7917/12257/11388 7918/12258/11389 +f 11893/12071/11205 7918/12258/11389 7919/12259/11390 +f 11892/12070/11204 7919/12259/11390 7920/12260/11391 +f 11891/12069/11203 7920/12260/11391 7921/12261/11392 +f 11890/12068/11202 7921/12261/11392 7922/12262/11393 +f 11889/12067/11201 7922/12262/11393 7923/12263/11394 +f 11888/12066/11200 7923/12263/11394 7924/12264/11395 +f 11887/12065/11199 7924/12264/11395 7925/12265/11396 +f 11886/12064/11198 7925/12265/11396 7926/12266/11397 +f 11885/12063/11197 7926/12266/11397 7927/12267/11398 +f 11884/12062/11196 7927/12267/11398 7928/12268/11399 +f 11883/12061/11195 7928/12268/11399 7929/12269/11400 +f 11882/12060/11194 7929/12269/11400 7930/12270/11401 +f 11881/12059/11193 7930/12270/11401 7931/12271/11402 +f 11880/12058/11192 7931/12271/11402 7932/12272/11403 +f 11879/12057/11191 7932/12272/11403 7933/12273/11404 +f 11878/12056/11190 7933/12273/11404 7934/12274/11405 +f 11877/12055/11189 7934/12274/11405 7935/12275/11406 +f 11876/12054/11188 7935/12275/11406 7936/12276/11407 +f 11875/12053/11187 7936/12276/11407 7937/12277/11408 +f 11874/12052/11186 7937/12277/11408 7938/12278/11409 +f 11873/12051/11185 7938/12278/11409 7939/12279/11410 +f 11872/12050/11184 7939/12279/11410 7940/12280/11411 +f 11871/12049/11183 7940/12280/11411 7941/12281/11412 +f 11870/12048/11182 7941/12281/11412 7942/12282/11413 +f 11869/12047/11181 7942/12282/11413 7943/12283/11414 +f 11868/12046/11180 7943/12283/11414 7944/12284/11415 +f 11867/12045/11179 7944/12284/11415 7945/12285/11416 +f 11866/12044/11178 7945/12285/11416 7946/12286/11417 +f 11865/12043/11177 7946/12286/11417 7947/12287/11418 +f 11864/12042/11176 7947/12287/11418 7948/12288/11419 +f 11863/12041/11175 7948/12288/11419 7949/12289/11420 +f 11862/12040/11174 7949/12289/11420 7950/12290/11421 +f 11861/12039/11173 7950/12290/11421 7951/12291/11422 +f 11860/12038/11172 7951/12291/11422 7952/12292/11423 +f 11859/12037/11171 7952/12292/11423 7699/12293/11424 +f 11796/11974/11109 11859/12037/11171 7701/12294/11425 +f 11733/11911/11047 11796/11974/11109 7702/12295/11426 +f 11670/11848/10984 11733/11911/11047 7703/12296/11427 +f 11607/11785/10922 11670/11848/10984 7704/12297/11428 +f 11544/11722/10859 11607/11785/10922 7705/12298/11429 +f 11481/11659/10796 11544/11722/10859 7706/12299/11430 +f 11418/11596/10733 11481/11659/10796 7707/12300/11431 +f 11355/11533/10670 11418/11596/10733 7708/12301/11432 +f 11292/11470/10607 11355/11533/10670 7709/12302/11433 +f 11229/11407/10545 11292/11470/10607 7710/12303/11434 +f 11166/11344/10482 11229/11407/10545 7711/12304/11435 +f 11103/11281/10420 11166/11344/10482 7712/12305/11436 +f 11040/11218/10358 11103/11281/10420 7713/12306/11437 +f 10977/11155/10296 11040/11218/10358 7714/12307/11438 +f 10914/11092/10233 10977/11155/10296 7715/12308/11439 +f 10851/11029/10170 10914/11092/10233 7716/12309/11440 +f 10788/10966/10107 10851/11029/10170 7717/12310/11441 +f 10725/10903/10045 10788/10966/10107 7718/12311/11442 +f 10662/10840/9838 10725/10903/10045 7719/12312/11443 +f 10599/10777/9921 10662/10840/9838 7720/12313/11444 +f 10536/10714/9858 10599/10777/9921 7721/12314/11445 +f 10473/10651/9795 10536/10714/9858 7722/12315/11446 +f 10410/10588/9734 10473/10651/9795 7723/12316/11447 +f 10347/10525/9671 10410/10588/9734 7724/12317/11448 +f 10284/10462/9608 10347/10525/9671 7725/12318/11449 +f 10221/10399/9545 10284/10462/9608 7726/12319/11450 +f 10158/10336/9482 10221/10399/9545 7727/12320/11451 +f 10095/10273/9419 10158/10336/9482 7728/12321/11452 +f 10032/10210/9356 10095/10273/9419 7729/12322/11453 +f 9969/10147/9293 10032/10210/9356 7730/12323/11454 +f 9906/10084/9230 9969/10147/9293 7731/12324/11455 +f 9843/10021/9167 9906/10084/9230 7732/12325/11456 +f 9780/9958/9104 9843/10021/9167 7733/12326/11457 +f 9717/9895/9042 9780/9958/9104 7734/12327/11458 +f 9654/9832/8980 9717/9895/9042 7735/12328/11459 +f 9591/9769/8917 9654/9832/8980 7736/12329/11460 +f 9528/9706/8854 9591/9769/8917 7737/12330/11461 +f 9465/9643/8792 9528/9706/8854 7738/12331/11462 +f 9402/9580/8730 9465/9643/8792 7739/12332/11463 +f 9339/9517/8667 9402/9580/8730 7740/12333/11464 +f 9276/9454/8604 9339/9517/8667 7741/12334/11465 +f 9213/9391/8541 9276/9454/8604 7742/12335/11466 +f 9150/9328/8479 9213/9391/8541 7743/12336/11467 +f 9087/9265/8416 9150/9328/8479 7744/12337/11468 +f 9024/9202/8353 9087/9265/8416 7745/12338/11469 +f 8961/9139/8291 9024/9202/8353 7746/12339/11470 +f 8898/9076/8229 8961/9139/8291 7747/12340/11471 +f 8835/9013/8167 8898/9076/8229 7748/12341/11472 +f 8772/8950/8104 8835/9013/8167 7749/12342/11473 +f 8709/8887/8041 8772/8950/8104 7750/12343/11474 +f 8646/8824/7978 8709/8887/8041 7751/12344/11475 +f 8583/8761/7915 8646/8824/7978 7752/12345/11476 +f 8520/8698/7852 8583/8761/7915 7753/12346/11477 +f 8457/8635/7789 8520/8698/7852 7754/12347/11478 +f 8394/8572/7726 8457/8635/7789 7755/12348/11479 +f 8331/8509/7663 8394/8572/7726 7756/12349/11480 +f 8268/8446/7600 8331/8509/7663 7757/12350/11481 +f 8205/8383/7537 8268/8446/7600 7758/12351/11482 +f 8142/8320/7474 8205/8383/7537 7759/12352/11483 +f 8079/8257/7411 8142/8320/7474 7760/12353/11484 +f 8016/8133/7287 8079/8257/7411 7761/12354/11485 +f 7953/8134/7288 8016/8133/7287 7762/12355/11486 diff --git a/bin/assets/textures/clouds.png b/bin/assets/textures/clouds.png new file mode 100644 index 0000000..f57d6f1 Binary files /dev/null and b/bin/assets/textures/clouds.png differ diff --git a/bin/spectrum/air.spd b/bin/spectrum/air.spd new file mode 100644 index 0000000..8579a99 --- /dev/null +++ b/bin/spectrum/air.spd @@ -0,0 +1,481 @@ +1.30 1.000273570659 +1.31 1.000273556727 +1.32 1.000273543114 +1.33 1.000273529809 +1.34 1.000273516805 +1.35 1.000273504092 +1.36 1.000273491661 +1.37 1.000273479504 +1.38 1.000273467614 +1.39 1.000273455982 +1.40 1.000273444601 +1.41 1.000273433464 +1.42 1.000273422564 +1.43 1.000273411893 +1.44 1.000273401447 +1.45 1.000273391217 +1.46 1.000273381199 +1.47 1.000273371387 +1.48 1.000273361774 +1.49 1.000273352355 +1.50 1.000273343125 +1.51 1.000273334079 +1.52 1.000273325212 +1.53 1.000273316519 +1.54 1.000273307996 +1.55 1.000273299637 +1.56 1.000273291440 +1.57 1.000273283399 +1.58 1.000273275510 +1.59 1.000273267770 +1.60 1.000273260175 +1.61 1.000273252721 +1.62 1.000273245404 +1.63 1.000273238222 +1.64 1.000273231171 +1.65 1.000273224247 +1.66 1.000273217448 +1.67 1.000273210770 +1.68 1.000273204211 +1.69 1.000273197768 +1.70 1.000273191437 +1.71 1.000273185217 +1.72 1.000273179105 +1.73 1.000273173098 +1.74 1.000273167194 +1.75 1.000273161390 +1.76 1.000273155684 +1.77 1.000273150074 +1.78 1.000273144558 +1.79 1.000273139134 +1.80 1.000273133799 +1.81 1.000273128552 +1.82 1.000273123391 +1.83 1.000273118314 +1.84 1.000273113318 +1.85 1.000273108403 +1.86 1.000273103567 +1.87 1.000273098807 +1.88 1.000273094123 +1.89 1.000273089513 +1.90 1.000273084975 +1.91 1.000273080507 +1.92 1.000273076109 +1.93 1.000273071778 +1.94 1.000273067515 +1.95 1.000273063316 +1.96 1.000273059181 +1.97 1.000273055109 +1.98 1.000273051098 +1.99 1.000273047147 +2.00 1.000273043255 +2.01 1.000273039421 +2.02 1.000273035643 +2.03 1.000273031922 +2.04 1.000273028254 +2.05 1.000273024641 +2.06 1.000273021080 +2.07 1.000273017570 +2.08 1.000273014111 +2.09 1.000273010701 +2.10 1.000273007341 +2.11 1.000273004028 +2.12 1.000273000762 +2.13 1.000272997542 +2.14 1.000272994367 +2.15 1.000272991237 +2.16 1.000272988151 +2.17 1.000272985107 +2.18 1.000272982106 +2.19 1.000272979146 +2.20 1.000272976227 +2.21 1.000272973347 +2.22 1.000272970507 +2.23 1.000272967706 +2.24 1.000272964943 +2.25 1.000272962216 +2.26 1.000272959527 +2.27 1.000272956874 +2.28 1.000272954256 +2.29 1.000272951673 +2.30 1.000272949124 +2.31 1.000272946609 +2.32 1.000272944127 +2.33 1.000272941678 +2.34 1.000272939260 +2.35 1.000272936875 +2.36 1.000272934520 +2.37 1.000272932196 +2.38 1.000272929902 +2.39 1.000272927638 +2.40 1.000272925403 +2.41 1.000272923196 +2.42 1.000272921018 +2.43 1.000272918868 +2.44 1.000272916745 +2.45 1.000272914648 +2.46 1.000272912579 +2.47 1.000272910535 +2.48 1.000272908517 +2.49 1.000272906525 +2.50 1.000272904557 +2.80 1.000272874881 +2.81 1.000272865477 +2.82 1.000272857462 +2.83 1.000272850682 +2.84 1.000272844993 +2.85 1.000272840266 +2.86 1.000272836382 +2.87 1.000272833232 +2.88 1.000272830715 +2.89 1.000272828743 +2.90 1.000272827234 +2.91 1.000272826112 +2.92 1.000272825312 +2.93 1.000272824772 +2.94 1.000272824441 +2.95 1.000272824268 +2.96 1.000272824211 +2.97 1.000272824233 +2.98 1.000272824300 +2.99 1.000272824384 +3.00 1.000272824458 +3.01 1.000272824501 +3.02 1.000272824495 +3.03 1.000272824425 +3.04 1.000272824277 +3.05 1.000272824042 +3.06 1.000272823712 +3.07 1.000272823280 +3.08 1.000272822744 +3.09 1.000272822100 +3.10 1.000272821348 +3.11 1.000272820488 +3.12 1.000272819522 +3.13 1.000272818453 +3.14 1.000272817284 +3.15 1.000272816021 +3.16 1.000272814668 +3.17 1.000272813230 +3.18 1.000272811715 +3.19 1.000272810129 +3.20 1.000272808479 +3.21 1.000272806772 +3.22 1.000272805015 +3.23 1.000272803217 +3.24 1.000272801384 +3.25 1.000272799524 +3.26 1.000272797644 +3.27 1.000272795753 +3.28 1.000272793857 +3.29 1.000272791962 +3.30 1.000272790077 +3.31 1.000272788207 +3.32 1.000272786360 +3.33 1.000272784540 +3.34 1.000272782753 +3.35 1.000272781005 +3.36 1.000272779301 +3.37 1.000272777645 +3.38 1.000272776042 +3.39 1.000272774495 +3.40 1.000272773008 +3.41 1.000272771583 +3.42 1.000272770223 +3.43 1.000272768931 +3.44 1.000272767708 +3.45 1.000272766555 +3.46 1.000272765473 +3.47 1.000272764462 +3.48 1.000272763523 +3.49 1.000272762655 +3.50 1.000272761857 +3.51 1.000272761127 +3.52 1.000272760465 +3.53 1.000272759867 +3.54 1.000272759332 +3.55 1.000272758856 +3.56 1.000272758437 +3.57 1.000272758069 +3.58 1.000272757750 +3.59 1.000272757474 +3.60 1.000272757238 +3.61 1.000272757035 +3.62 1.000272756861 +3.63 1.000272756709 +3.64 1.000272756573 +3.65 1.000272756447 +3.66 1.000272756324 +3.67 1.000272756197 +3.68 1.000272756058 +3.69 1.000272755900 +3.70 1.000272755715 +3.71 1.000272755494 +3.72 1.000272755230 +3.73 1.000272754913 +3.74 1.000272754535 +3.75 1.000272754087 +3.76 1.000272753558 +3.77 1.000272752940 +3.78 1.000272752223 +3.79 1.000272751396 +3.80 1.000272750451 +3.81 1.000272749376 +3.82 1.000272748161 +3.83 1.000272746795 +3.84 1.000272745269 +3.85 1.000272743570 +3.86 1.000272741688 +3.87 1.000272739612 +3.88 1.000272737331 +3.89 1.000272734833 +3.90 1.000272732107 +3.91 1.000272729141 +3.92 1.000272725925 +3.93 1.000272722445 +3.94 1.000272718691 +3.95 1.000272714652 +3.96 1.000272710314 +3.97 1.000272705666 +3.98 1.000272700697 +3.99 1.000272695394 +4.00 1.000272689746 +4.01 1.000272683740 +4.02 1.000272677365 +4.03 1.000272670608 +4.04 1.000272663458 +4.05 1.000272655903 +4.06 1.000272647931 +4.07 1.000272639529 +4.08 1.000272630686 +4.09 1.000272621390 +4.10 1.000272611630 +4.11 1.000272601392 +4.12 1.000272590666 +4.13 1.000272579440 +4.14 1.000272567702 +4.15 1.000272555440 +4.16 1.000272542643 +4.17 1.000272529299 +4.18 1.000272515396 +4.19 1.000272500924 +4.20 1.000272485871 +4.35 1.000273011293 +4.36 1.000272988240 +4.37 1.000272967424 +4.38 1.000272948658 +4.39 1.000272931765 +4.40 1.000272916582 +4.41 1.000272902955 +4.42 1.000272890743 +4.43 1.000272879814 +4.44 1.000272870046 +4.45 1.000272861325 +4.46 1.000272853547 +4.47 1.000272846616 +4.48 1.000272840441 +4.49 1.000272834942 +4.50 1.000272830043 +4.51 1.000272825675 +4.52 1.000272821776 +4.53 1.000272818288 +4.54 1.000272815159 +4.55 1.000272812343 +4.56 1.000272809798 +4.57 1.000272807484 +4.58 1.000272805367 +4.59 1.000272803419 +4.60 1.000272801611 +4.61 1.000272799920 +4.62 1.000272798325 +4.63 1.000272796808 +4.64 1.000272795355 +4.65 1.000272793951 +4.66 1.000272792586 +4.67 1.000272791251 +4.68 1.000272789939 +4.69 1.000272788643 +4.70 1.000272787361 +4.71 1.000272786088 +4.72 1.000272784824 +4.73 1.000272783566 +4.74 1.000272782316 +4.75 1.000272781075 +4.76 1.000272779843 +4.77 1.000272778622 +4.78 1.000272777416 +4.79 1.000272776226 +4.80 1.000272775056 +4.81 1.000272773908 +4.82 1.000272772786 +4.83 1.000272771693 +4.84 1.000272770631 +4.85 1.000272769604 +4.86 1.000272768614 +4.87 1.000272767664 +4.88 1.000272766754 +4.89 1.000272765888 +4.90 1.000272765065 +4.91 1.000272764287 +4.92 1.000272763553 +4.93 1.000272762864 +4.94 1.000272762217 +4.95 1.000272761611 +4.96 1.000272761044 +4.97 1.000272760512 +4.98 1.000272760012 +4.99 1.000272759539 +5.00 1.000272759087 +5.01 1.000272758650 +5.02 1.000272758222 +5.03 1.000272757794 +5.04 1.000272757358 +5.05 1.000272756904 +5.06 1.000272756422 +5.07 1.000272755900 +5.08 1.000272755328 +5.09 1.000272754690 +5.10 1.000272753975 +5.11 1.000272753167 +5.12 1.000272752250 +5.13 1.000272751209 +5.14 1.000272750025 +5.15 1.000272748680 +5.16 1.000272747157 +5.17 1.000272745433 +5.18 1.000272743490 +5.19 1.000272741304 +5.20 1.000272738855 +7.50 1.000272702046 +7.55 1.000272700581 +7.60 1.000272699435 +7.65 1.000272698557 +7.70 1.000272697902 +7.75 1.000272697430 +7.80 1.000272697108 +7.85 1.000272696907 +7.90 1.000272696800 +7.95 1.000272696765 +8.00 1.000272696785 +8.05 1.000272696842 +8.10 1.000272696924 +8.15 1.000272697020 +8.20 1.000272697119 +8.25 1.000272697215 +8.30 1.000272697301 +8.35 1.000272697373 +8.40 1.000272697428 +8.45 1.000272697461 +8.50 1.000272697473 +8.55 1.000272697461 +8.60 1.000272697425 +8.65 1.000272697365 +8.70 1.000272697283 +8.75 1.000272697178 +8.80 1.000272697053 +8.85 1.000272696907 +8.90 1.000272696744 +8.95 1.000272696564 +9.00 1.000272696370 +9.05 1.000272696164 +9.10 1.000272695947 +9.15 1.000272695721 +9.20 1.000272695488 +9.25 1.000272695251 +9.30 1.000272695010 +9.35 1.000272694768 +9.40 1.000272694527 +9.45 1.000272694287 +9.50 1.000272694051 +9.55 1.000272693819 +9.60 1.000272693593 +9.65 1.000272693374 +9.70 1.000272693164 +9.75 1.000272692962 +9.80 1.000272692770 +9.85 1.000272692588 +9.90 1.000272692417 +9.95 1.000272692258 +10.00 1.000272692110 +10.05 1.000272691975 +10.10 1.000272691851 +10.15 1.000272691739 +10.20 1.000272691639 +10.25 1.000272691551 +10.30 1.000272691474 +10.35 1.000272691408 +10.40 1.000272691353 +10.45 1.000272691308 +10.50 1.000272691273 +10.55 1.000272691246 +10.60 1.000272691227 +10.65 1.000272691215 +10.70 1.000272691210 +10.75 1.000272691210 +10.80 1.000272691215 +10.85 1.000272691223 +10.90 1.000272691233 +10.95 1.000272691245 +11.00 1.000272691257 +11.05 1.000272691267 +11.10 1.000272691276 +11.15 1.000272691280 +11.20 1.000272691280 +11.25 1.000272691274 +11.30 1.000272691261 +11.35 1.000272691239 +11.40 1.000272691207 +11.45 1.000272691163 +11.50 1.000272691107 +11.55 1.000272691037 +11.60 1.000272690951 +11.65 1.000272690849 +11.70 1.000272690728 +11.75 1.000272690588 +11.80 1.000272690427 +11.85 1.000272690244 +11.90 1.000272690037 +11.95 1.000272689805 +12.00 1.000272689547 +12.05 1.000272689262 +12.10 1.000272688948 +12.15 1.000272688603 +12.20 1.000272688228 +12.25 1.000272687819 +12.30 1.000272687377 +12.35 1.000272686899 +12.40 1.000272686385 +12.45 1.000272685834 +12.50 1.000272685244 +12.55 1.000272684614 +12.60 1.000272683943 +12.65 1.000272683230 +12.70 1.000272682473 +12.75 1.000272681673 +12.80 1.000272680827 +12.85 1.000272679934 +12.90 1.000272678995 +12.95 1.000272678007 +13.00 1.000272676969 +13.05 1.000272675882 +13.10 1.000272674743 +13.15 1.000272673552 +13.20 1.000272672308 +13.25 1.000272671010 +13.30 1.000272669658 +13.35 1.000272668251 +13.40 1.000272666787 +13.45 1.000272665266 +13.50 1.000272663688 +13.55 1.000272662051 +13.60 1.000272660355 +13.65 1.000272658600 +13.70 1.000272656784 +13.75 1.000272654907 +13.80 1.000272652969 +13.85 1.000272650969 +13.90 1.000272648906 +13.95 1.000272646779 +14.00 1.000272644589 +14.05 1.000272642335 +14.10 1.000272640016 diff --git a/bin/spectrum/carbon.spd b/bin/spectrum/carbon.spd new file mode 100644 index 0000000..9ff64a4 --- /dev/null +++ b/bin/spectrum/carbon.spd @@ -0,0 +1,53 @@ +0.3500 1.930 0.914 +0.3600 1.927 0.902 +0.3700 1.927 0.895 +0.3800 1.936 0.890 +0.3900 1.935 0.884 +0.4000 1.940 0.879 +0.4100 1.942 0.873 +0.4200 1.942 0.870 +0.4300 1.943 0.870 +0.4400 1.944 0.872 +0.4500 1.947 0.875 +0.4600 1.951 0.879 +0.4700 1.956 0.882 +0.4800 1.961 0.886 +0.4900 1.967 0.888 +0.5000 1.972 0.890 +0.5100 1.976 0.891 +0.5200 1.980 0.896 +0.5300 1.984 0.900 +0.5400 1.987 0.903 +0.5500 1.990 0.907 +0.5600 1.993 0.912 +0.5700 1.997 0.919 +0.5800 2.002 0.923 +0.5900 2.005 0.928 +0.6000 2.009 0.933 +0.6100 2.012 0.940 +0.6200 2.016 0.945 +0.6300 2.020 0.954 +0.6400 2.028 0.960 +0.6500 2.033 0.961 +0.6600 2.033 0.966 +0.6700 2.036 0.974 +0.6800 2.040 0.982 +0.6900 2.045 0.989 +0.7000 2.050 0.995 +0.7100 2.055 1.002 +0.7200 2.059 1.008 +0.7300 2.064 1.014 +0.7400 2.067 1.020 +0.7500 2.072 1.028 +0.7600 2.078 1.035 +0.7700 2.083 1.040 +0.7800 2.088 1.046 +0.7900 2.092 1.051 +0.8000 2.097 1.056 +0.8100 2.100 1.061 +0.8200 2.103 1.067 +0.8300 2.106 1.074 +0.8400 2.110 1.082 +0.8500 2.115 1.088 +0.8600 2.119 1.094 +0.8700 2.124 1.099 diff --git a/bin/spectrum/chrome.spd b/bin/spectrum/chrome.spd new file mode 100644 index 0000000..f99262a --- /dev/null +++ b/bin/spectrum/chrome.spd @@ -0,0 +1,18 @@ +0.354 1.84 2.64 +0.368 1.87 2.69 +0.381 1.92 2.74 +0.397 2.00 2.83 +0.413 2.08 2.93 +0.431 2.19 3.04 +0.451 2.33 3.14 +0.471 2.51 3.24 +0.496 2.75 3.30 +0.521 2.94 3.33 +0.549 3.18 3.33 +0.582 3.22 3.30 +0.617 3.17 3.30 +0.659 3.09 3.34 +0.704 3.05 3.39 +0.756 3.08 3.42 +0.821 3.20 3.48 +0.892 3.30 3.52 diff --git a/bin/spectrum/copper.spd b/bin/spectrum/copper.spd new file mode 100644 index 0000000..7b10d14 --- /dev/null +++ b/bin/spectrum/copper.spd @@ -0,0 +1,55 @@ +302.400421 1.380000 1.687000 +306.133759 1.358438 1.703313 +309.960449 1.340000 1.720000 +313.884003 1.329063 1.744563 +317.908142 1.325000 1.770000 +322.036835 1.332500 1.791625 +326.274139 1.340000 1.810000 +330.624481 1.334375 1.822125 +335.092377 1.325000 1.834000 +339.682678 1.317812 1.851750 +344.400482 1.310000 1.872000 +349.251221 1.300313 1.894250 +354.240509 1.290000 1.916000 +359.374420 1.281563 1.931688 +364.659332 1.270000 1.950000 +370.102020 1.249062 1.972438 +375.709625 1.225000 2.015000 +381.489777 1.200000 2.121562 +387.450562 1.180000 2.210000 +393.600555 1.174375 2.177188 +399.948975 1.175000 2.130000 +406.505493 1.177500 2.160063 +413.280579 1.180000 2.210000 +420.285339 1.178125 2.249938 +427.531647 1.175000 2.289000 +435.032196 1.172812 2.326000 +442.800629 1.170000 2.362000 +450.851562 1.165312 2.397625 +459.200653 1.160000 2.433000 +467.864838 1.155312 2.469187 +476.862213 1.150000 2.504000 +486.212463 1.142812 2.535875 +495.936707 1.135000 2.564000 +506.057861 1.131562 2.589625 +516.600769 1.120000 2.605000 +527.592224 1.092437 2.595562 +539.061646 1.040000 2.583000 +551.040771 0.950375 2.576500 +563.564453 0.826000 2.599000 +576.670593 0.645875 2.678062 +590.400818 0.468000 2.809000 +604.800842 0.351250 3.010750 +619.920898 0.272000 3.240000 +635.816284 0.230813 3.458187 +652.548279 0.214000 3.670000 +670.184753 0.209250 3.863125 +688.800964 0.213000 4.050000 +708.481018 0.216250 4.239563 +729.318665 0.223000 4.430000 +751.419250 0.236500 4.619563 +774.901123 0.250000 4.817000 +799.897949 0.254188 5.034125 +826.561157 0.260000 5.260000 +855.063293 0.280000 5.485625 +885.601257 0.300000 5.717000 diff --git a/bin/spectrum/copper_oxide.spd b/bin/spectrum/copper_oxide.spd new file mode 100644 index 0000000..31fb56d --- /dev/null +++ b/bin/spectrum/copper_oxide.spd @@ -0,0 +1,167 @@ +3.5842 2.302 0.045 +3.5971 2.302 0.045 +3.6101 2.302 0.045 +3.6232 2.302 0.045 +3.6364 2.302 0.045 +3.6496 2.302 0.045 +3.6630 2.303 0.045 +3.6765 2.303 0.045 +3.6900 2.303 0.045 +3.7037 2.304 0.045 +3.7175 2.304 0.045 +3.7313 2.304 0.045 +3.7453 2.305 0.043 +3.7594 2.305 0.045 +3.7736 2.305 0.044 +3.7879 2.305 0.044 +3.8023 2.305 0.044 +3.8168 2.306 0.044 +3.8314 2.306 0.044 +3.8462 2.306 0.044 +3.8610 2.306 0.044 +3.8760 2.306 0.044 +3.8911 2.306 0.043 +3.9063 2.306 0.043 +3.9216 2.306 0.043 +3.9370 2.307 0.043 +3.9526 2.307 0.043 +3.9683 2.307 0.043 +3.9841 2.307 0.043 +4.0000 2.307 0.043 +4.0161 2.307 0.043 +4.0323 2.307 0.043 +4.0486 2.307 0.043 +4.0650 2.307 0.044 +4.0816 2.308 0.044 +4.0984 2.308 0.043 +4.1152 2.308 0.043 +4.1322 2.308 0.043 +4.1494 2.308 0.043 +4.1667 2.309 0.043 +4.1841 2.308 0.042 +4.2017 2.308 0.043 +4.2194 2.308 0.043 +4.2373 2.308 0.043 +4.2553 2.308 0.043 +4.2735 2.309 0.043 +4.2918 2.309 0.043 +4.3103 2.309 0.043 +4.3290 2.309 0.043 +4.3478 2.309 0.043 +4.3668 2.309 0.042 +4.3860 2.309 0.042 +4.4053 2.309 0.043 +4.4248 2.310 0.043 +4.4444 2.310 0.043 +4.4643 2.310 0.042 +4.4843 2.310 0.042 +4.5045 2.310 0.042 +4.5249 2.309 0.042 +4.5455 2.310 0.042 +4.5662 2.310 0.042 +4.5872 2.310 0.042 +4.6083 2.310 0.042 +4.6296 2.309 0.042 +4.6512 2.310 0.043 +4.6729 2.310 0.043 +4.6948 2.310 0.043 +4.7170 2.310 0.042 +4.7393 2.310 0.042 +4.7619 2.310 0.043 +4.7847 2.310 0.043 +4.8077 2.311 0.043 +4.8309 2.311 0.043 +4.8544 2.311 0.043 +4.8780 2.310 0.042 +4.9020 2.310 0.043 +4.9261 2.310 0.043 +4.9505 2.311 0.043 +4.9751 2.310 0.043 +5.0000 2.310 0.044 +5.0251 2.311 0.045 +5.0505 2.312 0.045 +5.0761 2.313 0.044 +5.1020 2.313 0.044 +5.1282 2.313 0.044 +5.1546 2.313 0.044 +5.1813 2.314 0.044 +5.2083 2.314 0.044 +5.2356 2.314 0.043 +5.2632 2.314 0.043 +5.2910 2.314 0.044 +5.3191 2.315 0.043 +5.3476 2.315 0.043 +5.3763 2.313 0.043 +5.4054 2.315 0.042 +5.4348 2.315 0.042 +5.4645 2.315 0.042 +5.4945 2.315 0.042 +5.5249 2.315 0.042 +5.5556 2.315 0.041 +5.5866 2.314 0.042 +5.6180 2.315 0.042 +5.6497 2.315 0.042 +5.6818 2.315 0.042 +5.7143 2.315 0.042 +5.7471 2.315 0.041 +5.7803 2.315 0.041 +5.8140 2.315 0.041 +5.8480 2.315 0.040 +5.8824 2.314 0.040 +5.9172 2.314 0.040 +5.9524 2.314 0.040 +5.9880 2.314 0.040 +6.0241 2.314 0.040 +6.0606 2.314 0.040 +6.0976 2.314 0.040 +6.1350 2.314 0.040 +6.1728 2.313 0.041 +6.2112 2.313 0.041 +6.2500 2.313 0.041 +6.2893 2.314 0.041 +6.3291 2.314 0.041 +6.3694 2.314 0.041 +6.4103 2.314 0.040 +6.4516 2.314 0.040 +6.4935 2.314 0.040 +6.5359 2.314 0.040 +6.5789 2.314 0.040 +6.6225 2.314 0.040 +6.6667 2.314 0.039 +6.7114 2.313 0.040 +6.7568 2.313 0.040 +6.8027 2.314 0.039 +6.8493 2.313 0.039 +6.8966 2.312 0.039 +6.9444 2.312 0.039 +6.9930 2.312 0.040 +7.0423 2.312 0.039 +7.0922 2.312 0.040 +7.1429 2.313 0.040 +7.1942 2.313 0.040 +7.2464 2.313 0.039 +7.2993 2.314 0.039 +7.3529 2.314 0.037 +7.4074 2.313 0.037 +7.4627 2.313 0.036 +7.5188 2.312 0.036 +7.5758 2.312 0.035 +7.6336 2.312 0.034 +7.6923 2.311 0.034 +7.7519 2.310 0.033 +7.8125 2.309 0.033 +7.8740 2.308 0.033 +7.9365 2.307 0.032 +8.0000 2.307 0.032 +8.0645 2.306 0.032 +8.1301 2.305 0.031 +8.1967 2.303 0.031 +8.2645 2.302 0.031 +8.3333 2.301 0.031 +8.4034 2.299 0.031 +8.4746 2.298 0.031 +8.5470 2.296 0.031 +8.6207 2.294 0.032 +8.6957 2.293 0.034 +8.7719 2.293 0.036 +8.8496 2.293 0.037 diff --git a/bin/spectrum/diamond.spd b/bin/spectrum/diamond.spd new file mode 100644 index 0000000..4053beb --- /dev/null +++ b/bin/spectrum/diamond.spd @@ -0,0 +1,122 @@ +3.31 2.4625 +3.34 2.4635 +3.36 2.4648 +3.37 2.4661 +3.39 2.4675 +3.41 2.4685 +3.44 2.4689 +3.48 2.4690 +3.50 2.4685 +3.52 2.4677 +3.56 2.4663 +3.59 2.4650 +3.63 2.4627 +3.64 2.4626 +3.69 2.4621 +3.73 2.4610 +3.75 2.4604 +3.76 2.4601 +3.77 2.4598 +3.78 2.4596 +3.80 2.4590 +3.82 2.4585 +3.85 2.4577 +3.86 2.4556 +3.87 2.4553 +3.89 2.4546 +3.94 2.4519 +3.95 2.4514 +3.97 2.4496 +4.00 2.4491 +4.01 2.4490 +4.04 2.4474 +4.06 2.4451 +4.12 2.4445 +4.13 2.4444 +4.17 2.4442 +4.18 2.4441 +4.22 2.4412 +4.25 2.4392 +4.27 2.4379 +4.28 2.4371 +4.30 2.4355 +4.32 2.4340 +4.34 2.4324 +4.35 2.4318 +4.39 2.4295 +4.41 2.4283 +4.44 2.4265 +4.48 2.4240 +4.49 2.4234 +4.52 2.4215 +4.54 2.4204 +4.56 2.4192 +4.60 2.4155 +4.64 2.4131 +4.70 2.4114 +4.71 2.4111 +4.72 2.4108 +4.76 2.4095 +4.79 2.4090 +4.82 2.4086 +4.83 2.4086 +4.88 2.4084 +4.89 2.4084 +4.93 2.4087 +4.95 2.4089 +4.96 2.4089 +5.03 2.4092 +5.07 2.4096 +5.13 2.4101 +5.22 2.4113 +5.26 2.4130 +5.28 2.4138 +5.30 2.4155 +5.34 2.4164 +5.40 2.4174 +5.42 2.4177 +5.46 2.4188 +5.53 2.4193 +5.55 2.4194 +5.63 2.4198 +5.67 2.4207 +5.70 2.4216 +5.71 2.4218 +5.74 2.4222 +5.82 2.4225 +5.87 2.4223 +5.88 2.4222 +5.94 2.4216 +6.05 2.4213 +6.06 2.4213 +6.18 2.4212 +6.25 2.4200 +6.27 2.4197 +6.30 2.4174 +6.36 2.4152 +6.45 2.4139 +6.48 2.4135 +6.59 2.4111 +6.67 2.4086 +6.70 2.4068 +6.78 2.4063 +6.89 2.4056 +6.90 2.4056 +7.08 2.4053 +7.14 2.4005 +7.35 2.4038 +7.40 2.4032 +7.51 2.4020 +7.69 2.4005 +7.70 2.4004 +7.90 2.3991 +8.00 2.3971 +8.03 2.3965 +8.13 2.3942 +8.23 2.3922 +8.31 2.3908 +8.33 2.3907 +8.42 2.3900 +8.57 2.3891 +8.70 2.3887 +8.79 2.3884 diff --git a/bin/spectrum/glass.spd b/bin/spectrum/glass.spd new file mode 100644 index 0000000..a69df01 --- /dev/null +++ b/bin/spectrum/glass.spd @@ -0,0 +1,278 @@ +0.336 1.498976 +0.338 1.498603 +0.340 1.498238 +0.342 1.497878 +0.344 1.497525 +0.346 1.497179 +0.348 1.496838 +0.350 1.496504 +0.352 1.496175 +0.354 1.495852 +0.356 1.495534 +0.358 1.495222 +0.360 1.494915 +0.362 1.494613 +0.364 1.494316 +0.366 1.494025 +0.368 1.493738 +0.370 1.493455 +0.372 1.493177 +0.374 1.492904 +0.376 1.492635 +0.378 1.492370 +0.380 1.492110 +0.382 1.491854 +0.384 1.491601 +0.386 1.491353 +0.388 1.491108 +0.390 1.490867 +0.392 1.490629 +0.394 1.490396 +0.396 1.490165 +0.398 1.489938 +0.400 1.489714 +0.402 1.489494 +0.404 1.489276 +0.406 1.489062 +0.408 1.488850 +0.410 1.488641 +0.412 1.488435 +0.414 1.488231 +0.416 1.488031 +0.418 1.487833 +0.420 1.487638 +0.422 1.487446 +0.424 1.487256 +0.426 1.487069 +0.428 1.486884 +0.430 1.486702 +0.432 1.486522 +0.434 1.486345 +0.436 1.486170 +0.438 1.485997 +0.440 1.485827 +0.442 1.485659 +0.444 1.485493 +0.446 1.485329 +0.448 1.485167 +0.450 1.485008 +0.452 1.484851 +0.454 1.484695 +0.456 1.484542 +0.458 1.484390 +0.460 1.484241 +0.462 1.484094 +0.464 1.483948 +0.466 1.483804 +0.468 1.483662 +0.470 1.483522 +0.472 1.483383 +0.474 1.483247 +0.476 1.483111 +0.478 1.482978 +0.480 1.482846 +0.482 1.482716 +0.484 1.482588 +0.486 1.482461 +0.488 1.482335 +0.490 1.482211 +0.492 1.482089 +0.494 1.481968 +0.496 1.481848 +0.498 1.481730 +0.500 1.481613 +0.502 1.481498 +0.504 1.481384 +0.506 1.481271 +0.508 1.481160 +0.510 1.481050 +0.512 1.480941 +0.514 1.480834 +0.516 1.480727 +0.518 1.480622 +0.520 1.480518 +0.522 1.480416 +0.524 1.480314 +0.526 1.480214 +0.528 1.480115 +0.530 1.480016 +0.532 1.479919 +0.534 1.479823 +0.536 1.479729 +0.538 1.479635 +0.540 1.479542 +0.542 1.479450 +0.544 1.479359 +0.546 1.479269 +0.548 1.479181 +0.550 1.479093 +0.552 1.479006 +0.554 1.478920 +0.556 1.478835 +0.558 1.478751 +0.560 1.478667 +0.562 1.478585 +0.564 1.478503 +0.566 1.478423 +0.568 1.478343 +0.570 1.478264 +0.572 1.478186 +0.574 1.478108 +0.576 1.478032 +0.578 1.477956 +0.580 1.477881 +0.582 1.477807 +0.584 1.477733 +0.586 1.477660 +0.588 1.477588 +0.590 1.477517 +0.592 1.477447 +0.594 1.477377 +0.596 1.477308 +0.598 1.477239 +0.600 1.477171 +0.602 1.477104 +0.604 1.477038 +0.606 1.476972 +0.608 1.476907 +0.610 1.476842 +0.612 1.476778 +0.614 1.476715 +0.616 1.476652 +0.618 1.476590 +0.620 1.476529 +0.622 1.476468 +0.624 1.476408 +0.626 1.476348 +0.628 1.476289 +0.630 1.476230 +0.632 1.476172 +0.634 1.476115 +0.636 1.476058 +0.638 1.476001 +0.640 1.475946 +0.642 1.475890 +0.644 1.475835 +0.646 1.475781 +0.648 1.475727 +0.650 1.475674 +0.652 1.475621 +0.654 1.475568 +0.656 1.475517 +0.658 1.475465 +0.660 1.475414 +0.662 1.475364 +0.664 1.475314 +0.666 1.475264 +0.668 1.475215 +0.670 1.475166 +0.672 1.475118 +0.674 1.475070 +0.676 1.475022 +0.678 1.474975 +0.680 1.474929 +0.682 1.474883 +0.684 1.474837 +0.686 1.474791 +0.688 1.474746 +0.690 1.474702 +0.692 1.474657 +0.694 1.474614 +0.696 1.474570 +0.698 1.474527 +0.700 1.474484 +0.702 1.474442 +0.704 1.474400 +0.706 1.474358 +0.708 1.474317 +0.710 1.474276 +0.712 1.474235 +0.714 1.474195 +0.716 1.474155 +0.718 1.474115 +0.720 1.474076 +0.722 1.474037 +0.724 1.473998 +0.726 1.473960 +0.728 1.473922 +0.730 1.473884 +0.732 1.473847 +0.734 1.473810 +0.736 1.473773 +0.738 1.473737 +0.740 1.473700 +0.742 1.473665 +0.744 1.473629 +0.746 1.473594 +0.748 1.473559 +0.750 1.473524 +0.752 1.473489 +0.754 1.473455 +0.756 1.473421 +0.758 1.473387 +0.760 1.473354 +0.762 1.473321 +0.764 1.473288 +0.766 1.473255 +0.768 1.473223 +0.770 1.473191 +0.772 1.473159 +0.774 1.473127 +0.776 1.473096 +0.778 1.473065 +0.780 1.473034 +0.782 1.473003 +0.784 1.472973 +0.786 1.472942 +0.788 1.472912 +0.790 1.472883 +0.792 1.472853 +0.794 1.472824 +0.796 1.472795 +0.798 1.472766 +0.800 1.472737 +0.802 1.472709 +0.804 1.472680 +0.806 1.472652 +0.808 1.472625 +0.810 1.472597 +0.812 1.472570 +0.814 1.472542 +0.816 1.472515 +0.818 1.472489 +0.820 1.472462 +0.822 1.472436 +0.824 1.472409 +0.826 1.472383 +0.828 1.472357 +0.830 1.472332 +0.832 1.472306 +0.834 1.472281 +0.836 1.472256 +0.838 1.472231 +0.840 1.472206 +0.842 1.472182 +0.844 1.472157 +0.846 1.472133 +0.848 1.472109 +0.850 1.472085 +0.852 1.472061 +0.854 1.472038 +0.856 1.472014 +0.858 1.471991 +0.860 1.471968 +0.862 1.471945 +0.864 1.471922 +0.866 1.471900 +0.868 1.471877 +0.870 1.471855 +0.872 1.471833 +0.874 1.471811 +0.876 1.471789 +0.878 1.471767 +0.880 1.471746 +0.882 1.471724 +0.884 1.471703 +0.886 1.471682 +0.888 1.471661 +0.890 1.471640 diff --git a/bin/spectrum/glycerol.spd b/bin/spectrum/glycerol.spd new file mode 100644 index 0000000..f8a6d7d --- /dev/null +++ b/bin/spectrum/glycerol.spd @@ -0,0 +1,3 @@ +0.30996 1.500 +0.41328 1.480 +0.61992 1.470 diff --git a/bin/spectrum/gold.spd b/bin/spectrum/gold.spd new file mode 100644 index 0000000..c98615d --- /dev/null +++ b/bin/spectrum/gold.spd @@ -0,0 +1,56 @@ +298.757050 1.795000 1.920375 +302.400421 1.812000 1.920000 +306.133759 1.822625 1.918875 +309.960449 1.830000 1.916000 +313.884003 1.837125 1.911375 +317.908142 1.840000 1.904000 +322.036835 1.834250 1.891375 +326.274139 1.824000 1.878000 +330.624481 1.812000 1.868250 +335.092377 1.798000 1.860000 +339.682678 1.782000 1.851750 +344.400482 1.766000 1.846000 +349.251221 1.752500 1.845250 +354.240509 1.740000 1.848000 +359.374420 1.727625 1.852375 +364.659332 1.716000 1.862000 +370.102020 1.705875 1.883000 +375.709625 1.696000 1.906000 +381.489777 1.684750 1.922500 +387.450562 1.674000 1.936000 +393.600555 1.666000 1.947750 +399.948975 1.658000 1.956000 +406.505493 1.647250 1.959375 +413.280579 1.636000 1.958000 +420.285339 1.628000 1.951375 +427.531647 1.616000 1.940000 +435.032196 1.596250 1.924500 +442.800629 1.562000 1.904000 +450.851562 1.502125 1.875875 +459.200653 1.426000 1.846000 +467.864838 1.345875 1.814625 +476.862213 1.242000 1.796000 +486.212463 1.086750 1.797375 +495.936707 0.916000 1.840000 +506.057861 0.754500 1.956500 +516.600769 0.608000 2.120000 +527.592224 0.491750 2.326250 +539.061646 0.402000 2.540000 +551.040771 0.345500 2.730625 +563.564453 0.306000 2.880000 +576.670593 0.267625 2.940625 +590.400818 0.236000 2.970000 +604.800842 0.212375 3.015000 +619.920898 0.194000 3.060000 +635.816284 0.177750 3.070000 +652.548279 0.166000 3.150000 +670.184753 0.161000 3.445812 +688.800964 0.160000 3.800000 +708.481018 0.160875 4.087687 +729.318665 0.164000 4.357000 +751.419250 0.169500 4.610188 +774.901123 0.176000 4.860000 +799.897949 0.181375 5.125813 +826.561157 0.188000 5.390000 +855.063293 0.198125 5.631250 +885.601257 0.210000 5.880000 diff --git a/bin/spectrum/incandescent.spd b/bin/spectrum/incandescent.spd new file mode 100644 index 0000000..a543105 --- /dev/null +++ b/bin/spectrum/incandescent.spd @@ -0,0 +1,97 @@ +300 0.930483 +305 1.128210 +310 1.357690 +315 1.622190 +320 1.925080 +325 2.269800 +330 2.659810 +335 3.098610 +340 3.589680 +345 4.136480 +350 4.742380 +355 5.410700 +360 6.144620 +365 6.947200 +370 7.821350 +375 8.769800 +380 9.795100 +385 10.899600 +390 12.085300 +395 13.354300 +400 14.708000 +405 16.148000 +410 17.675300 +415 19.290700 +420 20.995000 +425 22.788300 +430 24.670900 +435 26.642500 +440 28.702700 +445 30.850800 +450 33.085900 +455 35.406800 +460 37.812100 +465 40.300200 +470 42.869300 +475 45.517400 +480 48.242300 +485 51.041800 +490 53.913200 +495 56.853900 +500 59.861100 +505 62.932000 +510 66.063500 +515 69.252500 +520 72.495900 +525 75.790300 +530 79.132600 +535 82.519300 +540 85.947000 +545 89.412400 +550 92.912000 +555 96.442300 +560 100.000000 +565 103.582000 +570 107.184000 +575 110.803000 +580 114.436000 +585 118.080000 +590 121.731000 +595 125.386000 +600 129.043000 +605 132.697000 +610 136.346000 +615 139.988000 +620 143.618000 +625 147.235000 +630 150.836000 +635 154.418000 +640 157.979000 +645 161.516000 +650 165.028000 +655 168.510000 +660 171.963000 +665 175.383000 +670 178.769000 +675 182.118000 +680 185.429000 +685 188.701000 +690 191.931000 +695 195.118000 +700 198.261000 +705 201.359000 +710 204.409000 +715 207.411000 +720 210.365000 +725 213.268000 +730 216.120000 +735 218.920000 +740 221.667000 +745 224.361000 +750 227.000000 +755 229.585000 +760 232.115000 +765 234.589000 +770 237.008000 +775 239.370000 +780 241.675000 diff --git a/bin/spectrum/mirror.spd b/bin/spectrum/mirror.spd new file mode 100644 index 0000000..a6880db --- /dev/null +++ b/bin/spectrum/mirror.spd @@ -0,0 +1,2 @@ +360 0 0 +830 0 0 \ No newline at end of file diff --git a/bin/spectrum/nickel.spd b/bin/spectrum/nickel.spd new file mode 100644 index 0000000..4c5d416 --- /dev/null +++ b/bin/spectrum/nickel.spd @@ -0,0 +1,18 @@ +0.354 1.74 2.32 +0.368 1.70 2.40 +0.381 1.72 2.48 +0.397 1.72 2.57 +0.413 1.70 2.69 +0.431 1.71 2.82 +0.451 1.73 2.95 +0.471 1.78 3.09 +0.496 1.82 3.25 +0.521 1.85 3.42 +0.549 1.92 3.61 +0.582 1.96 3.80 +0.617 1.99 4.02 +0.659 1.99 4.26 +0.704 2.06 4.50 +0.756 2.13 4.73 +0.821 2.26 4.97 +0.892 2.40 5.23 diff --git a/bin/spectrum/plastic.spd b/bin/spectrum/plastic.spd new file mode 100644 index 0000000..3aa70b9 --- /dev/null +++ b/bin/spectrum/plastic.spd @@ -0,0 +1,15 @@ +40.0000 1.519 0.0020 +41.6667 1.519 0.0024 +43.4783 1.519 0.0027 +45.4545 1.520 0.0029 +47.6190 1.521 0.0027 +50.0000 1.521 0.0024 +52.6316 1.521 0.0023 +55.5556 1.521 0.0021 +58.8235 1.521 0.0020 +62.5000 1.521 0.0019 +66.6667 1.521 0.0019 +71.4286 1.521 0.0018 +76.9231 1.520 0.0018 +83.3333 1.520 0.0017 +90.9091 1.520 0.0017 diff --git a/bin/spectrum/platinum.spd b/bin/spectrum/platinum.spd new file mode 100644 index 0000000..952dc37 --- /dev/null +++ b/bin/spectrum/platinum.spd @@ -0,0 +1,42 @@ +0.035937 0.7283 0.3247 +0.036466 0.7174 0.3387 +0.037010 0.7068 0.3544 +0.037571 0.6958 0.3730 +0.038149 0.6853 0.3933 +0.038745 0.6766 0.4168 +0.039360 0.6689 0.4432 +0.039995 0.6642 0.4735 +0.040651 0.6640 0.5068 +0.041328 0.6706 0.5428 +0.042029 0.6866 0.5782 +0.042753 0.7135 0.6075 +0.043503 0.7468 0.6227 +0.044280 0.7770 0.6210 +0.045085 0.7921 0.6078 +0.045920 0.7903 0.5947 +0.046786 0.7764 0.5906 +0.047686 0.7571 0.5977 +0.048621 0.7380 0.6145 +0.049594 0.7206 0.6390 +0.050606 0.7069 0.6698 +0.051660 0.6965 0.7057 +0.052759 0.6903 0.7460 +0.053906 0.6889 0.7903 +0.055104 0.6925 0.8382 +0.056356 0.7025 0.8897 +0.057667 0.7197 0.9434 +0.059040 0.7457 0.9990 +0.060480 0.7829 1.0550 +0.061992 0.8332 1.1078 +0.063582 0.8981 1.1518 +0.065255 0.9756 1.1793 +0.067018 1.0582 1.1827 +0.068880 1.1320 1.1586 +0.070848 1.1831 1.1153 +0.072932 1.2052 1.0675 +0.075142 1.2027 1.0293 +0.077490 1.1851 1.0087 +0.079990 1.1619 1.0065 +0.082656 1.1398 1.0208 +0.085506 1.1224 1.0478 +0.088560 1.1124 1.0842 diff --git a/bin/spectrum/sapphire.spd b/bin/spectrum/sapphire.spd new file mode 100644 index 0000000..afafef4 --- /dev/null +++ b/bin/spectrum/sapphire.spd @@ -0,0 +1,57 @@ +0.3300 1.737 +0.3400 1.736 +0.3500 1.734 +0.3600 1.733 +0.3700 1.733 +0.3800 1.733 +0.3900 1.733 +0.4000 1.732 +0.4100 1.731 +0.4200 1.730 +0.4300 1.730 +0.4400 1.730 +0.4500 1.730 +0.4600 1.730 +0.4700 1.730 +0.4800 1.729 +0.4900 1.729 +0.5000 1.729 +0.5100 1.729 +0.5200 1.729 +0.5300 1.729 +0.5400 1.729 +0.5500 1.729 +0.5600 1.728 +0.5700 1.728 +0.5800 1.728 +0.5900 1.728 +0.6000 1.728 +0.6100 1.728 +0.6200 1.728 +0.6300 1.728 +0.6400 1.727 +0.6500 1.727 +0.6600 1.727 +0.6700 1.727 +0.6800 1.727 +0.6900 1.727 +0.7000 1.727 +0.7100 1.727 +0.7200 1.727 +0.7300 1.727 +0.7400 1.727 +0.7500 1.727 +0.7600 1.727 +0.7700 1.727 +0.7800 1.727 +0.7900 1.727 +0.8000 1.727 +0.8100 1.726 +0.8200 1.726 +0.8300 1.726 +0.8400 1.726 +0.8500 1.726 +0.8600 1.726 +0.8700 1.726 +0.8800 1.726 +0.8900 1.726 diff --git a/bin/spectrum/silver.spd b/bin/spectrum/silver.spd new file mode 100644 index 0000000..2e49635 --- /dev/null +++ b/bin/spectrum/silver.spd @@ -0,0 +1,326 @@ +0.356113 0.082283 1.456321 +0.357705 0.079899 1.488752 +0.359302 0.077693 1.520143 +0.360902 0.075639 1.550652 +0.362495 0.073724 1.580296 +0.364092 0.071926 1.609153 +0.365692 0.070241 1.637295 +0.367284 0.068650 1.664816 +0.368880 0.067151 1.691718 +0.370478 0.065731 1.718057 +0.372079 0.064386 1.743859 +0.373671 0.063108 1.769176 +0.375266 0.061893 1.794054 +0.376863 0.060737 1.818485 +0.378462 0.059635 1.842541 +0.380051 0.058581 1.866208 +0.381654 0.057575 1.889528 +0.383247 0.056615 1.912487 +0.384841 0.055693 1.935149 +0.386436 0.054810 1.957499 +0.388033 0.053964 1.979574 +0.389630 0.053149 2.001356 +0.391228 0.052368 2.022904 +0.392827 0.051617 2.044203 +0.394427 0.050894 2.065258 +0.396014 0.050199 2.086102 +0.397615 0.049529 2.106740 +0.399215 0.048885 2.127155 +0.400815 0.048261 2.147377 +0.402402 0.047661 2.167411 +0.404002 0.047081 2.187285 +0.405601 0.046521 2.206981 +0.407200 0.045980 2.226503 +0.408798 0.045457 2.245878 +0.410394 0.044952 2.265087 +0.411990 0.044465 2.284158 +0.413584 0.043991 2.303071 +0.415177 0.043534 2.321873 +0.416768 0.043091 2.340525 +0.418371 0.042663 2.359051 +0.419972 0.042249 2.377474 +0.421557 0.041847 2.395757 +0.423154 0.041457 2.413943 +0.424749 0.041079 2.432013 +0.426356 0.040713 2.449971 +0.427945 0.040358 2.467819 +0.429546 0.040015 2.485579 +0.431144 0.039681 2.503233 +0.432740 0.039357 2.520803 +0.434331 0.039042 2.538272 +0.435935 0.038738 2.555661 +0.437519 0.038442 2.572951 +0.439115 0.038156 2.590185 +0.440723 0.037876 2.607304 +0.442311 0.037607 2.624369 +0.443910 0.037345 2.641343 +0.445506 0.037088 2.658247 +0.447096 0.036842 2.675081 +0.448698 0.036602 2.691828 +0.450295 0.036368 2.708528 +0.451887 0.036143 2.725143 +0.453490 0.035923 2.741713 +0.455088 0.035710 2.758201 +0.456681 0.035502 2.774646 +0.458284 0.035301 2.791012 +0.459865 0.035105 2.807318 +0.461474 0.034915 2.823583 +0.463060 0.034732 2.839772 +0.464656 0.034553 2.855923 +0.466264 0.034380 2.872017 +0.467847 0.034212 2.888057 +0.469442 0.034047 2.904042 +0.471047 0.033889 2.919974 +0.472645 0.033734 2.935871 +0.474236 0.033586 2.951699 +0.475837 0.033441 2.967494 +0.477432 0.033301 2.983238 +0.479018 0.033165 2.998950 +0.480615 0.033032 3.014613 +0.482222 0.032905 3.030228 +0.483803 0.032781 3.045796 +0.485413 0.032661 3.061334 +0.486996 0.032545 3.076826 +0.488588 0.032431 3.092273 +0.490192 0.032323 3.107691 +0.491786 0.032217 3.123065 +0.493391 0.032115 3.138396 +0.494986 0.032016 3.153700 +0.496572 0.031921 3.168914 +0.498169 0.031829 3.184182 +0.499775 0.031739 3.199376 +0.501351 0.031653 3.214499 +0.502958 0.031571 3.229705 +0.504555 0.031490 3.244841 +0.506141 0.031413 3.259906 +0.507737 0.031338 3.274902 +0.509343 0.031268 3.289829 +0.510938 0.031198 3.304841 +0.512522 0.031133 3.319785 +0.514116 0.031069 3.334661 +0.515720 0.031008 3.349621 +0.517312 0.030949 3.364515 +0.518914 0.030894 3.379342 +0.520505 0.030840 3.394105 +0.522105 0.030789 3.408804 +0.523692 0.030740 3.423587 +0.525290 0.030694 3.438305 +0.526875 0.030648 3.453106 +0.528469 0.030607 3.467699 +0.530074 0.030567 3.482375 +0.531665 0.030528 3.496989 +0.533265 0.030492 3.511542 +0.534853 0.030458 3.526177 +0.536449 0.030426 3.540752 +0.538032 0.030397 3.555267 +0.539648 0.030369 3.569723 +0.541227 0.030342 3.584260 +0.542814 0.030319 3.598739 +0.544411 0.030296 3.613159 +0.546018 0.030277 3.627522 +0.547609 0.030257 3.641966 +0.549210 0.030241 3.656353 +0.550796 0.030225 3.670683 +0.552391 0.030211 3.685093 +0.553996 0.030199 3.699448 +0.555584 0.030188 3.713746 +0.557182 0.030180 3.727990 +0.558764 0.030174 3.742180 +0.560355 0.030168 3.756449 +0.561955 0.030164 3.770664 +0.563539 0.030161 3.784958 +0.565131 0.030160 3.799067 +0.566733 0.030161 3.813254 +0.568318 0.030163 3.827389 +0.569911 0.030166 3.841603 +0.571514 0.030171 3.855634 +0.573099 0.030178 3.869743 +0.574693 0.030185 3.883930 +0.576295 0.030194 3.897937 +0.577880 0.030203 3.912022 +0.579474 0.030215 3.926056 +0.581076 0.030228 3.940040 +0.582660 0.030242 3.954101 +0.584252 0.030257 3.968112 +0.585854 0.030274 3.982074 +0.587436 0.030293 3.995988 +0.589027 0.030311 4.009977 +0.590626 0.030331 4.023918 +0.592206 0.030353 4.037811 +0.593822 0.030374 4.051780 +0.595391 0.030398 4.065701 +0.596996 0.030424 4.079574 +0.598582 0.030449 4.093400 +0.600175 0.030476 4.107302 +0.601777 0.030506 4.121035 +0.603359 0.030534 4.134965 +0.604949 0.030564 4.148727 +0.606547 0.030595 4.162564 +0.608153 0.030627 4.176355 +0.609738 0.030662 4.190100 +0.611332 0.030696 4.203801 +0.612903 0.030731 4.217576 +0.614513 0.030768 4.231306 +0.616101 0.030805 4.245109 +0.617697 0.030844 4.258750 +0.619271 0.030883 4.272465 +0.620883 0.030923 4.286135 +0.622473 0.030964 4.299879 +0.624040 0.031006 4.313579 +0.625646 0.031049 4.327235 +0.627228 0.031093 4.340849 +0.628819 0.031138 4.354534 +0.630417 0.031183 4.368063 +0.631992 0.031230 4.381664 +0.633607 0.031277 4.395336 +0.635197 0.031325 4.408966 +0.636763 0.031374 4.422554 +0.638370 0.031424 4.436100 +0.639951 0.031476 4.449606 +0.641541 0.031527 4.463182 +0.643138 0.031580 4.476717 +0.644744 0.031633 4.490212 +0.646323 0.031687 4.503777 +0.647911 0.031741 4.517301 +0.649506 0.031798 4.530785 +0.651075 0.031854 4.544339 +0.652686 0.031912 4.557743 +0.654270 0.031970 4.571217 +0.655862 0.032028 4.584760 +0.657462 0.032087 4.598155 +0.659035 0.032147 4.611619 +0.660615 0.032208 4.625045 +0.662203 0.032270 4.638539 +0.663798 0.032332 4.651886 +0.665401 0.032396 4.665303 +0.666976 0.032459 4.678681 +0.668559 0.032524 4.692127 +0.670149 0.032588 4.705535 +0.671746 0.032655 4.718905 +0.673351 0.032721 4.732237 +0.674928 0.032788 4.745637 +0.676511 0.032856 4.759000 +0.678102 0.032925 4.772325 +0.679701 0.032995 4.785613 +0.681269 0.033064 4.798968 +0.682845 0.033135 4.812286 +0.684466 0.033206 4.825568 +0.686019 0.033277 4.838916 +0.687617 0.033350 4.852228 +0.689222 0.033423 4.865503 +0.690797 0.033497 4.878742 +0.692378 0.033571 4.892047 +0.693967 0.033646 4.905317 +0.695564 0.033722 4.918550 +0.697128 0.033798 4.931850 +0.698739 0.033876 4.945012 +0.700317 0.033952 4.958342 +0.701903 0.034030 4.971535 +0.703496 0.034109 4.984793 +0.705097 0.034188 4.997916 +0.706664 0.034267 5.011205 +0.708238 0.034348 5.024359 +0.709820 0.034429 5.037577 +0.711408 0.034511 5.050761 +0.713004 0.034593 5.063911 +0.714606 0.034675 5.077125 +0.716175 0.034758 5.090305 +0.717750 0.034842 5.103451 +0.719333 0.034926 5.116563 +0.720922 0.035011 5.129739 +0.722519 0.035096 5.142882 +0.724122 0.035182 5.155990 +0.725690 0.035268 5.169163 +0.727265 0.035356 5.182205 +0.728847 0.035443 5.195311 +0.730436 0.035531 5.208480 +0.732032 0.035620 5.221520 +0.733634 0.035708 5.234623 +0.735200 0.035798 5.247788 +0.736773 0.035888 5.260826 +0.738353 0.035979 5.273926 +0.739939 0.036070 5.286994 +0.741532 0.036161 5.300029 +0.743132 0.036254 5.313127 +0.744695 0.036346 5.326192 +0.746308 0.036439 5.339225 +0.747884 0.036532 5.352227 +0.749466 0.036626 5.365290 +0.751055 0.036721 5.378322 +0.752605 0.036817 5.391322 +0.754208 0.036912 5.404384 +0.755771 0.037008 5.417321 +0.757387 0.037105 5.430320 +0.758963 0.037201 5.443380 +0.760546 0.037299 5.456317 +0.762135 0.037397 5.469314 +0.763685 0.037495 5.482372 +0.765287 0.037594 5.495308 +0.766849 0.037693 5.508305 +0.768465 0.037793 5.521271 +0.770040 0.037893 5.534206 +0.771622 0.037993 5.547201 +0.773210 0.038095 5.560077 +0.774756 0.038196 5.573101 +0.776357 0.038298 5.586006 +0.777916 0.038400 5.598971 +0.779530 0.038503 5.611905 +0.781101 0.038607 5.624810 +0.782679 0.038711 5.637686 +0.784263 0.038814 5.650620 +0.785854 0.038919 5.663525 +0.787401 0.039025 5.676401 +0.789005 0.039130 5.689335 +0.790564 0.039235 5.702240 +0.792130 0.039342 5.715116 +0.793753 0.039449 5.727963 +0.795331 0.039556 5.740868 +0.796916 0.039664 5.753744 +0.798456 0.039772 5.766592 +0.800053 0.039880 5.779497 +0.801605 0.039989 5.792374 +0.803215 0.040098 5.805222 +0.804779 0.040208 5.818042 +0.806349 0.040318 5.830920 +0.807925 0.040429 5.843769 +0.809508 0.040539 5.856590 +0.811096 0.040651 5.869383 +0.812691 0.040763 5.882233 +0.814239 0.040875 5.895055 +0.815847 0.040987 5.907849 +0.817406 0.041100 5.920700 +0.818972 0.041213 5.933523 +0.820544 0.041326 5.946319 +0.822122 0.041441 5.959087 +0.823706 0.041555 5.971911 +0.825296 0.041670 5.984709 +0.826892 0.041786 5.997478 +0.828439 0.041901 6.010221 +0.830048 0.042017 6.023020 +0.831606 0.042134 6.035791 +0.833171 0.042251 6.048536 +0.834742 0.042368 6.061336 +0.836318 0.042485 6.074109 +0.837901 0.042603 6.086856 +0.839489 0.042722 6.099576 +0.841027 0.042840 6.112351 +0.842627 0.042959 6.125100 +0.844176 0.043079 6.137822 +0.845789 0.043199 6.150518 +0.847350 0.043319 6.163268 +0.848916 0.043439 6.175993 +0.850488 0.043560 6.188691 +0.852067 0.043681 6.201444 +0.853650 0.043803 6.214171 +0.855240 0.043925 6.226872 +0.856777 0.044047 6.239546 +0.858379 0.044170 6.252276 +0.859926 0.044293 6.264979 +0.861540 0.044416 6.277657 +0.863099 0.044541 6.290309 +0.864664 0.044664 6.303015 +0.866235 0.044789 6.315695 +0.867811 0.044915 6.328350 +0.869393 0.045039 6.341059 +0.870981 0.045165 6.353742 +0.872514 0.045291 6.366400 diff --git a/bin/spectrum/superglass.spd b/bin/spectrum/superglass.spd new file mode 100644 index 0000000..970a737 --- /dev/null +++ b/bin/spectrum/superglass.spd @@ -0,0 +1,31 @@ +0.365 1.68 +0.40466 1.673 +0.43583 1.666 +0.47999 1.659 +0.48613 1.652 +0.488 1.645 +0.514 1.638 +0.5208 1.631 +0.53 1.624 +0.54607 1.617 +0.5682 1.61 +0.58756 1.603 +0.58929 1.596 +0.6328 1.589 +0.64385 1.582 +0.6471 1.575 +0.65627 1.568 +0.6943 1.561 +0.70652 1.554 +0.7682 1.547 +0.8521 1.54 +0.89 1.533 +1.0139 1.526 +1.06 1.519 +1.1286 1.512 +1.3951 1.505 +1.5296 1.498 +1.8131 1.491 +1.9701 1.484 +2.2493 1.477 +2.3254 1.47 diff --git a/bin/spectrum/titan.spd b/bin/spectrum/titan.spd new file mode 100644 index 0000000..32f4f82 --- /dev/null +++ b/bin/spectrum/titan.spd @@ -0,0 +1,337 @@ +0.355390259 1.434292 1.669324 +0.356986664 1.440808 1.673635 +0.358583099 1.447274 1.677809 +0.360179504 1.453685 1.68185 +0.361775909 1.460035 1.685763 +0.363372284 1.466322 1.689551 +0.364968658 1.472539 1.693221 +0.366565002 1.478682 1.696775 +0.368161346 1.484748 1.700218 +0.36975766 1.490732 1.703555 +0.371353973 1.49663 1.70679 +0.372950287 1.502438 1.709929 +0.37454657 1.508152 1.712976 +0.376142853 1.513766 1.715937 +0.377739075 1.519277 1.718817 +0.379335327 1.524679 1.721623 +0.380931549 1.529966 1.724364 +0.382527771 1.535135 1.727054 +0.384123932 1.540188 1.729703 +0.385720093 1.545128 1.732321 +0.387316223 1.549959 1.734915 +0.388912384 1.554684 1.737493 +0.390508484 1.559307 1.740061 +0.392104553 1.563832 1.742624 +0.393700623 1.568263 1.745187 +0.395296692 1.572604 1.747754 +0.396892731 1.576859 1.75033 +0.398488708 1.581033 1.752917 +0.400084717 1.585129 1.75552 +0.401680695 1.589152 1.75814 +0.403276642 1.593106 1.76078 +0.404872559 1.596995 1.763443 +0.406468445 1.600823 1.766129 +0.408064331 1.604594 1.768841 +0.409660156 1.608311 1.77158 +0.411256012 1.61198 1.774346 +0.412851807 1.615604 1.77714 +0.414447571 1.619187 1.779964 +0.416043304 1.622732 1.782816 +0.417639069 1.626245 1.785697 +0.419234772 1.629729 1.788606 +0.420830414 1.633189 1.791542 +0.422426086 1.636629 1.794502 +0.424021729 1.640051 1.797482 +0.425617279 1.643456 1.800479 +0.427212891 1.646845 1.803491 +0.428808411 1.650218 1.806516 +0.4304039 1.653576 1.809552 +0.43199942 1.656918 1.812598 +0.433594818 1.660245 1.815652 +0.435190277 1.663557 1.818713 +0.436785645 1.666853 1.821781 +0.438381012 1.670133 1.824854 +0.439976379 1.673398 1.827932 +0.441571625 1.676646 1.831013 +0.443166931 1.679878 1.834097 +0.444762146 1.683093 1.837184 +0.446357361 1.686291 1.840273 +0.447952545 1.689471 1.843365 +0.449547668 1.692633 1.846457 +0.451142761 1.695776 1.849552 +0.452737854 1.6989 1.852647 +0.454332855 1.702004 1.855744 +0.455927887 1.705087 1.858842 +0.457522858 1.708149 1.861942 +0.459117767 1.71119 1.865043 +0.460712708 1.714208 1.868146 +0.462307556 1.717202 1.871251 +0.463902405 1.720172 1.874358 +0.465497162 1.723117 1.877469 +0.467091888 1.726036 1.880584 +0.468686615 1.728927 1.883704 +0.470281311 1.731789 1.886829 +0.471875916 1.73462 1.889963 +0.47347052 1.73742 1.893108 +0.475065094 1.740189 1.896269 +0.476659607 1.742927 1.899448 +0.478254089 1.745638 1.902646 +0.479848541 1.748322 1.905866 +0.481442932 1.75098 1.909109 +0.483037292 1.753615 1.912377 +0.484631592 1.756229 1.915671 +0.486225891 1.758822 1.918992 +0.487820129 1.761397 1.922341 +0.489414307 1.763956 1.925719 +0.491008453 1.7665 1.929125 +0.492602539 1.76903 1.932562 +0.494196625 1.77155 1.936028 +0.495790619 1.77406 1.939525 +0.497384613 1.776561 1.943053 +0.498978516 1.779057 1.946611 +0.500572418 1.781548 1.9502 +0.50216626 1.784036 1.95382 +0.503760071 1.786522 1.957471 +0.505353821 1.789008 1.961153 +0.50694751 1.791496 1.964864 +0.508541168 1.793987 1.968606 +0.510134766 1.796482 1.972377 +0.511728333 1.798983 1.976178 +0.513321838 1.801492 1.980008 +0.514915283 1.804009 1.983866 +0.516508667 1.806536 1.987752 +0.518102051 1.809074 1.991665 +0.519695435 1.811625 1.995606 +0.521288696 1.81419 1.999572 +0.522881897 1.816769 2.003564 +0.524475037 1.819366 2.007581 +0.526068176 1.821979 2.011621 +0.527661255 1.824611 2.015685 +0.529254211 1.827263 2.019771 +0.530847168 1.829935 2.023878 +0.532440063 1.83263 2.028006 +0.534032959 1.835349 2.032154 +0.535625732 1.838091 2.036319 +0.537218506 1.84086 2.040501 +0.538811157 1.843656 2.044698 +0.540403809 1.846478 2.048908 +0.541996399 1.849326 2.053129 +0.543588928 1.852203 2.05736 +0.545181396 1.855106 2.0616 +0.546773804 1.858037 2.065848 +0.54836615 1.860994 2.070103 +0.549958496 1.863979 2.074363 +0.55155072 1.866992 2.078627 +0.553142944 1.870031 2.082895 +0.554735046 1.873097 2.087165 +0.556327148 1.876191 2.091437 +0.557919128 1.879311 2.09571 +0.559511108 1.882457 2.099982 +0.561102966 1.88563 2.104253 +0.562694824 1.88883 2.108523 +0.564286621 1.892055 2.11279 +0.565878296 1.895306 2.117054 +0.567470032 1.898583 2.121314 +0.569061646 1.901886 2.125569 +0.570653137 1.905214 2.129819 +0.572244629 1.908566 2.134063 +0.57383606 1.911944 2.1383 +0.575427368 1.915347 2.14253 +0.577018677 1.918773 2.146753 +0.578609863 1.922224 2.150967 +0.58020105 1.925699 2.155173 +0.581792114 1.929198 2.159369 +0.583383179 1.93272 2.163555 +0.584974121 1.936266 2.167731 +0.586565063 1.939834 2.171896 +0.588155884 1.943426 2.17605 +0.589746704 1.94704 2.180192 +0.591337341 1.950676 2.184321 +0.592927979 1.954335 2.188438 +0.594518555 1.958016 2.192542 +0.59610907 1.961719 2.196633 +0.597699524 1.965443 2.200709 +0.599289917 1.969189 2.204771 +0.600880188 1.972956 2.208818 +0.602470398 1.976744 2.21285 +0.604060608 1.980553 2.216867 +0.605650696 1.984382 2.220867 +0.607240723 1.988233 2.224852 +0.608830688 1.992104 2.228819 +0.610420532 1.995995 2.232769 +0.612010376 1.999907 2.236702 +0.613600098 2.003839 2.240616 +0.615189758 2.007791 2.244512 +0.616779358 2.011764 2.248389 +0.618368896 2.015756 2.252247 +0.619958374 2.019769 2.256084 +0.621547729 2.023803 2.2599 +0.623137024 2.027857 2.263694 +0.624726257 2.031931 2.267464 +0.62631543 2.036024 2.27121 +0.62790448 2.040135 2.274931 +0.62949353 2.044265 2.278625 +0.631082458 2.048411 2.282294 +0.632671265 2.052573 2.285935 +0.634260132 2.056751 2.289549 +0.635848755 2.060943 2.293135 +0.637437378 2.065149 2.296693 +0.639026001 2.069368 2.300222 +0.640614441 2.0736 2.303723 +0.64220282 2.077843 2.307194 +0.643791138 2.082098 2.310635 +0.645379395 2.086362 2.314047 +0.64696759 2.090636 2.317429 +0.648555664 2.094919 2.320782 +0.650143677 2.099209 2.324104 +0.651731567 2.103507 2.327396 +0.653319458 2.107812 2.330657 +0.654907166 2.112123 2.333889 +0.656494873 2.116438 2.33709 +0.658082458 2.120759 2.340261 +0.659669983 2.125083 2.343401 +0.661257446 2.129411 2.346511 +0.662844788 2.133742 2.349591 +0.664432007 2.138075 2.35264 +0.666019165 2.142409 2.35566 +0.667606323 2.146744 2.358649 +0.669193298 2.15108 2.361609 +0.670780273 2.155415 2.364538 +0.672367065 2.15975 2.367438 +0.673953857 2.164083 2.370308 +0.675540527 2.168414 2.373149 +0.677127136 2.172743 2.37596 +0.678713623 2.177069 2.378742 +0.680300049 2.181392 2.381495 +0.681886353 2.185711 2.38422 +0.683472656 2.190026 2.386916 +0.685058777 2.194335 2.389583 +0.686644897 2.198639 2.392222 +0.688230835 2.202938 2.394833 +0.689816772 2.20723 2.397416 +0.691402527 2.211515 2.399972 +0.69298822 2.215794 2.4025 +0.694573853 2.220065 2.405001 +0.696159424 2.224327 2.407475 +0.697744873 2.228582 2.409923 +0.6993302 2.232827 2.412344 +0.700915466 2.237064 2.414739 +0.70250061 2.241291 2.417108 +0.704085693 2.245508 2.419451 +0.705670715 2.249714 2.421769 +0.707255554 2.25391 2.424061 +0.708840393 2.258095 2.426329 +0.71042511 2.262268 2.428572 +0.712009705 2.266429 2.430791 +0.713594177 2.270579 2.432986 +0.715178589 2.274715 2.435158 +0.716762939 2.278839 2.437305 +0.718347168 2.28295 2.43943 +0.719931335 2.287047 2.441532 +0.721515381 2.29113 2.443611 +0.723099304 2.295199 2.445668 +0.724683167 2.299253 2.447704 +0.726266907 2.303293 2.449718 +0.727850525 2.307317 2.45171 +0.729434143 2.311326 2.453682 +0.731017578 2.315318 2.455633 +0.732600952 2.319294 2.457565 +0.734184204 2.323254 2.459476 +0.735767334 2.327196 2.461369 +0.737350403 2.331121 2.463243 +0.73893335 2.335027 2.465099 +0.740516235 2.338916 2.466938 +0.742098999 2.342787 2.468761 +0.743681641 2.346639 2.470569 +0.745264221 2.350473 2.472361 +0.746846619 2.354289 2.474138 +0.748429016 2.358088 2.475902 +0.75001123 2.361868 2.477651 +0.751593384 2.365631 2.479388 +0.753175415 2.369375 2.481112 +0.754757385 2.373103 2.482824 +0.756339233 2.376812 2.484524 +0.757920959 2.380505 2.486212 +0.759502563 2.38418 2.487889 +0.761084106 2.387838 2.489556 +0.762665527 2.391479 2.491212 +0.764246826 2.395103 2.492857 +0.765828003 2.398711 2.494494 +0.767409119 2.402302 2.49612 +0.768990112 2.405876 2.497738 +0.770570984 2.409434 2.499346 +0.772151733 2.412976 2.500947 +0.773732483 2.416502 2.502538 +0.775312988 2.420011 2.504122 +0.776893433 2.423506 2.505697 +0.778473755 2.426984 2.507265 +0.780054077 2.430447 2.508826 +0.781634155 2.433895 2.510379 +0.783214172 2.437327 2.511925 +0.784794067 2.440745 2.513465 +0.786373901 2.444147 2.514998 +0.787953552 2.447535 2.516525 +0.789533081 2.450908 2.518045 +0.79111261 2.454267 2.51956 +0.792691956 2.457611 2.521069 +0.794271118 2.460941 2.522572 +0.795850281 2.464257 2.524069 +0.797429321 2.467558 2.525561 +0.799008179 2.470846 2.527048 +0.800586975 2.474121 2.52853 +0.802165649 2.477382 2.530007 +0.803744202 2.480629 2.53148 +0.805322632 2.483864 2.532947 +0.80690094 2.487085 2.53441 +0.808479126 2.490293 2.535869 +0.810057251 2.493488 2.537323 +0.811635193 2.49667 2.538774 +0.813213013 2.49984 2.54022 +0.814790771 2.502997 2.541662 +0.816368408 2.506142 2.543101 +0.817945923 2.509274 2.544536 +0.819523254 2.512394 2.545967 +0.821100586 2.515503 2.547395 +0.822677734 2.518599 2.548819 +0.8242547 2.521683 2.55024 +0.825831665 2.524756 2.551658 +0.827408386 2.527817 2.553072 +0.828985046 2.530867 2.554484 +0.830561646 2.533906 2.555892 +0.832138062 2.536933 2.557298 +0.833714355 2.539949 2.558701 +0.835290527 2.542954 2.560101 +0.836866577 2.545948 2.561498 +0.838442505 2.548932 2.562893 +0.840018372 2.551904 2.564285 +0.841594055 2.554866 2.565675 +0.843169617 2.557818 2.567062 +0.844744995 2.560759 2.568447 +0.846320313 2.56369 2.569829 +0.847895508 2.56661 2.57121 +0.849470581 2.569521 2.572588 +0.851045593 2.572422 2.573964 +0.852620422 2.575312 2.575338 +0.854195007 2.578193 2.57671 +0.855769653 2.581064 2.578079 +0.857344055 2.583925 2.579447 +0.858918335 2.586777 2.580813 +0.860492554 2.58962 2.582177 +0.862066589 2.592453 2.583539 +0.863640503 2.595276 2.5849 +0.865214355 2.598091 2.586259 +0.866787964 2.600896 2.587616 +0.868361511 2.603693 2.588971 +0.869934937 2.60648 2.590325 +0.871508179 2.609259 2.591677 +0.87308136 2.612029 2.593027 +0.874654419 2.61479 2.594376 +0.876227356 2.617543 2.595724 +0.87780011 2.620287 2.59707 +0.879372681 2.623022 2.598414 +0.88094519 2.625749 2.599757 +0.882517456 2.628468 2.601099 +0.884089722 2.631179 2.602439 +0.885661804 2.633881 2.603778 +0.887233765 2.636575 2.605116 +0.888805664 2.639262 2.606452 diff --git a/bin/spectrum/water.spd b/bin/spectrum/water.spd new file mode 100644 index 0000000..4c05e05 --- /dev/null +++ b/bin/spectrum/water.spd @@ -0,0 +1,23 @@ +0.325 1.346 1.08E-8 +0.350 1.343 6.50E-9 +0.375 1.341 3.50E-9 +0.400 1.339 1.86E-9 +0.425 1.338 1.30E-9 +0.450 1.337 1.02E-9 +0.475 1.336 9.35E-10 +0.500 1.335 1.00E-9 +0.525 1.334 1.32E-9 +0.550 1.333 1.96E-9 +0.575 1.333 3.60E-9 +0.600 1.332 1.09E-8 +0.625 1.332 1.39E-8 +0.650 1.331 1.64E-8 +0.675 1.331 2.23E-8 +0.700 1.331 3.35E-8 +0.725 1.330 9.15E-8 +0.750 1.330 1.56E-7 +0.775 1.330 1.48E-7 +0.800 1.329 1.25E-7 +0.825 1.329 1.82E-7 +0.850 1.329 2.93E-7 +0.875 1.328 3.91E-7 diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 648c85e..7d3c08a 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -6,14 +6,30 @@ This description will be updated during the development process. Most of external libraries will be located directly in the source code, to reduce a number of dependencies and make building faster. But this libraries and tools you have to install by yourself: - CMake +- [Intel Embree](https://www.embree.org/) for CPU ray-tracing - CUDA - OptiX - optionally OpenVDB if you want to load .vdb files with volumetric data. ## Building for Windows Windows is the only one platform, which is supported at the moment. -Building should be as simple as creating a folder for build files and calling CMake, something like: +- download and install the latest release of Intel Embree from [GitHub](https://github.com/embree/embree/releases) +- copy embree binaries (embree3.dll and tbb12.dll) to "bin" folder in the root directory of etx-tracer; +- and then building should be as simple as creating a folder for build files and calling CMake, something like: ``` cmake -G "Visual Studio 17 2022" .. ``` +## Built-in dependencies +These libraries are included into the source code in `thirdparty` folder: +- [enkits](https://github.com/dougbinks/enkiTS) - A permissively licensed C and C++ Task Scheduler for creating parallel programs +- [glm](https://github.com/g-truc/glm) - OpenGL Mathematics +- [imgui](https://github.com/ocornut/imgui) - Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies +- [jansson](https://github.com/akheron/jansson) - C library for encoding, decoding and manipulating JSON data +- [mikktspace](https://github.com/mmikk/MikkTSpace) - A common standard for tangent space used in baking tools to produce normal maps. +- [sokol_app, sokol_gfx, sokol_imgui](https://github.com/floooh/sokol) - minimal cross-platform standalone C headers +- [stb_image](https://github.com/nothings/stb) - stb single-file public domain libraries for C/C++ +- [tinyexr](https://github.com/syoyo/tinyexr) - Tiny OpenEXR image loader/saver library +- [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader) - Tiny but powerful single file wavefront obj loader + + diff --git a/docs/CODESTYLE.md b/docs/CODESTYLE.md deleted file mode 100644 index ad5dc1e..0000000 --- a/docs/CODESTYLE.md +++ /dev/null @@ -1,6 +0,0 @@ -# Codestyle of the project - -The project basically have to code styles, when it comes to naming: -- **camelCase** style is the legacy from the original game engine; -- but recently I switched to **snake_code_style** -- for the rest (formatting, tabs, etc) there is .clang-format file. \ No newline at end of file diff --git a/docs/images/laser-2.png b/docs/images/laser-2.png new file mode 100644 index 0000000..6a91247 Binary files /dev/null and b/docs/images/laser-2.png differ diff --git a/docs/preview/laser-2.png b/docs/preview/laser-2.png new file mode 100644 index 0000000..4c52757 Binary files /dev/null and b/docs/preview/laser-2.png differ diff --git a/sources/CMakeLists.txt b/sources/CMakeLists.txt index cc23cd3..a88dd3f 100644 --- a/sources/CMakeLists.txt +++ b/sources/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(rt-api) +add_subdirectory(etx) add_subdirectory(raytracer) diff --git a/sources/etx/CMakeLists.txt b/sources/etx/CMakeLists.txt new file mode 100644 index 0000000..7108775 --- /dev/null +++ b/sources/etx/CMakeLists.txt @@ -0,0 +1,64 @@ +function(etx_build_pack target folder) + if(NOT IS_DIRECTORY "${folder}") + message(ERROR "Unable to find folder ${folder}") + return() + endif() + + file(GLOB_RECURSE hxx_sources "${folder}/*.hxx") + list(APPEND sources ${hxx_sources}) + + file(GLOB_RECURSE cxx_sources "${folder}/*.cxx") + list(APPEND sources ${cxx_sources}) + + source_group(TREE "${folder}/../" FILES ${sources}) + +#[[ + set(lib_source "${CMAKE_CURRENT_BINARY_DIR}/../compile_packs/${target}.pack.cpp") + file(WRITE ${lib_source}) + + foreach(source ${sources}) + target_sources(${target} PRIVATE ${source}) + set_property(SOURCE ${source} PROPERTY HEADER_FILE_ONLY TRUE) + file(APPEND ${lib_source} "#include \"${source}\"\n") + endforeach() + + list(APPEND packed_sources ${lib_source}) + target_sources(${target} PRIVATE ${packed_sources}) + source_group("" FILES ${lib_source}) + target_sources(${target} PRIVATE ${headers}) +#]] + + target_sources(${target} PRIVATE ${headers}) + target_sources(${target} PRIVATE ${sources}) +endfunction(etx_build_pack) + +function(create_library folder) + message(STATUS "Creating etx library `etx-${folder}` ...") + set(lib_name "etx-${folder}") + string(REPLACE "/" "-" lib_name ${lib_name}) + + add_library(${lib_name} STATIC) + etx_build_pack(${lib_name} "${CMAKE_CURRENT_LIST_DIR}/${folder}") + + target_compile_options(${lib_name} PRIVATE "/Zl") + target_compile_options(${lib_name} PRIVATE -DNOMINMAX=1 -D_CRT_SECURE_NO_WARNINGS=1 -DWIN32_LEAN_AND_MEAN=1) + + set_property(TARGET ${lib_name} PROPERTY FOLDER "etx") + set_property(TARGET ${lib_name} PROPERTY LINKER_LANGUAGE CXX) +endfunction(create_library) + +create_library(core) +target_link_libraries(etx-core PUBLIC jansson) +target_include_directories(etx-core PUBLIC .. ${JANSSON_INCLUDE_DIRS}) + +create_library(log) +target_link_libraries(etx-log PRIVATE etx-core) + +create_library(render) +target_link_libraries(etx-render PRIVATE glm stb_image tinyexr tiny_obj_loader mikktspace enkiTS etx-core) +target_include_directories(etx-render PRIVATE ${JANSSON_INCLUDE_DIRS}) + +find_package(embree 3.0 REQUIRED) + +create_library(rt) +target_link_libraries(etx-rt PRIVATE glm embree etx-core etx-render) diff --git a/sources/etx/core/core.cxx b/sources/etx/core/core.cxx new file mode 100644 index 0000000..cc1d9e3 --- /dev/null +++ b/sources/etx/core/core.cxx @@ -0,0 +1,59 @@ +#include + +#include + +#include +#include + +namespace etx { + +TimeMeasure::TimeMeasure() { + reset(); +} + +void TimeMeasure::reset() { + _data = std::chrono::steady_clock::now().time_since_epoch().count(); +} + +double TimeMeasure::measure_ms() const { + auto exact = measure_exact(); + return double(exact) / double(std::micro::den); +} + +double TimeMeasure::measure() const { + auto exact = measure_exact(); + return double(exact) / double(std::nano::den); +} + +double TimeMeasure::lap() { + auto m = measure(); + reset(); + return m; +} + +uint64_t TimeMeasure::measure_exact() const { + return std::chrono::steady_clock::now().time_since_epoch().count() - _data; +} + +std::string open_file(const std::vector& filters) { + char name_buffer[MAX_PATH] = {}; + + size_t fp = 0; + char filter_buffer[2048] = {}; + for (const std::string& w : filters) { + memcpy(filter_buffer + fp, w.data(), w.length()); + fp += 1 + w.length(); + } + + OPENFILENAME of = {}; + of.lStructSize = sizeof(of); + of.hInstance = GetModuleHandle(nullptr); + of.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; + of.lpstrFile = name_buffer; + of.nMaxFile = MAX_PATH; + of.lpstrFilter = filter_buffer; + of.nFilterIndex = filters.empty() ? 0 : 1; + return GetOpenFileNameA(&of) ? of.lpstrFile : ""; +} + +} // namespace etx diff --git a/sources/etx/core/core.hxx b/sources/etx/core/core.hxx new file mode 100644 index 0000000..b8a82de --- /dev/null +++ b/sources/etx/core/core.hxx @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace etx { + +struct TimeMeasure { + TimeMeasure(); + + void reset(); + double lap(); + + double measure() const; + double measure_ms() const; + uint64_t measure_exact() const; + + private: + uint64_t _data; +}; + +std::string open_file(const std::vector& filters); + +} // namespace etx diff --git a/sources/etx/core/debug.hxx b/sources/etx/core/debug.hxx new file mode 100644 index 0000000..b88afcf --- /dev/null +++ b/sources/etx/core/debug.hxx @@ -0,0 +1,63 @@ +#pragma once + +#include + +#if defined(NDEBUG) || defined(_NDEBUG) +#define ETX_DEBUG 0 +#else +#define ETX_DEBUG 1 +#endif + +#if defined(__NVCC__) +#define ETX_NVCC_COMPILER 1 +#else +#define ETX_NVCC_COMPILER 0 +#endif + +#if (ETX_NVCC_COMPILER) +#define ETX_DEBUG_BREAK() +#define ETX_ABORT() assert(false) +#else +#define ETX_DEBUG_BREAK() __debugbreak() +#define ETX_ABORT() abort() +#endif + +#define ETX_FORCE_ASSERTS 0 + +#if (ETX_DEBUG || ETX_FORCE_ASSERTS) + +#define ETX_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + printf("Condition %s failed at %s [%u]\n", #condition, __FILE__, __LINE__); \ + ETX_DEBUG_BREAK(); \ + } \ + } while (0) + +#else + +#define ETX_ASSERT(condition) \ + do { \ + } while (0) + +#endif + +#define ETX_CRITICAL(condition) \ + do { \ + if (!(condition)) { \ + printf("Critical condition %s failed at %s [%u]\n", #condition, __FILE__, __LINE__); \ + ETX_DEBUG_BREAK(); \ + } \ + } while (0) + +#define ETX_FAIL(msg) \ + do { \ + printf("Critical fail: %s\n", msg); \ + ETX_ABORT(); \ + } while (0) + +#define ETX_FAIL_FMT(fmt, ...) \ + do { \ + printf(fmt, __VA_ARGS__); \ + ETX_ABORT(); \ + } while (0) diff --git a/sources/etx/core/environment.cxx b/sources/etx/core/environment.cxx new file mode 100644 index 0000000..3b5c3b7 --- /dev/null +++ b/sources/etx/core/environment.cxx @@ -0,0 +1,58 @@ +#include +#include + +#include +#include + +namespace etx { + +static struct { + char data_folder[2048] = {}; + Environment e; +} _env; + +const char* Environment::data_folder() { + return _env.data_folder; +} + +const char* Environment::file_in_data(const char* f) { + static char buffer[2048] = {}; + snprintf(buffer, sizeof(buffer), "%s%s", _env.data_folder, f); + return buffer; +} + +void Environment::setup(const char* executable_path) { + get_file_folder(executable_path, _env.data_folder, sizeof(_env.data_folder)); +} + +uint64_t get_file_folder(const char* file_name, char buffer[], uint64_t buffer_size) { + uint64_t fn_len = file_name ? strlen(file_name) : 0; + if (fn_len == 0) { + return 0; + } + int len = snprintf(buffer, buffer_size, "%s", file_name); + while ((len > 0) && (buffer[len] != '/') && (buffer[len] != '\\')) { + --len; + } + buffer[len] = '\\'; + ETX_ASSERT(len + 1 < buffer_size); + buffer[1llu + len] = 0; + return 1ll + len; +} + +const char* get_file_ext(const char* file_name) { + uint64_t fn_len = file_name ? strlen(file_name) : 0; + while (fn_len > 0) { + if (file_name[fn_len - 1] == '.') { + return file_name + fn_len - 1; + } + --fn_len; + } + return ""; +} + +Environment& env() { + return _env.e; +} + +} // namespace etx diff --git a/sources/etx/core/environment.hxx b/sources/etx/core/environment.hxx new file mode 100644 index 0000000..5f2636b --- /dev/null +++ b/sources/etx/core/environment.hxx @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace etx { + +struct Environment { + const char* data_folder(); + + // not thread save, uses static data storage, use at your own risk + const char* file_in_data(const char*); + + void setup(const char* executable_path); +}; + +uint64_t get_file_folder(const char* file_name, char buffer[], uint64_t buffer_size); +const char* get_file_ext(const char* file_name); // returns `ext` with dot + +Environment& env(); + +} // namespace etx diff --git a/sources/etx/core/handle.hxx b/sources/etx/core/handle.hxx new file mode 100644 index 0000000..1a8ddb6 --- /dev/null +++ b/sources/etx/core/handle.hxx @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace etx { + +union Handle { + enum : uint64_t { + ClsBits = 8, + ClsMax = (1 << ClsBits) - 1, + IndexBits = 28, + IndexMax = (1 << IndexBits) - 1, + GenBits = 28, + GenMax = (1 << GenBits) - 1, + BitCount = ClsBits + IndexBits + GenBits, + }; + static_assert(BitCount == 64); + + uint64_t value = 0; + struct { + uint64_t cls : ClsBits; + uint64_t index : IndexBits; + uint64_t generation : GenBits; + }; + + bool operator==(const Handle& h) const { + return value == h.value; + } + + static inline Handle construct(uint64_t a_cls, uint64_t a_index, uint64_t a_generation) { + ETX_ASSERT(a_cls < ClsMax); + ETX_ASSERT(a_index < IndexMax); + ETX_ASSERT(a_generation < GenMax); + Handle result = {}; + result.cls = a_cls; + result.index = a_index; + result.generation = a_generation; + return result; + } +}; + +static_assert(sizeof(Handle) == sizeof(uint64_t)); + +} // namespace etx + +#include + +namespace std { + +template <> +struct hash { + size_t operator()(const etx::Handle handle) const { + return handle.value; + } +}; + +} // namespace std diff --git a/sources/etx/core/options.cxx b/sources/etx/core/options.cxx new file mode 100644 index 0000000..86689b1 --- /dev/null +++ b/sources/etx/core/options.cxx @@ -0,0 +1,78 @@ +#include + +#include + +namespace etx { + +void Options::save_to_file(const char* filename) { + json_t* js = json_object(); + + for (const auto& val : values) { + switch (val.cls) { + case OptionalValue::Class::Boolean: { + json_object_set_new(js, val.id.c_str(), json_boolean(val.to_bool())); + break; + } + case OptionalValue::Class::Float: { + json_object_set_new(js, val.id.c_str(), json_real(val.to_float())); + break; + } + case OptionalValue::Class::InfoString: { + json_object_set_new(js, val.id.c_str(), json_string(val.name.c_str())); + break; + } + case OptionalValue::Class::Integer: { + json_object_set_new(js, val.id.c_str(), json_integer(val.to_integer())); + break; + } + default: + break; + } + } + json_dump_file(js, filename, JSON_INDENT(2) | JSON_ESCAPE_SLASH); + json_decref(js); +} + +bool Options::load_from_file(const char* filename) { + json_error_t err = {}; + auto js = json_load_file(filename, 0, &err); + if (js == nullptr) { + return false; + } + + if (json_is_object(js)) { + const char* key = {}; + json_t* value = {}; + json_object_foreach(js, key, value) { + switch (json_typeof(value)) { + case JSON_STRING: { + set(key, std::string(json_string_value(value))); + break; + } + case JSON_INTEGER: { + set(uint32_t(json_integer_value(value)), key, std::string{}); + break; + } + case JSON_REAL: { + set(float(json_real_value(value)), key, std::string{}); + break; + } + case JSON_TRUE: { + set(true, key, std::string{}); + break; + } + case JSON_FALSE: { + set(false, key, std::string{}); + break; + } + default: + break; + } + } + } + + json_decref(js); + return true; +} + +} // namespace etx diff --git a/sources/etx/core/options.hxx b/sources/etx/core/options.hxx new file mode 100644 index 0000000..fd3b7e8 --- /dev/null +++ b/sources/etx/core/options.hxx @@ -0,0 +1,184 @@ +#pragma once + +#include + +#include +#include + +namespace etx { + +struct OptionalValue { + enum class Class : uint32_t { + Undefined, + Integer, + Boolean, + InfoString, + Float, + Enum, + + Count, + }; + + Class cls = Class::Integer; + std::string id = {}; + std::string name = {}; + + union Value { + uint32_t integer; + float flt; + bool boolean; + }; + + Value min_value = {}; + Value value = {}; + Value max_value = {}; + std::string (*name_func)(uint32_t) = {}; + + OptionalValue() = default; + + OptionalValue(uint32_t val, const std::string& a_id, const std::string& desc) + : cls(Class::Integer) + , id(a_id) + , name(desc) { + min_value.integer = val; + value.integer = val; + max_value.integer = val; + } + + OptionalValue(float val, const std::string& a_id, const std::string& desc) + : cls(Class::Float) + , id(a_id) + , name(desc) { + min_value.flt = val; + value.flt = val; + max_value.flt = val; + } + + OptionalValue(uint32_t min_val, uint32_t val, uint32_t max_val, const std::string& a_id, const std::string& desc) + : cls(Class::Integer) + , id(a_id) + , name(desc) { + min_value.integer = min_val; + value.integer = val; + max_value.integer = max_val; + } + + OptionalValue(float min_val, float val, float max_val, const std::string& a_id, const std::string& desc) + : cls(Class::Float) + , id(a_id) + , name(desc) { + min_value.flt = min_val; + value.flt = val; + max_value.flt = max_val; + } + + OptionalValue(bool val, const std::string& a_id, const std::string& desc) + : cls(Class::Boolean) + , id(a_id) + , name(desc) { + value.boolean = val; + } + + OptionalValue(const std::string& a_id, const std::string& desc) + : cls(Class::InfoString) + , id(a_id) + , name(desc) { + } + + template + OptionalValue(T v, T end, std::string (*f)(uint32_t), const std::string& a_id, const std::string& desc) + : cls(Class::Enum) + , name_func(f) + , id(a_id) + , name(desc) { + min_value.integer = 0; + value.integer = uint32_t(v); + max_value.integer = uint32_t(end) - 1u; + } + + void set(uint32_t new_integer_value) { + ETX_ASSERT((cls == Class::Integer) || (cls == Class::Enum)); + value.integer = clamp_to(new_integer_value, min_value.integer, max_value.integer); + } + + void set(bool new_bool_value) { + ETX_ASSERT(cls == Class::Boolean); + value.boolean = new_bool_value; + } + + void set(float new_float_value) { + ETX_ASSERT(cls == Class::Float); + value.flt = new_float_value; + } + + uint32_t to_integer() const { + ETX_ASSERT((cls == Class::Integer) || (cls == Class::Enum)); + return clamp_to(value.integer, min_value.integer, max_value.integer); + } + + float to_float() const { + ETX_ASSERT(cls == Class::Float); + return clamp_to(value.flt, min_value.flt, max_value.flt); + } + + bool to_bool() const { + ETX_ASSERT(cls == Class::Boolean); + return value.boolean; + } + + template + T to_enum() { + ETX_ASSERT((cls == Class::Enum) || (cls == Class::Integer)); + return T(value.integer); + } + + private: + template + inline static T clamp_to(T value, T min, T max) { + return value < min ? min : (value > max ? max : value); + } +}; + +struct Options { + std::vector values; + + template + OptionalValue get(const std::string& id, T def) const { + for (const auto& option : values) { + if (option.id == id) { + return option; + } + } + return {def, id, {}}; + } + + template <> + OptionalValue get(const std::string& id, std::string def) const { + for (const auto& option : values) { + if (option.id == id) { + return option; + } + } + return {id, def}; + } + + OptionalValue& set(const OptionalValue& def) { + for (auto& option : values) { + if (option.id == def.id) { + option = def; + return option; + } + } + return values.emplace_back(def); + } + + template + void set(args&&... a) { + set({std::forward(a)...}); + } + + void save_to_file(const char*); + bool load_from_file(const char*); +}; + +} // namespace etx diff --git a/sources/etx/core/pimpl.hxx b/sources/etx/core/pimpl.hxx new file mode 100644 index 0000000..ea0612f --- /dev/null +++ b/sources/etx/core/pimpl.hxx @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include +#include +#include + +#define ETX_PIMPL_DECLARE(T, SUFFIX, SZ) \ + public: \ + T(const T&) = delete; \ + T& operator=(const T&) = delete; \ + T(T&&) noexcept; \ + T& operator=(T&&) noexcept; \ + \ + private: \ + uint8_t _private_storage[SZ]{}; \ + struct T##SUFFIX* _private = nullptr + +#define ETX_PIMPL_IMPLEMENT(T, SUFFIX) \ + T::T(T&& other) noexcept { \ + if (_private) { \ + _private->~T##SUFFIX(); \ + } \ + memcpy(_private_storage, other._private_storage, sizeof(_private_storage)); \ + _private = reinterpret_cast(_private_storage); \ + memset(other._private_storage, 0, sizeof(_private_storage)); \ + other._private = nullptr; \ + } \ + T& T::operator=(T&& other) noexcept { \ + if (_private) { \ + _private->~T##SUFFIX(); \ + } \ + memcpy(_private_storage, other._private_storage, sizeof(_private_storage)); \ + _private = reinterpret_cast(_private_storage); \ + memset(other._private_storage, 0, sizeof(_private_storage)); \ + other._private = nullptr; \ + return *this; \ + } + +#define ETX_PIMPL_IMPLEMENT_ALL(T, SUFFIX) \ + ETX_PIMPL_IMPLEMENT(T, SUFFIX) \ + T::T() { \ + ETX_PIMPL_CREATE(T, SUFFIX); \ + } \ + T::~T() { \ + ETX_PIMPL_DESTROY(T, SUFFIX); \ + } + +#define ETX_PIMPL_CREATE(T, SUFFIX, ...) \ + static_assert(sizeof(_private_storage) >= sizeof(T##SUFFIX), "Not enough storage for private implementation"); \ + ETX_ASSERT(_private == nullptr); \ + memset(_private_storage, 0, sizeof(_private_storage)); \ + _private = new (_private_storage) T##SUFFIX(__VA_ARGS__) + +#define ETX_PIMPL_DESTROY(T, SUFFIX) \ + if (_private != nullptr) { \ + _private->~T##SUFFIX(); \ + _private = nullptr; \ + memset(_private_storage, 0, sizeof(_private_storage)); \ + } \ + do { \ + } while (false) + +#define ETX_DECLARE_PIMPL(T, SZ) ETX_PIMPL_DECLARE(T, Impl, SZ) +#define ETX_IMPLEMENT_PIMPL(T) ETX_PIMPL_IMPLEMENT(T, Impl) +#define ETX_PIMPL_INIT(T, ...) ETX_PIMPL_CREATE(T, Impl, __VA_ARGS__) +#define ETX_PIMPL_CLEANUP(T) ETX_PIMPL_DESTROY(T, Impl) diff --git a/sources/etx/core/windows.hxx b/sources/etx/core/windows.hxx new file mode 100644 index 0000000..f5fcf0c --- /dev/null +++ b/sources/etx/core/windows.hxx @@ -0,0 +1,15 @@ +#pragma once + +#if !defined(NOMINMAX) +#error NOMINMAX should be defined +#endif + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#error _CRT_SECURE_NO_WARNINGS should be defined +#endif + +#if !defined(WIN32_LEAN_AND_MEAN) +#error WIN32_LEAN_AND_MEAN should be defined +#endif + +#include diff --git a/sources/etx/log/log.cxx b/sources/etx/log/log.cxx new file mode 100644 index 0000000..b553c58 --- /dev/null +++ b/sources/etx/log/log.cxx @@ -0,0 +1,61 @@ +#include + +#include + +#include +#include +#include +#include + +namespace etx { + +inline void set_console_color(log::Color clr) { + auto con = GetStdHandle(STD_OUTPUT_HANDLE); + switch (clr) { + case log::Color::White: { + SetConsoleTextAttribute(con, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + break; + } + case log::Color::Yellow: { + SetConsoleTextAttribute(con, FOREGROUND_RED | FOREGROUND_GREEN); + break; + } + case log::Color::Red: { + SetConsoleTextAttribute(con, FOREGROUND_RED); + break; + } + case log::Color::Green: { + SetConsoleTextAttribute(con, FOREGROUND_GREEN); + break; + } + default: + SetConsoleTextAttribute(con, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + } +} + +void log::output(Color clr, const char* fmt, ...) { + constexpr int local_buffer_size = 1024; + set_console_color(clr); + + va_list list = {}; + va_start(list, fmt); + int required_size = _vscprintf(fmt, list) + 1; + if (required_size + 1 < local_buffer_size) { + char* buffer = (char*)_malloca(required_size + 1); + vsnprintf(buffer, required_size, fmt, list); + puts(buffer); + _freea(buffer); + } else { + char* buffer = (char*)calloc(required_size + 1, 1); + if (buffer != nullptr) { + vsnprintf(buffer, required_size, fmt, list); + puts(buffer); + free(buffer); + } + } + va_end(list); + + set_console_color(Color::White); +} + +} // namespace etx diff --git a/sources/etx/log/log.hxx b/sources/etx/log/log.hxx new file mode 100644 index 0000000..354451a --- /dev/null +++ b/sources/etx/log/log.hxx @@ -0,0 +1,36 @@ +#pragma once + +namespace etx { + +struct log { + enum class Color { + Green, + White, + Yellow, + Red, + }; + + static void output(Color color, const char* fmt, ...); + + template + static inline void success(const char* fmt, args... a) { + output(Color::Green, fmt, static_cast(a)...); + } + + template + static inline void info(const char* fmt, args... a) { + output(Color::White, fmt, static_cast(a)...); + } + + template + static inline void warning(const char* fmt, args... a) { + output(Color::Yellow, fmt, static_cast(a)...); + } + + template + static inline void error(const char* fmt, args... a) { + output(Color::Red, fmt, static_cast(a)...); + } +}; + +} // namespace etx diff --git a/sources/etx/render/host/distribution_builder.hxx b/sources/etx/render/host/distribution_builder.hxx new file mode 100644 index 0000000..ae22d62 --- /dev/null +++ b/sources/etx/render/host/distribution_builder.hxx @@ -0,0 +1,54 @@ +#pragma once + +#include + +namespace etx { + +struct DistributionBuilder { + DistributionBuilder(Distribution& dist, uint32_t capacity) + : _dist(dist) + , _capacity(capacity + 1) { + ETX_ASSERT(capacity > 0); + ETX_ASSERT(_dist.size == 0); + ETX_ASSERT(_dist.values == nullptr); + _dist.size = capacity; + _dist.values = reinterpret_cast(calloc(_capacity, sizeof(Distribution::Entry))); + } + + void add(float value) { + ETX_ASSERT(_size + 1 <= _capacity); + _dist.values[_size++] = {value, 0.0f, 0.0f}; + } + + void finalize() { + ETX_ASSERT(_size + 1 == _capacity); + + _dist.total_weight = 0.0f; + for (uint32_t i = 0; i < _size; ++i) { + _dist.values[i].cdf = _dist.total_weight; + _dist.total_weight += _dist.values[i].value; + } + + if (_dist.total_weight == 0.0f) { + for (uint64_t i = 0; i < _dist.size; ++i) { + _dist.values[i].value = 1.0f; + _dist.values[i].pdf = 1.0f / float(_dist.size); + _dist.values[i].cdf = float(i) / float(_dist.size); + } + } else { + for (uint32_t i = 0; i < _size; ++i) { + _dist.values[i].pdf = _dist.values[i].value / _dist.total_weight; + _dist.values[i].cdf /= _dist.total_weight; + } + } + + _dist.values[_size++] = {0.0f, 0.0f, 1.0f}; + } + + private: + Distribution& _dist; + uint32_t _capacity = 0; + uint32_t _size = 0; +}; + +} // namespace etx diff --git a/sources/etx/render/host/image_pool.cxx b/sources/etx/render/host/image_pool.cxx new file mode 100644 index 0000000..d590300 --- /dev/null +++ b/sources/etx/render/host/image_pool.cxx @@ -0,0 +1,403 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace etx { + +bool load_pfm(const char* path, uint2& size, std::vector& data); + +struct ImagePoolImpl { + void init(uint32_t capacity) { + image_pool.init(capacity); + } + + void cleanup() { + ETX_ASSERT(image_pool.count_alive() == 0); + image_pool.cleanup(); + } + + uint32_t add_from_file(const std::string& path, uint32_t image_options) { + auto i = mapping.find(path); + if (i != mapping.end()) { + return i->second; + } + + auto handle = image_pool.alloc(); + auto& image = image_pool.get(handle); + load_image(image, path.c_str(), image_options); + if (image_options & Image::BuildSamplingTable) { + build_sampling_table(image); + } + + mapping[path] = handle; + return handle; + } + + const Image& get(uint32_t handle) const { + return image_pool.get(handle); + } + + void remove(uint32_t handle) { + if (handle == kInvalidIndex) { + return; + } + + free_image(image_pool.get(handle)); + image_pool.free(handle); + + for (auto i = mapping.begin(), e = mapping.end(); i != e; ++i) { + if (i->second == handle) { + mapping.erase(i); + break; + } + } + } + + void remove_all() { + image_pool.free_all(std::bind(&ImagePoolImpl::free_image, this, std::placeholders::_1)); + mapping.clear(); + } + + void load_image(Image& img, const char* file_name, uint32_t options) { + ETX_ASSERT(img.pixels == nullptr); + ETX_ASSERT(img.x_distributions == nullptr); + ETX_ASSERT(img.y_distribution.size == 0); + ETX_ASSERT(img.y_distribution.values == 0); + + std::vector source_data = {}; + Image::Format format = load_data(file_name, source_data, img.isize); + if ((format == Image::Format::Undefined) || (img.isize.x * img.isize.y == 0)) { + source_data.resize(sizeof(float4)); + *(float4*)(source_data.data()) = {1.0f, 1.0f, 1.0f, 1.0f}; + format = Image::Format::RGBA32F; + img.options = Image::RepeatU | Image::RepeatV; + img.isize.x = 1; + img.isize.y = 1; + } + + img.options = img.options | options; + img.fsize.x = static_cast(img.isize.x); + img.fsize.y = static_cast(img.isize.y); + img.pixels = reinterpret_cast(calloc(1llu * img.isize.x * img.isize.y, sizeof(float4))); + + bool srgb = (options & Image::Linear) == 0; + + if (format == Image::Format::RGBA8) { + auto src_data = reinterpret_cast(source_data.data()); + for (uint32_t y = 0; y < img.isize.y; ++y) { + for (uint32_t x = 0; x < img.isize.x; ++x) { + uint32_t i = x + y * img.isize.x; + float4 f{float(src_data[i].x) / 255.0f, float(src_data[i].y) / 255.0f, float(src_data[i].z) / 255.0f, float(src_data[i].w) / 255.0f}; + if (srgb) { + f.x = std::pow(f.x, 2.2f); // TODO : fix gamma conversion + f.y = std::pow(f.y, 2.2f); // TODO : fix gamma conversion + f.z = std::pow(f.z, 2.2f); // TODO : fix gamma conversion + } + uint32_t j = x + (img.isize.y - 1 - y) * img.isize.x; + img.pixels[j] = f; + } + } + } else if (format == Image::Format::RGBA32F) { + memcpy(img.pixels, source_data.data(), source_data.size()); + } else { + ETX_FAIL_FMT("Unsupported image format %u", format); + } + + for (uint32_t i = 0, e = img.isize.x * img.isize.y; i < e; ++i) { + if (img.pixels[i].w < 1.0f) { + img.options = img.options | Image::HasAlphaChannel; + break; + } + } + } + + void build_sampling_table(Image& img) { + float total_weight = 0.0f; + bool uniform_sampling = (img.options & Image::UniformSamplingTable) == Image::UniformSamplingTable; + DistributionBuilder y_dist(img.y_distribution, img.isize.y); + img.x_distributions = reinterpret_cast(calloc(img.isize.y, sizeof(Distribution))); + + for (uint32_t y = 0; y < img.isize.y; ++y) { + float v = (float(y) + 0.5f) / img.fsize.y; + float row_value = 0.0f; + + DistributionBuilder d_x(img.x_distributions[y], img.isize.x); + for (uint32_t x = 0; x < img.isize.x; ++x) { + float u = (float(x) + 0.5f) / img.fsize.x; + float4 px = img.read(img.fsize * float2{u, v}); + float lum = luminance(px); + row_value += lum; + d_x.add(lum); + } + d_x.finalize(); + + float row_weight = uniform_sampling ? 1.0f : std::sin(v * kPi); + row_value *= row_weight; + + total_weight += row_value; + y_dist.add(row_value); + } + y_dist.finalize(); + + img.normalization = total_weight / (img.fsize.x * img.fsize.y); + } + + void free_image(Image& img) { + free(img.pixels); + for (uint32_t i = 0; i < img.y_distribution.size; ++i) { + free(img.x_distributions[i].values); + } + free(img.x_distributions); + free(img.y_distribution.values); + img = {}; + } + + Image::Format load_data(const char* source, std::vector& data, uint2& dimensions) { + if (source == nullptr) + return Image::Format::Undefined; + + const char* ext = nullptr; + if (uint64_t l = strlen(source)) { + while ((l > 0) && (source[--l] != '.')) { + } + ext = source + l; + } else { + return Image::Format::Undefined; + } + + if (strcmp(ext, ".exr") == 0) { + int w = 0; + int h = 0; + const char* error = nullptr; + float* rgba_data = nullptr; + if (LoadEXR(&rgba_data, &w, &h, source, &error) != TINYEXR_SUCCESS) { + printf("Failed to load EXR from file: %s\n", error); + return Image::Format::Undefined; + } + + for (int i = 0; i < 4 * w * h; ++i) { + if (std::isinf(rgba_data[i])) { + rgba_data[i] = 65504.0f; // max value in half-float + } + if (std::isnan(rgba_data[i]) || (rgba_data[i] < 0.0f)) { + rgba_data[i] = 0.0f; + } + } + + dimensions = {w, h}; + data.resize(sizeof(float4) * w * h); + memcpy(data.data(), rgba_data, sizeof(float4) * w * h); + // auto row_size = sizeof(float4) * w; + // for (int y = 0; y < h; ++y) { + // memcpy(data.data() + row_size * (h - 1 - y), rgba_data + 4llu * y * w, row_size); + // } + free(rgba_data); + + return Image::Format::RGBA32F; + } + + if (strcmp(ext, ".hdr") == 0) { + int w = 0; + int h = 0; + int c = 0; + stbi_set_flip_vertically_on_load(false); + auto image = stbi_loadf(source, &w, &h, &c, 0); + if (image == nullptr) { + return Image::Format::Undefined; + } + + dimensions = {w, h}; + data.resize(sizeof(float4) * w * h); + auto ptr = reinterpret_cast(data.data()); + if (c == 4) { + memcpy(ptr, image, sizeof(float4) * w * h); + } else { + for (int i = 0; i < w * h; ++i) { + ptr[i] = {image[3 * i + 0], image[3 * i + 1], image[3 * i + 1], 1.0f}; + } + } + free(image); + return Image::Format::RGBA32F; + } + + if (strcmp(ext, ".pfm") == 0) { + return load_pfm(source, dimensions, data) ? Image::Format::RGBA32F : Image::Format::Undefined; + } + + int w = 0; + int h = 0; + int c = 0; + stbi_set_flip_vertically_on_load(true); + auto image = stbi_load(source, &w, &h, &c, 0); + if (image == nullptr) { + return Image::Format::Undefined; + } + + if ((c != 3) && (c != 4)) { + free(image); + ETX_FAIL_FMT("Unsupported (yet) image format with %d channels", c); + } + + dimensions = {w, h}; + data.resize(4llu * w * h); + uint8_t* ptr = reinterpret_cast(data.data()); + switch (c) { + case 4: { + memcpy(ptr, image, 4llu * w * h); + break; + } + + case 3: { + for (int i = 0; i < w * h; ++i) { + ptr[4 * i + 0] = image[3 * i + 0]; + ptr[4 * i + 1] = image[3 * i + 1]; + ptr[4 * i + 2] = image[3 * i + 2]; + ptr[4 * i + 3] = 255; + } + break; + } + + default: + break; + } + + free(image); + return Image::Format::RGBA8; + } + + ObjectIndexPool image_pool; + std::unordered_map mapping; + Image empty; +}; + +ETX_PIMPL_IMPLEMENT_ALL(ImagePool, Impl); + +void ImagePool::init(uint32_t capacity) { + _private->init(capacity); +} + +void ImagePool::cleanup() { + _private->cleanup(); +} + +uint32_t ImagePool::add_from_file(const std::string& path, uint32_t image_options) { + return _private->add_from_file(path, image_options); +} + +const Image& ImagePool::get(uint32_t handle) { + return _private->get(handle); +} + +void ImagePool::remove(uint32_t handle) { + _private->remove(handle); +} + +void ImagePool::remove_all() { + _private->remove_all(); +} + +Image* ImagePool::as_array() { + return _private->image_pool.data(); +} + +uint64_t ImagePool::array_size() { + return 1llu + _private->image_pool.latest_alive_index(); +} + +bool load_pfm(const char* path, uint2& size, std::vector& data) { + FILE* in_file = fopen(path, "rb"); + if (in_file == nullptr) { + return false; + } + + char buffer[16] = {}; + + auto read_line = [&]() { + memset(buffer, 0, sizeof(buffer)); + char c = {}; + int p = 0; + while ((p < 16) && (fread(&c, 1, 1, in_file) == 1)) { + if (c == '\n') { + return; + } else { + buffer[p++] = c; + } + } + }; + + read_line(); + if ((buffer[0] != 'P') && (buffer[1] != 'f') && (buffer[1] != 'F')) { + fclose(in_file); + return false; + } + char format = buffer[1]; + + read_line(); + if (sscanf(buffer, "%d", &size.x) != 1) { + fclose(in_file); + return false; + } + + read_line(); + if (sscanf(buffer, "%d", &size.y) != 1) { + fclose(in_file); + return false; + } + + read_line(); + float scale = 0.0f; + if (sscanf(buffer, "%f", &scale) != 1) { + fclose(in_file); + return false; + } + + auto sw = [](float t) { + uint32_t x; + memcpy(&x, &t, 4); + x = ((x & 0x000000ff) >> 0) << 24 | ((x & 0x0000ff00) >> 8) << 16 | ((x & 0x00ff0000) >> 16) << 8 | ((x & 0xff000000) >> 24) << 0; + memcpy(&t, &x, 4); + return t; + }; + + data.resize(sizeof(float4) * size.x * size.y); + auto data_ptr = reinterpret_cast(data.data()); + + if (format == 'f') { + for (uint32_t i = 0; i < size.y; ++i) { + for (uint32_t j = 0; j < size.x; ++j) { + float value = 0.0f; + if (fread(&value, sizeof(float), 1, in_file) != 1) { + fclose(in_file); + return false; + } + data_ptr[j + i * size.x] = {value, value, value, 1.0f}; + } + } + } else if (format == 'F') { + for (uint32_t i = 0; i < size.y; ++i) { + for (uint32_t j = 0; j < size.x; ++j) { + float3 value = {}; + if (fread(&value, 3 * sizeof(float), 1, in_file) != 1) { + fclose(in_file); + return false; + } + data_ptr[j + i * size.x] = {value, 1.0f}; + } + } + } else { + fclose(in_file); + return false; + } + + fclose(in_file); + return true; +} + +} // namespace etx diff --git a/sources/etx/render/host/image_pool.hxx b/sources/etx/render/host/image_pool.hxx new file mode 100644 index 0000000..bbe4cad --- /dev/null +++ b/sources/etx/render/host/image_pool.hxx @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include + +namespace etx { + +struct ImagePool { + ImagePool(); + ~ImagePool(); + + void init(uint32_t capacity); + void cleanup(); + + uint32_t add_from_file(const std::string& path, uint32_t image_options); + void remove(uint32_t handle); + void remove_all(); + + const Image& get(uint32_t); + + Image* as_array(); + uint64_t array_size(); + + ETX_DECLARE_PIMPL(ImagePool, 256); +}; + +} // namespace etx diff --git a/sources/etx/render/host/medium_pool.cxx b/sources/etx/render/host/medium_pool.cxx new file mode 100644 index 0000000..9634887 --- /dev/null +++ b/sources/etx/render/host/medium_pool.cxx @@ -0,0 +1,191 @@ +#include +#include + +#include +#include + +namespace etx { + +struct MediumPoolImpl { + void init(uint32_t capacity) { + medium_pool.init(capacity); + } + + void cleanup() { + ETX_ASSERT(medium_pool.count_alive() == 0); + medium_pool.cleanup(); + } + + uint32_t add_homogenous(const std::string& id, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g) { + auto i = mapping.find(id); + if (i != mapping.end()) { + return i->second; + } + + auto handle = medium_pool.alloc(); + + auto& medium = medium_pool.get(handle); + medium.s_absorption = s_a; + medium.s_outscattering = s_o; + medium.phase_function_g = g; + medium.max_sigma = s_a.maximum_power() + s_o.maximum_power(); + medium.cls = s_a.is_zero() && s_o.is_zero() ? Medium::Class::Vacuum : Medium::Class::Homogeneous; + + mapping[id] = handle; + return handle; + } + + uint32_t add_heterogenous(const std::string& id, const char* volume_file, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g) { + auto i = mapping.find(id); + if (i != mapping.end()) { + return i->second; + } + + auto handle = medium_pool.alloc(); + + auto& medium = medium_pool.get(handle); + medium.s_absorption = s_a; + medium.s_outscattering = s_o; + medium.phase_function_g = g; + medium.max_sigma = s_a.maximum_power() + s_o.maximum_power(); + medium.cls = s_a.is_zero() && s_o.is_zero() ? Medium::Class::Vacuum : Medium::Class::Heterogeneous; + + if (medium.cls == Medium::Class::Heterogeneous) { + auto density = load_density_grid(volume_file, medium.dimensions.x, medium.dimensions.y, medium.dimensions.z, medium.max_density); + medium.density.count = density.size(); + medium.density.a = reinterpret_cast(malloc(medium.density.count * sizeof(float))); + } + + mapping[id] = handle; + return handle; + } + + Medium& get(uint32_t handle) { + return medium_pool.get(handle); + } + + void remove(uint32_t handle) { + if (handle == kInvalidIndex) { + return; + } + + free_medium(medium_pool.get(handle)); + medium_pool.free(handle); + + for (auto i = mapping.begin(), e = mapping.end(); i != e; ++i) { + if (i->second == handle) { + mapping.erase(i); + break; + } + } + } + + void remove_all() { + medium_pool.free_all(std::bind(&MediumPoolImpl::free_medium, this, std::placeholders::_1)); + mapping.clear(); + } + + void free_medium(Medium& m) { + if (m.density.count > 0) { + free(m.density.a); + } + m = {}; + } + + std::vector load_density_grid(const char* file_name, uint32_t& dx, uint32_t& dy, uint32_t& dz, float& max_density) { + // TODO : check validity + char buffer[2048] = {}; + int last_char = snprintf(buffer, sizeof(buffer), "%s", file_name); + while ((last_char > 0) && (buffer[--last_char] != '.')) { + } + auto ext = buffer + last_char; + + std::vector density; + +#if (ETX_HAVE_OPENVDB) + if (strcmp(ext, ".vdb") == 0) { + load_vdb(file_name, density, dx, dy, dz); + snprintf(ext, sizeof(buffer) - last_char, "%s", ".et-vdb"); + save_raw(buffer, density, dx, dy, dz); + } else +#endif + if (strcmp(ext, ".et-vdb") == 0) { + load_raw(file_name, density, dx, dy, dz); + } + + max_density = 0.0f; + for (auto f : density) { + max_density = max(max_density, f); + } + + return density; + } + + void load_raw(const char* file_name, std::vector& density, uint32_t& dx, uint32_t& dy, uint32_t& dz) { + auto fin = fopen(file_name, "rb"); + if (fin == nullptr) { + return; + } + uint32_t d[3] = {}; + fread(d, sizeof(d), 1, fin); + dx = d[0]; + dy = d[1]; + dz = d[2]; + + density.resize(1llu * dx * dy * dz); + fread(density.data(), sizeof(float), 1llu * dx * dy * dz, fin); + fclose(fin); + } + + ObjectIndexPool medium_pool; + std::unordered_map mapping; +}; + +ETX_PIMPL_IMPLEMENT_ALL(MediumPool, Impl); + +void MediumPool::init(uint32_t capacity) { + _private->init(capacity); +} + +void MediumPool::cleanup() { + _private->cleanup(); +} + +uint32_t MediumPool::add_homogenous(const std::string& id, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g) { + return _private->add_homogenous(id, s_a, s_o, g); +} + +uint32_t MediumPool::add_heterogenous(const std::string& id, const char* volume, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g) { + return _private->add_heterogenous(id, volume, s_a, s_o, g); +} + +Medium& MediumPool::get(uint32_t handle) { + return _private->get(handle); +} + +const Medium& MediumPool::get(uint32_t handle) const { + return _private->get(handle); +} + +void MediumPool::remove(uint32_t handle) { + _private->remove(handle); +} + +void MediumPool::remove_all() { + _private->remove_all(); +} + +Medium* MediumPool::as_array() { + return _private->medium_pool.data(); +} + +uint64_t MediumPool::array_size() { + return 1llu + _private->medium_pool.latest_alive_index(); +} + +uint32_t MediumPool::find(const char* id) { + auto i = _private->mapping.find(id); + return (i == _private->mapping.end()) ? kInvalidIndex : i->second; +} + +} // namespace etx diff --git a/sources/etx/render/host/medium_pool.hxx b/sources/etx/render/host/medium_pool.hxx new file mode 100644 index 0000000..8a12dd2 --- /dev/null +++ b/sources/etx/render/host/medium_pool.hxx @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include + +namespace etx { + +struct MediumPool { + MediumPool(); + ~MediumPool(); + + void init(uint32_t capacity); + void cleanup(); + + uint32_t add_homogenous(const std::string&, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g); + uint32_t add_heterogenous(const std::string&, const char* volume, const SpectralDistribution& s_a, const SpectralDistribution& s_o, float g); + + uint32_t find(const char* id); + + void remove(uint32_t handle); + void remove_all(); + + Medium& get(uint32_t); + const Medium& get(uint32_t) const; + + Medium* as_array(); + uint64_t array_size(); + + ETX_DECLARE_PIMPL(MediumPool, 256); +}; + +} // namespace etx diff --git a/sources/etx/render/host/pool.hxx b/sources/etx/render/host/pool.hxx new file mode 100644 index 0000000..9f15517 --- /dev/null +++ b/sources/etx/render/host/pool.hxx @@ -0,0 +1,238 @@ +#pragma once + +#include + +namespace etx { + +template +struct ObjectPool { + void init(uint64_t capacity, uint64_t type_id) { + cleanup(); + + _head = 0; + _capacity = capacity; + _type_id = type_id; + _objects = reinterpret_cast(::calloc(capacity, sizeof(TData))); + for (auto i = _objects, e = _objects + capacity; i < e; ++i) { + i->next = i - _objects + 1; + } + } + + void cleanup() { + ::free(_objects); + _head = 0; + _capacity = 0; + _type_id = 0; + _objects = nullptr; + } + + template + Handle alloc(Args... args) { + ETX_CRITICAL(_head != _capacity); + + auto& obj = _objects[_head]; + ETX_ASSERT(obj.alive == 0); + + obj.alive = 1; + obj.generation += 1; + ETX_ASSERT(obj.generation != 0); + + new (&obj.object) T(std::forward(args)...); + auto result = Handle::construct(_type_id, _head, obj.generation); + _head = obj.next; + return result; + } + + T& get(Handle h) { + ETX_ASSERT(h.index < _capacity); + auto& obj = _objects[h.index]; + ETX_ASSERT(obj.alive); + ETX_ASSERT(obj.generation == h.generation); + return obj.object; + } + + const T& get(Handle h) const { + ETX_ASSERT(h.index < _capacity); + const auto& obj = _objects[h.index]; + ETX_ASSERT(obj.alive); + ETX_ASSERT(obj.generation == h.generation); + return obj.object; + } + + void free(Handle h) { + ETX_ASSERT(h.index < _capacity); + auto& obj = _objects[h.index]; + ETX_ASSERT(obj.alive); + ETX_ASSERT(obj.generation = h.generation); + (obj.object).~T(); + obj.alive = 0; + obj.next = _head; + _head = h.index; + } + + void free_all() { + for (auto i = _objects, e = _objects + _capacity; i < e; ++i) { + if (i->alive) { + (i->object).~T(); + i->alive = 0; + } + i->generation = 0; + i->next = i - _objects + 1; + } + } + + template + void free_all(ReleaseFunc release_func) { + for (auto i = _objects, e = _objects + _capacity; i < e; ++i) { + if (i->alive) { + release_func(i->object); + (i->object).~T(); + i->alive = 0; + } + i->generation = 0; + i->next = i - _objects + 1; + } + } + + uint64_t count_alive() const { + uint64_t result = 0; + for (uint64_t i = 0; i < _capacity; ++i) { + result += _objects[i].alive; + } + return result; + } + + private: + struct alignas(T) TData { + T object; + uint64_t alive : 1; + uint64_t generation : Handle::GenBits; + uint64_t next : Handle::IndexBits; + }; + TData* _objects = nullptr; + uint64_t _type_id = 0; + uint64_t _capacity = 0; + uint64_t _head = 0; +}; + +template +struct ObjectIndexPool { + void init(uint32_t capacity) { + cleanup(); + + _head = 0; + _capacity = capacity; + _objects = reinterpret_cast(::calloc(capacity, sizeof(T))); + _info = reinterpret_cast(::calloc(capacity, sizeof(TData))); + for (uint32_t i = 0; i < _capacity; ++i) { + _info[i].next = i + 1; + } + } + + void cleanup() { + ::free(_objects); + _objects = nullptr; + ::free(_info); + _info = nullptr; + _head = 0; + _capacity = 0; + } + + template + uint32_t alloc(Args... args) { + ETX_ASSERT(_capacity > 0); + ETX_CRITICAL(_head != _capacity); + + auto& info = _info[_head]; + ETX_ASSERT(info.alive == 0); + info.alive = 1; + + new (_objects + _head) T(std::forward(args)...); + + auto result = _head; + _head = info.next; + return result; + } + + T& get(uint32_t h) { + ETX_ASSERT(h < _capacity); + ETX_ASSERT(_info[h].alive); + return _objects[h]; + } + + const T& get(uint32_t h) const { + ETX_ASSERT(h < _capacity); + ETX_ASSERT(_info[h].alive); + return _objects[h]; + } + + void free(uint32_t h) { + ETX_ASSERT(h < _capacity); + ETX_ASSERT(_info[h].alive); + + auto& obj = _objects[h]; + obj.~T(); + + auto& info = _info[h]; + info.alive = 0; + info.next = _head; + + _head = h; + } + + void free_all() { + for (uint32_t i = 0; i < _capacity; ++i) { + if (_info[i].alive) { + _objects[i].~T(); + _info[i].alive = 0; + } + _info[i].next = i + 1; + } + } + + template + void free_all(ReleaseFunc release_func) { + for (uint32_t i = 0; i < _capacity; ++i) { + if (_info[i].alive) { + release_func(_objects[i]); + _objects[i].~T(); + _info[i].alive = 0; + } + _info[i].next = i + 1; + } + } + + uint32_t count_alive() const { + uint32_t result = 0; + for (uint32_t i = 0; i < _capacity; ++i) { + result += _info[i].alive; + } + return result; + } + + T* data() { + return _objects; + } + + uint32_t latest_alive_index() { + uint32_t result = 0; + for (uint32_t i = 0; i < _capacity; ++i) { + if (_info[i].alive) { + result = i; + } + } + return result; + } + + private: + struct TData { + uint32_t alive = 0; + uint32_t next = uint32_t(-1); + }; + T* _objects = nullptr; + TData* _info = nullptr; + uint32_t _capacity = 0; + uint32_t _head = 0; +}; + +} // namespace etx diff --git a/sources/etx/render/host/rnd_sampler.hxx b/sources/etx/render/host/rnd_sampler.hxx new file mode 100644 index 0000000..8951eb6 --- /dev/null +++ b/sources/etx/render/host/rnd_sampler.hxx @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace etx { + +struct RNDSampler : public Sampler { + RNDSampler() { + init(_dis(_gen), _dis(_gen)); + } + + RNDSampler(uint32_t state) + : Sampler(state) { + } + + RNDSampler(const RNDSampler& other) { + seed = other.seed; + } + + private: + std::random_device _rd; + std::mt19937 _gen = std::mt19937(_rd()); + std::uniform_int_distribution _dis; +}; + +} // namespace etx diff --git a/sources/etx/render/host/scene_loader.cxx b/sources/etx/render/host/scene_loader.cxx new file mode 100644 index 0000000..9a7ea17 --- /dev/null +++ b/sources/etx/render/host/scene_loader.cxx @@ -0,0 +1,1068 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace etx { + +Spectrums* spectrums() { + static Spectrums _spectrums; + static auto invoke_once = []() { + using SPD = SpectralDistribution; + rgb::init_spectrums(_spectrums); + { + static float w[2] = {spectrum::kShortestWavelength, spectrum::kLongestWavelength}; + static float eta[2] = {1.5f, 1.5f}; + static float k[2] = {0.0f, 0.0f}; + + static const float2 chrome_samples_eta[] = {{0.354f, 1.84f}, {0.368f, 1.87f}, {0.381f, 1.92f}, {0.397f, 2.00f}, {0.413f, 2.08f}, {0.431f, 2.19f}, {0.451f, 2.33f}, + {0.471f, 2.51f}, {0.496f, 2.75f}, {0.521f, 2.94f}, {0.549f, 3.18f}, {0.582f, 3.22f}, {0.617f, 3.17f}, {0.659f, 3.09f}, {0.704f, 3.05f}, {0.756f, 3.08f}, {0.821f, 3.20f}, + {0.892f, 3.30f}}; + + static const float2 chrome_samples_k[] = {{0.354f, 2.64f}, {0.368f, 2.69f}, {0.381f, 2.74f}, {0.397f, 2.83f}, {0.413f, 2.93f}, {0.431f, 3.04f}, {0.451f, 3.14f}, + {0.471f, 3.24f}, {0.496f, 3.30f}, {0.521f, 3.33f}, {0.549f, 3.33f}, {0.582f, 3.30f}, {0.617f, 3.30f}, {0.659f, 3.34f}, {0.704f, 3.39f}, {0.756f, 3.42f}, {0.821f, 3.48f}, + {0.892f, 3.52f}}; + + static const float2 plastic_samples_eta[] = {{40.0000f, 1.519f}, {41.6667f, 1.519f}, {43.4783f, 1.519f}, {45.4545f, 1.520f}, {47.6190f, 1.521f}, {50.0000f, 1.521f}, + {52.6316f, 1.521f}, {55.5556f, 1.521f}, {58.8235f, 1.521f}, {62.5000f, 1.521f}, {66.6667f, 1.521f}, {71.4286f, 1.521f}, {76.9231f, 1.520f}, {83.3333f, 1.520f}, + {90.9091f, 1.520f}}; + + _spectrums.thinfilm.eta = SPD::from_samples(w, eta, 2, SPD::Class::Reflectance, &_spectrums); + _spectrums.thinfilm.k = SPD::from_samples(w, k, 2, SPD::Class::Reflectance, &_spectrums); + + _spectrums.conductor.eta = SPD::from_samples(chrome_samples_eta, std::size(chrome_samples_eta), SPD::Class::Reflectance, &_spectrums); + _spectrums.conductor.k = SPD::from_samples(chrome_samples_eta, std::size(chrome_samples_k), SPD::Class::Reflectance, &_spectrums); + + _spectrums.dielectric.eta = SPD::from_samples(plastic_samples_eta, std::size(plastic_samples_eta), SPD::Class::Reflectance, &_spectrums); + _spectrums.dielectric.k = SPD::from_constant(0.0f); + } + return true; + }(); + + return &_spectrums; +} + +inline bool value_is_correct(float t) { + return !std::isnan(t) && !std::isinf(t); +} + +inline bool value_is_correct(const float3& v) { + return value_is_correct(v.x) && value_is_correct(v.y) && value_is_correct(v.z); +} + +inline bool is_valid_vector(const float3& v) { + return value_is_correct(v) && (dot(v, v) > 0.0f); +} + +struct SceneRepresentationImpl { + std::vector vertices; + std::vector triangles; + std::vector materials; + std::vector emitters; + + ImagePool images; + MediumPool mediums; + + std::unordered_map material_mapping; + uint32_t camera_medium_index = kInvalidIndex; + uint32_t camera_lens_shape_image_index = kInvalidIndex; + + Scene scene; + bool loaded = false; + + uint32_t add_image(const char* path, uint32_t options) { + std::string id = path ? path : ("image-" + std::to_string(images.array_size())); + return images.add_from_file(path, options); + } + + uint32_t add_material(const char* name) { + std::string id = (name != nullptr) && (name[0] != 0) ? name : ("material-" + std::to_string(materials.size())); + auto i = material_mapping.find(id); + if (i != material_mapping.end()) { + return i->second; + } + uint32_t index = static_cast(materials.size()); + materials.emplace_back(); + material_mapping[id] = index; + return index; + } + + uint32_t add_medium(const char* name, const SpectralDistribution& s_a, const SpectralDistribution& s_t, float g) { + std::string id = name ? name : ("medium-" + std::to_string(mediums.array_size())); + return mediums.add_homogenous(id, s_a, s_t, g); + } + + uint32_t add_medium(const char* name, const char* volume_file, const SpectralDistribution& s_a, const SpectralDistribution& s_t, float g) { + std::string id = name ? name : ("medium-" + std::to_string(mediums.array_size())); + return mediums.add_heterogenous(id, volume_file, s_a, s_t, g); + } + + SceneRepresentationImpl() { + images.init(1024u); + mediums.init(1024u); + scene.camera = build_camera({5.0f, 5.0f, 5.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1280.0f, 720.0f}, 26.99f, 0.0f, 1.0f); + } + + ~SceneRepresentationImpl() { + cleanup(); + images.cleanup(); + mediums.cleanup(); + } + + void cleanup() { + vertices.clear(); + triangles.clear(); + materials.clear(); + emitters.clear(); + material_mapping.clear(); + camera_medium_index = kInvalidIndex; + camera_lens_shape_image_index = kInvalidIndex; + + images.remove_all(); + mediums.remove_all(); + materials.reserve(1024); // TODO : fix, images when reallocated are destroyed releasing memory + + free(scene.emitters_distribution.values); + scene.emitters_distribution = {}; + + auto camera = scene.camera; + scene = {}; + scene.camera = camera; + + loaded = false; + } + + bool calculate_area(Triangle& t) { + t.geo_n = cross(vertices[t.i[1]].pos - vertices[t.i[0]].pos, vertices[t.i[2]].pos - vertices[t.i[0]].pos); + t.area = 0.5f * length(t.geo_n); + t.geo_n *= 0.5f / t.area; + return t.area > 0.0f; + } + + void validate_materials() { + for (auto& mtl : materials) { + if (mtl.int_ior.eta.empty() && mtl.int_ior.k.empty()) { + if (mtl.cls == Material::Class::Conductor) { + mtl.int_ior = spectrums()->conductor; + } else { + mtl.int_ior = spectrums()->dielectric; + } + } + } + } + + void validate_normals(std::vector& referenced_vertices) { + std::set reset_normals; + + referenced_vertices.resize(vertices.size()); + for (const auto& tri : triangles) { + for (uint32_t i = 0; i < 3; ++i) { + uint32_t index = tri.i[i]; + ETX_CRITICAL(is_valid_vector(tri.geo_n)); + referenced_vertices[index] = true; + if (is_valid_vector(vertices[index].nrm) == false) { + if (reset_normals.count(index) == 0) { + vertices[index].nrm = tri.geo_n * tri.area; + reset_normals.insert(index); + } else { + vertices[index].nrm += tri.geo_n * tri.area; + } + } + } + } + + if (reset_normals.empty() == false) { + for (auto i : reset_normals) { + ETX_ASSERT(is_valid_vector(vertices[i].nrm)); + vertices[i].nrm = normalize(vertices[i].nrm); + ETX_ASSERT(is_valid_vector(vertices[i].nrm)); + } + } + } + + void build_tangents() { + SMikkTSpaceInterface contextInterface = {}; + contextInterface.m_getNumFaces = [](const SMikkTSpaceContext* pContext) -> int { + auto data = reinterpret_cast(pContext->m_pUserData); + return static_cast(data->triangles.count); + }; + contextInterface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) -> int { + return 3; + }; + contextInterface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) { + auto data = reinterpret_cast(pContext->m_pUserData); + const auto& tri = data->triangles[iFace]; + const auto& vertex = data->vertices[tri.i[iVert]]; + fvPosOut[0] = vertex.pos[0]; + fvPosOut[1] = vertex.pos[1]; + fvPosOut[2] = vertex.pos[2]; + }; + contextInterface.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) { + auto data = reinterpret_cast(pContext->m_pUserData); + const auto& tri = data->triangles[iFace]; + const auto& vertex = data->vertices[tri.i[iVert]]; + fvNormOut[0] = vertex.nrm[0]; + fvNormOut[1] = vertex.nrm[1]; + fvNormOut[2] = vertex.nrm[2]; + }; + contextInterface.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) { + auto data = reinterpret_cast(pContext->m_pUserData); + const auto& tri = data->triangles[iFace]; + const auto& vertex = data->vertices[tri.i[iVert]]; + fvTexcOut[0] = vertex.tex[0]; + fvTexcOut[1] = vertex.tex[1]; + }; + contextInterface.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) { + auto data = reinterpret_cast(pContext->m_pUserData); + const auto& tri = data->triangles[iFace]; + auto& vertex = data->vertices[tri.i[iVert]]; + vertex.tan[0] = fvTangent[0]; + vertex.tan[1] = fvTangent[1]; + vertex.tan[2] = fvTangent[2]; + vertex.btn = normalize(cross(vertex.tan, vertex.nrm) * fSign); + }; + + SMikkTSpaceContext context = {}; + context.m_pUserData = &scene; + context.m_pInterface = &contextInterface; + + genTangSpaceDefault(&context); + } + + void validate_tangents(std::vector& referenced_vertices) { + for (uint64_t vertex_index = 0, e = vertices.size(); vertex_index < e; ++vertex_index) { + auto& v = vertices[vertex_index]; + if (is_valid_vector(v.tan) && is_valid_vector(v.btn)) { + continue; + } + + if (referenced_vertices[vertex_index]) { + ETX_ASSERT(is_valid_vector(v.nrm)); + auto [t, b] = orthonormal_basis(v.nrm); + v.tan = t; + v.btn = b; + } + } + } + + void commit() { + float3 bbox_min = {FLT_MAX, FLT_MAX, FLT_MAX}; + float3 bbox_max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + for (const auto& tri : triangles) { + bbox_min = min(bbox_min, vertices[tri.i[0]].pos); + bbox_min = min(bbox_min, vertices[tri.i[1]].pos); + bbox_min = min(bbox_min, vertices[tri.i[2]].pos); + bbox_max = max(bbox_max, vertices[tri.i[0]].pos); + bbox_max = max(bbox_max, vertices[tri.i[1]].pos); + bbox_max = max(bbox_max, vertices[tri.i[2]].pos); + } + scene.bounding_sphere_center = 0.5f * (bbox_min + bbox_max); + scene.bounding_sphere_radius = length(bbox_max - scene.bounding_sphere_center); + scene.camera_medium_index = camera_medium_index; + scene.camera_lens_shape_image_index = camera_lens_shape_image_index; + + for (auto& emitter : emitters) { + if (emitter.is_distant()) { + ETX_ASSERT(emitter.weight == 0.0f); + emitter.weight = kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius; + } + } + + scene.vertices = {vertices.data(), vertices.size()}; + scene.triangles = {triangles.data(), triangles.size()}; + scene.materials = {materials.data(), materials.size()}; + scene.emitters = {emitters.data(), emitters.size()}; + scene.images = {images.as_array(), images.array_size()}; + scene.mediums = {mediums.as_array(), mediums.array_size()}; + scene.spectrums = spectrums(); + scene.environment_emitters.count = 0; + + log::info("Building emitters distribution for %llu emitters...\n", scene.emitters.count); + DistributionBuilder emitters_distribution(scene.emitters_distribution, static_cast(scene.emitters.count)); + for (uint32_t i = 0; i < scene.emitters.count; ++i) { + auto& emitter = emitters[i]; + emitter.equivalent_disk_size = 2.0f * std::tan(emitter.angular_size / 2.0f); + emitter.angular_size_cosine = std::cos(emitter.angular_size / 2.0f); + emitters_distribution.add(emitter.weight); + if (emitter.is_local()) { + triangles[emitter.triangle_index].emitter_index = i; + } else if ((emitter.cls == Emitter::Class::Environment) || (emitter.cls == Emitter::Class::Directional)) { + scene.environment_emitters.emitters[scene.environment_emitters.count++] = i; + } + } + emitters_distribution.finalize(); + + build_gpu_data(); + + loaded = true; + } + + void build_gpu_data() { + /*/ + _gpu.image_buffers.resize(images.count); + std::vector images_array(images.count); + for (uint64_t i = 0, e = _images.size(); i < e; ++i) { + const auto& img = _images[i]; + const auto& dim = img.dimensions(); + const auto& y_dist = img.y_distribution(); + + uint64_t buffer_size = align_up(sizeof(float4) * dim.x * dim.y, 16llu); // pixels + buffer_size += align_up(y_dist.size() * sizeof(Distribution1DData::Entry), 16llu); // y-values + buffer_size += align_up(y_dist.size() * sizeof(Distribution1DData), 16llu); // x-distributions + for (uint64_t j = 0; j < y_dist.size(); ++j) { + buffer_size += align_up(img.x_distribution(j).size() * sizeof(Distribution1DData::Entry), 16llu); // x-values + } + + _gpu.image_buffers[i] = gpu_device.create_buffer(buffer_size, nullptr, optix::Buffer::Suballocations); + images_array[i] = img.data(); + + if (images_array[i].pixels != nullptr) { + auto pixels = gpu_device.upload_gpu_data(_gpu.image_buffers[i], nullptr, images_array[i].pixels, sizeof(float4) * dim.x * dim.y); + images_array[i].pixels = reinterpret_cast(pixels); + } else { + images_array[i].pixels = nullptr; + } + + if (y_dist.size() > 0) { + auto y_values = gpu_device.upload_gpu_data(_gpu.image_buffers[i], nullptr, y_dist.values(), y_dist.size() * sizeof(Distribution1DData::Entry)); + images_array[i].y_distribution.values = reinterpret_cast(y_values); + + std::vector x_dists(y_dist.size()); + for (uint64_t j = 0; j < y_dist.size(); ++j) { + const auto& x_dist = img.x_distribution(j); + x_dists[j].size = x_dist.size(); + x_dists[j].total_weight = x_dist.total_weight(); + + auto x_values = gpu_device.upload_gpu_data(_gpu.image_buffers[i], nullptr, x_dist.values(), x_dist.size() * sizeof(Distribution1DData::Entry)); + x_dists[j].values = reinterpret_cast(x_values); + } + + auto x_distributions = gpu_device.upload_gpu_data(_gpu.image_buffers[i], nullptr, x_dists.data(), y_dist.size() * sizeof(Distribution1DData)); + images_array[i].x_distributions = reinterpret_cast(x_distributions); + } + } + + if (mediums.count > 0) { + std::vector gpu_medium_data; + gpu_medium_data.resize(mediums.count); + + uint64_t medium_buffer_size = align_up(sizeof(MediumData) * mediums.count, 16llu); + for (uint64_t i = 0; i < mediums.count; ++i) { + gpu_medium_data[i] = mediums[i]; + medium_buffer_size += align_up(mediums[i].density.count * sizeof(float), 16llu); + } + _gpu.mediums = gpu_device.create_buffer(medium_buffer_size, nullptr, optix::Buffer::Suballocations); + + for (uint64_t i = 0; i < mediums.count; ++i) { + if (gpu_medium_data[i].density.count > 0) { + auto ptr = gpu_device.upload_gpu_data(_gpu.mediums, nullptr, gpu_medium_data[i].density.a, sizeof(float) * gpu_medium_data[i].density.count); + gpu_medium_data[i].density = make_array_view(ptr, gpu_medium_data[i].density.count); // + } + } + + auto ptr = gpu_device.upload_gpu_data(_gpu.mediums, nullptr, gpu_medium_data.data(), gpu_medium_data.size() * sizeof(MediumData)); + _gpu.data.mediums = make_array_view(ptr, mediums.count); + } + + uint64_t emitter_buffer_size = align_up(emitters.count * sizeof(Emitter), 16llu) + align_up(emitters_distribution.size * sizeof(Distribution1DData::Entry), 16llu); + _gpu.emitters = gpu_device.create_buffer(emitter_buffer_size, nullptr, optix::Buffer::Suballocations); + auto emitters_ptr = gpu_device.upload_gpu_data(_gpu.emitters, nullptr, emitters.a, emitters.count * sizeof(Emitter)); + auto emitters_dist_ptr = gpu_device.upload_gpu_data(_gpu.emitters, nullptr, emitters_distribution.values, emitters_distribution.size * sizeof(Distribution1DData::Entry)); + + _gpu.vertices = gpu_device.create_buffer(vertices.count * sizeof(Vertex), vertices.a, 0u); + _gpu.triangles = gpu_device.create_buffer(triangles.count * sizeof(Triangle), triangles.a, 0u); + _gpu.materials = gpu_device.create_buffer(materials.count * sizeof(Material), materials.a, 0u); + _gpu.images = gpu_device.create_buffer(images.count * sizeof(ImageData), images_array.data(), 0u); + + _gpu.spectrums = gpu_device.create_buffer(sizeof(Spectrums), spectrums, 0); + + _gpu.acceleration_structure = gpu_device.build_acceleration_structure( // + _gpu.vertices, static_cast(vertices.count), // + _gpu.triangles, static_cast(triangles.count)); + + _gpu.data.vertices = make_array_view(gpu_device.get_buffer_device_pointer(_gpu.vertices), vertices.count); + _gpu.data.triangles = make_array_view(gpu_device.get_buffer_device_pointer(_gpu.triangles), triangles.count); + _gpu.data.materials = make_array_view(gpu_device.get_buffer_device_pointer(_gpu.materials), materials.count); + _gpu.data.emitters = make_array_view(emitters_ptr, emitters.count); + _gpu.data.images = make_array_view(gpu_device.get_buffer_device_pointer(_gpu.images), images.count); + _gpu.data.emitters_distribution.size = emitters_distribution.size; + _gpu.data.emitters_distribution.total_weight = emitters_distribution.total_weight; + _gpu.data.emitters_distribution.values = reinterpret_cast(emitters_dist_ptr); + _gpu.data.spectrums = reinterpret_cast(gpu_device.get_buffer_device_pointer(_gpu.spectrums)); + _gpu.data.environment_emitters = environment_emitters; + _gpu.data.bounding_sphere_center = bounding_sphere_center; + _gpu.data.bounding_sphere_radius = bounding_sphere_radius; + _gpu.data.acceleration_structure = reinterpret_cast(gpu_device.get_acceleration_structure_device_pointer(_gpu.acceleration_structure)); + _gpu.data.camera_medium_index = camera_medium_index; + _gpu.data.camera_lens_shape_image_index = camera_lens_shape_image_index; + // */ + } + + enum : uint32_t { + LoadFailed = 0u, + LoadSucceeded = 1u << 0u, + HaveTangents = 1u << 1u, + }; + + uint32_t load_from_obj(const char* file_name, const char* mtl_file); + void parse_obj_materials(const char* base_dir, const std::vector& obj_materials); +}; + +Camera build_camera(const float3& origin, const float3& target, const float3& up, const float2& viewport, float fov, float lens_radius, float focal_distance) { + Camera result = {}; + result.focal_distance = focal_distance; + result.lens_radius = lens_radius; + update_camera(result, origin, target, up, viewport, fov); + return result; +} + +void update_camera(Camera& camera, const float3& origin, const float3& target, const float3& up, const float2& viewport, float fov) { + float4x4 view = glm::lookAtRH(origin, target, up); + float4x4 proj = glm::perspectiveFovRH_ZO(fov * kPi / 180.0f, viewport.x, viewport.y, 1.0f, 1024.0f); + + auto inv_view = glm::inverse(view); + camera.position = {inv_view[3][0], inv_view[3][1], inv_view[3][2]}; + camera.side = {view[0][0], view[1][0], view[2][0]}; + camera.up = {view[0][1], view[1][1], view[2][1]}; + camera.direction = {-view[0][2], -view[1][2], -view[2][2]}; + camera.tan_half_fov = 1.0f / std::abs(proj[1][1]); + camera.aspect = proj[1][1] / proj[0][0]; + camera.view_proj = proj * view; + + float plane_w = 2.0f * camera.tan_half_fov * camera.aspect; + float plane_h = 2.0f * camera.tan_half_fov; + camera.area = plane_w * plane_h; + camera.image_size = viewport; + camera.image_plane = float(camera.image_size.x) / (2.0f * camera.tan_half_fov); +} + +float get_camera_fov(const Camera& camera) { + return 2.0f * atanf(camera.tan_half_fov) * 180.0f / kPi; +} + +ETX_PIMPL_IMPLEMENT_ALL(SceneRepresentation, Impl); + +const Scene& SceneRepresentation::scene() const { + return _private->scene; +} + +Camera& SceneRepresentation::camera() { + return _private->scene.camera; +} + +SceneRepresentation::operator bool() const { + return _private->loaded; +} + +template +V json_to_float_n(json_t* a) { + V result = {}; + int i = 0; + json_t* val = {}; + json_array_foreach(a, i, val) { + if ((i < n) && json_is_number(val)) { + result[i] = static_cast(json_number_value(val)); + } else { + break; + } + } + return result; +} +const auto json_to_float2 = json_to_float_n; +const auto json_to_float3 = json_to_float_n; + +bool SceneRepresentation::load_from_file(const char* filename, uint32_t options) { + _private->cleanup(); + + uint32_t load_result = SceneRepresentationImpl::LoadFailed; + + std::string file_to_load = filename; + std::string material_file = {}; + + char base_folder[2048] = {}; + get_file_folder(filename, base_folder, sizeof(base_folder)); + + auto& cam = _private->scene.camera; + float3 camera_pos = cam.position; + float3 camera_up = {0.0f, 1.0f, 0.0f}; + float3 camera_view = cam.position + cam.direction; + float2 viewport = cam.image_size; + float camera_fov = get_camera_fov(cam); + + if (strcmp(get_file_ext(filename), ".json") == 0) { + json_error_t err = {}; + auto js = json_load_file(filename, 0, &err); + if (js == nullptr) { + log::error("Failed to parse json file: %s\n%d / %d : %s", filename, err.line, err.column, err.text); + return false; + } + + if (json_is_object(js) == false) { + log::error("Invalid scene description file: %s", filename); + json_decref(js); + return false; + } + + const char* key = {}; + json_t* js_value = {}; + json_object_foreach(js, key, js_value) { + if (strcmp(key, "geometry") == 0) { + if (json_is_string(js_value) == false) { + log::error("`geometry` in scene description should be a string (file name)"); + json_decref(js); + return false; + } + file_to_load = std::string(base_folder) + json_string_value(js_value); + } else if (strcmp(key, "materials") == 0) { + if (json_is_string(js_value) == false) { + log::error("`materials` in scene description should be a string (file name)"); + json_decref(js); + return false; + } + material_file = json_string_value(js_value); + } else if (strcmp(key, "camera") == 0) { + if (json_is_object(js_value) == false) { + log::error("`camera` in scene description should be an object"); + continue; + } + const char* cam_key = {}; + json_t* cam_value = {}; + json_object_foreach(js_value, cam_key, cam_value) { + if ((strcmp(cam_key, "origin") == 0) && json_is_array(cam_value)) { + camera_pos = json_to_float3(cam_value); + } else if ((strcmp(cam_key, "target") == 0) && json_is_array(cam_value)) { + camera_view = json_to_float3(cam_value); + } else if ((strcmp(cam_key, "up") == 0) && json_is_array(cam_value)) { + camera_up = json_to_float3(cam_value); + } else if ((strcmp(cam_key, "viewport") == 0) && json_is_array(cam_value)) { + viewport = json_to_float2(cam_value); + } else if ((strcmp(cam_key, "fov") == 0) && json_is_number(cam_value)) { + camera_fov = static_cast(json_number_value(cam_value)); + } else if ((strcmp(cam_key, "lens-radius") == 0) && json_is_number(cam_value)) { + cam.lens_radius = static_cast(json_number_value(cam_value)); + } else if ((strcmp(cam_key, "focal-distance") == 0) && json_is_number(cam_value)) { + cam.focal_distance = static_cast(json_number_value(cam_value)); + } + } + } + } + json_decref(js); + } + + auto ext = get_file_ext(file_to_load.c_str()); + if (strcmp(ext, ".obj") == 0) { + load_result = _private->load_from_obj(file_to_load.c_str(), material_file.c_str()); + } + + if ((load_result & SceneRepresentationImpl::LoadSucceeded) == 0) { + return false; + } + + if (_private->triangles.empty() || _private->materials.empty()) { + return false; + } + + if (options & SetupCamera) { + if (viewport.x * viewport.y == 0) { + viewport = {1280, 720}; + } + update_camera(cam, camera_pos, camera_view, camera_up, viewport, camera_fov); + } + + if (_private->emitters.empty()) { + printf("No emitters found, adding default environment image...\n"); + auto& sky = _private->emitters.emplace_back(Emitter::Class::Environment); + sky.emission = SpectralDistribution::from_constant(1.0f); + sky.image_index = _private->add_image(env().file_in_data("assets/hdri/environment.exr"), Image::RepeatU | Image::BuildSamplingTable); + } + + _private->validate_materials(); + + std::vector referenced_vertices; + _private->validate_normals(referenced_vertices); + + if ((load_result & SceneRepresentationImpl::HaveTangents) == 0) { + TimeMeasure m = {}; + log::warning("Calculating tangents..."); + _private->build_tangents(); + log::warning("Tangents calculated in %.2f sec\n", m.measure()); + } + _private->validate_tangents(referenced_vertices); + _private->commit(); + + return true; +} + +inline auto to_float2(const float values[]) -> float2 { + return {values[0], values[1]}; +}; + +inline auto to_float3(const float values[]) -> float3 { + return {values[0], values[1], values[2]}; +}; + +inline std::vector split_params(char* data) { + std::vector params; + const char* begin = data; + char* token = data; + while (*token != 0) { + if (*token == 0x20) { + *token++ = 0; + params.emplace_back(begin); + begin = token; + } else { + ++token; + } + } + params.emplace_back(begin); + return params; +} + +inline auto get_param(const tinyobj::material_t& m, const char* param, char buffer[]) -> bool { + for (const auto& p : m.unknown_parameter) { + if (_stricmp(p.first.c_str(), param) == 0) { + if (buffer != nullptr) { + memcpy(buffer, p.second.c_str(), p.second.size()); + buffer[p.second.size()] = 0; + } + return true; + } + } + return false; +} + +inline Material::Class material_string_to_class(const char* s) { + if (strcmp(s, "diffuse") == 0) + return Material::Class::Diffuse; + else if (strcmp(s, "plastic") == 0) + return Material::Class::Plastic; + else if (strcmp(s, "conductor") == 0) + return Material::Class::Conductor; + else if (strcmp(s, "dielectric") == 0) + return Material::Class::Dielectric; + else if (strcmp(s, "thinfilm") == 0) + return Material::Class::Thinfilm; + else if (strcmp(s, "translucent") == 0) + return Material::Class::Translucent; + else if (strcmp(s, "mirror") == 0) + return Material::Class::Mirror; + else if (strcmp(s, "boundary") == 0) + return Material::Class::Boundary; + else if (strcmp(s, "generic") == 0) + return Material::Class::Generic; + else if (strcmp(s, "coating") == 0) + return Material::Class::Coating; + else + return Material::Class::Undefined; +} + +uint32_t SceneRepresentationImpl::load_from_obj(const char* file_name, const char* mtl_file) { + tinyobj::attrib_t obj_attrib; + std::vector obj_shapes; + std::vector obj_materials; + std::string warnings; + std::string errors; + + char base_dir[2048] = {}; + get_file_folder(file_name, base_dir, sizeof(base_dir)); + + if (tinyobj::LoadObj(&obj_attrib, &obj_shapes, &obj_materials, &warnings, &errors, file_name, base_dir, mtl_file) == false) { + log::error("Failed to load OBJ from file: `%s`\n%s", file_name, errors.c_str()); + return LoadFailed; + } + + if (warnings.empty() == false) { + log::warning("Loaded OBJ from file: `%s`\n%s", file_name, warnings.c_str()); + } + + parse_obj_materials(base_dir, obj_materials); + + uint64_t total_triangles = 0; + for (const auto& shape : obj_shapes) { + total_triangles += shape.mesh.num_face_vertices.size(); + } + + triangles.reserve(total_triangles); + vertices.reserve(total_triangles * 3); + + for (const auto& shape : obj_shapes) { + uint64_t index_offset = 0; + float3 shape_bbox_min = {FLT_MAX, FLT_MAX, FLT_MAX}; + float3 shape_bbox_max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + + for (uint64_t face = 0, face_e = shape.mesh.num_face_vertices.size(); face < face_e; ++face) { + int material_id = shape.mesh.material_ids[face]; + if (material_id == -1) { + continue; + } + const auto& source_material = obj_materials[material_id]; + + uint64_t face_size = shape.mesh.num_face_vertices[face]; + ETX_ASSERT(face_size == 3); + + auto& tri = triangles.emplace_back(); + tri.material_index = material_mapping[source_material.name]; + auto& mtl = materials[tri.material_index]; + + for (uint64_t vertex_index = 0; vertex_index < face_size; ++vertex_index) { + const auto& index = shape.mesh.indices[index_offset + vertex_index]; + tri.i[vertex_index] = static_cast(vertices.size()); + auto& vertex = vertices.emplace_back(); + vertex.pos = to_float3(obj_attrib.vertices.data() + (3 * index.vertex_index)); + if (index.normal_index >= 0) { + vertex.nrm = to_float3(obj_attrib.normals.data() + (3 * index.normal_index)); + } + if (index.texcoord_index >= 0) { + vertex.tex = to_float2(obj_attrib.texcoords.data() + (2 * index.texcoord_index)); + } + } + index_offset += face_size; + + if (calculate_area(tri) == false) { + triangles.pop_back(); + } + + float texture_emission = 1.0f; + + if (mtl.emissive_image_index != kInvalidIndex) { + const auto& img = images.get(mtl.emissive_image_index); + + constexpr float kBCScale = 4.0f; + + auto min_uv = min(vertices[tri.i[0]].tex, min(vertices[tri.i[1]].tex, vertices[tri.i[2]].tex)); + auto max_uv = max(vertices[tri.i[0]].tex, max(vertices[tri.i[1]].tex, vertices[tri.i[2]].tex)); + + float u_size = kBCScale * max(1.0f, ceil((max_uv.x - min_uv.x) * img.fsize.x)); + float du = 1.0f / u_size; + + float v_size = kBCScale * max(1.0f, ceil((max_uv.y - min_uv.y) * img.fsize.y)); + float dv = 1.0f / v_size; + + float texture_emission = 0.0f; + for (float v = 0.0f; v < 1.0f; v += dv) { + for (float u = 0.0f; u < 1.0f; u += dv) { + float2 uv = lerp_uv({vertices.data(), vertices.size()}, tri, random_barycentric(u, v)); + float4 val = img.evaluate(uv); + texture_emission += luminance(val) * du * dv * val.w; + } + } + } + + bool emissive_material = (source_material.emission[0] > 0.0f) || (source_material.emission[1] > 0.0f) || (source_material.emission[2] > 0.0f); + + if (emissive_material && (texture_emission > 0.0f)) { + auto& e = emitters.emplace_back(Emitter::Class::Area); + e.emission = rgb::make_illuminant_spd(to_float3(source_material.emission), spectrums()); + + char data_buffer[2048] = {}; + if (get_param(source_material, "spectrum_ke", data_buffer)) { + char buffer[1024] = {}; + snprintf(buffer, sizeof(buffer), "%s/%s", base_dir, data_buffer); + SpectralDistribution::load_from_file(buffer, e.emission, nullptr, SpectralDistribution::Class::Illuminant, spectrums()); + } + + if (get_param(obj_materials[material_id], "emitter", data_buffer)) { + auto params = split_params(data_buffer); + + for (uint64_t i = 0, end = params.size(); i < end; ++i) { + if (strcmp(params[i], "twosided") == 0) { + e.emission_direction = Emitter::Direction::TwoSided; + } else if (strcmp(params[i], "omni") == 0) { + e.emission_direction = Emitter::Direction::Omni; + } else if ((strcmp(params[i], "collimated") == 0) && (i + 1 < end)) { + e.collimation = static_cast(atof(params[i + 1])); + i += 1; + } else if ((strcmp(params[i], "blackbody") == 0) && (i + 1 < end)) { + e.emission = SpectralDistribution::from_black_body(static_cast(atof(params[i + 1])), SpectralDistribution::Class::Illuminant, spectrums()); + i += 1; + } else if ((strcmp(params[i], "scale") == 0) && (i + 1 < end)) { + e.emission *= static_cast(atof(params[i + 1])); + i += 1; + } + } + } + + float power_scale = 1.0f; + switch (e.emission_direction) { + case Emitter::Direction::TwoSided: { + power_scale = 2.0f; + break; + } + case Emitter::Direction::Omni: { + power_scale = 4.0f * kPi; + break; + } + default: + break; + } + e.medium_index = mtl.ext_medium; + e.triangle_index = static_cast(triangles.size() - 1llu); + e.weight = power_scale * (tri.area * kPi) * (e.emission.total_power() * texture_emission); + e.image_index = mtl.emissive_image_index; + } + + // TODO : deal with bounds! + shape_bbox_max = glm::max(shape_bbox_max, vertices[tri.i[0]].pos); + shape_bbox_max = glm::max(shape_bbox_max, vertices[tri.i[1]].pos); + shape_bbox_max = glm::max(shape_bbox_max, vertices[tri.i[2]].pos); + shape_bbox_min = glm::min(shape_bbox_min, vertices[tri.i[0]].pos); + shape_bbox_min = glm::min(shape_bbox_min, vertices[tri.i[1]].pos); + shape_bbox_min = glm::min(shape_bbox_min, vertices[tri.i[2]].pos); + + if (mtl.int_medium != kInvalidIndex) { + mediums.get(mtl.int_medium).bounds = {shape_bbox_min, shape_bbox_max}; + } + } + } + + return true; +} + +void SceneRepresentationImpl::parse_obj_materials(const char* base_dir, const std::vector& obj_materials) { + auto get_file = [base_dir](const std::string& base, char buffer[]) -> bool { + if (base.empty()) { + return false; + } + sprintf(buffer, "%s/%s", base_dir, base.c_str()); + return true; + }; + + for (const auto& material : obj_materials) { + char data_buffer[1024] = {}; + char tmp_buffer[2048] = {}; + + if (material.name == "et::camera") { + if (get_param(material, "shape", data_buffer)) { + snprintf(tmp_buffer, sizeof(tmp_buffer), "%s/%s", base_dir, data_buffer); + camera_lens_shape_image_index = add_image(tmp_buffer, Image::BuildSamplingTable | Image::UniformSamplingTable); + } + } else if (material.name == "et::medium") { + char name_buffer[2048] = {}; + if (get_param(material, "id", name_buffer) == false) { + continue; + } + + SpectralDistribution s_a = SpectralDistribution::from_constant(0.0f); + if (get_param(material, "sigma_a", data_buffer)) { + float val[3] = {}; + if (sscanf(data_buffer, "%f %f %f", val + 0, val + 1, val + 2) == 3) { + s_a = rgb::make_reflectance_spd({val[0], val[1], val[2]}, spectrums()); + } + } + + SpectralDistribution s_t = SpectralDistribution::from_constant(0.0f); + if (get_param(material, "sigma_s", data_buffer)) { + float val[3] = {}; + if (sscanf(data_buffer, "%f %f %f", val + 0, val + 1, val + 2) == 3) { + s_t = rgb::make_reflectance_spd({val[0], val[1], val[2]}, spectrums()); + } + } + + float g = 0.0f; + if (get_param(material, "g", data_buffer)) { + float val = {}; + if (sscanf(data_buffer, "%f", &val) == 1) { + g = val; + } + } + + if (get_param(material, "volume", data_buffer)) { + snprintf(tmp_buffer, sizeof(tmp_buffer), "%s/%s", base_dir, data_buffer); + } + + uint32_t medium_index = kInvalidIndex; + + if (strlen(tmp_buffer) == 0) { + medium_index = add_medium(name_buffer, s_a, s_t, g); + } else { + medium_index = add_medium(name_buffer, tmp_buffer, s_a, s_t, g); + } + + if (strcmp(data_buffer, "camera") == 0) { + camera_medium_index = medium_index; + } + + } else if (material.name == "et::dir") { + auto color = float3{material.diffuse[0], material.diffuse[1], material.diffuse[2]}; + auto dir = float3{material.specular[0], material.specular[1], material.specular[2]}; + + auto& e = emitters.emplace_back(Emitter::Class::Directional); + e.emission = rgb::make_illuminant_spd(color, spectrums()); + e.direction = normalize(dir); + + if (get_param(material, "angular_diameter", data_buffer)) { + float val = {}; + if (sscanf(data_buffer, "%f", &val) == 1) { + e.angular_size = val * kPi / 180.0f; + } + } + } else if (material.name == "et::env") { + if (get_param(material, "image", data_buffer)) { + snprintf(tmp_buffer, sizeof(tmp_buffer), "%s/%s", base_dir, data_buffer); + } + + auto& e = emitters.emplace_back(Emitter::Class::Environment); + e.emission = rgb::make_illuminant_spd({1.0f, 1.0f, 1.0f}, spectrums()); + e.image_index = add_image(tmp_buffer, Image::BuildSamplingTable | Image::RepeatU); + + if (get_param(material, "color", data_buffer)) { + float color[3] = {}; + if (sscanf(data_buffer, "%f %f %f", color + 0, color + 1, color + 2) == 3) { + e.emission = rgb::make_illuminant_spd({color[0], color[1], color[2]}, spectrums()); + } + } + } else { + if (material_mapping.count(material.name) == 0) { + add_material(material.name.c_str()); + } + uint32_t material_index = material_mapping[material.name]; + auto& mtl = materials[material_index]; + mtl.diffuse = rgb::make_reflectance_spd(to_float3(material.diffuse), spectrums()); + mtl.specular = rgb::make_reflectance_spd(to_float3(material.specular), spectrums()); + mtl.transmittance = rgb::make_reflectance_spd(to_float3(material.transmittance), spectrums()); + mtl.roughness = {material.roughness, material.roughness}; + mtl.metalness = material.metallic; + + if (get_param(material, "int_ior", data_buffer)) { + float n_i = 0.0f; + float n_k = 0.0f; + if (sscanf(data_buffer, "%f %f", &n_i, &n_k) >= 1) { + mtl.int_ior.eta = SpectralDistribution::from_constant(n_i); + mtl.int_ior.k = SpectralDistribution::from_constant(n_k); + } else { + char buffer[256] = {}; + snprintf(buffer, sizeof(buffer), "%sspectrum/%s.spd", env().data_folder(), data_buffer); + SpectralDistribution::load_from_file(buffer, mtl.int_ior.eta, &mtl.int_ior.k, SpectralDistribution::Class::Reflectance, spectrums()); + } + } + + if (get_param(material, "ext_ior", data_buffer)) { + float n_i = 0.0f; + float n_k = 0.0f; + if (sscanf(data_buffer, "%f %f", &n_i, &n_k) >= 1) { + mtl.ext_ior.eta = SpectralDistribution::from_constant(n_i); + mtl.ext_ior.k = SpectralDistribution::from_constant(n_k); + } else { + char buffer[256] = {}; + snprintf(buffer, sizeof(buffer), "%sspectrum/%s.spd", env().data_folder(), data_buffer); + SpectralDistribution::load_from_file(buffer, mtl.ext_ior.eta, &mtl.ext_ior.k, SpectralDistribution::Class::Reflectance, spectrums()); + } + } + + if (get_param(material, "int_medium", data_buffer)) { + auto m = mediums.find(data_buffer); + if (m == kInvalidIndex) { + log::warning("Medium %s was not declared, but used in material %s as internal medium", data_buffer, material.name.c_str()); + } + mtl.int_medium = m; + } + + if (get_param(material, "ext_medium", data_buffer)) { + auto m = mediums.find(data_buffer); + if (m == kInvalidIndex) { + log::warning("Medium %s was not declared, but used in material %s as external medium\n", data_buffer, material.name.c_str()); + } + mtl.ext_medium = m; + } + + if (get_param(material, "spectrum_kd", data_buffer)) { + char buffer[1024] = {}; + snprintf(buffer, sizeof(buffer), "%s/%s", base_dir, data_buffer); + SpectralDistribution::load_from_file(buffer, mtl.diffuse, nullptr, SpectralDistribution::Class::Reflectance, spectrums()); + } + + if (get_param(material, "normalmap", data_buffer)) { + auto params = split_params(data_buffer); + for (uint64_t i = 0, e = params.size(); i < e; ++i) { + if ((strcmp(params[i], "image") == 0) && (i + 1 < e)) { + char buffer[1024] = {}; + snprintf(buffer, sizeof(buffer), "%s/%s", base_dir, params[i + 1]); + mtl.normal_image_index = add_image(buffer, Image::RepeatU | Image::RepeatV | Image::Linear); + i += 1; + } + if ((strcmp(params[i], "scale") == 0) && (i + 1 < e)) { + mtl.normal_scale = static_cast(atof(params[i + 1])); + i += 1; + } + } + } + + if (get_param(material, "thinfilm", data_buffer)) { + auto params = split_params(data_buffer); + + for (uint64_t i = 0, e = params.size(); i < e; ++i) { + if ((strcmp(params[i], "image") == 0) && (i + 1 < e)) { + char buffer[1024] = {}; + snprintf(buffer, sizeof(buffer), "%s/%s", base_dir, params[i + 1]); + mtl.thinfilm.image_index = add_image(buffer, Image::RepeatU | Image::RepeatV | Image::Linear); + i += 1; + } + + if ((strcmp(params[i], "range") == 0) && (i + 2 < e)) { + mtl.thinfilm.min_thickness = static_cast(atof(params[i + 1])); + mtl.thinfilm.max_thickness = static_cast(atof(params[i + 2])); + i += 2; + } + } + } + + if (get_param(material, "material", data_buffer)) { + auto params = split_params(data_buffer); + for (uint64_t i = 0, e = params.size(); i < e; ++i) { + if ((strcmp(params[i], "class") == 0) && (i + 1 < e)) { + mtl.cls = material_string_to_class(params[i + 1]); + i += 1; + } + if ((strcmp(params[i], "uroughness") == 0) && (i + 1 < e)) { + float param = 0.0f; + if (sscanf(params[i + 1], "%f", ¶m) == 1) { + mtl.roughness.x = param; + } + i += 1; + } + if ((strcmp(params[i], "vroughness") == 0) && (i + 1 < e)) { + float param = 0.0f; + if (sscanf(params[i + 1], "%f", ¶m) == 1) { + mtl.roughness.y = param; + } + i += 1; + } + if (strcmp(params[i], "twosided") == 0) { + mtl.options |= Material::DoubleSided; + } + } + } + + if (get_file(material.diffuse_texname, data_buffer)) { + mtl.diffuse_image_index = add_image(data_buffer, Image::RepeatU | Image::RepeatV); + } + if (get_file(material.specular_texname, data_buffer)) { + mtl.specular_image_index = add_image(data_buffer, Image::RepeatU | Image::RepeatV); + } + if (get_file(material.emissive_texname, data_buffer)) { + mtl.emissive_image_index = add_image(data_buffer, Image::RepeatU | Image::RepeatV | Image::BuildSamplingTable); + } + + if (mtl.cls == Material::Class::Undefined) { + mtl.cls = Material::Class::Diffuse; + } + } + } +} + +} // namespace etx diff --git a/sources/etx/render/host/scene_loader.hxx b/sources/etx/render/host/scene_loader.hxx new file mode 100644 index 0000000..70fe330 --- /dev/null +++ b/sources/etx/render/host/scene_loader.hxx @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace etx { + +struct SceneRepresentation { + enum : uint32_t { + LoadGeometry = 0u, + SetupCamera = 1u << 0u, + LoadEverything = LoadGeometry | SetupCamera, + }; + + SceneRepresentation(); + ~SceneRepresentation(); + + bool load_from_file(const char* filename, uint32_t options); + + const Scene& scene() const; + Camera& camera(); + + operator bool() const; + + ETX_DECLARE_PIMPL(SceneRepresentation, 2048); +}; + +Camera build_camera(const float3& origin, const float3& target, const float3& up, const float2& viewport, float fov, float lens_radius, float focal_distance); +void update_camera(Camera& camera, const float3& origin, const float3& target, const float3& up, const float2& viewport, float fov); +float get_camera_fov(const Camera& camera); + +} // namespace etx diff --git a/sources/etx/render/host/spectrum.cxx b/sources/etx/render/host/spectrum.cxx new file mode 100644 index 0000000..3a0f4bf --- /dev/null +++ b/sources/etx/render/host/spectrum.cxx @@ -0,0 +1,394 @@ +#include + +#include +#include + +namespace etx { + +SpectralDistribution SpectralDistribution::from_constant(float value) { + SpectralDistribution result; + if constexpr (spectrum::kSpectralRendering) { + result.count = 2; + result.entries[0] = {spectrum::kShortestWavelength, value}; + result.entries[1] = {spectrum::kLongestWavelength, value}; + } else { + result.count = 3; + result.entries[0] = {spectrum::kUndefinedWavelength, value}; + result.entries[1] = {spectrum::kUndefinedWavelength, value}; + result.entries[2] = {spectrum::kUndefinedWavelength, value}; + } + return result; +} + +SpectralDistribution SpectralDistribution::from_black_body(float temperature, Class cls, Spectrums* spectrums) { + SpectralDistribution result; + result.count = spectrum::WavelengthCount; + for (uint64_t i = 0; i < spectrum::WavelengthCount; ++i) { + float wl = float(i + spectrum::ShortestWavelength); + result.entries[i] = {wl, spectrum::black_body_radiation(wl, temperature)}; + } + + if constexpr (spectrum::kSpectralRendering == false) { + float3 xyz = result.integrate_to_xyz(); + result = rgb::make_spd(spectrum::xyz_to_rgb(xyz), (cls == Class::Reflectance) ? spectrums->rgb_reflection : spectrums->rgb_illuminant); + } + + return result; +} + +void SpectralDistribution::load_from_file(const char* file_name, SpectralDistribution& values0, SpectralDistribution* values1, Class cls, Spectrums* spectrums) { + auto file = fopen(file_name, "r"); + if (file == nullptr) { + printf("Failed to load SpectralDistribution from file: %s\n", file_name); + return; + } + + fseek(file, 0, SEEK_END); + uint64_t file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + std::vector data(file_size + 1, 0); + fread(data.data(), 1, file_size, file); + fclose(file); + + struct Sample { + float wavelength = 0.0f; + float values[2] = {}; + bool operator<(const Sample& other) const { + return wavelength < other.wavelength; + } + }; + + std::vector samples; + samples.reserve(spectrum::WavelengthCount); + + char* begin = data.data(); + char* end = data.data() + file_size; + while (begin < end) { + auto line_end = begin; + while ((line_end < end) && (*line_end != '\n')) { + ++line_end; + } + *line_end = 0; + + float wavelength = 0.0f; + float v0 = 1.0f; + float v1 = 0.0f; + + int args_read = sscanf(begin, "%f %f %f", &wavelength, &v0, &v1); + if (args_read >= 2) { + samples.emplace_back(Sample{wavelength, {v0, v1}}); + } + + begin = line_end + 1; + } + + std::sort(samples.begin(), samples.end()); + + float scale = 1.0f; + float min_value = samples.front().wavelength; + while (min_value < 100.0f) { + min_value *= 10.0f; + scale *= 10.0f; + } + + for (auto& sample : samples) { + sample.wavelength *= scale; + } + + { + values0.count = 0; + for (const auto& sample : samples) { + if ((sample.wavelength >= spectrum::kShortestWavelength) && (sample.wavelength <= spectrum::kLongestWavelength)) { + values0.entries[values0.count++] = {sample.wavelength, sample.values[0]}; + if (values0.count >= spectrum::kWavelengthCount) { + break; + } + } + } + if constexpr (spectrum::kSpectralRendering == false) { + float3 xyz = values0.integrate_to_xyz(); + values0 = rgb::make_spd(spectrum::xyz_to_rgb(xyz), (cls == Class::Reflectance) ? spectrums->rgb_reflection : spectrums->rgb_illuminant); + } + } + + if (values1 != nullptr) { + for (const auto& sample : samples) { + if ((sample.wavelength >= spectrum::kShortestWavelength) && (sample.wavelength <= spectrum::kLongestWavelength)) { + values1->entries[values1->count++] = {sample.wavelength, sample.values[1]}; + if (values1->count >= spectrum::kWavelengthCount) { + break; + } + } + } + if constexpr (spectrum::kSpectralRendering == false) { + float3 xyz = values1->integrate_to_xyz(); + *values1 = rgb::make_spd(spectrum::xyz_to_rgb(xyz), (cls == Class::Reflectance) ? spectrums->rgb_reflection : spectrums->rgb_illuminant); + } + } +} + +bool SpectralDistribution::valid() const { + for (uint64_t i = 0; i < count; ++i) { + if (valid_value(entries[i].power) == false) { + return false; + } + } + return true; +} +bool SpectralDistribution::is_zero() const { + for (uint64_t i = 0; i < count; ++i) { + if (entries[i].power != 0.0f) { + return false; + } + } + return true; +} + +float3 SpectralDistribution::to_xyz() const { + if constexpr (spectrum::kSpectralRendering) { + return integrate_to_xyz(); + } else { + return spectrum::rgb_to_xyz({entries[0].power, entries[1].power, entries[2].power}); + } +} + +float SpectralDistribution::maximum_power() const { + float result = entries[0].power; + for (uint64_t i = 0; i < count; ++i) { + result = glm::max(result, entries[i].power); + } + return result; +} + +float3 SpectralDistribution::integrate_to_xyz() const { + auto xyz_at = [](float wl) -> float3 { + uint64_t i = static_cast(clamp(wl, spectrum::kShortestWavelength, spectrum::kLongestWavelength) - spectrum::ShortestWavelength); + uint64_t j = min(i + 1llu, spectrum::WavelengthCount - 1); + auto v0 = spectrum::spectral_xyz(i); + auto v1 = spectrum::spectral_xyz(j); + float dw = wl - std::floor(wl); + return lerp(v0, v1, dw); + }; + + auto integrate = [entries = entries, xyz_at](uint64_t index) -> float3 { + float3 result = {}; + + float l0 = entries[index + 0].wavelength; + float l1 = entries[index + 1].wavelength; + float p0 = entries[index + 0].power; + float p1 = entries[index + 1].power; + float begin = l0; + for (;;) { + float end = min(l1, begin + 1.0f); + float t0 = (begin - l0) / (l1 - l0); + float t1 = (end - l0) / (l1 - l0); + float p_begin = lerp(p0, p1, t0); + float p_end = lerp(p0, p1, t1); + + auto v0 = xyz_at(begin) * p_begin; + auto v1 = xyz_at(end) * p_end; + + result += (end - begin) * (v0 + 0.5f * (v1 - v0)); + if (end == l1) { + break; + } + begin = end; + } + return result / spectrum::kYIntegral; + }; + + float3 result = {}; + for (uint64_t i = 0; i + 1 < count; ++i) { + result += integrate(i); + } + return result; +} + +float SpectralDistribution::total_power() const { + if constexpr (spectrum::kSpectralRendering) { + return integrate_to_xyz().y; + } else { + return entries[0].power * 0.2627f + entries[1].power * 0.678f + entries[2].power * 0.0593f; + } +} + +SpectralDistribution SpectralDistribution::from_samples(const float wavelengths[], const float power[], uint64_t count) { + float value = (count > 0) ? wavelengths[0] : 100.0f; + float wavelength_scale = 1.0f; + while (value < 100.0f) { + wavelength_scale *= 10.0f; + value *= 10.0f; + } + + SpectralDistribution result; + result.count = count; + for (uint64_t i = 0; i < count; ++i) { + result.entries[i] = {wavelengths[i] * wavelength_scale, power ? power[i] : 0.0f}; + } + + for (uint64_t i = 0; i < count; ++i) { + for (uint64_t j = i + 1; j < count; ++j) { + if (result.entries[i].wavelength > result.entries[j].wavelength) { + auto t = result.entries[i]; + result.entries[i] = result.entries[j]; + result.entries[j] = t; + } + } + } + + return result; +} + +SpectralDistribution SpectralDistribution::from_samples(const float wavelengths[], const float power[], uint64_t count, Class cls, Spectrums* spectrums) { + auto result = from_samples(wavelengths, power, count); + if constexpr (spectrum::kSpectralRendering == false) { + float3 xyz = result.integrate_to_xyz(); + result = rgb::make_spd(spectrum::xyz_to_rgb(xyz), (cls == Class::Reflectance) ? spectrums->rgb_reflection : spectrums->rgb_illuminant); + } + return result; +} + +SpectralDistribution SpectralDistribution::from_samples(const float2 wavelengths_power[], uint64_t count, Class cls, Spectrums* spectrums) { + float value = (count > 0) ? wavelengths_power[0].x : 100.0f; + float wavelength_scale = 1.0f; + while (value < 100.0f) { + wavelength_scale *= 10.0f; + value *= 10.0f; + } + + SpectralDistribution result; + result.count = count; + for (uint64_t i = 0; i < count; ++i) { + result.entries[i] = {wavelengths_power[i].x * wavelength_scale, wavelengths_power[i].y}; + } + + for (uint64_t i = 0; i < count; ++i) { + for (uint64_t j = i + 1; j < count; ++j) { + if (result.entries[i].wavelength > result.entries[j].wavelength) { + auto t = result.entries[i]; + result.entries[i] = result.entries[j]; + result.entries[j] = t; + } + } + } + + if constexpr (spectrum::kSpectralRendering == false) { + float3 xyz = result.integrate_to_xyz(); + result = rgb::make_spd(spectrum::xyz_to_rgb(xyz), (cls == Class::Reflectance) ? spectrums->rgb_reflection : spectrums->rgb_illuminant); + } + + return result; +} + +namespace rgb { + +constexpr float kRGBLambda[SampleCount] = {380.000000f, 390.967743f, 401.935486f, 412.903229f, 423.870972f, 434.838715f, 445.806458f, 456.774200f, 467.741943f, 478.709686f, + 489.677429f, 500.645172f, 511.612915f, 522.580627f, 533.548340f, 544.516052f, 555.483765f, 566.451477f, 577.419189f, 588.386902f, 599.354614f, 610.322327f, 621.290039f, + 632.257751f, 643.225464f, 654.193176f, 665.160889f, 676.128601f, 687.096313f, 698.064026f, 709.031738f, 720.000000f}; + +constexpr float kRGBRefectionWhite[SampleCount] = {1.0618958571272863e+00f, 1.0615019980348779e+00f, 1.0614335379927147e+00f, 1.0622711654692485e+00f, 1.0622036218416742e+00f, + 1.0625059965187085e+00f, 1.0623938486985884e+00f, 1.0624706448043137e+00f, 1.0625048144827762e+00f, 1.0624366131308856e+00f, 1.0620694238892607e+00f, 1.0613167586932164e+00f, + 1.0610334029377020e+00f, 1.0613868564828413e+00f, 1.0614215366116762e+00f, 1.0620336151299086e+00f, 1.0625497454805051e+00f, 1.0624317487992085e+00f, 1.0625249140554480e+00f, + 1.0624277664486914e+00f, 1.0624749854090769e+00f, 1.0625538581025402e+00f, 1.0625326910104864e+00f, 1.0623922312225325e+00f, 1.0623650980354129e+00f, 1.0625256476715284e+00f, + 1.0612277619533155e+00f, 1.0594262608698046e+00f, 1.0599810758292072e+00f, 1.0602547314449409e+00f, 1.0601263046243634e+00f, 1.0606565756823634e+00f}; + +constexpr float kRGBRefectionCyan[SampleCount] = {1.0414628021426751e+00f, 1.0328661533771188e+00f, 1.0126146228964314e+00f, 1.0350460524836209e+00f, 1.0078661447098567e+00f, + 1.0422280385081280e+00f, 1.0442596738499825e+00f, 1.0535238290294409e+00f, 1.0180776226938120e+00f, 1.0442729908727713e+00f, 1.0529362541920750e+00f, 1.0537034271160244e+00f, + 1.0533901869215969e+00f, 1.0537782700979574e+00f, 1.0527093770467102e+00f, 1.0530449040446797e+00f, 1.0550554640191208e+00f, 1.0553673610724821e+00f, 1.0454306634683976e+00f, + 6.2348950639230805e-01f, 1.8038071613188977e-01f, -7.6303759201984539e-03f, -1.5217847035781367e-04f, -7.5102257347258311e-03f, -2.1708639328491472e-03f, 6.5919466602369636e-04f, + 1.2278815318539780e-02f, -4.4669775637208031e-03f, 1.7119799082865147e-02f, 4.9211089759759801e-03f, 5.8762925143334985e-03f, 2.5259399415550079e-02f}; + +constexpr float kRGBRefectionMagenta[SampleCount] = {9.9422138151236850e-01f, 9.8986937122975682e-01f, 9.8293658286116958e-01f, 9.9627868399859310e-01f, 1.0198955019000133e+00f, + 1.0166395501210359e+00f, 1.0220913178757398e+00f, 9.9651666040682441e-01f, 1.0097766178917882e+00f, 1.0215422470827016e+00f, 6.4031953387790963e-01f, 2.5012379477078184e-03f, + 6.5339939555769944e-03f, 2.8334080462675826e-03f, -5.1209675389074505e-11, -9.0592291646646381e-03f, 3.3936718323331200e-03f, -3.0638741121828406e-03f, 2.2203936168286292e-01f, + 6.3141140024811970e-01f, 9.7480985576500956e-01f, 9.7209562333590571e-01f, 1.0173770302868150e+00f, 9.9875194322734129e-01f, 9.4701725739602238e-01f, 8.5258623154354796e-01f, + 9.4897798581660842e-01f, 9.4751876096521492e-01f, 9.9598944191059791e-01f, 8.6301351503809076e-01f, 8.9150987853523145e-01f, 8.4866492652845082e-01f}; + +constexpr float kRGBRefectionYellow[SampleCount] = {5.5740622924920873e-03f, -4.7982831631446787e-03f, -5.2536564298613798e-03f, -6.4571480044499710e-03f, -5.9693514658007013e-03f, + -2.1836716037686721e-03f, 1.6781120601055327e-02f, 9.6096355429062641e-02f, 2.1217357081986446e-01f, 3.6169133290685068e-01f, 5.3961011543232529e-01f, 7.4408810492171507e-01f, + 9.2209571148394054e-01f, 1.0460304298411225e+00f, 1.0513824989063714e+00f, 1.0511991822135085e+00f, 1.0510530911991052e+00f, 1.0517397230360510e+00f, 1.0516043086790485e+00f, + 1.0511944032061460e+00f, 1.0511590325868068e+00f, 1.0516612465483031e+00f, 1.0514038526836869e+00f, 1.0515941029228475e+00f, 1.0511460436960840e+00f, 1.0515123758830476e+00f, + 1.0508871369510702e+00f, 1.0508923708102380e+00f, 1.0477492815668303e+00f, 1.0493272144017338e+00f, 1.0435963333422726e+00f, 1.0392280772051465e+00f}; + +constexpr float kRGBRefectionRed[SampleCount] = {1.6575604867086180e-01f, 1.1846442802747797e-01f, 1.2408293329637447e-01f, 1.1371272058349924e-01f, 7.8992434518899132e-02f, + 3.2205603593106549e-02f, -1.0798365407877875e-02f, 1.8051975516730392e-02f, 5.3407196598730527e-03f, 1.3654918729501336e-02f, -5.9564213545642841e-03f, -1.8444365067353252e-03f, + -1.0571884361529504e-02f, -2.9375521078000011e-03f, -1.0790476271835936e-02f, -8.0224306697503633e-03f, -2.2669167702495940e-03f, 7.0200240494706634e-03f, + -8.1528469000299308e-03f, 6.0772866969252792e-01f, 9.8831560865432400e-01f, 9.9391691044078823e-01f, 1.0039338994753197e+00f, 9.9234499861167125e-01f, 9.9926530858855522e-01f, + 1.0084621557617270e+00f, 9.8358296827441216e-01f, 1.0085023660099048e+00f, 9.7451138326568698e-01f, 9.8543269570059944e-01f, 9.3495763980962043e-01f, 9.8713907792319400e-01f}; + +constexpr float kRGBRefectionGreen[SampleCount] = {2.6494153587602255e-03f, -5.0175013429732242e-03f, -1.2547236272489583e-02f, -9.4554964308388671e-03f, -1.2526086181600525e-02f, + -7.9170697760437767e-03f, -7.9955735204175690e-03f, -9.3559433444469070e-03f, 6.5468611982999303e-02f, 3.9572875517634137e-01f, 7.5244022299886659e-01f, 9.6376478690218559e-01f, + 9.9854433855162328e-01f, 9.9992977025287921e-01f, 9.9939086751140449e-01f, 9.9994372267071396e-01f, 9.9939121813418674e-01f, 9.9911237310424483e-01f, 9.6019584878271580e-01f, + 6.3186279338432438e-01f, 2.5797401028763473e-01f, 9.4014888527335638e-03f, -3.0798345608649747e-03f, -4.5230367033685034e-03f, -6.8933410388274038e-03f, -9.0352195539015398e-03f, + -8.5913667165340209e-03f, -8.3690869120289398e-03f, -7.8685832338754313e-03f, -8.3657578711085132e-06f, 5.4301225442817177e-03f, -2.7745589759259194e-03f}; + +constexpr float kRGBRefectionBlue[SampleCount] = {9.9209771469720676e-01f, 9.8876426059369127e-01f, 9.9539040744505636e-01f, 9.9529317353008218e-01f, 9.9181447411633950e-01f, + 1.0002584039673432e+00f, 9.9968478437342512e-01f, 9.9988120766657174e-01f, 9.8504012146370434e-01f, 7.9029849053031276e-01f, 5.6082198617463974e-01f, 3.3133458513996528e-01f, + 1.3692410840839175e-01f, 1.8914906559664151e-02f, -5.1129770932550889e-06f, -4.2395493167891873e-04f, -4.1934593101534273e-04f, 1.7473028136486615e-03f, 3.7999160177631316e-03f, + -5.5101474906588642e-04f, -4.3716662898480967e-05f, 7.5874501748732798e-03f, 2.5795650780554021e-02f, 3.8168376532500548e-02f, 4.9489586408030833e-02f, 4.9595992290102905e-02f, + 4.9814819505812249e-02f, 3.9840911064978023e-02f, 3.0501024937233868e-02f, 2.1243054765241080e-02f, 6.9596532104356399e-03f, 4.1733649330980525e-03f}; + +constexpr float kRGBIlluminantWhite[SampleCount] = {1.1565232050369776e+00f, 1.1567225000119139e+00f, 1.1566203150243823e+00f, 1.1555782088080084e+00f, 1.1562175509215700e+00f, + 1.1567674012207332e+00f, 1.1568023194808630e+00f, 1.1567677445485520e+00f, 1.1563563182952830e+00f, 1.1567054702510189e+00f, 1.1565134139372772e+00f, 1.1564336176499312e+00f, + 1.1568023181530034e+00f, 1.1473147688514642e+00f, 1.1339317140561065e+00f, 1.1293876490671435e+00f, 1.1290515328639648e+00f, 1.0504864823782283e+00f, 1.0459696042230884e+00f, + 9.9366687168595691e-01f, 9.5601669265393940e-01f, 9.2467482033511805e-01f, 9.1499944702051761e-01f, 8.9939467658453465e-01f, 8.9542520751331112e-01f, 8.8870566693814745e-01f, + 8.8222843814228114e-01f, 8.7998311373826676e-01f, 8.7635244612244578e-01f, 8.8000368331709111e-01f, 8.8065665428441120e-01f, 8.8304706460276905e-01f}; + +constexpr float kRGBIlluminantCyan[SampleCount] = {1.1334479663682135e+00f, 1.1266762330194116e+00f, 1.1346827504710164e+00f, 1.1357395805744794e+00f, 1.1356371830149636e+00f, + 1.1361152989346193e+00f, 1.1362179057706772e+00f, 1.1364819652587022e+00f, 1.1355107110714324e+00f, 1.1364060941199556e+00f, 1.1360363621722465e+00f, 1.1360122641141395e+00f, + 1.1354266882467030e+00f, 1.1363099407179136e+00f, 1.1355450412632506e+00f, 1.1353732327376378e+00f, 1.1349496420726002e+00f, 1.1111113947168556e+00f, 9.0598740429727143e-01f, + 6.1160780787465330e-01f, 2.9539752170999634e-01f, 9.5954200671150097e-02f, -1.1650792030826267e-02f, -1.2144633073395025e-02f, -1.1148167569748318e-02f, -1.1997606668458151e-02f, + -5.0506855475394852e-03f, -7.9982745819542154e-03f, -9.4722817708236418e-03f, -5.5329541006658815e-03f, -4.5428914028274488e-03f, -1.2541015360921132e-02f}; + +constexpr float kRGBIlluminantMagenta[SampleCount] = {1.0371892935878366e+00f, 1.0587542891035364e+00f, 1.0767271213688903e+00f, 1.0762706844110288e+00f, 1.0795289105258212e+00f, + 1.0743644742950074e+00f, 1.0727028691194342e+00f, 1.0732447452056488e+00f, 1.0823760816041414e+00f, 1.0840545681409282e+00f, 9.5607567526306658e-01f, 5.5197896855064665e-01f, + 8.4191094887247575e-02f, 8.7940070557041006e-05f, -2.3086408335071251e-03f, -1.1248136628651192e-03f, -7.7297612754989586e-11, -2.7270769006770834e-04f, 1.4466473094035592e-02f, + 2.5883116027169478e-01f, 5.2907999827566732e-01f, 9.0966624097105164e-01f, 1.0690571327307956e+00f, 1.0887326064796272e+00f, 1.0637622289511852e+00f, 1.0201812918094260e+00f, + 1.0262196688979945e+00f, 1.0783085560613190e+00f, 9.8333849623218872e-01f, 1.0707246342802621e+00f, 1.0634247770423768e+00f, 1.0150875475729566e+00f}; + +constexpr float kRGBIlluminantYellow[SampleCount] = {2.7756958965811972e-03f, 3.9673820990646612e-03f, -1.4606936788606750e-04f, 3.6198394557748065e-04f, -2.5819258699309733e-04f, + -5.0133191628082274e-05f, -2.4437242866157116e-04f, -7.8061419948038946e-05f, 4.9690301207540921e-02f, 4.8515973574763166e-01f, 1.0295725854360589e+00f, 1.0333210878457741e+00f, + 1.0368102644026933e+00f, 1.0364884018886333e+00f, 1.0365427939411784e+00f, 1.0368595402854539e+00f, 1.0365645405660555e+00f, 1.0363938240707142e+00f, 1.0367205578770746e+00f, + 1.0365239329446050e+00f, 1.0361531226427443e+00f, 1.0348785007827348e+00f, 1.0042729660717318e+00f, 8.4218486432354278e-01f, 7.3759394894801567e-01f, 6.5853154500294642e-01f, + 6.0531682444066282e-01f, 5.9549794132420741e-01f, 5.9419261278443136e-01f, 5.6517682326634266e-01f, 5.6061186014968556e-01f, 5.8228610381018719e-01f}; + +constexpr float kRGBIlluminantRed[SampleCount] = {5.4711187157291841e-02f, 5.5609066498303397e-02f, 6.0755873790918236e-02f, 5.6232948615962369e-02f, 4.6169940535708678e-02f, + 3.8012808167818095e-02f, 2.4424225756670338e-02f, 3.8983580581592181e-03f, -5.6082252172734437e-04f, 9.6493871255194652e-04f, 3.7341198051510371e-04f, -4.3367389093135200e-04f, + -9.3533962256892034e-05f, -1.2354967412842033e-04f, -1.4524548081687461e-04f, -2.0047691915543731e-04f, -4.9938587694693670e-04f, 2.7255083540032476e-02f, + 1.6067405906297061e-01f, 3.5069788873150953e-01f, 5.7357465538418961e-01f, 7.6392091890718949e-01f, 8.9144466740381523e-01f, 9.6394609909574891e-01f, 9.8879464276016282e-01f, + 9.9897449966227203e-01f, 9.8605140403564162e-01f, 9.9532502805345202e-01f, 9.7433478377305371e-01f, 9.9134364616871407e-01f, 9.8866287772174755e-01f, 9.9713856089735531e-01f}; + +constexpr float kRGBIlluminantGreen[SampleCount] = {2.5168388755514630e-02f, 3.9427438169423720e-02f, 6.2059571596425793e-03f, 7.1120859807429554e-03f, 2.1760044649139429e-04f, + 7.3271839984290210e-12, -2.1623066217181700e-02f, 1.5670209409407512e-02f, 2.8019603188636222e-03f, 3.2494773799897647e-01f, 1.0164917292316602e+00f, 1.0329476657890369e+00f, + 1.0321586962991549e+00f, 1.0358667411948619e+00f, 1.0151235476834941e+00f, 1.0338076690093119e+00f, 1.0371372378155013e+00f, 1.0361377027692558e+00f, 1.0229822432557210e+00f, + 9.6910327335652324e-01f, -5.1785923899878572e-03f, 1.1131261971061429e-03f, 6.6675503033011771e-03f, 7.4024315686001957e-04f, 2.1591567633473925e-02f, 5.1481620056217231e-03f, + 1.4561928645728216e-03f, 1.6414511045291513e-04f, -6.4630764968453287e-03f, 1.0250854718507939e-02f, 4.2387394733956134e-02f, 2.1252716926861620e-02f}; + +constexpr float kRGBIlluminantBlue[SampleCount] = {1.0570490759328752e+00f, 1.0538466912851301e+00f, 1.0550494258140670e+00f, 1.0530407754701832e+00f, 1.0579930596460185e+00f, + 1.0578439494812371e+00f, 1.0583132387180239e+00f, 1.0579712943137616e+00f, 1.0561884233578465e+00f, 1.0571399285426490e+00f, 1.0425795187752152e+00f, 3.2603084374056102e-01f, + -1.9255628442412243e-03f, -1.2959221137046478e-03f, -1.4357356276938696e-03f, -1.2963697250337886e-03f, -1.9227081162373899e-03f, 1.2621152526221778e-03f, + -1.6095249003578276e-03f, -1.3029983817879568e-03f, -1.7666600873954916e-03f, -1.2325281140280050e-03f, 1.0316809673254932e-02f, 3.1284512648354357e-02f, 8.8773879881746481e-02f, + 1.3873621740236541e-01f, 1.5535067531939065e-01f, 1.4878477178237029e-01f, 1.6624255403475907e-01f, 1.6997613960634927e-01f, 1.5769743995852967e-01f, 1.9069090525482305e-01f}; + +inline const float* power(uint32_t cls, uint32_t clr) { + constexpr const float* ptr[2][7] = { + {kRGBRefectionRed, kRGBRefectionGreen, kRGBRefectionBlue, kRGBRefectionYellow, kRGBRefectionMagenta, kRGBRefectionCyan, kRGBRefectionWhite}, + {kRGBIlluminantRed, kRGBIlluminantGreen, kRGBIlluminantBlue, kRGBIlluminantYellow, kRGBIlluminantMagenta, kRGBIlluminantCyan, kRGBIlluminantWhite}, + }; + return ptr[cls][clr]; +} + +void init_spectrums(Spectrums& spectrums) { + using SPD = SpectralDistribution; + for (uint32_t i = 0; i < SampleCount; ++i) { + for (uint32_t c = 0; c < Color::Count; ++c) { + spectrums.rgb_reflection.values[c][i] = 0.941f * power(0u, c)[i]; + spectrums.rgb_illuminant.values[c][i] = 0.86445f * power(1u, c)[i]; + } + } +} + +} // namespace rgb + +} // namespace etx diff --git a/sources/etx/render/host/tasks.cxx b/sources/etx/render/host/tasks.cxx new file mode 100644 index 0000000..75cff95 --- /dev/null +++ b/sources/etx/render/host/tasks.cxx @@ -0,0 +1,119 @@ +#include +#include + +#include + +#include + +namespace etx { + +struct TaskWrapper : public enki::ITaskSet { + Task* task = nullptr; + + TaskWrapper(Task* t, uint32_t range) + : enki::ITaskSet(range) + , task(t) { + } + + void ExecuteRange(enki::TaskSetPartition range_, uint32_t threadnum_) override { + task->execute_range(range_.start, range_.end, threadnum_); + } +}; + +struct FunctionTask : public Task { + using F = std::function; + F func; + + FunctionTask(F f) + : func(f) { + } + + void execute_range(uint32_t begin, uint32_t end, uint32_t thread_id) override { + func(begin, end, thread_id); + } +}; + +struct TaskSchedulerImpl { + enki::TaskScheduler scheduler; + ObjectIndexPool task_pool; + + TaskSchedulerImpl() { + task_pool.init(1024u); + scheduler.Initialize(enki::GetNumHardwareThreads() + 1u); + } + + ~TaskSchedulerImpl() { + ETX_ASSERT(task_pool.count_alive() == 0); + task_pool.cleanup(); + } +}; + +TaskScheduler::TaskScheduler() { + ETX_PIMPL_INIT(TaskScheduler); +} + +TaskScheduler::~TaskScheduler() { + ETX_PIMPL_CLEANUP(TaskScheduler); +} + +uint32_t TaskScheduler::max_thread_count() { + return _private->scheduler.GetConfig().numTaskThreadsToCreate + 1; +} + +Task::Handle TaskScheduler::schedule(Task* t, uint32_t range) { + auto handle = _private->task_pool.alloc(t, range); + auto& task_wrapper = _private->task_pool.get(handle); + _private->scheduler.AddTaskSetToPipe(&task_wrapper); + return {handle}; +} + +void TaskScheduler::execute(Task* t, uint32_t range) { + wait(schedule(t, range)); +} + +void TaskScheduler::execute(uint32_t range, std::function func) { + FunctionTask t(func); + wait(schedule(&t, range)); +} + +bool TaskScheduler::completed(Task::Handle handle) { + if (handle.internal == Task::InvalidHandle) { + return true; + } + + auto& task_wrapper = _private->task_pool.get(handle.internal); + return task_wrapper.GetIsComplete(); +} + +void TaskScheduler::wait(Task::Handle handle) { + if (handle.internal == Task::InvalidHandle) { + return; + } + + auto& task_wrapper = _private->task_pool.get(handle.internal); + _private->scheduler.WaitforTaskSet(&task_wrapper); + _private->task_pool.free(handle.internal); +} + +void TaskScheduler::restart(Task::Handle handle, uint32_t new_rage) { + if (handle.internal == Task::InvalidHandle) { + return; + } + + auto& task_wrapper = _private->task_pool.get(handle.internal); + if (task_wrapper.GetIsComplete() == false) { + _private->scheduler.WaitforTaskSet(&task_wrapper); + } + task_wrapper.m_SetSize = new_rage; + _private->scheduler.AddTaskSetToPipe(&task_wrapper); +} + +void TaskScheduler::restart(Task::Handle handle) { + if (handle.internal == Task::InvalidHandle) { + return; + } + auto& task_wrapper = _private->task_pool.get(handle.internal); + restart(handle, task_wrapper.m_SetSize); +} + +} // namespace etx diff --git a/sources/etx/render/host/tasks.hxx b/sources/etx/render/host/tasks.hxx new file mode 100644 index 0000000..bf52edb --- /dev/null +++ b/sources/etx/render/host/tasks.hxx @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include + +namespace etx { + +struct Task { + enum : uint32_t { + InvalidHandle = ~0u, + }; + + struct Handle { + uint32_t internal = InvalidHandle; + }; + + virtual ~Task() = default; + + virtual void execute_range(uint32_t begin, uint32_t end, uint32_t thread_id) = 0; +}; + +struct TaskScheduler { + TaskScheduler(); + ~TaskScheduler(); + + uint32_t max_thread_count(); + + Task::Handle schedule(Task*, uint32_t range); + + void execute(Task*, uint32_t range); + void execute(uint32_t range, std::function func); + + bool completed(Task::Handle); + void wait(Task::Handle); + + void restart(Task::Handle); + void restart(Task::Handle, uint32_t new_rage); + + private: + ETX_DECLARE_PIMPL(TaskScheduler, 256); +}; + +} // namespace etx diff --git a/sources/etx/render/shared/base.hxx b/sources/etx/render/shared/base.hxx new file mode 100644 index 0000000..62119fe --- /dev/null +++ b/sources/etx/render/shared/base.hxx @@ -0,0 +1,79 @@ +#pragma once + +#include + +#if (ETX_NVCC_COMPILER) +#define ETX_GPU_CODE inline __device__ +#define ETX_GPU_DATA __device__ +#define ETX_INIT_WITH(S) +#else +#define ETX_GPU_CODE inline +#define ETX_GPU_DATA +#define ETX_INIT_WITH(S) = S +#endif + +#define ETX_EMPTY_INIT ETX_INIT_WITH({}) + +#define ETX_FORCE_VALIDATION 0 + +#define ETX_RENDER_BASE_INCLUDED 1 +#include +#undef ETX_RENDER_BASE_INCLUDED + +#if (ETX_DEBUG || ETX_FORCE_VALIDATION) + +#define ETX_VALIDATE(VALUE) \ + do { \ + if (valid_value((VALUE)) == false) { \ + printf("Validation failed [%s, %u]:\n ", __FILE__, __LINE__); \ + print_value(#VALUE, "invalid value", VALUE); \ + ETX_DEBUG_BREAK(); \ + } \ + } while (0) + +#else + +#define ETX_VALIDATE(VALUE) \ + do { \ + } while (0) + +#endif + +namespace etx { + +template +struct alignas(16) ArrayView { + T* a ETX_EMPTY_INIT; + uint64_t count ETX_EMPTY_INIT; + + ArrayView() = default; + + ETX_GPU_CODE ArrayView(T* p, uint64_t c) + : a(p) + , count(c) { + } + + ETX_GPU_CODE const T& operator[](uint64_t i) const { + ETX_ASSERT(count > 0); + ETX_ASSERT(a != nullptr); + ETX_ASSERT(i < count); + return a[i]; + } + + ETX_GPU_CODE T& operator[](uint64_t i) { + ETX_ASSERT(count > 0); + ETX_ASSERT(a != nullptr); + ETX_ASSERT(i < count); + return a[i]; + } +}; + +ETX_GPU_CODE void print_value(const char* name, const char* tag, float t) { + printf("%s : %s %f\n", name, tag, t); +} + +ETX_GPU_CODE void print_value(const char* name, const char* tag, const float3& v) { + printf("%s : %s (%f, %f, %f)\n", name, tag, v.x, v.y, v.z); +} + +} // namespace etx diff --git a/sources/etx/render/shared/bsdf.hxx b/sources/etx/render/shared/bsdf.hxx new file mode 100644 index 0000000..3b49b0c --- /dev/null +++ b/sources/etx/render/shared/bsdf.hxx @@ -0,0 +1,406 @@ +#pragma once + +#include + +namespace etx { + +enum class PathSource : uint32_t { + Undefined, + Camera, + Light, +}; + +struct BSDFData : public Vertex { + ETX_GPU_CODE BSDFData(SpectralQuery spect, uint32_t medium, const Material& m, PathSource tm, const Vertex& av, const float3& awi, const float3& awo) + : Vertex(av) + , material(m) + , mode(tm) + , spectrum_sample(spect) + , medium_index(medium) + , w_i(awi) + , w_o(awo) { + } + + ETX_GPU_CODE BSDFData swap_directions() const { + BSDFData result = *this; + result.w_i = -w_o; + result.w_o = -w_i; + return result; + } + + ETX_GPU_CODE bool check_side(Frame& f_out) const { + float n_dot_i = dot(nrm, w_i); + + if (material.double_sided()) { + float scale = (n_dot_i >= 0.0f ? -1.0f : +1.0f); + f_out = {tan * scale, btn * scale, nrm * scale}; + return true; + } + + f_out = {tan, btn, nrm}; + return (n_dot_i < 0.0f); + } + + ETX_GPU_CODE bool get_normal_frame(Frame& f_out) const { + bool entering_material = dot(nrm, w_i) < 0.0f; + if (entering_material) { + f_out = {tan, btn, nrm}; + } else { + f_out = {-tan, -btn, -nrm}; + } + return entering_material; + } + + const Material& material; + PathSource mode = PathSource::Undefined; + SpectralQuery spectrum_sample; + uint32_t medium_index = kInvalidIndex; + float3 geo_n = {}; + float3 w_i = {}; + float3 w_o = {}; +}; + +struct BSDFEval { + BSDFEval() = default; + + ETX_GPU_CODE BSDFEval(float wl, float power) + : weight(wl, power) + , bsdf(wl, power) { + } + + SpectralResponse func = {}; + SpectralResponse bsdf = {}; + SpectralResponse weight = {}; + float pdf = 0.0f; + float eta = 1.0f; + + ETX_GPU_CODE bool valid() const { + return (pdf > 0.0f) && bsdf.valid(); + } +}; + +struct BSDFSample { + enum Properties : uint32_t { + Diffuse = 1u << 0u, + DeltaReflection = 1u << 1u, + DeltaTransmission = 1u << 2u, + MediumChanged = 1u << 3u, + }; + + SpectralResponse weight = {}; + float3 w_o = {}; + float pdf = 0.0f; + float eta = 1.0f; + uint32_t properties = 0u; + uint32_t medium_index = kInvalidIndex; + + BSDFSample() = default; + + ETX_GPU_CODE BSDFSample(const SpectralResponse& a_weight) + : weight(a_weight) { + } + + ETX_GPU_CODE BSDFSample(const float3& a_w_o, const SpectralResponse& a_weight, float a_pdf, float a_eta, uint32_t props) + : weight(a_weight) + , w_o(a_w_o) + , pdf(a_pdf) + , eta(a_eta) + , properties(props) { + } + + ETX_GPU_CODE BSDFSample(const float3& w, const BSDFEval& eval, uint32_t props) + : weight(eval.weight) + , w_o(w) + , pdf(eval.pdf) + , eta(eval.eta) + , properties(props) { + } + + ETX_GPU_CODE bool valid() const { + return (pdf > 0.0f) && weight.valid(); + } + + ETX_GPU_CODE bool is_diffuse() const { + return (properties & Diffuse) != 0; + } + + ETX_GPU_CODE bool is_delta() const { + return ((properties & DeltaReflection) != 0) || ((properties & DeltaTransmission) != 0); + } +}; + +namespace bsdf { + +struct LocalFrame : public Frame { + ETX_GPU_CODE LocalFrame(const Frame& f) + : Frame(f) { + _to_local = { + {tan.x, btn.x, nrm.x}, + {tan.y, btn.y, nrm.y}, + {tan.z, btn.z, nrm.z}, + }; + _from_local = transpose(_to_local); + } + + ETX_GPU_CODE float3 to_local(const float3& v) const { + return _to_local * v; + } + + ETX_GPU_CODE float3 from_local(const float3& v) const { + return _from_local * v; + } + + private: + float3x3 _to_local = {}; + float3x3 _from_local = {}; +}; + +struct NormalDistribution { + struct Eval { + float ndf = 0.0f; + float g1_in = 0.0f; + float visibility = 0.0f; + float pdf = 0.0f; + }; + + ETX_GPU_CODE NormalDistribution(const Frame& f, const float2& alpha) + : _frame(f) + , _alpha(alpha) { + } + + [[nodiscard]] ETX_GPU_CODE float3 sample(Sampler& smp, const float3& in_w_i) const { + auto w_i = _frame.to_local(-in_w_i); + auto v_h = normalize(float3{_alpha.x * w_i.x, _alpha.y * w_i.y, w_i.z}); + + float v_h_len = v_h.x * v_h.x + v_h.y * v_h.y; + float3 u = v_h_len > 0.0f ? float3{-v_h.y, v_h.x, 0.0f} / sqrtf(v_h_len) : float3{1.0f, 0.0f, 0.0f}; + float3 v = cross(v_h, u); + + float r = sqrtf(smp.next()); + float phi = kDoublePi * smp.next(); + float t1 = r * cosf(phi); + float t2 = r * sinf(phi); + float s = 0.5f * (1.0f + v_h.z); + t2 = (1.0f - s) * sqrtf(1.0f - t1 * t1) + s * t2; + float3 n_h = t1 * u + t2 * v + sqrtf(max(0.0f, 1.0f - t1 * t1 - t2 * t2)) * v_h; + float3 local_m = normalize(float3{_alpha.x * n_h.x, _alpha.y * n_h.y, n_h.z}); + + return _frame.from_local(local_m); + } + + [[nodiscard]] ETX_GPU_CODE Eval evaluate(const float3& in_m, const float3& in_w_i, const float3& in_w_o) const { + auto local_w_i = _frame.to_local(-in_w_i); + if (local_w_i.z <= kEpsilon) { + return {}; + } + + auto local_w_o = _frame.to_local(in_w_o); + auto local_m = _frame.to_local(in_m); + + Eval result = {}; + result.visibility = visibility_term_local(_alpha, local_m, local_w_i, local_w_o); + ETX_VALIDATE(result.visibility); + result.ndf = normal_distribution_local(_alpha, local_m); + ETX_VALIDATE(result.ndf); + result.g1_in = visibility_local(_alpha, local_m, local_w_i); + ETX_VALIDATE(result.g1_in); + { + float s = fabsf(dot(local_w_i, local_m)) / local_w_i.z; + ETX_VALIDATE(s); + result.pdf = result.ndf * result.g1_in * s; + ETX_VALIDATE(result.pdf); + } + return result; + } + + [[nodiscard]] ETX_GPU_CODE float pdf(const float3& in_m, const float3& in_w_i, const float3& in_w_o) const { + auto local_w_i = _frame.to_local(-in_w_i); + if (local_w_i.z <= kEpsilon) { + return 0.0f; + } + + auto local_m = _frame.to_local(in_m); + + float g1 = visibility_local(_alpha, local_m, local_w_i); + ETX_VALIDATE(g1); + float d = normal_distribution_local(_alpha, local_m); + ETX_VALIDATE(d); + float s = fabsf(dot(local_w_i, local_m)) / local_w_i.z; + ETX_VALIDATE(s); + return g1 * d * s; + } + + private: + ETX_GPU_CODE float lambda_local(const float2& alpha, const float3& w) const { + float a = sqrtf(alpha.x * alpha.y); + float n_dot_w = fabsf(w.z); + return 0.5f * (sqrtf(a + (1.0f - a) * n_dot_w * n_dot_w) / n_dot_w - 1.0f); + } + + // G1 + ETX_GPU_CODE float visibility_local(const float2& alpha, const float3& m, const float3& w) const { + float xy_alpha_2 = sqr(alpha.x * w.x) + sqr(alpha.y * w.y); + if (xy_alpha_2 == 0.0f) { + return 1.0f; + } + + if (dot(w, m) * w.z <= 0.0f) { + return 0.0f; + } + + float tan_theta_alpha_2 = xy_alpha_2 / sqr(w.z); + float result = 2.0f / (1.0f + sqrtf(1.0f + tan_theta_alpha_2)); + ETX_VALIDATE(result); + return result; + } + + // G + ETX_GPU_CODE float visibility_term_local(const float2& alpha, const float3& m, const float3& w_i, const float3& w_o) const { + return visibility_local(alpha, m, w_i) * visibility_local(alpha, m, w_o); + } + + // D + ETX_GPU_CODE float normal_distribution_local(const float2& alpha, const float3& m) const { + float alpha_uv = alpha.x * alpha.y; + float result = 1.0f / (kPi * alpha_uv * sqr(sqr(m.x / alpha.x) + sqr(m.y / alpha.y) + sqr(m.z))); + ETX_VALIDATE(result); + return result; + } + + private: + LocalFrame _frame; + float2 _alpha = {}; +}; + +ETX_GPU_CODE float fix_shading_normal(const float3& n_g, const float3& n_s, const float3& w_i, const float3& w_o) { + float w_i_g = dot(w_i, n_g); + float w_i_s = dot(w_i, n_s); + float w_o_g = dot(w_o, n_g); + float w_o_s = dot(w_o, n_s); + return (w_o_s * w_i_g == 0.0f) ? 0.0f : fabsf((w_o_g * w_i_s) / (w_o_s * w_i_g)); +} + +} // namespace bsdf + +namespace fresnel { + +ETX_GPU_CODE auto reflectance(float ext_ior, float cos_theta_i, float int_ior, float cos_theta_j) { + struct result { + float rs, rp; + }; + auto ni = ext_ior; + auto nj = int_ior; + auto rs = (ni * cos_theta_i - nj * cos_theta_j) / (ni * cos_theta_i + nj * cos_theta_j); + auto rp = (nj * cos_theta_i - ni * cos_theta_j) / (nj * cos_theta_i + ni * cos_theta_j); + return result{rs, rp}; +} + +ETX_GPU_CODE auto transmittance(float ext_ior, float cos_theta_i, float int_ior, float cos_theta_j) { + struct result { + float ts, tp; + }; + auto ni = ext_ior; + auto nj = int_ior; + auto ts = (2.0f * ni * cos_theta_i) / (ni * cos_theta_i + nj * cos_theta_j); + auto tp = (2.0f * ni * cos_theta_i) / (ni * cos_theta_j + nj * cos_theta_i); + return result{ts, tp}; +} + +ETX_GPU_CODE SpectralResponse dielectric(SpectralQuery spect, const float cos_theta_i, float ext_ior, float int_ior) { + SpectralResponse result = {spect.wavelength, 1.0f}; + float eta = (ext_ior / int_ior); + float sin_theta_o_squared = (eta * eta) * (1.0f - cos_theta_i * cos_theta_i); + if (sin_theta_o_squared <= 1.0) { + float cos_theta_o = sqrtf(clamp(1.0f - sin_theta_o_squared, 0.0f, 1.0f)); + auto rsrp = reflectance(ext_ior, cos_theta_i, int_ior, cos_theta_o); + result = SpectralResponse{spect.wavelength, 0.5f * (rsrp.rs * rsrp.rs + rsrp.rp * rsrp.rp)}; + } + return result; +} + +ETX_GPU_CODE SpectralResponse dielectric(SpectralQuery spect, const float3& i, const float3& m, float ext_ior, float int_ior) { + return dielectric(spect, fabsf(dot(i, m)), ext_ior, int_ior); +} + +ETX_GPU_CODE SpectralResponse dielectric_thinfilm(SpectralQuery spect, const float cos_theta_0, float ext_ior, float film_ior, float int_ior, float thickness) { + float eta_01 = (ext_ior / film_ior); + float sin_theta_1_squared = sqr(eta_01) * (1.0f - cos_theta_0 * cos_theta_0); + if (sin_theta_1_squared >= 1.0f) { + return {spect.wavelength, 1.0f}; + } + + float cos_theta_1 = std::sqrt(1.0f - sin_theta_1_squared); + + float eta_12 = (film_ior / int_ior); + float sin_theta_2_squared = sqr(eta_12) * (1.0f - cos_theta_1 * cos_theta_1); + if (sin_theta_2_squared >= 1.0f) { + return {spect.wavelength, 1.0f}; + } + + float cos_theta_2 = std::sqrt(1.0f - sin_theta_2_squared); + + float delta_10 = film_ior > ext_ior ? 0.0f : kPi; + float delta_21 = int_ior > film_ior ? 0.0f : kPi; + float phase_shift = delta_10 + delta_21; + + SpectralResponse phi = {spect.wavelength, kDoublePi * 2.0f * thickness * cos_theta_1 + phase_shift * film_ior}; + if constexpr (spectrum::kSpectralRendering) { + phi /= spect.wavelength; + } else { + phi /= {spect.wavelength, {690.0f, 550.0f, 430.0f}}; + } + + auto r10 = reflectance(film_ior, cos_theta_1, ext_ior, cos_theta_0); + auto r12 = reflectance(film_ior, cos_theta_1, int_ior, cos_theta_2); + auto t01 = transmittance(ext_ior, cos_theta_0, film_ior, cos_theta_1); + auto t12 = transmittance(film_ior, cos_theta_1, int_ior, cos_theta_2); + + auto alpha_p = r10.rp * r12.rp; + auto beta_p = t01.tp * t12.tp; + auto tp = (beta_p * beta_p) / ((alpha_p * alpha_p) - 2.0f * alpha_p * cos(phi) + 1.0f); + + auto alpha_s = r10.rs * r12.rs; + auto beta_s = t01.ts * t12.ts; + auto ts = (beta_s * beta_s) / ((alpha_s * alpha_s) - 2.0f * alpha_s * cos(phi) + 1.0f); + auto ratio = (int_ior * cos_theta_2) / (ext_ior * cos_theta_0); + + return 1.0f - ratio * 0.5f * (tp + ts); +} + +ETX_GPU_CODE SpectralResponse dielectric_thinfilm(SpectralQuery spect, const float3& i, const float3& m, float ext_ior, float film_ior, float int_ior, float thickness) { + return dielectric_thinfilm(spect, fabsf(dot(i, m)), ext_ior, film_ior, int_ior, thickness); +} + +ETX_GPU_CODE SpectralResponse conductor(SpectralQuery spect, const float3& i, const float3& m, const RefractiveIndex::Sample& sample_out, + const RefractiveIndex::Sample& sample_in) { + ETX_ASSERT(spect.wavelength == sample_in.wavelength); + ETX_ASSERT(spect.wavelength == sample_out.wavelength); + + float cos_theta = fabsf(dot(i, m)); + float cos_theta_2 = cos_theta * cos_theta; + float sin_theta_2 = clamp(1.0f - cos_theta_2, 0.0f, 1.0f); + + bool entring_material = (cos_theta > 0.0f); + RefractiveIndex::Sample ior_sample = (entring_material) ? (sample_in / sample_out) : (sample_out / sample_in); + + SpectralResponse eta_2 = ior_sample.eta * ior_sample.eta; + SpectralResponse k_2 = ior_sample.k * ior_sample.k; + SpectralResponse t0 = eta_2 - k_2 - sin_theta_2; + SpectralResponse a2plusb2 = sqrt(t0 * t0 + 4.0f * eta_2 * k_2); + + SpectralResponse t1 = a2plusb2 + cos_theta_2; + SpectralResponse t2 = 2.0f * sqrt(0.5f * (a2plusb2 + t0)) * fabsf(cos_theta); + SpectralResponse Rs = abs((t1 - t2) / (t1 + t2)); + ETX_VALIDATE(Rs); + + SpectralResponse t3 = cos_theta_2 * a2plusb2 + sin_theta_2 * sin_theta_2; + SpectralResponse t4 = t2 * sin_theta_2; + SpectralResponse Rp = Rs * ((t3 + t4).is_zero() ? SpectralResponse(spect.wavelength, 1.0f) : (t3 - t4) / (t3 + t4)); + ETX_VALIDATE(Rp); + + return 0.5f * (Rp + Rs); +} + +} // namespace fresnel + +} // namespace etx diff --git a/sources/etx/render/shared/bsdf_conductor.hxx b/sources/etx/render/shared/bsdf_conductor.hxx new file mode 100644 index 0000000..c9244af --- /dev/null +++ b/sources/etx/render/shared/bsdf_conductor.hxx @@ -0,0 +1,129 @@ +namespace etx { +namespace DeltaConductorBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + SpectralResponse f = fresnel::conductor(data.spectrum_sample, data.w_i, frame.nrm, data.material.ext_ior(data.spectrum_sample), data.material.int_ior(data.spectrum_sample)); + auto specular = bsdf::apply_image(data.spectrum_sample, data.material.specular(data.spectrum_sample), data.material.specular_image_index, data.tex, scene); + + BSDFSample result; + result.w_o = normalize(reflect(data.w_i, frame.nrm)); + result.weight = specular * f; + ETX_VALIDATE(result.weight); + result.pdf = 1.0f; + result.properties = BSDFSample::DeltaReflection; + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + return {data.spectrum_sample.wavelength, 0.0f}; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + return 0.0f; +} + +} // namespace DeltaConductorBSDF + +namespace ConductorBSDF { + +ETX_GPU_CODE BSDFSample sample(Sampler& smp, const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaConductorBSDF::sample(smp, data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto m = ggx.sample(smp, data.w_i); + + BSDFData eval_data = data; + eval_data.w_o = normalize(reflect(data.w_i, m)); + return {eval_data.w_o, evaluate(eval_data, scene), 0}; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaConductorBSDF::evaluate(data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float n_dot_i = -dot(frame.nrm, data.w_i); + float n_dot_o = dot(frame.nrm, data.w_o); + if ((n_dot_o <= kEpsilon) || (n_dot_i <= kEpsilon)) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + if (m_dot_o <= kEpsilon) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto eval = ggx.evaluate(m, data.w_i, data.w_o); + + SpectralResponse f = fresnel::conductor(data.spectrum_sample, data.w_i, frame.nrm, data.material.ext_ior(data.spectrum_sample), data.material.int_ior(data.spectrum_sample)); + + auto specular = bsdf::apply_image(data.spectrum_sample, data.material.specular(data.spectrum_sample), data.material.specular_image_index, data.tex, scene); + + BSDFEval result; + result.func = specular * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i * n_dot_o)); + ETX_VALIDATE(result.func); + + result.bsdf = specular * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i)); + ETX_VALIDATE(result.bsdf); + + result.pdf = eval.pdf / (4.0f * m_dot_o); + ETX_VALIDATE(result.pdf); + + if (result.pdf > 0.0f) { + result.weight = result.bsdf / result.pdf; + ETX_VALIDATE(result.weight); + } + + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaConductorBSDF::pdf(data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + if (m_dot_o <= kEpsilon) { + return 0.0f; + } + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + return ggx.pdf(m, data.w_i, data.w_o) / (4.0f * m_dot_o); +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.specular_image_index == kInvalidIndex) { + return false; + } + const auto& img = scene.images[material.specular_image_index]; + return (img.options & Image::HasAlphaChannel) && (img.evaluate(tex).w < smp.next()); +} + +} // namespace ConductorBSDF + +} // namespace etx diff --git a/sources/etx/render/shared/bsdf_dielectric.hxx b/sources/etx/render/shared/bsdf_dielectric.hxx new file mode 100644 index 0000000..713baed --- /dev/null +++ b/sources/etx/render/shared/bsdf_dielectric.hxx @@ -0,0 +1,322 @@ +namespace etx { + +namespace DielectricBSDF { + +namespace DeltaDielectricBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + bool entering_material = data.get_normal_frame(frame); + + auto eta_i = (entering_material ? data.material.ext_ior : data.material.int_ior)(data.spectrum_sample).eta.monochromatic(); + auto eta_o = (entering_material ? data.material.int_ior : data.material.ext_ior)(data.spectrum_sample).eta.monochromatic(); + float eta = (eta_i / eta_o); + + SpectralResponse fr; + if (data.material.thinfilm.image_index != kInvalidIndex) { + auto t = scene.images[data.material.thinfilm.image_index].evaluate(data.tex); + float thickness = lerp(data.material.thinfilm.min_thickness, data.material.thinfilm.max_thickness, t.x); + auto ior_eta = scene.spectrums->thinfilm(data.spectrum_sample).eta.monochromatic(); + fr = fresnel::dielectric_thinfilm(data.spectrum_sample, data.w_i, frame.nrm, eta_i, ior_eta, eta_o, thickness); + } else { + fr = fresnel::dielectric(data.spectrum_sample, data.w_i, frame.nrm, eta_i, eta_o); + } + float f = fr.monochromatic(); + + BSDFSample result; + if (smp.next() <= f) { + result.w_o = normalize(reflect(data.w_i, frame.nrm)); + result.pdf = f; + ETX_VALIDATE(result.pdf); + result.weight = (fr / f) * data.material.specular(data.spectrum_sample); + ETX_VALIDATE(result.weight); + result.properties = BSDFSample::DeltaReflection; + result.medium_index = entering_material ? data.material.ext_medium : data.material.int_medium; + } else { + float cos_theta_i = dot(frame.nrm, -data.w_i); + float sin_theta_o_squared = (eta * eta) * (1.0f - cos_theta_i * cos_theta_i); + float cos_theta_o = sqrtf(clamp(1.0f - sin_theta_o_squared, 0.0f, 1.0f)); + result.w_o = normalize(eta * data.w_i + frame.nrm * (eta * cos_theta_i - cos_theta_o)); + result.pdf = 1.0f - f; + ETX_VALIDATE(result.pdf); + + result.weight = bsdf::apply_image(data.spectrum_sample, data.material.transmittance(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + ETX_VALIDATE(result.weight); + + result.weight *= (1.0f - fr) / (1.0f - f); + ETX_VALIDATE(result.weight); + + result.properties = BSDFSample::DeltaTransmission | BSDFSample::MediumChanged; + result.medium_index = entering_material ? data.material.int_medium : data.material.ext_medium; + if (data.mode == PathSource::Camera) { + result.weight *= eta * eta; + } + } + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + return {data.spectrum_sample.wavelength, 0.0f}; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + return 0.0f; +} + +} // namespace DeltaDielectricBSDF + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaDielectricBSDF::sample(smp, data, scene); + } + + Frame frame; + bool entering_material = data.get_normal_frame(frame); + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto m = ggx.sample(smp, data.w_i); + + auto eta_i = (entering_material ? data.material.ext_ior : data.material.int_ior)(data.spectrum_sample).eta.monochromatic(); + auto eta_o = (entering_material ? data.material.int_ior : data.material.ext_ior)(data.spectrum_sample).eta.monochromatic(); + float eta = (eta_i / eta_o); + + SpectralResponse fr; + if (data.material.thinfilm.image_index != kInvalidIndex) { + auto t = scene.images[data.material.thinfilm.image_index].evaluate(data.tex); + float thickness = lerp(data.material.thinfilm.min_thickness, data.material.thinfilm.max_thickness, t.x); + auto ior_eta = scene.spectrums->thinfilm(data.spectrum_sample).eta.monochromatic(); + fr = fresnel::dielectric_thinfilm(data.spectrum_sample, data.w_i, m, eta_i, ior_eta, eta_o, thickness); + } else { + fr = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_i, eta_o); + } + + bool reflection = smp.next() <= fr.monochromatic(); + BSDFData eval_data = data; + if (reflection) { + eval_data.w_o = reflect(data.w_i, m); + if (dot(eval_data.w_o, frame.nrm) <= kEpsilon) { + // if (dot(data.w_i, frame.nrm) * dot(eval_data.w_o, frame.nrm) >= 0.0f) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + eval_data.w_o = normalize(eval_data.w_o); + } else { + float cos_theta_i = dot(m, -data.w_i); + float sin_theta_o_squared = (eta * eta) * (1.0f - cos_theta_i * cos_theta_i); + float cos_theta_o = sqrtf(clamp(1.0f - sin_theta_o_squared, 0.0f, 1.0f)); + eval_data.w_o = eta * data.w_i + m * (eta * cos_theta_i - cos_theta_o); + if (dot(eval_data.w_o, frame.nrm) >= -kEpsilon) { + // if (dot(data.w_i, frame.nrm) * dot(eval_data.w_o, frame.nrm) < 0.0f) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + eval_data.w_o = normalize(eval_data.w_o); + } + + BSDFSample result = {eval_data.w_o, evaluate(eval_data, scene), reflection ? 0u : BSDFSample::MediumChanged}; + if (entering_material) { + result.medium_index = reflection ? data.material.ext_medium : data.material.int_medium; + } else { + result.medium_index = reflection ? data.material.int_medium : data.material.ext_medium; + } + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaDielectricBSDF::evaluate(data, scene); + } + + Frame frame; + bool entering_material = data.get_normal_frame(frame); + + float n_dot_i = -dot(frame.nrm, data.w_i); + float n_dot_o = dot(frame.nrm, data.w_o); + if ((n_dot_o == 0.0f) || (n_dot_i == 0.0f)) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + bool reflection = n_dot_o * n_dot_i >= 0.0f; + auto eta_i = (entering_material ? data.material.ext_ior : data.material.int_ior)(data.spectrum_sample).eta.monochromatic(); + auto eta_o = (entering_material ? data.material.int_ior : data.material.ext_ior)(data.spectrum_sample).eta.monochromatic(); + + float3 m = normalize(reflection ? (data.w_o - data.w_i) : (data.w_i * eta_i - data.w_o * eta_o)); + m *= (dot(frame.nrm, m) < 0.0f) ? -1.0f : 1.0f; + + float m_dot_i = -dot(m, data.w_i); + float m_dot_o = dot(m, data.w_o); + + SpectralResponse fr; + if (data.material.thinfilm.image_index != kInvalidIndex) { + auto t = scene.images[data.material.thinfilm.image_index].evaluate(data.tex); + float thickness = lerp(data.material.thinfilm.min_thickness, data.material.thinfilm.max_thickness, t.x); + auto ior_eta = scene.spectrums->thinfilm(data.spectrum_sample).eta.monochromatic(); + fr = fresnel::dielectric_thinfilm(data.spectrum_sample, data.w_i, m, eta_i, ior_eta, eta_o, thickness); + } else { + fr = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_i, eta_o); + } + float f = fr.monochromatic(); + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto eval = ggx.evaluate(m, data.w_i, data.w_o); + if (eval.pdf == 0.0f) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + BSDFEval result = {}; + if (reflection) { + auto specular = data.material.specular(data.spectrum_sample); + + result.func = specular * fr * (eval.ndf * eval.visibility / (4.0f * n_dot_i * n_dot_o)); + ETX_VALIDATE(result.func); + + result.bsdf = specular * fr * (eval.ndf * eval.visibility / (4.0f * n_dot_i)); + ETX_VALIDATE(result.bsdf); + + result.weight = specular * (fr / f) * (eval.visibility / eval.g1_in); + ETX_VALIDATE(result.weight); + + float j = 1.0f / fabsf(4.0f * m_dot_o); + result.pdf = eval.pdf * f * j; + ETX_VALIDATE(result.pdf); + } else { + auto transmittance = bsdf::apply_image(data.spectrum_sample, data.material.transmittance(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + result.func = abs(transmittance * (1.0f - fr) * (m_dot_i * m_dot_o * sqr(eta_o) * eval.visibility * eval.ndf) / (n_dot_i * n_dot_o * sqr(m_dot_i * eta_i + m_dot_o * eta_o))); + ETX_VALIDATE(result.func); + + result.bsdf = abs(transmittance * (1.0f - fr) * (m_dot_i * m_dot_o * sqr(eta_o) * eval.visibility * eval.ndf) / (n_dot_i * sqr(m_dot_i * eta_i + m_dot_o * eta_o))); + ETX_VALIDATE(result.bsdf); + + result.weight = transmittance * ((1.0f - fr) / (1.0f - f)) * (eval.visibility / eval.g1_in); + ETX_VALIDATE(result.weight); + + auto j = sqr(eta_o) * fabsf(m_dot_o) / sqr(m_dot_i * eta_i + m_dot_o * eta_o); + result.pdf = eval.pdf * (1.0f - f) * j; + ETX_VALIDATE(result.pdf); + + result.eta = eta_i / eta_o; + + if (data.mode == PathSource::Camera) { + result.bsdf *= result.eta * result.eta; + result.weight *= result.eta * result.eta; + } + } + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + if (data.material.is_delta()) { + return DeltaDielectricBSDF::pdf(data, scene); + } + + Frame frame; + bool entering_material = data.get_normal_frame(frame); + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + + float n_dot_i = -dot(frame.nrm, data.w_i); + float n_dot_o = dot(frame.nrm, data.w_o); + bool reflection = n_dot_o * n_dot_i >= 0.0f; + auto eta_i = (entering_material ? data.material.ext_ior : data.material.int_ior)(data.spectrum_sample).eta.monochromatic(); + auto eta_o = (entering_material ? data.material.int_ior : data.material.ext_ior)(data.spectrum_sample).eta.monochromatic(); + + float3 m = normalize(reflection ? (data.w_o - data.w_i) : (data.w_i * eta_i - data.w_o * eta_o)); + m *= (dot(frame.nrm, m) < 0.0f) ? -1.0f : 1.0f; + + float m_dot_i = -dot(m, data.w_i); + float m_dot_o = dot(m, data.w_o); + + SpectralResponse fr; + if (data.material.thinfilm.image_index != kInvalidIndex) { + auto t = scene.images[data.material.thinfilm.image_index].evaluate(data.tex); + float thickness = lerp(data.material.thinfilm.min_thickness, data.material.thinfilm.max_thickness, t.x); + auto ior_eta = scene.spectrums->thinfilm(data.spectrum_sample).eta.monochromatic(); + fr = fresnel::dielectric_thinfilm(data.spectrum_sample, data.w_i, m, eta_i, ior_eta, eta_o, thickness); + } else { + fr = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_i, eta_o); + } + float f = fr.monochromatic(); + + float pdf = ggx.pdf(m, data.w_i, data.w_o); + + if (reflection) { + float j = 1.0f / fabsf(4.0f * m_dot_o); + pdf *= f * j; + } else { + auto j = sqr(eta_o) * fabsf(m_dot_o) / sqr(m_dot_i * eta_i + m_dot_o * eta_o); + pdf *= (1.0f - f) * j; + } + + ETX_VALIDATE(pdf); + return pdf; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && (img.evaluate(tex).w < smp.next()); +} + +} // namespace DielectricBSDF + +namespace ThinfilmBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + bool entering_material = data.get_normal_frame(frame); + + auto ext_ior = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto int_ior = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + + float thickness = spectrum::kLongestWavelength; + if (data.material.thinfilm.image_index != kInvalidIndex) { + const auto& img = scene.images[data.material.thinfilm.image_index]; + auto t = img.evaluate(data.tex); + thickness = lerp(data.material.thinfilm.min_thickness, data.material.thinfilm.max_thickness, t.x); + } + + SpectralResponse fr = fresnel::dielectric_thinfilm(data.spectrum_sample, data.w_i, frame.nrm, ext_ior, int_ior, ext_ior, thickness); + float f = fr.monochromatic(); + + BSDFSample result = {}; + if (smp.next() <= f) { + result.w_o = reflect(data.w_i, frame.nrm); + if (dot(data.w_i, frame.nrm) * dot(result.w_o, frame.nrm) >= 0.0f) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + result.w_o = normalize(result.w_o); + result.pdf = f; + result.weight = data.material.specular(data.spectrum_sample); + result.weight *= (fr / f); + result.properties = BSDFSample::DeltaReflection; + result.medium_index = entering_material ? data.material.ext_medium : data.material.int_medium; + } else { + result.w_o = data.w_i; + result.pdf = 1.0f - f; + result.weight = bsdf::apply_image(data.spectrum_sample, data.material.transmittance(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + result.weight *= (1.0f - fr) / (1.0f - f); + result.properties = BSDFSample::DeltaTransmission | BSDFSample::MediumChanged; + result.medium_index = entering_material ? data.material.int_medium : data.material.ext_medium; + } + + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + return {data.spectrum_sample.wavelength, 0.0f}; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + return 0.0f; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && img.evaluate(tex).w < smp.next(); +} + +} // namespace ThinfilmBSDF +} // namespace etx diff --git a/sources/etx/render/shared/bsdf_generic.hxx b/sources/etx/render/shared/bsdf_generic.hxx new file mode 100644 index 0000000..6f31996 --- /dev/null +++ b/sources/etx/render/shared/bsdf_generic.hxx @@ -0,0 +1,135 @@ +namespace etx { +namespace GenericBSDF { + +ETX_GPU_CODE float2 remap_alpha(float2 a) { + return sqr(max(a, float2{1.0f / 16.0f, 1.0f / 16.0f})); +} + +ETX_GPU_CODE float remap_metalness(float m) { + return sqrtf(m); +} + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {}; + } + + float2 alpha = data.material.roughness; + float metalness = data.material.metalness; + if (data.material.metal_roughness_image_index != kInvalidIndex) { + auto value = scene.images[data.material.metal_roughness_image_index].evaluate(data.tex); + alpha *= value.y; + metalness *= value.z; + } + alpha = remap_alpha(alpha); + metalness = remap_metalness(metalness); + + auto ggx = bsdf::NormalDistribution(frame, alpha); + auto m = ggx.sample(smp, data.w_i); + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + float t = fabsf(dot(data.w_i, m)); + SpectralResponse f0 = SpectralResponse{data.spectrum_sample.wavelength, 0.04f} * (1.0f - metalness) + diffuse * metalness; + SpectralResponse f = f0 + (1.0f - f0) * std::pow(1.0f - t, 5.0f); + + uint32_t properties = 0; + BSDFData eval_data = data; + if (smp.next() <= f.monochromatic()) { + eval_data.w_o = normalize(reflect(data.w_i, m)); + } else { + eval_data.w_o = sample_cosine_distribution(smp.next(), smp.next(), frame.nrm, 1.0f); + properties = BSDFSample::Diffuse; + } + + return {eval_data.w_o, evaluate(eval_data, scene), properties}; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + float n_dot_i = -dot(frame.nrm, data.w_i); + if ((n_dot_o <= kEpsilon) || (n_dot_i <= kEpsilon)) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float2 alpha = data.material.roughness; + float metalness = data.material.metalness; + if (data.material.metal_roughness_image_index != kInvalidIndex) { + auto value = scene.images[data.material.metal_roughness_image_index].evaluate(data.tex); + alpha *= value.y; + metalness *= value.z; + } + alpha = remap_alpha(alpha); + metalness = remap_metalness(metalness); + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + auto specular = bsdf::apply_image(data.spectrum_sample, data.material.specular(data.spectrum_sample), data.material.specular_image_index, data.tex, scene); + + float t = fabsf(dot(data.w_i, m)); + SpectralResponse f0 = SpectralResponse{data.spectrum_sample.wavelength, 0.04f * (1.0f - metalness)} + diffuse * metalness; + SpectralResponse f = f0 + (1.0f - f0) * std::pow(1.0f - t, 5.0f); + + auto ggx = bsdf::NormalDistribution(frame, alpha); + auto eval = ggx.evaluate(m, data.w_i, data.w_o); + float j = 1.0f / (4.0f * m_dot_o); + + BSDFEval result; + result.func = diffuse * (kInvPi * (1.0f - metalness)) + specular * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i * n_dot_o)); + result.bsdf = diffuse * (kInvPi * (1.0f - metalness) * n_dot_o) + specular * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i)); + result.pdf = kInvPi * n_dot_o * (1.0f - f.monochromatic()) + eval.pdf * j * f.monochromatic(); + result.weight = result.bsdf / result.pdf; + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + if (n_dot_o <= kEpsilon) { + return 0.0f; + } + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + float2 alpha = data.material.roughness; + float metalness = data.material.metalness; + if (data.material.metal_roughness_image_index != kInvalidIndex) { + auto value = scene.images[data.material.metal_roughness_image_index].evaluate(data.tex); + alpha *= value.y; + metalness *= value.z; + } + alpha = remap_alpha(alpha); + metalness = remap_metalness(metalness); + + float t = fabsf(dot(data.w_i, m)); + SpectralResponse f0 = SpectralResponse{data.spectrum_sample.wavelength, 0.04f} * (1.0f - metalness) + diffuse * metalness; + SpectralResponse f = f0 + (1.0f - f0) * std::pow(1.0f - t, 5.0f); + + auto ggx = bsdf::NormalDistribution(frame, alpha); + float j = 1.0f / (4.0f * m_dot_o); + float result = kInvPi * n_dot_o * (1.0f - f.monochromatic()) + ggx.pdf(m, data.w_i, data.w_o) * j * f.monochromatic(); + ETX_VALIDATE(result); + return result; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + return false; +} + +} // namespace GenericBSDF +} // namespace etx diff --git a/sources/etx/render/shared/bsdf_plastic.hxx b/sources/etx/render/shared/bsdf_plastic.hxx new file mode 100644 index 0000000..b541c5d --- /dev/null +++ b/sources/etx/render/shared/bsdf_plastic.hxx @@ -0,0 +1,303 @@ +namespace etx { + +namespace PlasticBSDF { + +ETX_GPU_CODE BSDFSample sample_delta(Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, frame.nrm, eta_e, eta_i); + + bool reflection = smp.next() <= f.monochromatic(); + + BSDFSample result; + result.properties = BSDFSample::Diffuse; + if (reflection) { + result.w_o = normalize(reflect(data.w_i, frame.nrm)); + result.properties = result.properties | BSDFSample::DeltaReflection; + } else { + result.w_o = sample_cosine_distribution(smp.next(), smp.next(), frame.nrm, 1.0f); + } + + float n_dot_o = dot(frame.nrm, result.w_o); + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + if (reflection) { + auto bsdf = diffuse * (kInvPi * n_dot_o * (1.0f - f)) + data.material.specular(data.spectrum_sample) * f; + result.pdf = kInvPi * n_dot_o * (1.0f - f.monochromatic()) + f.monochromatic(); + result.weight = bsdf / result.pdf; + } else { + result.pdf = kInvPi * n_dot_o; + result.weight = diffuse; + } + + return result; +} + +ETX_GPU_CODE BSDFEval evaluate_delta(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + if (n_dot_o <= kEpsilon) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float3 m = normalize(data.w_o - data.w_i); + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + BSDFEval result; + result.func = diffuse * (kInvPi * (1.0f - f.monochromatic())); + ETX_VALIDATE(result.func); + result.bsdf = diffuse * (kInvPi * n_dot_o * (1.0f - f.monochromatic())); + ETX_VALIDATE(result.bsdf); + result.weight = diffuse; + ETX_VALIDATE(result.weight); + result.pdf = kInvPi * n_dot_o * (1.0f - f.monochromatic()); + ETX_VALIDATE(result.pdf); + return result; +} + +ETX_GPU_CODE float pdf_delta(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + if (n_dot_o <= kEpsilon) { + return 0.0f; + } + + float3 m = normalize(data.w_o - data.w_i); + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + return kInvPi * n_dot_o * (1.0f - f.monochromatic()); +} + +ETX_GPU_CODE BSDFSample sample(Sampler& smp, const BSDFData& data, const Scene& scene) { + if (dot(data.material.roughness, float2{0.5f, 0.5f}) <= kDeltaAlphaTreshold) { + return sample_delta(smp, data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto m = ggx.sample(smp, data.w_i); + + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + uint32_t properties = 0; + BSDFData eval_data = data; + if (smp.next() <= f.monochromatic()) { + eval_data.w_o = normalize(reflect(data.w_i, m)); + } else { + eval_data.w_o = sample_cosine_distribution(smp.next(), smp.next(), frame.nrm, 1.0f); + properties = BSDFSample::Diffuse; + } + + return {eval_data.w_o, evaluate(eval_data, scene), properties}; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + if (dot(data.material.roughness, float2{0.5f, 0.5f}) <= kDeltaAlphaTreshold) { + return evaluate_delta(data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + float n_dot_i = -dot(frame.nrm, data.w_i); + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + + if ((n_dot_o <= kEpsilon) || (n_dot_i <= kEpsilon) || (m_dot_o <= kEpsilon)) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + auto eval = ggx.evaluate(m, data.w_i, data.w_o); + float j = 1.0f / (4.0f * m_dot_o); + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + BSDFEval result; + result.func = diffuse * (kInvPi * (1.0f - f)) + data.material.specular(data.spectrum_sample) * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i * n_dot_o)); + ETX_VALIDATE(result.func); + result.bsdf = diffuse * (kInvPi * n_dot_o * (1.0f - f)) + data.material.specular(data.spectrum_sample) * (f * eval.ndf * eval.visibility / (4.0f * n_dot_i)); + ETX_VALIDATE(result.bsdf); + result.pdf = kInvPi * n_dot_o * (1.0f - f.monochromatic()) + eval.pdf * j * f.monochromatic(); + ETX_VALIDATE(result.pdf); + result.weight = result.bsdf / result.pdf; + ETX_VALIDATE(result.weight); + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + if (dot(data.material.roughness, float2{0.5f, 0.5f}) <= kDeltaAlphaTreshold) { + return pdf_delta(data, scene); + } + + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + float n_dot_o = dot(frame.nrm, data.w_o); + + if ((n_dot_o <= kEpsilon) || (m_dot_o <= kEpsilon)) { + return 0.0f; + } + + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + auto ggx = bsdf::NormalDistribution(frame, data.material.roughness); + + float j = 1.0f / (4.0f * m_dot_o); + float result = kInvPi * n_dot_o * (1.0f - f.monochromatic()) + ggx.pdf(m, data.w_i, data.w_o) * j * f.monochromatic(); + ETX_VALIDATE(result); + return result; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && img.evaluate(tex).w < smp.next(); +} + +} // namespace PlasticBSDF + +namespace CoatingBSDF { + +ETX_GPU_CODE float2 remap_alpha(float2 a) { + return sqr(max(a, float2{1.0f / 16.0f, 1.0f / 16.0f})); +} + +ETX_GPU_CODE BSDFSample sample(Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + uint32_t properties = 0; + BSDFData eval_data = data; + if (smp.next() <= 0.5f) { + auto ggx = bsdf::NormalDistribution(frame, remap_alpha(data.material.roughness)); + auto m = ggx.sample(smp, data.w_i); + eval_data.w_o = normalize(reflect(data.w_i, m)); + } else { + eval_data.w_o = sample_cosine_distribution(smp.next(), smp.next(), frame.nrm, 1.0f); + properties = BSDFSample::Diffuse; + } + + return {eval_data.w_o, evaluate(eval_data, scene), properties}; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + auto pow5 = [](float value) { + return sqr(value) * sqr(value) * fabsf(value); + }; + + float n_dot_o = dot(frame.nrm, data.w_o); + float n_dot_i = -dot(frame.nrm, data.w_i); + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + + if ((n_dot_o <= kEpsilon) || (n_dot_i <= kEpsilon) || (m_dot_o <= kEpsilon)) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + auto eta_e = data.material.ext_ior(data.spectrum_sample).eta.monochromatic(); + auto eta_i = data.material.int_ior(data.spectrum_sample).eta.monochromatic(); + auto f = fresnel::dielectric(data.spectrum_sample, data.w_i, m, eta_e, eta_i); + + auto ggx = bsdf::NormalDistribution(frame, remap_alpha(data.material.roughness)); + auto eval = ggx.evaluate(m, data.w_i, data.w_o); + + auto specular_value = bsdf::apply_image(data.spectrum_sample, data.material.specular(data.spectrum_sample), data.material.specular_image_index, data.tex, scene); + auto diffuse_value = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + auto fresnel = specular_value + f * (1.0f - specular_value); + + auto diffuse_factor = (28.f / (23.f * kPi)) * (1.0 - specular_value) * (1.0f - pow5(1.0f - 0.5f * n_dot_i)) * (1.0f - pow5(1.0f - 0.5f * n_dot_o)); + auto specular = fresnel * eval.ndf / (4.0f * m_dot_o * m_dot_o); + + BSDFEval result; + result.func = diffuse_value * diffuse_factor + specular; + ETX_VALIDATE(result.func); + result.bsdf = diffuse_value * diffuse_factor * n_dot_o + specular * n_dot_o; + ETX_VALIDATE(result.bsdf); + result.pdf = 0.5f * (kInvPi * n_dot_o + eval.pdf / (4.0f * m_dot_o)); + ETX_VALIDATE(result.pdf); + result.weight = result.bsdf / result.pdf; + ETX_VALIDATE(result.weight); + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + + float3 m = normalize(data.w_o - data.w_i); + float m_dot_o = dot(m, data.w_o); + float n_dot_o = dot(frame.nrm, data.w_o); + + if ((n_dot_o <= kEpsilon) || (m_dot_o <= kEpsilon)) { + return 0.0f; + } + + auto ggx = bsdf::NormalDistribution(frame, remap_alpha(data.material.roughness)); + float result = 0.5f * (kInvPi * n_dot_o + ggx.pdf(m, data.w_i, data.w_o) / (4.0f * m_dot_o)); + ETX_VALIDATE(result); + return result; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && img.evaluate(tex).w < smp.next(); +} +} // namespace CoatingBSDF + +} // namespace etx diff --git a/sources/etx/render/shared/bsdf_various.hxx b/sources/etx/render/shared/bsdf_various.hxx new file mode 100644 index 0000000..c3e97f7 --- /dev/null +++ b/sources/etx/render/shared/bsdf_various.hxx @@ -0,0 +1,161 @@ +namespace etx { +namespace DiffuseBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + BSDFData eval_data = data; + eval_data.w_o = sample_cosine_distribution(smp.next(), smp.next(), frame.nrm, 1.0f); + return {eval_data.w_o, evaluate(eval_data, scene), BSDFSample::Diffuse}; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + float n_dot_o = dot(frame.nrm, data.w_o); + if (n_dot_o <= kEpsilon) { + return {data.spectrum_sample.wavelength, 0.0f}; + } + + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + + BSDFEval result; + result.func = diffuse * kInvPi; + result.bsdf = diffuse * (kInvPi * n_dot_o); + result.weight = diffuse; + result.pdf = kInvPi * n_dot_o; + ETX_VALIDATE(result.pdf); + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return 0.0f; + } + float n_dot_o = dot(frame.nrm, data.w_o); + if (n_dot_o <= kEpsilon) { + return 0.0f; + } + float result = kInvPi * n_dot_o; + ETX_VALIDATE(result); + return result; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && img.evaluate(tex).w < smp.next(); +} + +} // namespace DiffuseBSDF + +namespace TranslucentBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + bool entering_material = dot(data.nrm, data.w_i) < 0.0f; + float3 n = entering_material ? -data.nrm : data.nrm; + + BSDFData eval_data = data; + eval_data.w_o = sample_cosine_distribution(smp.next(), smp.next(), n, 1.0f); + + BSDFSample result = {eval_data.w_o, evaluate(eval_data, scene), BSDFSample::Diffuse | BSDFSample::MediumChanged}; + result.medium_index = entering_material ? data.material.int_medium : data.material.ext_medium; + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + auto diffuse = bsdf::apply_image(data.spectrum_sample, data.material.diffuse(data.spectrum_sample), data.material.diffuse_image_index, data.tex, scene); + auto n_dot_o = fabsf(dot(data.nrm, data.w_o)); + + BSDFEval result; + result.func = diffuse * kInvPi; + result.bsdf = diffuse * (kInvPi * n_dot_o); + result.weight = diffuse; + result.pdf = kInvPi * n_dot_o; + return result; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + auto n_dot_o = fabsf(dot(data.nrm, data.w_o)); + return kInvPi * n_dot_o; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + if (material.diffuse_image_index == kInvalidIndex) { + return false; + } + + const auto& img = scene.images[material.diffuse_image_index]; + return (img.options & Image::HasAlphaChannel) && img.evaluate(tex).w < smp.next(); +} + +} // namespace TranslucentBSDF + +namespace MirrorBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + Frame frame; + if (data.check_side(frame) == false) { + return {{data.spectrum_sample.wavelength, 0.0f}}; + } + + BSDFSample result; + result.w_o = normalize(reflect(data.w_i, frame.nrm)); + result.weight = bsdf::apply_image(data.spectrum_sample, data.material.specular(data.spectrum_sample), data.material.specular_image_index, data.tex, scene); + result.pdf = 1.0f; + result.properties = BSDFSample::DeltaReflection; + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + return {data.spectrum_sample.wavelength, 0.0f}; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + return 0.0f; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + return false; +} + +} // namespace MirrorBSDF + +namespace BoundaryBSDF { + +ETX_GPU_CODE BSDFSample sample(struct Sampler& smp, const BSDFData& data, const Scene& scene) { + bool entering_material = dot(data.nrm, data.w_i) < 0.0f; + + BSDFSample result; + result.w_o = data.w_i; + result.pdf = 1.0f; + result.weight = {data.spectrum_sample.wavelength, 1.0f}; + result.properties = BSDFSample::MediumChanged; + result.medium_index = entering_material ? data.material.int_medium : data.material.ext_medium; + return result; +} + +ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const Scene& scene) { + return {data.spectrum_sample.wavelength, 0.0f}; +} + +ETX_GPU_CODE float pdf(const BSDFData& data, const Scene& scene) { + return 0.0f; +} + +ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const Scene& scene, struct Sampler& smp) { + return false; +} + +} // namespace BoundaryBSDF +} // namespace etx \ No newline at end of file diff --git a/sources/etx/render/shared/camera.hxx b/sources/etx/render/shared/camera.hxx new file mode 100644 index 0000000..9946013 --- /dev/null +++ b/sources/etx/render/shared/camera.hxx @@ -0,0 +1,42 @@ +#pragma once + +#include + +namespace etx { + +struct alignas(16) Camera { + float4x4 view_proj ETX_EMPTY_INIT; + + float3 position ETX_EMPTY_INIT; + float tan_half_fov ETX_EMPTY_INIT; + + float3 side ETX_EMPTY_INIT; + float aspect ETX_EMPTY_INIT; + + float3 up ETX_EMPTY_INIT; + float area ETX_EMPTY_INIT; + + float3 direction ETX_EMPTY_INIT; + float lens_radius ETX_EMPTY_INIT; + + float focal_distance ETX_EMPTY_INIT; + float image_plane ETX_EMPTY_INIT; + float2 image_size ETX_EMPTY_INIT; +}; + +struct CameraSample { + float3 position ETX_EMPTY_INIT; + float3 normal ETX_EMPTY_INIT; + float3 direction ETX_EMPTY_INIT; + float2 uv ETX_EMPTY_INIT; + float weight ETX_EMPTY_INIT; + float pdf_dir ETX_EMPTY_INIT; + float pdf_area ETX_EMPTY_INIT; + float pdf_dir_out ETX_EMPTY_INIT; + + ETX_GPU_CODE bool valid() const { + return (pdf_dir > 0.0f) && (weight > 0.0f); + } +}; + +} // namespace etx diff --git a/sources/etx/render/shared/distribution.hxx b/sources/etx/render/shared/distribution.hxx new file mode 100644 index 0000000..e65da78 --- /dev/null +++ b/sources/etx/render/shared/distribution.hxx @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace etx { + +struct alignas(16) Distribution { + struct Entry { + float value = 0.0f; + float pdf = 0.0f; + float cdf = 0.0f; + }; + Entry* values ETX_EMPTY_INIT; + uint32_t size ETX_EMPTY_INIT; + float total_weight ETX_EMPTY_INIT; + + ETX_GPU_CODE uint32_t sample(float rnd, float& pdf) const { + auto index = find(rnd); + pdf = values[index].pdf; + return index; + } + + ETX_GPU_CODE float pdf(float value, uint32_t& index) const { + index = min(static_cast(value * float(size) + 0.5f), size - 1u); + return values[index].pdf; + } + + ETX_GPU_CODE uint32_t find(float rnd) const { + uint32_t b = 0; + uint32_t e = size; + do { + uint32_t m = b + (e - b) / 2; + if (values[m].cdf >= rnd) { + e = m; + } else { + b = m; + } + } while ((e - b) > 1); + return b; + } +}; + +} // namespace etx \ No newline at end of file diff --git a/sources/etx/render/shared/emitter.hxx b/sources/etx/render/shared/emitter.hxx new file mode 100644 index 0000000..4ce159e --- /dev/null +++ b/sources/etx/render/shared/emitter.hxx @@ -0,0 +1,77 @@ +#pragma once + +#include + +namespace etx { + +struct alignas(16) Emitter { + enum class Class : uint32_t { + Area, + Environment, + Directional, + Undefined = kInvalidIndex, + }; + + enum class Direction : uint32_t { + Single, + TwoSided, + Omni, + }; + + SpectralDistribution emission = {}; + Class cls = Class::Undefined; + Direction emission_direction = Direction::Single; + uint32_t triangle_index = kInvalidIndex; + uint32_t medium_index = kInvalidIndex; + uint32_t image_index = kInvalidIndex; + float3 direction = {}; + float collimation = 1.0f; + float angular_size = 0.0f; + float equivalent_disk_size = 0.0f; + float angular_size_cosine = 1.0f; + float weight = 0.0f; + + Emitter() = default; + + Emitter(Class c) + : cls(c) { + } + + ETX_GPU_CODE bool is_distant() const { + return (cls == Class::Environment) || (cls == Class::Directional); + } + + ETX_GPU_CODE bool is_local() const { + return (cls == Class::Area); + } + + ETX_GPU_CODE bool is_delta() const { + return (cls == Class::Directional); + } +}; + +struct alignas(16) EmitterSample { + SpectralResponse value = {}; + + float3 barycentric = {}; + float pdf_sample = 0.0f; + + float3 origin = {}; + float pdf_area = 0.0f; + + float3 normal = {}; + float pdf_dir = 0.0f; + + float3 direction = {}; + float pdf_dir_out = 0.0f; + + float2 image_uv = {}; + uint32_t emitter_index = kInvalidIndex; + uint32_t triangle_index = kInvalidIndex; + uint32_t medium_index = kInvalidIndex; + + bool is_delta = false; + bool is_distant = false; +}; + +} // namespace etx diff --git a/sources/etx/render/shared/image.hxx b/sources/etx/render/shared/image.hxx new file mode 100644 index 0000000..2646355 --- /dev/null +++ b/sources/etx/render/shared/image.hxx @@ -0,0 +1,152 @@ +#pragma once + +#include +#include + +namespace etx { + +struct Image { + enum class Format : uint32_t { + Undefined, + RGBA32F, + RGBA8, + }; + + enum : uint32_t { + Regular = 0u, + BuildSamplingTable = 1u << 0u, + RepeatU = 1u << 1u, + RepeatV = 1u << 2u, + Linear = 1u << 3u, + HasAlphaChannel = 1u << 4u, + UniformSamplingTable = 1u << 5u, + }; + + struct Gather { + float4 p00 = {}; + float4 p01 = {}; + float4 p10 = {}; + float4 p11 = {}; + uint32_t row_0 = 0; + uint32_t row_1 = 0; + }; + + float4* pixels = nullptr; + Distribution* x_distributions = nullptr; + Distribution y_distribution = {}; + float2 fsize = {}; + uint2 isize = {}; + float normalization = 0.0f; + uint32_t options = 0; + uint32_t pad[2] = {}; + + ETX_GPU_CODE Gather gather(const float2& in_uv) const { + float2 uv = in_uv * fsize; + auto x0 = tex_coord_u(uv.x, fsize.x); + auto y0 = tex_coord_v(uv.y, fsize.y); + float dx = x0 - floorf(x0); + float dy = y0 - floorf(y0); + + uint32_t row_0 = clamp(static_cast(y0), 0u, isize.x - 1u); + uint32_t row_1 = clamp(row_0 + 1u, 0u, isize.x - 1u); + uint32_t col_0 = clamp(static_cast(x0), 0u, isize.x - 1u); + uint32_t col_1 = clamp(col_0 + 1u, 0u, isize.x - 1u); + + const auto& p00 = pixel(col_0, row_0) * (1.0f - dx) * (1.0f - dy); + const auto& p01 = pixel(col_1, row_0) * (dx) * (1.0f - dy); + const auto& p10 = pixel(col_0, row_1) * (1.0f - dx) * (dy); + const auto& p11 = pixel(col_1, row_1) * (dx) * (dy); + + return {p00, p01, p10, p11, row_0, row_1}; + } + + ETX_GPU_CODE float4 evaluate(const float2& in_uv) const { + auto g = gather(in_uv); + return g.p00 + g.p01 + g.p10 + g.p11; + } + + ETX_GPU_CODE float pdf(const float2& in_uv) const { + auto g = gather(in_uv); + auto t = luminance(to_float3(g.p00 + g.p01)) * (options & UniformSamplingTable ? 1.0f : sin(kPi * (float(g.row_0) + 0.5f) / fsize.y)); + auto b = luminance(to_float3(g.p10 + g.p11)) * (options & UniformSamplingTable ? 1.0f : sin(kPi * (float(g.row_1) + 0.5f) / fsize.y)); + return (t + b) / normalization; + } + + ETX_GPU_CODE float4 pixel(uint32_t x, uint32_t y) const { + int32_t i = min(x + y * isize.x, isize.x * isize.y - 1u); + return pixels[i]; + } + + ETX_GPU_CODE float3 evaluate_normal(const float2& uv, float scale) const { + float4 value = evaluate(uv); + return { + scale * (value.x * 2.0f - 1.0f), + scale * (value.y * 2.0f - 1.0f), + scale * (value.z * 2.0f - 1.0f) + (1.0f - scale), + }; + } + + ETX_GPU_CODE float2 sample(float xi0, float xi1, float& image_pdf, uint2& location) const { + float y_pdf = 0.0f; + location.y = y_distribution.sample(xi1, y_pdf); + + float x_pdf = 0.0f; + const auto& x_distribution = x_distributions[location.y]; + location.x = x_distribution.sample(xi0, x_pdf); + + auto x0 = x_distribution.values[location.x]; + auto x1 = x_distribution.values[min(location.x + 1u, x_distribution.size)]; + float dx = (xi0 - x0.cdf); + if (x1.cdf - x0.cdf > 0.0f) { + dx /= (x1.cdf - x0.cdf); + } + + auto y0 = y_distribution.values[location.y]; + auto y1 = y_distribution.values[min(location.y + 1u, y_distribution.size)]; + float dy = (xi1 - y0.cdf); + if (y1.cdf - y0.cdf > 0.0f) { + dy /= (y1.cdf - y0.cdf); + } + + float2 uv = { + (float(location.x) + dx) / fsize.x, + (float(location.y) + dy) / fsize.y, + }; + + image_pdf = pdf(uv); + return uv; + } + + ETX_GPU_CODE float tex_coord_repeat(float u, float size) const { + auto x = fmodf(u, size); + return x < 0.0f ? (x + size) : x; + } + + ETX_GPU_CODE float tex_coord_clamp(float u, float size) const { + return clamp(u, 0.0f, nextafterf(size, 0.0f)); + } + + ETX_GPU_CODE float tex_coord_u(float u, float size) const { + return (options & RepeatU) ? tex_coord_repeat(u, size) : tex_coord_clamp(u, size); + } + + ETX_GPU_CODE float tex_coord_v(float u, float size) const { + return (options & RepeatV) ? tex_coord_repeat(u, size) : tex_coord_clamp(u, size); + } + + ETX_GPU_CODE float4 read(const float2& uv) const { + auto x0 = tex_coord_u(uv.x - 0.0f, fsize.x); + auto x1 = tex_coord_u(uv.x + 1.0f, fsize.x); + auto y0 = tex_coord_v(uv.y - 0.0f, fsize.y); + auto y1 = tex_coord_v(uv.y + 1.0f, fsize.y); + float dx = x0 - floorf(x0); + float dy = y0 - floorf(y0); + const auto& p00 = pixel(uint32_t(x0), uint32_t(y0)) * (1.0f - dx) * (1.0f - dy); + const auto& p01 = pixel(uint32_t(x1), uint32_t(y0)) * (dx) * (1.0f - dy); + const auto& p10 = pixel(uint32_t(x0), uint32_t(y1)) * (1.0f - dx) * (dy); + const auto& p11 = pixel(uint32_t(x1), uint32_t(y1)) * (dx) * (dy); + return p00 + p01 + p10 + p11; + } +}; + +} // namespace etx \ No newline at end of file diff --git a/sources/etx/render/shared/material.hxx b/sources/etx/render/shared/material.hxx new file mode 100644 index 0000000..ffcaee8 --- /dev/null +++ b/sources/etx/render/shared/material.hxx @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +namespace etx { + +struct alignas(16) Material { + enum class Class : uint32_t { + Diffuse, + Plastic, + Conductor, + Dielectric, + Thinfilm, + Translucent, + Mirror, + Boundary, + Generic, + Coating, + + Count, + Undefined = kInvalidIndex, + }; + + enum : uint32_t { + DoubleSided = 1u << 0u, + }; + + struct alignas(16) Thinfilm { + uint32_t image_index = kInvalidIndex; + float min_thickness = 0.0f; + float max_thickness = 0.0f; + float pad; + }; + + Class cls = Class::Undefined; + uint32_t diffuse_image_index = kInvalidIndex; + uint32_t specular_image_index = kInvalidIndex; + uint32_t normal_image_index = kInvalidIndex; + + uint32_t emissive_image_index = kInvalidIndex; + uint32_t metal_roughness_image_index = kInvalidIndex; + uint32_t int_medium = kInvalidIndex; + uint32_t ext_medium = kInvalidIndex; + + SpectralDistribution diffuse = {}; + SpectralDistribution specular = {}; + SpectralDistribution transmittance = {}; + RefractiveIndex ext_ior = {}; + RefractiveIndex int_ior = {}; + + Thinfilm thinfilm = {}; + + float2 roughness = {0.0f, 0.0f}; + float metalness = 0.0f; + float normal_scale = 0.5f; + + uint32_t options = {}; + uint32_t pad[3] = {}; + + ETX_GPU_CODE bool double_sided() const { + return (options & DoubleSided) == DoubleSided; + } + + ETX_GPU_CODE bool is_delta() const { + switch (cls) { + case Class::Diffuse: + case Class::Translucent: + case Class::Boundary: + case Class::Plastic: + return false; + + case Class::Conductor: + case Class::Dielectric: + case Class::Generic: + return max(roughness.x, roughness.y) <= kDeltaAlphaTreshold; + + case Class::Thinfilm: + case Class::Mirror: + return true; + + default: + return false; + } + } +}; + +} // namespace etx diff --git a/sources/etx/render/shared/math.hxx b/sources/etx/render/shared/math.hxx new file mode 100644 index 0000000..67a472b --- /dev/null +++ b/sources/etx/render/shared/math.hxx @@ -0,0 +1,348 @@ +#pragma once + +#if (ETX_RENDER_BASE_INCLUDED) + +#if (ETX_NVCC_COMPILER) + +#else + +#define GLM_FORCE_XYZW_ONLY 1 +#define GLM_FORCE_DEPTH_ZERO_TO_ONE 1 +#include +#include +#include +#include + +using float2 = glm::vec2; +using float3 = glm::vec3; +using float4 = glm::vec4; +using int2 = glm::ivec2; +using int3 = glm::ivec3; +using uint2 = glm::uvec2; +using uint3 = glm::uvec3; +using uint4 = glm::uvec4; +using float3x3 = glm::mat3x3; +using float4x4 = glm::mat4x4; +using ubyte2 = glm::u8vec2; +using ubyte3 = glm::u8vec3; +using ubyte4 = glm::u8vec4; + +template +inline constexpr T clamp(T val, T min_val, T max_val) { + return glm::clamp(val, min_val, max_val); +} + +template +inline constexpr T saturate(T val) { + return glm::clamp(val, 0.0f, 1.0f); +} + +template +inline constexpr T min(T a, T b) { + return glm::min(a, b); +} + +template +inline constexpr T max(T a, T b) { + return glm::max(a, b); +} + +template +inline constexpr T lerp(T a, T b, float t) { + return glm::mix(a, b, t); +} + +template +inline constexpr T sqr(T t) { + return t * t; +} + +#endif + +#else + +#error This file should not be included separately. Use etx/render/shared/base.hxx instead + +#endif + +namespace etx { + +constexpr float kQuarterPi = 0.78539816339744830961566084581988f; +constexpr float kHalfPi = 1.5707963267948966192313216916398f; +constexpr float kPi = 3.1415926535897932384626433832795f; +constexpr float kDoublePi = 6.283185307179586476925286766559f; +constexpr float kSqrt2 = 1.4142135623730950488016887242097f; +constexpr float kInvPi = 0.31830988618379067153776752674503f; +constexpr float kEpsilon = 1.192092896e-07f; +constexpr float kMaxFloat = 3.402823466e+38f; +constexpr float kRayEpsilon = 1.0e-4f; +constexpr float kDeltaAlphaTreshold = 1.0e-4f; + +constexpr uint32_t kInvalidIndex = ~0u; + +struct alignas(16) BoundingBox { + float3 p_min ETX_EMPTY_INIT; + float3 p_max ETX_EMPTY_INIT; + + ETX_GPU_CODE float3 to_bounding_box(const float3& p) const { + return (p - p_min) / (p_max - p_min); + } + + ETX_GPU_CODE float3 from_bounding_box(const float3& p) const { + return p * (p_max - p_min) + p_min; + } + + ETX_GPU_CODE bool contains(const float3& p) const { + return (p.x >= p_min.x) && (p.y >= p_min.y) && (p.z >= p_min.z) && // + (p.x <= p_max.x) && (p.y <= p_max.y) && (p.z <= p_max.z); + } +}; + +struct alignas(16) Vertex { + float3 pos = {}; + float3 nrm = {}; + float3 tan = {}; + float3 btn = {}; + float2 tex = {}; +}; + +struct alignas(16) Triangle { + uint32_t i[3] = {kInvalidIndex, kInvalidIndex, kInvalidIndex}; + uint32_t material_index = kInvalidIndex; + float3 geo_n = {}; + float area = {}; + uint32_t emitter_index = kInvalidIndex; + uint32_t pad[3] = {}; +}; + +struct alignas(16) Frame { + float3 tan = {}; + float3 btn = {}; + float3 nrm = {}; +}; + +struct Ray { + Ray() = default; + + ETX_GPU_CODE Ray(const float3& origin, const float3& direction) + : o(origin) + , d(direction) { + } + + ETX_GPU_CODE Ray(const float3& origin, const float3& direction, float t_min, float t_max) + : o(origin) + , min_t(t_min) + , d(direction) + , max_t(t_max) { + } + + float3 o = {}; + float min_t = kRayEpsilon; + float3 d = {}; + float max_t = kMaxFloat; +}; + +struct alignas(16) Intersection : public Vertex { + float3 barycentric = {}; + uint32_t triangle_index = kInvalidIndex; + float3 w_i = {}; + float t = -kMaxFloat; + + Intersection() = default; + + ETX_GPU_CODE Intersection(const Vertex& v) + : Vertex(v) { + } + + ETX_GPU_CODE float distance() const { + return t; + } + + ETX_GPU_CODE operator bool() const { + return t >= 0.0f; + } +}; + +ETX_GPU_CODE float3 to_float3(const float4& v) { + return {v.x, v.y, v.z}; +} + +ETX_GPU_CODE float luminance(const float3& value) { + return value.x * 0.212671f + value.y * 0.715160f + value.z * 0.072169f; +} + +ETX_GPU_CODE auto orthonormal_basis(const float3& n) { + struct basis { + float3 u, v; + }; + float s = (n.z < 0.0 ? -1.0f : 1.0f); + float a = -1.0f / (s + n.z); + float b = n.x * n.y * a; + return basis{ + {1.0f + s * n.x * n.x * a, s * b, -s * n.x}, + {b, s + n.y * n.y * a, -n.y}, + }; +} + +ETX_GPU_CODE float3 sample_cosine_distribution(float xi0, float xi1, const float3& n, const float3& u, const float3& v, float exponent) { + float cos_theta = powf(xi0, 1.0f / (exponent + 1.0f)); + float sin_theta = sqrtf(1.0f - cos_theta * cos_theta); + return (u * cosf(xi1 * kDoublePi) + v * sinf(xi1 * kDoublePi)) * sin_theta + n * cos_theta; +} + +ETX_GPU_CODE float3 sample_cosine_distribution(float xi0, float xi1, const float3& n, float exponent) { + auto basis = orthonormal_basis(n); + return sample_cosine_distribution(xi0, xi1, n, basis.u, basis.v, exponent); +} + +ETX_GPU_CODE float3 random_barycentric(float r1, float r2) { + r1 = sqrtf(r1); + return {1.0f - r1, r1 * (1.0f - r2), r1 * r2}; +} + +ETX_GPU_CODE float2 sample_disk(float xi0, float xi1) { + float2 offset = {2.0f * xi0 - 1.0f, 2.0f * xi1 - 1.0f}; + if ((offset.x == 0.0f) && (offset.y == 0.0f)) + return {}; + + float r = 0.0f; + float theta = 0.0f; + if (fabsf(offset.x) > fabsf(offset.y)) { + r = offset.x; + theta = kQuarterPi * (offset.y / offset.x); + } else { + r = offset.y; + theta = kHalfPi - kQuarterPi * (offset.x / offset.y); + } + + return {r * std::cos(theta), r * std::sin(theta)}; +} + +ETX_GPU_CODE float3 orthogonalize(const float3& t, const float3& n) { + return normalize(t - n * dot(n, t)); +}; + +ETX_GPU_CODE float3 orthogonalize(const float3& t, const float3& b, const float3& n) { + return normalize(t - n * dot(n, t)) * (dot(cross(n, t), b) < 0.0f ? -1.0f : 1.0f); +} + +ETX_GPU_CODE bool valid_value(float t) { + return (isnan(t) == false) && (isinf(t) == false) && (t >= 0.0f); +} + +ETX_GPU_CODE bool valid_value(const float2& v) { + return valid_value(v.x) && valid_value(v.y); +} + +ETX_GPU_CODE bool valid_value(const float3& v) { + return valid_value(v.x) && valid_value(v.y) && valid_value(v.z); +} + +ETX_GPU_CODE bool valid_value(const float4& v) { + return valid_value(v.x) && valid_value(v.y) && valid_value(v.z) && valid_value(v.w); +} + +ETX_GPU_CODE float to_float(uint32_t value) { + float result; + memcpy(&result, &value, sizeof(float)); + return result; +} + +ETX_GPU_CODE float to_float(int32_t value) { + float result; + memcpy(&result, &value, sizeof(float)); + return result; +} + +ETX_GPU_CODE uint32_t to_uint(float value) { + uint32_t result; + memcpy(&result, &value, sizeof(float)); + return result; +} + +ETX_GPU_CODE uint32_t to_int(float value) { + int32_t result; + memcpy(&result, &value, sizeof(float)); + return result; +} + +ETX_GPU_CODE float3 offset_ray(const float3& p, const float3& n) { + constexpr float int_scale = 256.0f; + constexpr float float_scale = 1.0f / 65536.0f; + constexpr float origin = 1.0f / 32.0f; + + int32_t of_i_x = static_cast(int_scale * n.x); + int32_t of_i_y = static_cast(int_scale * n.y); + int32_t of_i_z = static_cast(int_scale * n.z); + + float p_i_x = to_float(to_int(p.x) + ((p.x > 0.0f) ? of_i_x : -of_i_x)); + float p_i_y = to_float(to_int(p.y) + ((p.y > 0.0f) ? of_i_y : -of_i_y)); + float p_i_z = to_float(to_int(p.z) + ((p.z > 0.0f) ? of_i_z : -of_i_z)); + + return { + fabsf(p.x) < origin ? p.x + float_scale * n.x : p_i_x, + fabsf(p.y) < origin ? p.y + float_scale * n.y : p_i_y, + fabsf(p.z) < origin ? p.z + float_scale * n.z : p_i_z, + }; +} + +ETX_GPU_CODE float power_heuristic(float f, float g) { + float f2 = f * f; + float g2 = g * g; + return saturate(f2 / (f2 + g2)); +} + +ETX_GPU_CODE float area_to_solid_angle_probability(float pdf_pos, const float3& source_point, const float3& target_normal, const float3& target_point, float p) { + auto w_o = source_point - target_point; + float a_distance_squared = dot(w_o, w_o); + if (a_distance_squared == 0.0f) { + return 0.0f; + } + + w_o = w_o / sqrtf(a_distance_squared); + float cos_t = fabsf(clamp(dot(w_o, target_normal), -1.0f, 1.0f)); + if (p != 1.0f) { + cos_t = powf(cos_t, p); + } + return (cos_t > 1.0e-5f) ? (pdf_pos * a_distance_squared / cos_t) : 0.0f; +} + +ETX_GPU_CODE float2 uv_to_phi_theta(float u, float v) { + float phi = (u * 2.0f - 1.0f) * kPi; + float theta = (0.5f - v) * kPi; + return {phi, theta}; +} + +ETX_GPU_CODE float2 phi_theta_to_uv(float phi, float theta) { + float u = (phi / kPi + 1.0f) / 2.0f; + float v = 0.5f - theta / kPi; + return {u, v}; +} + +ETX_GPU_CODE float2 direction_to_phi_theta(const float3& dir) { + return {atan2f(dir.z, dir.x), asinf(dir.y)}; +} + +ETX_GPU_CODE float2 direction_to_uv(const float3& dir) { + float2 p_t = direction_to_phi_theta(dir); + return phi_theta_to_uv(p_t.x, p_t.y); +} + +ETX_GPU_CODE float3 phi_theta_to_direction(float phi, float theta) { + float cos_p = cosf(phi); + float sin_p = sinf(phi); + float cos_t = cosf(theta); + float sin_t = sinf(theta); + return { + cos_p * cos_t, + sin_t, + sin_p * cos_t, + }; +} + +ETX_GPU_CODE float3 uv_to_direction(const float2& uv) { + float2 p_t = uv_to_phi_theta(uv.x, uv.y); + return phi_theta_to_direction(p_t.x, p_t.y); +} + +} // namespace etx diff --git a/sources/etx/render/shared/medium.hxx b/sources/etx/render/shared/medium.hxx new file mode 100644 index 0000000..712b879 --- /dev/null +++ b/sources/etx/render/shared/medium.hxx @@ -0,0 +1,297 @@ +#pragma once + +#include +#include + +namespace etx { + +struct alignas(16) Medium { + enum class Class : uint32_t { + Vacuum = 0, + Homogeneous = 1, + Heterogeneous = 2, + }; + + struct alignas(16) Sample { + SpectralResponse weight = {}; + float3 pos = {}; + float3 w_i = {}; + uint32_t sampled_medium = {}; + float t = {}; + + bool valid() const { + return weight.valid(); + } + }; + + SpectralDistribution s_absorption = {}; + SpectralDistribution s_outscattering = {}; + ArrayView density = {}; + BoundingBox bounds = {}; + Class cls = Class::Vacuum; + float phase_function_g = 0.0f; + float max_density = 0.0f; + float max_sigma = 0.0f; + uint3 dimensions = {}; + uint32_t pad = {}; + + ETX_GPU_CODE SpectralResponse transmittance(const SpectralQuery spect, Sampler& smp, const float3& pos, const float3& direction, float distance) const { + switch (cls) { + case Class::Vacuum: + return {spect.wavelength, 1.0f}; + + case Class::Homogeneous: + return transmittance_homogeneous(spect, smp, pos, direction, distance); + + case Class::Heterogeneous: + return transmittance_heterogeneous(spect, smp, pos, direction, distance); + + default: + ETX_FAIL_FMT("Invalid medium: %u\n", uint32_t(cls)); + return {}; + } + } + + ETX_GPU_CODE SpectralResponse transmittance_homogeneous(const SpectralQuery spect, Sampler& smp, const float3& pos, const float3& direction, float distance) const { + return exp((s_outscattering(spect) + s_absorption(spect)) * (-distance)); + } + + ETX_GPU_CODE SpectralResponse transmittance_heterogeneous(const SpectralQuery spect, Sampler& smp, const float3& p, const float3& d, float max_t) const { + float3 pos = p; + float3 dir = d; + float t_min = 0.0f; + float t_max = 0.0f; + if (intersects_medium_bounds(p, d, max_t, pos, dir, t_min, t_max) == false) { + return {spect.wavelength, 1.0f}; + } + + const float rr_threshold = 0.1f; + + float tr = 1.0f; + + float t = t_min; + while (true) { + t -= std::log(1.0f - smp.next()) / (max_density * max_sigma); + if (t >= t_max) + break; + + float density = sample_density(pos + dir * t); + tr *= 1 - max(0.0f, density / max_density); + + if (tr < rr_threshold) { + float q = max(0.05f, 1.0f - tr); + + if (smp.next() < q) + return {spect.wavelength, 0.0f}; + + tr /= 1.0f - q; + } + } + + return {spect.wavelength, tr}; + } + + ETX_GPU_CODE Sample sample(const SpectralQuery spect, Sampler& smp, const float3& pos, const float3& w_i, float max_t) const { + switch (cls) { + case Class::Vacuum: + return {{spect.wavelength, 1.0f}}; + + case Class::Homogeneous: + return sample_homogeneous(spect, smp, pos, w_i, max_t); + + case Class::Heterogeneous: + return sample_heterogeneous(spect, smp, pos, w_i, max_t); + + default: + ETX_FAIL_FMT("Invalid medium: %u\n", uint32_t(cls)); + return {}; + } + } + + ETX_GPU_CODE Sample sample_homogeneous(const SpectralQuery spect, Sampler& smp, const float3& pos, const float3& w_i, float max_t) const { + auto s_t = s_outscattering.random_entry_power(smp.next()); + float t = -logf(1.0f - smp.next()) / s_t; + t = min(t, max_t); + + Sample result = {}; + result.sampled_medium = t < max_t; + result.pos = pos + w_i * t; + result.w_i = w_i; + result.t = t; + + SpectralResponse tr = transmittance(spect, smp, pos, w_i, t); + + SpectralResponse density = result.sampled_medium ? ((s_outscattering(spect) + s_absorption(spect)) * tr) : (tr); + float pdf = density.average(); + + if (pdf == 0.0f) { + ETX_ASSERT(tr.is_zero()); + pdf = 1.0f; + } + + result.weight = tr / pdf; + ETX_VALIDATE(result.weight); + + if (result.sampled_medium) { + result.weight *= s_outscattering(spect); + ETX_VALIDATE(result.weight); + } + + return result; + } + + ETX_GPU_CODE Sample sample_heterogeneous(const SpectralQuery spect, Sampler& smp, const float3& in_pos, const float3& in_dir, float in_max_t) const { + float3 pos = in_pos; + float3 dir = in_dir; + float t_min = 0.0f; + float t_max = 0.0f; + if (intersects_medium_bounds(in_pos, in_dir, in_max_t, pos, dir, t_min, t_max) == false) { + return {{spect.wavelength, 1.0f}}; + } + + float t = t_min; + while (true) { + t -= std::log(1.0f - smp.next()) / (max_density * max_sigma); + if (t >= t_max) + break; + + float3 local_pos = pos + dir * t; + float density = sample_density(local_pos); + if (smp.next() <= (density / max_density)) { + Sample result; + result.w_i = in_dir; + result.weight = s_outscattering(spect) / (s_outscattering(spect) + s_absorption(spect)); + result.pos = bounds.from_bounding_box(local_pos); + result.sampled_medium = true; + result.t = t; + return result; + } + } + + return {{spect.wavelength, 1.0f}}; + } + + ETX_GPU_CODE float phase_function(const SpectralQuery spect, const float3& pos, const float3& w_i, const float3& w_o) const { + if (cls == Class::Vacuum) { + return 1.0f; + } + + float cos_t = dot(w_i, w_o); + float d = 1.0f + phase_function_g * phase_function_g + 2.0f * phase_function_g * cos_t; + return (1.0f / (4.0f * kPi)) * (1.0f - phase_function_g * phase_function_g) / (d * sqrtf(d)); + } + + ETX_GPU_CODE float3 sample_phase_function(const SpectralQuery spect, Sampler& smp, const float3& pos, const float3& w_i) const { + if (cls == Class::Vacuum) { + return w_i; + } + + float xi0 = smp.next(); + float xi1 = smp.next(); + + float cos_theta = 0.0f; + if (fabsf(phase_function_g) < 1e-3) { + cos_theta = 1.0f - 2.0f * xi0; + } else { + float sqr_term = (1.0f - phase_function_g * phase_function_g) / (1.0f + phase_function_g - 2.0f * phase_function_g * xi0); + cos_theta = -(1.0f + phase_function_g * phase_function_g - sqr_term * sqr_term) / (2.0f * phase_function_g); + } + + float sin_theta = sqrtf(max(0.0f, 1.0f - cos_theta * cos_theta)); + + auto basis = orthonormal_basis(w_i); + return (basis.u * cosf(xi1 * kDoublePi) + basis.v * sinf(xi1 * kDoublePi)) * sin_theta + w_i * cos_theta; + } + + ETX_GPU_CODE float sample_density(const float3& coord) const { + ETX_ASSERT(cls == Class::Heterogeneous); + + if ((coord.x < 0.0f) || (coord.y < 0.0f) || (coord.z < 0.0f) || (coord.x >= 1.0f) || (coord.y >= 1.0f) || (coord.z >= 1.0f)) { + return 0.0f; + } + + float px = clamp(coord.x * float(dimensions.x) - 0.5f, 0.0f, float(dimensions.x) - 1.0f); + float py = clamp(coord.y * float(dimensions.y) - 0.5f, 0.0f, float(dimensions.y) - 1.0f); + float pz = clamp(coord.z * float(dimensions.z) - 0.5f, 0.0f, float(dimensions.z) - 1.0f); + + uint64_t ix = min(dimensions.x - 1llu, static_cast(px)); + uint64_t nx = min(dimensions.x - 1llu, ix + 1); + + uint64_t iy = min(dimensions.y - 1llu, static_cast(py)); + uint64_t ny = min(dimensions.y - 1llu, iy + 1); + + uint64_t iz = min(dimensions.z - 1llu, static_cast(pz)); + uint64_t nz = min(dimensions.z - 1llu, iz + 1); + + float d000 = density[ix + iy * dimensions.x + iz * dimensions.x * dimensions.y]; + float d001 = density[nx + iy * dimensions.x + iz * dimensions.x * dimensions.y]; + float d010 = density[ix + ny * dimensions.x + iz * dimensions.x * dimensions.y]; + float d011 = density[nx + ny * dimensions.x + iz * dimensions.x * dimensions.y]; + float d100 = density[ix + iy * dimensions.x + nz * dimensions.x * dimensions.y]; + float d101 = density[nx + iy * dimensions.x + nz * dimensions.x * dimensions.y]; + float d110 = density[ix + ny * dimensions.x + nz * dimensions.x * dimensions.y]; + float d111 = density[nx + ny * dimensions.x + nz * dimensions.x * dimensions.y]; + + float dx = px - std::floor(px); + float dy = py - std::floor(py); + float dz = pz - std::floor(pz); + + float d_bottom = lerp(lerp(d000, d001, dx), lerp(d010, d011, dx), dy); + float d_top = lerp(lerp(d100, d101, dx), lerp(d110, d111, dx), dy); + return lerp(d_bottom, d_top, dz); + } + + private: + ETX_GPU_CODE constexpr static float gamma(int n) { + constexpr auto e = kEpsilon * 0.5f; + return (n * e) / (1.0f - n * e); + } + + ETX_GPU_CODE bool medium_bounds(const float3& in_pos, const float3& in_dir, const float max_t, float& t_min, float& t_max) const { + constexpr float g3 = 1.0f + 2.0f * gamma(3); + + float pos[3] = {in_pos.x, in_pos.y, in_pos.z}; + float dir[3] = {in_dir.x, in_dir.y, in_dir.z}; + + t_min = 0.0f; + t_max = max_t; + for (int i = 0; i < 3; ++i) { + float t_near = (0.0f - pos[i]) / dir[i]; + float t_far = (1.0f - pos[i]) / dir[i]; + + if (t_near > t_far) { + float t = t_far; + t_far = t_near; + t_near = t; + } + + t_far *= g3; + + t_min = t_near > t_min ? t_near : t_min; + t_max = t_far < t_max ? t_far : t_max; + + if (t_min > t_max) + return false; + } + + return true; + } + + ETX_GPU_CODE bool intersects_medium_bounds(const float3& in_pos, const float3& in_direction, float in_max_t, float3& medium_pos, float3& medium_dir, float& t_min, + float& t_max) const { + if (in_max_t >= kMaxFloat) { + return false; + } + + float3 end_pos = in_pos + in_direction * in_max_t; + float3 medium_end_pos = bounds.to_bounding_box(end_pos); + + medium_pos = bounds.to_bounding_box(in_pos); + medium_dir = normalize(medium_end_pos - medium_pos); + in_max_t = length(medium_end_pos - medium_pos); + + return medium_bounds(medium_pos, medium_dir, in_max_t, t_min, t_max); + } +}; + +} // namespace etx \ No newline at end of file diff --git a/sources/etx/render/shared/sampler.hxx b/sources/etx/render/shared/sampler.hxx new file mode 100644 index 0000000..5d1e4b8 --- /dev/null +++ b/sources/etx/render/shared/sampler.hxx @@ -0,0 +1,56 @@ +#pragma once + +#include + +namespace etx { + +struct Sampler { + uint32_t seed = 0; + + Sampler() = default; + + ETX_GPU_CODE Sampler(uint32_t state) + : seed(state) { + } + + ETX_GPU_CODE Sampler(uint32_t a, uint32_t b) + : seed(random_seed(a, b)) { + } + + ETX_GPU_CODE void init(uint32_t a, uint32_t b) { + seed = random_seed(a, b); + } + + ETX_GPU_CODE float next() { + return next_random(seed); + } + + ETX_GPU_CODE void start_pixel(const int2&) { + } + + ETX_GPU_CODE void next_sample() { + } + + static ETX_GPU_CODE uint32_t random_seed(const uint32_t val0, const uint32_t val1) { + uint32_t v0 = val0; + uint32_t v1 = val1; + uint32_t s0 = 0; + for (uint32_t n = 0; n < 16; ++n) { + s0 += 0x9e3779b9; + v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); + v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); + } + return v0; + } + + static ETX_GPU_CODE float next_random(uint32_t& previous) { + previous = previous * 1664525u + 1013904223u; + union { + uint32_t i; + float f; + } wrap = {(previous >> 9) | 0x3f800000}; + return wrap.f - 1.0f; + } +}; + +} // namespace etx diff --git a/sources/etx/render/shared/scene.hxx b/sources/etx/render/shared/scene.hxx new file mode 100644 index 0000000..8ea44e0 --- /dev/null +++ b/sources/etx/render/shared/scene.hxx @@ -0,0 +1,472 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace etx { + +struct alignas(16) EnvironmentEmitters { + constexpr static const uint32_t kMaxCount = 7; + uint32_t emitters[kMaxCount]; + uint32_t count; +}; + +struct alignas(16) Scene { + Camera camera; + ArrayView vertices ETX_EMPTY_INIT; + ArrayView triangles ETX_EMPTY_INIT; + ArrayView materials ETX_EMPTY_INIT; + ArrayView emitters ETX_EMPTY_INIT; + ArrayView images ETX_EMPTY_INIT; + ArrayView mediums ETX_EMPTY_INIT; + Distribution emitters_distribution ETX_EMPTY_INIT; + EnvironmentEmitters environment_emitters ETX_EMPTY_INIT; + Spectrums* spectrums ETX_EMPTY_INIT; + float3 bounding_sphere_center ETX_EMPTY_INIT; + float bounding_sphere_radius ETX_EMPTY_INIT; + uint64_t acceleration_structure ETX_EMPTY_INIT; + uint32_t camera_medium_index ETX_INIT_WITH(kInvalidIndex); + uint32_t camera_lens_shape_image_index ETX_INIT_WITH(kInvalidIndex); + + ETX_GPU_CODE bool valid() const { + return (vertices.count > 0) && (triangles.count > 0) && (materials.count > 0) && (emitters.count > 0) && (bounding_sphere_radius > 0.0f); + } +}; + +ETX_GPU_CODE float2 get_jittered_uv(Sampler& smp, const uint2& pixel, const uint2& dim) { + return { + (float(pixel.x) + smp.next()) / float(dim.x) * 2.0f - 1.0f, + (float(pixel.y) + smp.next()) / float(dim.y) * 2.0f - 1.0f, + }; +} + +ETX_GPU_CODE Ray generate_ray(Sampler& smp, const Scene& scene, const float2& uv) { + float3 s = (uv.x * scene.camera.aspect) * scene.camera.side; + float3 u = (uv.y) * scene.camera.up; + float3 w_o = normalize(scene.camera.tan_half_fov * (s + u) + scene.camera.direction); + + float3 origin = scene.camera.position; + if (scene.camera.lens_radius > 0.0f) { + float2 sensor_sample = {}; + if (scene.camera_lens_shape_image_index == kInvalidIndex) { + sensor_sample = sample_disk(smp.next(), smp.next()); + } else { + float pdf = {}; + uint2 location = {}; + sensor_sample = scene.images[scene.camera_lens_shape_image_index].sample(smp.next(), smp.next(), pdf, location); + sensor_sample = sensor_sample * 2.0f - 1.0f; + } + sensor_sample *= scene.camera.lens_radius; + origin = origin + scene.camera.side * sensor_sample.x + scene.camera.up * sensor_sample.y; + float focal_plane_distance = scene.camera.focal_distance / dot(w_o, scene.camera.direction); + float3 p = scene.camera.position + focal_plane_distance * w_o; + w_o = normalize(p - origin); + } + + return {origin, w_o, kRayEpsilon, kMaxFloat}; +} + +ETX_GPU_CODE float3 lerp_pos(const ArrayView& vertices, const Triangle& t, const float3& bc) { + return vertices[t.i[0]].pos * bc.x + // + vertices[t.i[1]].pos * bc.y + // + vertices[t.i[2]].pos * bc.z; // +} + +ETX_GPU_CODE float3 lerp_normal(const ArrayView& vertices, const Triangle& t, const float3& bc) { + return normalize(vertices[t.i[0]].nrm * bc.x + // + vertices[t.i[1]].nrm * bc.y + // + vertices[t.i[2]].nrm * bc.z); // +} + +ETX_GPU_CODE float2 lerp_uv(const ArrayView& vertices, const Triangle& t, const float3& b) { + return vertices[t.i[0]].tex * b.x + // + vertices[t.i[1]].tex * b.y + // + vertices[t.i[2]].tex * b.z; // +} + +ETX_GPU_CODE Vertex lerp_vertex(const ArrayView& vertices, const Triangle& t, const float3& bc) { + const auto& v0 = vertices[t.i[0]]; + const auto& v1 = vertices[t.i[1]]; + const auto& v2 = vertices[t.i[2]]; + return { + /* */ v0.pos * bc.x + v1.pos * bc.y + v2.pos * bc.z, + normalize(v0.nrm * bc.x + v1.nrm * bc.y + v2.nrm * bc.z), + normalize(v0.tan * bc.x + v1.tan * bc.y + v2.tan * bc.z), + normalize(v0.btn * bc.x + v1.btn * bc.y + v2.btn * bc.z), + /* */ v0.tex * bc.x + v1.tex * bc.y + v2.tex * bc.z, + }; +} + +ETX_GPU_CODE float3 shading_pos_project(const float3& position, const float3& origin, const float3& normal) { + return position - dot(position - origin, normal) * normal; +} + +ETX_GPU_CODE float3 shading_pos(const ArrayView& vertices, const Triangle& t, const float3& bc, const float3& w_o) { + float3 geo_pos = lerp_pos(vertices, t, bc); + float3 sh_normal = lerp_normal(vertices, t, bc); + float direction = (dot(sh_normal, w_o) >= 0.0f) ? +1.0f : -1.0f; + float3 p0 = shading_pos_project(geo_pos, vertices[t.i[0]].pos, direction * vertices[t.i[0]].nrm); + float3 p1 = shading_pos_project(geo_pos, vertices[t.i[1]].pos, direction * vertices[t.i[1]].nrm); + float3 p2 = shading_pos_project(geo_pos, vertices[t.i[2]].pos, direction * vertices[t.i[2]].nrm); + float3 sh_pos = p0 * bc.x + p1 * bc.y + p2 * bc.z; + bool convex = dot(sh_pos - geo_pos, sh_normal) * direction > 0.0f; + return offset_ray(convex ? sh_pos : geo_pos, t.geo_n * direction); +} + +ETX_GPU_CODE bool apply_rr(float eta_scale, float rnd, SpectralResponse& throughput) { + float max_t = throughput.maximum() * (eta_scale * eta_scale); + if (valid_value(max_t) == false) { + return false; + } + + float q = min(0.95f, max_t); + if ((q > 0.0f) && (rnd < q)) { + throughput *= (1.0f / q); + return true; + } + + return false; +} + +ETX_GPU_CODE float emitter_pdf_area_local(const Emitter& em, const Scene& scene) { + ETX_ASSERT(em.is_local()); + const auto& tri = scene.triangles[em.triangle_index]; + return 1.0f / tri.area; +} + +ETX_GPU_CODE SpectralResponse emitter_evaluate_in_local(const Emitter& em, const SpectralQuery spect, const float2& uv, const float3& pos, const float3& to_point, float& pdf_area, + float& pdf_dir, float& pdf_dir_out, const Scene& scene, const bool no_collimation) { + ETX_ASSERT(em.is_local()); + + const auto& tri = scene.triangles[em.triangle_index]; + if ((em.emission_direction == Emitter::Direction::Single) && (dot(tri.geo_n, to_point - pos) >= 0.0f)) { + return {spect.wavelength, 0.0f}; + } + + auto dp = pos - to_point; + + pdf_area = emitter_pdf_area_local(em, scene); + if (em.emission_direction == Emitter::Direction::Omni) { + pdf_dir = pdf_area * dot(dp, dp); + pdf_dir_out = pdf_area; + } else { + pdf_dir = area_to_solid_angle_probability(pdf_area, to_point, tri.geo_n, pos, no_collimation ? 1.0f : em.collimation); + pdf_dir_out = pdf_area * fabsf(dot(tri.geo_n, normalize(dp))) * kInvPi; + } + + SpectralResponse result = em.emission(spect); + ETX_VALIDATE(result); + + if (em.image_index != kInvalidIndex) { + auto sampled_value = scene.images[em.image_index].evaluate(uv); + result *= rgb::query_spd(spect, {sampled_value.x, sampled_value.y, sampled_value.z}, scene.spectrums->rgb_illuminant); + ETX_VALIDATE(result); + } + + return result; +} + +ETX_GPU_CODE SpectralResponse emitter_evaluate_out_local(const Emitter& em, const SpectralQuery spect, const float2& uv, const float3& emitter_normal, const float3& direction, + float& pdf_area, float& pdf_dir, float& pdf_dir_out, const Scene& scene) { + ETX_ASSERT(em.is_local()); + + switch (em.emission_direction) { + case Emitter::Direction::Single: { + pdf_dir = max(0.0f, dot(emitter_normal, direction)) * kInvPi; + break; + } + case Emitter::Direction::TwoSided: { + pdf_dir = 0.5f * fabsf(dot(emitter_normal, direction)) * kInvPi; + break; + } + case Emitter::Direction::Omni: { + pdf_dir = kInvPi; + break; + } + } + ETX_ASSERT(pdf_dir > 0.0f); + + pdf_area = emitter_pdf_area_local(em, scene); + ETX_ASSERT(pdf_area > 0.0f); + + pdf_dir_out = pdf_dir * pdf_area; + ETX_ASSERT(pdf_dir_out > 0.0f); + + SpectralResponse result = em.emission(spect); + if (em.image_index != kInvalidIndex) { + auto sampled_value = scene.images[em.image_index].evaluate(uv); + result *= rgb::query_spd(spect, {sampled_value.x, sampled_value.y, sampled_value.z}, scene.spectrums->rgb_illuminant); + } + + ETX_VALIDATE(result); + return result; +} + +ETX_GPU_CODE SpectralResponse emitter_evaluate_in_dist(const Emitter& em, const SpectralQuery spect, const float3& in_direction, float& pdf_area, float& pdf_dir, + float& pdf_dir_out, const Scene& scene) { + ETX_ASSERT(em.is_distant()); + + if (em.cls == Emitter::Class::Directional) { + if ((em.angular_size > 0.0f) && (dot(in_direction, em.direction) >= em.angular_size_cosine)) { + pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + pdf_dir = 1.0f; + pdf_dir_out = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + return em.emission(spect); + } else { + pdf_area = 0.0f; + pdf_dir = 0.0f; + pdf_dir_out = 0.0f; + return {spect.wavelength, 0.0f}; + } + } + + float2 uv = direction_to_uv(in_direction); + float sin_t = sinf(uv.y * kPi); + if (sin_t == 0.0f) { + pdf_area = 0.0f; + pdf_dir = 0.0f; + pdf_dir_out = 0.0f; + return {spect.wavelength, 0.0f}; + } + + const auto& img = scene.images[em.image_index]; + pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + pdf_dir = img.pdf(uv) / (2.0f * kPi * kPi * sin_t); + pdf_dir_out = pdf_area * pdf_dir; + return em.emission(spect) * rgb::query_spd(spect, to_float3(img.evaluate(uv)), scene.spectrums->rgb_illuminant); +} + +ETX_GPU_CODE SpectralResponse emitter_evaluate_env_dist(const Emitter& em, const SpectralQuery spect, const float2& uv, float& pdf_area, float& pdf_dir, float& pdf_dir_out, + const Scene& scene) { + ETX_ASSERT(em.cls == Emitter::Class::Environment); + + float sin_t = sinf(uv.y * kPi); + if (sin_t == 0.0f) { + pdf_area = 0.0f; + pdf_dir = 0.0f; + pdf_dir_out = 0.0f; + return {spect.wavelength, 0.0f}; + } + + const auto& img = scene.images[em.image_index]; + pdf_dir = img.pdf(uv) / (2.0f * kPi * kPi * sin_t); + pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + pdf_dir_out = pdf_area * pdf_dir; + + auto eval = to_float3(img.evaluate(uv)); + return SpectralResponse(spect.wavelength, eval); +} + +ETX_GPU_CODE SpectralResponse emitter_evaluate_out_dist(const Emitter& em, const SpectralQuery spect, const float3& in_direction, float& pdf_area, float& pdf_dir, + float& pdf_dir_out, const Scene& scene) { + ETX_ASSERT(em.is_distant()); + + float2 uv = direction_to_uv(in_direction); + float sin_t = sinf(uv.y * kPi); + if (sin_t == 0.0f) { + pdf_dir = 0.0f; + pdf_area = 0.0f; + pdf_dir_out = pdf_dir; + return {spect.wavelength, 0.0f}; + } + + switch (em.cls) { + case Emitter::Class::Environment: { + const auto& img = scene.images[em.image_index]; + pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + pdf_dir = img.pdf(uv) / (2.0f * kPi * kPi * sin_t); + pdf_dir_out = pdf_dir * pdf_area; + return em.emission(spect) * rgb::query_spd(spect, to_float3(img.evaluate(uv)), scene.spectrums->rgb_illuminant); + } + case Emitter::Class::Directional: { + pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + pdf_dir = 1.0f; + pdf_dir_out = pdf_dir * pdf_area; + return em.emission(spect); + } + + default: + return {spect.wavelength, 0.0f}; + } +} + +ETX_GPU_CODE float emitter_pdf_in_dist(const Emitter& em, const float3& in_direction, const Scene& scene) { + ETX_ASSERT(em.is_distant()); + + if (em.cls == Emitter::Class::Directional) { + if ((em.angular_size > 0.0f) && (dot(in_direction, em.direction) >= em.angular_size_cosine)) { + return 1.0f; + } else { + return 0.0f; + } + } + + float2 uv = direction_to_uv(in_direction); + float sin_t = sinf(uv.y * kPi); + if (sin_t <= kEpsilon) { + return 0.0f; + } + + const auto& img = scene.images[em.image_index]; + return img.pdf(uv) / (2.0f * kPi * kPi * sin_t); +} + +ETX_GPU_CODE EmitterSample emitter_sample_in(const Emitter& em, const SpectralQuery spect, Sampler& smp, const float3& from_point, const Scene& scene) { + constexpr float kDisantRadiusScale = 2.0f; + + EmitterSample result; + switch (em.cls) { + case Emitter::Class::Area: { + const auto& tri = scene.triangles[em.triangle_index]; + result.barycentric = random_barycentric(smp.next(), smp.next()); + result.origin = lerp_pos(scene.vertices, tri, result.barycentric); + result.normal = lerp_normal(scene.vertices, tri, result.barycentric); + result.direction = normalize(result.origin - from_point); + result.value = emitter_evaluate_in_local(em, spect, lerp_uv(scene.vertices, tri, result.barycentric), from_point, result.origin, result.pdf_area, result.pdf_dir, + result.pdf_dir_out, scene, false); + break; + } + + case Emitter::Class::Environment: { + const auto& img = scene.images[em.image_index]; + float pdf_image = 0.0f; + uint2 image_location = {}; + result.image_uv = img.sample(smp.next(), smp.next(), pdf_image, image_location); + result.direction = uv_to_direction(result.image_uv); + result.normal = -result.direction; + result.origin = from_point + kDisantRadiusScale * scene.bounding_sphere_radius * result.direction; + result.value = emitter_evaluate_env_dist(em, spect, result.image_uv, result.pdf_area, result.pdf_dir, result.pdf_dir_out, scene); + break; + } + + case Emitter::Class::Directional: { + if (em.angular_size > 0.0f) { + auto basic = orthonormal_basis(em.direction); + float2 disk = em.equivalent_disk_size * sample_disk(smp.next(), smp.next()); + result.direction = normalize(em.direction + basic.u * disk.x + basic.v * disk.y); + } else { + result.direction = em.direction; + } + result.pdf_area = 1.0f / (kPi * scene.bounding_sphere_radius * scene.bounding_sphere_radius); + result.pdf_dir = 1.0f; + result.pdf_dir_out = result.pdf_dir * result.pdf_area; + result.origin = from_point + kDisantRadiusScale * scene.bounding_sphere_radius * result.direction; + result.normal = em.direction * (-1.0f); + result.value = em.emission(spect); + break; + } + default: { + ETX_FAIL("Invalid emitter"); + } + } + return result; +} + +ETX_GPU_CODE EmitterSample sample_emitter(SpectralQuery spect, Sampler& smp, const float3& from_point, const Scene& scene) { + float pdf_sample = 0.0f; + uint32_t emitter_index = static_cast(scene.emitters_distribution.sample(smp.next(), pdf_sample)); + ETX_ASSERT(emitter_index < scene.emitters_distribution.size); + + const auto& emitter = scene.emitters[emitter_index]; + EmitterSample sample = emitter_sample_in(emitter, spect, smp, from_point, scene); + sample.pdf_sample = pdf_sample; + sample.emitter_index = emitter_index; + sample.triangle_index = emitter.triangle_index; + sample.is_delta = emitter.is_delta(); + return sample; +} + +ETX_GPU_CODE float emitter_discrete_pdf(const Emitter& emitter, const Distribution& dist) { + return emitter.weight / dist.total_weight; +} + +#define ETX_DECLARE_BSDF(Class) \ + namespace Class##BSDF { \ + ETX_GPU_CODE BSDFSample sample(struct Sampler&, const struct BSDFData&, const Scene& scene); \ + ETX_GPU_CODE BSDFEval evaluate(const struct BSDFData& data, const Scene& scene); \ + ETX_GPU_CODE float pdf(const struct BSDFData& data, const Scene& scene); \ + ETX_GPU_CODE bool continue_tracing(const struct Material&, const float2& tex, const Scene& scene, struct Sampler& smp); \ + } + +ETX_DECLARE_BSDF(Diffuse); +ETX_DECLARE_BSDF(Plastic); +ETX_DECLARE_BSDF(Conductor); +ETX_DECLARE_BSDF(Dielectric); +ETX_DECLARE_BSDF(Thinfilm); +ETX_DECLARE_BSDF(Translucent); +ETX_DECLARE_BSDF(Mirror); +ETX_DECLARE_BSDF(Boundary); +ETX_DECLARE_BSDF(Generic); +ETX_DECLARE_BSDF(Coating); + +namespace bsdf { + +#define CASE_IMPL(CLS, FUNC, ...) \ + case Material::Class::CLS: \ + return CLS##BSDF::FUNC(__VA_ARGS__) + +#define CASE_IMPL_SAMPLE(A) CASE_IMPL(A, sample, smp, data, scene) +#define CASE_IMPL_EVALUATE(A) CASE_IMPL(A, evaluate, data, scene) +#define CASE_IMPL_PDF(A) CASE_IMPL(A, pdf, data, scene) +#define CASE_IMPL_CONTINUE(A) CASE_IMPL(A, continue_tracing, material, tex, scene, smp) + +#define ALL_CASES(MACRO, CLS) \ + switch (CLS) { \ + MACRO(Diffuse); \ + MACRO(Plastic); \ + MACRO(Conductor); \ + MACRO(Dielectric); \ + MACRO(Thinfilm); \ + MACRO(Translucent); \ + MACRO(Mirror); \ + MACRO(Boundary); \ + MACRO(Generic); \ + MACRO(Coating); \ + default: \ + ETX_FAIL("Unhandled material class"); \ + return {}; \ + } + +[[nodiscard]] ETX_GPU_CODE BSDFSample sample(const BSDFData& data, const struct Scene& scene, struct Sampler& smp) { + ALL_CASES(CASE_IMPL_SAMPLE, data.material.cls); +}; +[[nodiscard]] ETX_GPU_CODE BSDFEval evaluate(const BSDFData& data, const struct Scene& scene) { + ALL_CASES(CASE_IMPL_EVALUATE, data.material.cls); +} + +[[nodiscard]] ETX_GPU_CODE float pdf(const BSDFData& data, const struct Scene& scene) { + ALL_CASES(CASE_IMPL_PDF, data.material.cls); +} + +[[nodiscard]] ETX_GPU_CODE bool continue_tracing(const Material& material, const float2& tex, const struct Scene& scene, struct Sampler& smp) { + ALL_CASES(CASE_IMPL_CONTINUE, material.cls); +} + +#undef CASE_IMPL + +ETX_GPU_CODE SpectralResponse apply_image(SpectralQuery spect, const SpectralResponse& value, uint32_t image_index, const float2& uv, const Scene& scene) { + SpectralResponse result = value; + + if (image_index != kInvalidIndex) { + float4 eval = scene.images[image_index].evaluate(uv); + result *= rgb::query_spd(spect, {eval.x, eval.y, eval.z}, scene.spectrums->rgb_reflection); + ETX_VALIDATE(result); + } + return result; +} + +} // namespace bsdf + +} // namespace etx + +#include +#include +#include +#include +#include diff --git a/sources/etx/render/shared/spectrum.hxx b/sources/etx/render/shared/spectrum.hxx new file mode 100644 index 0000000..738aae7 --- /dev/null +++ b/sources/etx/render/shared/spectrum.hxx @@ -0,0 +1,694 @@ +#pragma once + +#include + +namespace etx { + +struct SpectralQuery { + float wavelength = 0.0f; +}; + +namespace spectrum { + +constexpr bool kSpectralRendering = false; +constexpr float kUndefinedWavelength = -1.0f; + +constexpr uint64_t WavelengthCount = 471u; +constexpr uint64_t ShortestWavelength = 360u; +constexpr uint64_t LongestWavelength = ShortestWavelength + WavelengthCount - 1u; + +constexpr float kShortestWavelength = static_cast(ShortestWavelength); +constexpr float kLongestWavelength = static_cast(LongestWavelength); +constexpr float kWavelengthCount = static_cast(WavelengthCount); +constexpr float kYIntegral = 106.85689544677734375f; + +ETX_GPU_CODE float3 spectral_xyz(uint64_t i) { + ETX_ASSERT(i < WavelengthCount); + + ETX_GPU_DATA constexpr static const float kX[WavelengthCount] = {0.0001299000f, 0.0001458470f, 0.0001638021f, 0.0001840037f, 0.0002066902f, 0.0002321000f, 0.0002607280f, + 0.0002930750f, 0.0003293880f, 0.0003699140f, 0.0004149000f, 0.0004641587f, 0.0005189860f, 0.0005818540f, 0.0006552347f, 0.0007416000f, 0.0008450296f, 0.0009645268f, + 0.001094949f, 0.001231154f, 0.001368000f, 0.001502050f, 0.001642328f, 0.001802382f, 0.001995757f, 0.002236000f, 0.002535385f, 0.002892603f, 0.003300829f, 0.003753236f, + 0.004243000f, 0.004762389f, 0.005330048f, 0.005978712f, 0.006741117f, 0.007650000f, 0.008751373f, 0.01002888f, 0.01142170f, 0.01286901f, 0.01431000f, 0.01570443f, 0.01714744f, + 0.01878122f, 0.02074801f, 0.02319000f, 0.02620736f, 0.02978248f, 0.03388092f, 0.03846824f, 0.04351000f, 0.04899560f, 0.05502260f, 0.06171880f, 0.06921200f, 0.07763000f, + 0.08695811f, 0.09717672f, 0.1084063f, 0.1207672f, 0.1343800f, 0.1493582f, 0.1653957f, 0.1819831f, 0.1986110f, 0.2147700f, 0.2301868f, 0.2448797f, 0.2587773f, 0.2718079f, + 0.2839000f, 0.2949438f, 0.3048965f, 0.3137873f, 0.3216454f, 0.3285000f, 0.3343513f, 0.3392101f, 0.3431213f, 0.3461296f, 0.3482800f, 0.3495999f, 0.3501474f, 0.3500130f, + 0.3492870f, 0.3480600f, 0.3463733f, 0.3442624f, 0.3418088f, 0.3390941f, 0.3362000f, 0.3331977f, 0.3300411f, 0.3266357f, 0.3228868f, 0.3187000f, 0.3140251f, 0.3088840f, + 0.3032904f, 0.2972579f, 0.2908000f, 0.2839701f, 0.2767214f, 0.2689178f, 0.2604227f, 0.2511000f, 0.2408475f, 0.2298512f, 0.2184072f, 0.2068115f, 0.1953600f, 0.1842136f, + 0.1733273f, 0.1626881f, 0.1522833f, 0.1421000f, 0.1321786f, 0.1225696f, 0.1132752f, 0.1042979f, 0.09564000f, 0.08729955f, 0.07930804f, 0.07171776f, 0.06458099f, 0.05795001f, + 0.05186211f, 0.04628152f, 0.04115088f, 0.03641283f, 0.03201000f, 0.02791720f, 0.02414440f, 0.02068700f, 0.01754040f, 0.01470000f, 0.01216179f, 0.009919960f, 0.007967240f, + 0.006296346f, 0.004900000f, 0.003777173f, 0.002945320f, 0.002424880f, 0.002236293f, 0.002400000f, 0.002925520f, 0.003836560f, 0.005174840f, 0.006982080f, 0.009300000f, + 0.01214949f, 0.01553588f, 0.01947752f, 0.02399277f, 0.02910000f, 0.03481485f, 0.04112016f, 0.04798504f, 0.05537861f, 0.06327000f, 0.07163501f, 0.08046224f, 0.08973996f, + 0.09945645f, 0.1096000f, 0.1201674f, 0.1311145f, 0.1423679f, 0.1538542f, 0.1655000f, 0.1772571f, 0.1891400f, 0.2011694f, 0.2133658f, 0.2257499f, 0.2383209f, 0.2510668f, + 0.2639922f, 0.2771017f, 0.2904000f, 0.3038912f, 0.3175726f, 0.3314384f, 0.3454828f, 0.3597000f, 0.3740839f, 0.3886396f, 0.4033784f, 0.4183115f, 0.4334499f, 0.4487953f, + 0.4643360f, 0.4800640f, 0.4959713f, 0.5120501f, 0.5282959f, 0.5446916f, 0.5612094f, 0.5778215f, 0.5945000f, 0.6112209f, 0.6279758f, 0.6447602f, 0.6615697f, 0.6784000f, + 0.6952392f, 0.7120586f, 0.7288284f, 0.7455188f, 0.7621000f, 0.7785432f, 0.7948256f, 0.8109264f, 0.8268248f, 0.8425000f, 0.8579325f, 0.8730816f, 0.8878944f, 0.9023181f, + 0.9163000f, 0.9297995f, 0.9427984f, 0.9552776f, 0.9672179f, 0.9786000f, 0.9893856f, 0.9995488f, 1.0090892f, 1.0180064f, 1.0263000f, 1.0339827f, 1.0409860f, 1.0471880f, + 1.0524667f, 1.0567000f, 1.0597944f, 1.0617992f, 1.0628068f, 1.0629096f, 1.0622000f, 1.0607352f, 1.0584436f, 1.0552244f, 1.0509768f, 1.0456000f, 1.0390369f, 1.0313608f, + 1.0226662f, 1.0130477f, 1.0026000f, 0.9913675f, 0.9793314f, 0.9664916f, 0.9528479f, 0.9384000f, 0.9231940f, 0.9072440f, 0.8905020f, 0.8729200f, 0.8544499f, 0.8350840f, + 0.8149460f, 0.7941860f, 0.7729540f, 0.7514000f, 0.7295836f, 0.7075888f, 0.6856022f, 0.6638104f, 0.6424000f, 0.6215149f, 0.6011138f, 0.5811052f, 0.5613977f, 0.5419000f, + 0.5225995f, 0.5035464f, 0.4847436f, 0.4661939f, 0.4479000f, 0.4298613f, 0.4120980f, 0.3946440f, 0.3775333f, 0.3608000f, 0.3444563f, 0.3285168f, 0.3130192f, 0.2980011f, + 0.2835000f, 0.2695448f, 0.2561184f, 0.2431896f, 0.2307272f, 0.2187000f, 0.2070971f, 0.1959232f, 0.1851708f, 0.1748323f, 0.1649000f, 0.1553667f, 0.1462300f, 0.1374900f, + 0.1291467f, 0.1212000f, 0.1136397f, 0.1064650f, 0.09969044f, 0.09333061f, 0.08740000f, 0.08190096f, 0.07680428f, 0.07207712f, 0.06768664f, 0.06360000f, 0.05980685f, + 0.05628216f, 0.05297104f, 0.04981861f, 0.04677000f, 0.04378405f, 0.04087536f, 0.03807264f, 0.03540461f, 0.03290000f, 0.03056419f, 0.02838056f, 0.02634484f, 0.02445275f, + 0.02270000f, 0.02108429f, 0.01959988f, 0.01823732f, 0.01698717f, 0.01584000f, 0.01479064f, 0.01383132f, 0.01294868f, 0.01212920f, 0.01135916f, 0.01062935f, 0.009938846f, + 0.009288422f, 0.008678854f, 0.008110916f, 0.007582388f, 0.007088746f, 0.006627313f, 0.006195408f, 0.005790346f, 0.005409826f, 0.005052583f, 0.004717512f, 0.004403507f, + 0.004109457f, 0.003833913f, 0.003575748f, 0.003334342f, 0.003109075f, 0.002899327f, 0.002704348f, 0.002523020f, 0.002354168f, 0.002196616f, 0.002049190f, 0.001910960f, + 0.001781438f, 0.001660110f, 0.001546459f, 0.001439971f, 0.001340042f, 0.001246275f, 0.001158471f, 0.001076430f, 0.0009999493f, 0.0009287358f, 0.0008624332f, 0.0008007503f, + 0.0007433960f, 0.0006900786f, 0.0006405156f, 0.0005945021f, 0.0005518646f, 0.0005124290f, 0.0004760213f, 0.0004424536f, 0.0004115117f, 0.0003829814f, 0.0003566491f, + 0.0003323011f, 0.0003097586f, 0.0002888871f, 0.0002695394f, 0.0002515682f, 0.0002348261f, 0.0002191710f, 0.0002045258f, 0.0001908405f, 0.0001780654f, 0.0001661505f, + 0.0001550236f, 0.0001446219f, 0.0001349098f, 0.0001258520f, 0.0001174130f, 0.0001095515f, 0.0001022245f, 0.00009539445f, 0.00008902390f, 0.00008307527f, 0.00007751269f, + 0.00007231304f, 0.00006745778f, 0.00006292844f, 0.00005870652f, 0.00005477028f, 0.00005109918f, 0.00004767654f, 0.00004448567f, 0.00004150994f, 0.00003873324f, 0.00003614203f, + 0.00003372352f, 0.00003146487f, 0.00002935326f, 0.00002737573f, 0.00002552433f, 0.00002379376f, 0.00002217870f, 0.00002067383f, 0.00001927226f, 0.00001796640f, 0.00001674991f, + 0.00001561648f, 0.00001455977f, 0.00001357387f, 0.00001265436f, 0.00001179723f, 0.00001099844f, 0.00001025398f, 0.000009559646f, 0.000008912044f, 0.000008308358f, + 0.000007745769f, 0.000007221456f, 0.000006732475f, 0.000006276423f, 0.000005851304f, 0.000005455118f, 0.000005085868f, 0.000004741466f, 0.000004420236f, 0.000004120783f, + 0.000003841716f, 0.000003581652f, 0.000003339127f, 0.000003112949f, 0.000002902121f, 0.000002705645f, 0.000002522525f, 0.000002351726f, 0.000002192415f, 0.000002043902f, + 0.000001905497f, 0.000001776509f, 0.000001656215f, 0.000001544022f, 0.000001439440f, 0.000001341977f, 0.000001251141f}; + + ETX_GPU_DATA constexpr static const float kY[WavelengthCount] = {0.000003917000f, 0.000004393581f, 0.000004929604f, 0.000005532136f, 0.000006208245f, 0.000006965000f, + 0.000007813219f, 0.000008767336f, 0.000009839844f, 0.00001104323f, 0.00001239000f, 0.00001388641f, 0.00001555728f, 0.00001744296f, 0.00001958375f, 0.00002202000f, + 0.00002483965f, 0.00002804126f, 0.00003153104f, 0.00003521521f, 0.00003900000f, 0.00004282640f, 0.00004691460f, 0.00005158960f, 0.00005717640f, 0.00006400000f, 0.00007234421f, + 0.00008221224f, 0.00009350816f, 0.0001061361f, 0.0001200000f, 0.0001349840f, 0.0001514920f, 0.0001702080f, 0.0001918160f, 0.0002170000f, 0.0002469067f, 0.0002812400f, + 0.0003185200f, 0.0003572667f, 0.0003960000f, 0.0004337147f, 0.0004730240f, 0.0005178760f, 0.0005722187f, 0.0006400000f, 0.0007245600f, 0.0008255000f, 0.0009411600f, + 0.001069880f, 0.001210000f, 0.001362091f, 0.001530752f, 0.001720368f, 0.001935323f, 0.002180000f, 0.002454800f, 0.002764000f, 0.003117800f, 0.003526400f, 0.004000000f, + 0.004546240f, 0.005159320f, 0.005829280f, 0.006546160f, 0.007300000f, 0.008086507f, 0.008908720f, 0.009767680f, 0.01066443f, 0.01160000f, 0.01257317f, 0.01358272f, 0.01462968f, + 0.01571509f, 0.01684000f, 0.01800736f, 0.01921448f, 0.02045392f, 0.02171824f, 0.02300000f, 0.02429461f, 0.02561024f, 0.02695857f, 0.02835125f, 0.02980000f, 0.03131083f, + 0.03288368f, 0.03452112f, 0.03622571f, 0.03800000f, 0.03984667f, 0.04176800f, 0.04376600f, 0.04584267f, 0.04800000f, 0.05024368f, 0.05257304f, 0.05498056f, 0.05745872f, + 0.06000000f, 0.06260197f, 0.06527752f, 0.06804208f, 0.07091109f, 0.07390000f, 0.07701600f, 0.08026640f, 0.08366680f, 0.08723280f, 0.09098000f, 0.09491755f, 0.09904584f, + 0.1033674f, 0.1078846f, 0.1126000f, 0.1175320f, 0.1226744f, 0.1279928f, 0.1334528f, 0.1390200f, 0.1446764f, 0.1504693f, 0.1564619f, 0.1627177f, 0.1693000f, 0.1762431f, + 0.1835581f, 0.1912735f, 0.1994180f, 0.2080200f, 0.2171199f, 0.2267345f, 0.2368571f, 0.2474812f, 0.2586000f, 0.2701849f, 0.2822939f, 0.2950505f, 0.3085780f, 0.3230000f, + 0.3384021f, 0.3546858f, 0.3716986f, 0.3892875f, 0.4073000f, 0.4256299f, 0.4443096f, 0.4633944f, 0.4829395f, 0.5030000f, 0.5235693f, 0.5445120f, 0.5656900f, 0.5869653f, + 0.6082000f, 0.6293456f, 0.6503068f, 0.6708752f, 0.6908424f, 0.7100000f, 0.7281852f, 0.7454636f, 0.7619694f, 0.7778368f, 0.7932000f, 0.8081104f, 0.8224962f, 0.8363068f, + 0.8494916f, 0.8620000f, 0.8738108f, 0.8849624f, 0.8954936f, 0.9054432f, 0.9148501f, 0.9237348f, 0.9320924f, 0.9399226f, 0.9472252f, 0.9540000f, 0.9602561f, 0.9660074f, + 0.9712606f, 0.9760225f, 0.9803000f, 0.9840924f, 0.9874812f, 0.9903128f, 0.9928116f, 0.9949501f, 0.9967108f, 0.9980983f, 0.9991120f, 0.9997482f, 1.0000000f, 0.9998567f, + 0.9993046f, 0.9983255f, 0.9968987f, 0.9950000f, 0.9926005f, 0.9897426f, 0.9864444f, 0.9827241f, 0.9786000f, 0.9740837f, 0.9691712f, 0.9638568f, 0.9581349f, 0.9520000f, + 0.9454504f, 0.9384992f, 0.9311628f, 0.9234576f, 0.9154000f, 0.9070064f, 0.8982772f, 0.8892048f, 0.8797816f, 0.8700000f, 0.8598613f, 0.8493920f, 0.8386220f, 0.8275813f, + 0.8163000f, 0.8047947f, 0.7930820f, 0.7811920f, 0.7691547f, 0.7570000f, 0.7447541f, 0.7324224f, 0.7200036f, 0.7074965f, 0.6949000f, 0.6822192f, 0.6694716f, 0.6566744f, + 0.6438448f, 0.6310000f, 0.6181555f, 0.6053144f, 0.5924756f, 0.5796379f, 0.5668000f, 0.5539611f, 0.5411372f, 0.5283528f, 0.5156323f, 0.5030000f, 0.4904688f, 0.4780304f, + 0.4656776f, 0.4534032f, 0.4412000f, 0.4290800f, 0.4170360f, 0.4050320f, 0.3930320f, 0.3810000f, 0.3689184f, 0.3568272f, 0.3447768f, 0.3328176f, 0.3210000f, 0.3093381f, + 0.2978504f, 0.2865936f, 0.2756245f, 0.2650000f, 0.2547632f, 0.2448896f, 0.2353344f, 0.2260528f, 0.2170000f, 0.2081616f, 0.1995488f, 0.1911552f, 0.1829744f, 0.1750000f, + 0.1672235f, 0.1596464f, 0.1522776f, 0.1451259f, 0.1382000f, 0.1315003f, 0.1250248f, 0.1187792f, 0.1127691f, 0.1070000f, 0.1014762f, 0.09618864f, 0.09112296f, 0.08626485f, + 0.08160000f, 0.07712064f, 0.07282552f, 0.06871008f, 0.06476976f, 0.06100000f, 0.05739621f, 0.05395504f, 0.05067376f, 0.04754965f, 0.04458000f, 0.04175872f, 0.03908496f, + 0.03656384f, 0.03420048f, 0.03200000f, 0.02996261f, 0.02807664f, 0.02632936f, 0.02470805f, 0.02320000f, 0.02180077f, 0.02050112f, 0.01928108f, 0.01812069f, 0.01700000f, + 0.01590379f, 0.01483718f, 0.01381068f, 0.01283478f, 0.01192000f, 0.01106831f, 0.01027339f, 0.009533311f, 0.008846157f, 0.008210000f, 0.007623781f, 0.007085424f, 0.006591476f, + 0.006138485f, 0.005723000f, 0.005343059f, 0.004995796f, 0.004676404f, 0.004380075f, 0.004102000f, 0.003838453f, 0.003589099f, 0.003354219f, 0.003134093f, 0.002929000f, + 0.002738139f, 0.002559876f, 0.002393244f, 0.002237275f, 0.002091000f, 0.001953587f, 0.001824580f, 0.001703580f, 0.001590187f, 0.001484000f, 0.001384496f, 0.001291268f, + 0.001204092f, 0.001122744f, 0.001047000f, 0.0009765896f, 0.0009111088f, 0.0008501332f, 0.0007932384f, 0.0007400000f, 0.0006900827f, 0.0006433100f, 0.0005994960f, 0.0005584547f, + 0.0005200000f, 0.0004839136f, 0.0004500528f, 0.0004183452f, 0.0003887184f, 0.0003611000f, 0.0003353835f, 0.0003114404f, 0.0002891656f, 0.0002684539f, 0.0002492000f, + 0.0002313019f, 0.0002146856f, 0.0001992884f, 0.0001850475f, 0.0001719000f, 0.0001597781f, 0.0001486044f, 0.0001383016f, 0.0001287925f, 0.0001200000f, 0.0001118595f, + 0.0001043224f, 0.00009733560f, 0.00009084587f, 0.00008480000f, 0.00007914667f, 0.00007385800f, 0.00006891600f, 0.00006430267f, 0.00006000000f, 0.00005598187f, 0.00005222560f, + 0.00004871840f, 0.00004544747f, 0.00004240000f, 0.00003956104f, 0.00003691512f, 0.00003444868f, 0.00003214816f, 0.00003000000f, 0.00002799125f, 0.00002611356f, 0.00002436024f, + 0.00002272461f, 0.00002120000f, 0.00001977855f, 0.00001845285f, 0.00001721687f, 0.00001606459f, 0.00001499000f, 0.00001398728f, 0.00001305155f, 0.00001217818f, 0.00001136254f, + 0.00001060000f, 0.000009885877f, 0.000009217304f, 0.000008592362f, 0.000008009133f, 0.000007465700f, 0.000006959567f, 0.000006487995f, 0.000006048699f, 0.000005639396f, + 0.000005257800f, 0.000004901771f, 0.000004569720f, 0.000004260194f, 0.000003971739f, 0.000003702900f, 0.000003452163f, 0.000003218302f, 0.000003000300f, 0.000002797139f, + 0.000002607800f, 0.000002431220f, 0.000002266531f, 0.000002113013f, 0.000001969943f, 0.000001836600f, 0.000001712230f, 0.000001596228f, 0.000001488090f, 0.000001387314f, + 0.000001293400f, 0.000001205820f, 0.000001124143f, 0.000001048009f, 0.0000009770578f, 0.0000009109300f, 0.0000008492513f, 0.0000007917212f, 0.0000007380904f, 0.0000006881098f, + 0.0000006415300f, 0.0000005980895f, 0.0000005575746f, 0.0000005198080f, 0.0000004846123f, 0.0000004518100f}; + + ETX_GPU_DATA constexpr static const float kZ[WavelengthCount] = {0.0006061000f, 0.0006808792f, 0.0007651456f, 0.0008600124f, 0.0009665928f, 0.001086000f, 0.001220586f, + 0.001372729f, 0.001543579f, 0.001734286f, 0.001946000f, 0.002177777f, 0.002435809f, 0.002731953f, 0.003078064f, 0.003486000f, 0.003975227f, 0.004540880f, 0.005158320f, + 0.005802907f, 0.006450001f, 0.007083216f, 0.007745488f, 0.008501152f, 0.009414544f, 0.01054999f, 0.01196580f, 0.01365587f, 0.01558805f, 0.01773015f, 0.02005001f, 0.02251136f, + 0.02520288f, 0.02827972f, 0.03189704f, 0.03621000f, 0.04143771f, 0.04750372f, 0.05411988f, 0.06099803f, 0.06785001f, 0.07448632f, 0.08136156f, 0.08915364f, 0.09854048f, + 0.1102000f, 0.1246133f, 0.1417017f, 0.1613035f, 0.1832568f, 0.2074000f, 0.2336921f, 0.2626114f, 0.2947746f, 0.3307985f, 0.3713000f, 0.4162091f, 0.4654642f, 0.5196948f, + 0.5795303f, 0.6456000f, 0.7184838f, 0.7967133f, 0.8778459f, 0.9594390f, 1.0390501f, 1.1153673f, 1.1884971f, 1.2581233f, 1.3239296f, 1.3856000f, 1.4426352f, 1.4948035f, + 1.5421903f, 1.5848807f, 1.6229600f, 1.6564048f, 1.6852959f, 1.7098745f, 1.7303821f, 1.7470600f, 1.7600446f, 1.7696233f, 1.7762637f, 1.7804334f, 1.7826000f, 1.7829682f, + 1.7816998f, 1.7791982f, 1.7758671f, 1.7721100f, 1.7682589f, 1.7640390f, 1.7589438f, 1.7524663f, 1.7441000f, 1.7335595f, 1.7208581f, 1.7059369f, 1.6887372f, 1.6692000f, + 1.6475287f, 1.6234127f, 1.5960223f, 1.5645280f, 1.5281000f, 1.4861114f, 1.4395215f, 1.3898799f, 1.3387362f, 1.2876400f, 1.2374223f, 1.1878243f, 1.1387611f, 1.0901480f, + 1.0419000f, 0.9941976f, 0.9473473f, 0.9014531f, 0.8566193f, 0.8129501f, 0.7705173f, 0.7294448f, 0.6899136f, 0.6521049f, 0.6162000f, 0.5823286f, 0.5504162f, 0.5203376f, + 0.4919673f, 0.4651800f, 0.4399246f, 0.4161836f, 0.3938822f, 0.3729459f, 0.3533000f, 0.3348578f, 0.3175521f, 0.3013375f, 0.2861686f, 0.2720000f, 0.2588171f, 0.2464838f, + 0.2347718f, 0.2234533f, 0.2123000f, 0.2011692f, 0.1901196f, 0.1792254f, 0.1685608f, 0.1582000f, 0.1481383f, 0.1383758f, 0.1289942f, 0.1200751f, 0.1117000f, 0.1039048f, + 0.09666748f, 0.08998272f, 0.08384531f, 0.07824999f, 0.07320899f, 0.06867816f, 0.06456784f, 0.06078835f, 0.05725001f, 0.05390435f, 0.05074664f, 0.04775276f, 0.04489859f, + 0.04216000f, 0.03950728f, 0.03693564f, 0.03445836f, 0.03208872f, 0.02984000f, 0.02771181f, 0.02569444f, 0.02378716f, 0.02198925f, 0.02030000f, 0.01871805f, 0.01724036f, + 0.01586364f, 0.01458461f, 0.01340000f, 0.01230723f, 0.01130188f, 0.01037792f, 0.009529306f, 0.008749999f, 0.008035200f, 0.007381600f, 0.006785400f, 0.006242800f, 0.005749999f, + 0.005303600f, 0.004899800f, 0.004534200f, 0.004202400f, 0.003900000f, 0.003623200f, 0.003370600f, 0.003141400f, 0.002934800f, 0.002749999f, 0.002585200f, 0.002438600f, + 0.002309400f, 0.002196800f, 0.002100000f, 0.002017733f, 0.001948200f, 0.001889800f, 0.001840933f, 0.001800000f, 0.001766267f, 0.001737800f, 0.001711200f, 0.001683067f, + 0.001650001f, 0.001610133f, 0.001564400f, 0.001513600f, 0.001458533f, 0.001400000f, 0.001336667f, 0.001270000f, 0.001205000f, 0.001146667f, 0.001100000f, 0.001068800f, + 0.001049400f, 0.001035600f, 0.001021200f, 0.001000000f, 0.0009686400f, 0.0009299200f, 0.0008868800f, 0.0008425600f, 0.0008000000f, 0.0007609600f, 0.0007236800f, 0.0006859200f, + 0.0006454400f, 0.0006000000f, 0.0005478667f, 0.0004916000f, 0.0004354000f, 0.0003834667f, 0.0003400000f, 0.0003072533f, 0.0002831600f, 0.0002654400f, 0.0002518133f, + 0.0002400000f, 0.0002295467f, 0.0002206400f, 0.0002119600f, 0.0002021867f, 0.0001900000f, 0.0001742133f, 0.0001556400f, 0.0001359600f, 0.0001168533f, 0.0001000000f, + 0.00008613333f, 0.00007460000f, 0.00006500000f, 0.00005693333f, 0.00004999999f, 0.00004416000f, 0.00003948000f, 0.00003572000f, 0.00003264000f, 0.00003000000f, 0.00002765333f, + 0.00002556000f, 0.00002364000f, 0.00002181333f, 0.00002000000f, 0.00001813333f, 0.00001620000f, 0.00001420000f, 0.00001213333f, 0.00001000000f, 0.000007733333f, + 0.000005400000f, 0.000003200000f, 0.000001333333f}; + + return {kX[i], kY[i], kZ[i]}; +} + +ETX_GPU_CODE float3 xyz_to_rgb(const float3& xyz) { + return { + 3.2404790f * xyz.x - 1.537150f * xyz.y - 0.498535f * xyz.z, + -0.969256f * xyz.x + 1.875991f * xyz.y + 0.041556f * xyz.z, + 0.0556480f * xyz.x - 0.204043f * xyz.y + 1.057311f * xyz.z, + }; +} + +ETX_GPU_CODE float3 rgb_to_xyz(const float3& rgb) { + return { + 0.412453f * rgb.x + 0.357580f * rgb.y + 0.180423f * rgb.z, + 0.212671f * rgb.x + 0.715160f * rgb.y + 0.072169f * rgb.z, + 0.019334f * rgb.x + 0.119193f * rgb.y + 0.950227f * rgb.z, + }; +} + +ETX_GPU_CODE float4 rgb_to_xyz4(const float3& rgb) { + return { + 0.412453f * rgb.x + 0.357580f * rgb.y + 0.180423f * rgb.z, + 0.212671f * rgb.x + 0.715160f * rgb.y + 0.072169f * rgb.z, + 0.019334f * rgb.x + 0.119193f * rgb.y + 0.950227f * rgb.z, + 1.0f, + }; +} + +ETX_GPU_CODE float black_body_radiation_maximum_wavelength(float t_kelvins) { + return 2.8977729e+6f / t_kelvins; +} + +ETX_GPU_CODE float black_body_radiation(float wavelength_nm, float t_kelvins) { + ETX_ASSERT(t_kelvins > 0); + + // wavelength (in nm) is scaled to reduce floating point errors, constants are scaled correspondingly + constexpr float wavelengt_scale = 1.0f / 1000.0f; + constexpr float Lc1 = 3.7417712e+5f; // 2 * pi * h * c * c * (10^21 - from wavelength scale) + constexpr float Lc2 = 1.4387752e+4f; // h * c / k * (10^-6 - from wavelength scale) + + wavelength_nm *= wavelengt_scale; + float wl5 = wavelength_nm * (wavelength_nm * wavelength_nm) * (wavelength_nm * wavelength_nm); + + float e0 = std::exp(Lc2 / (wavelength_nm * t_kelvins)); + ETX_ASSERT(std::isnan(e0) == false); + + float d = wl5 * (e0 - 1.0f); + ETX_ASSERT(std::isnan(d) == false); + + return std::isinf(d) ? 0.0f : (Lc1 / d); +} + +ETX_GPU_CODE SpectralQuery sample(float rnd) { + if constexpr (kSpectralRendering) { + return SpectralQuery{kShortestWavelength + rnd * kWavelengthCount}; + } else { + return SpectralQuery{kUndefinedWavelength}; + } +} + +ETX_GPU_CODE constexpr float sample_pdf() { + if constexpr (kSpectralRendering) { + return 1.0f / kWavelengthCount; + } else { + return 1.0f; + } +} + +} // namespace spectrum + +struct alignas(16) SpectralResponse { + float3 components = {}; + float wavelength = 0.0f; + + SpectralResponse() = default; + + ETX_GPU_CODE SpectralResponse(float w, const float3& value) + : components(value) + , wavelength(w) { + } + + ETX_GPU_CODE SpectralResponse(float w, float v) + : components{v, v, v} + , wavelength(w) { + } + + ETX_GPU_CODE float3 to_xyz() const { + if constexpr (spectrum::kSpectralRendering) { + if ((wavelength < spectrum::kShortestWavelength) || (wavelength > spectrum::kLongestWavelength)) { + return {}; + } + + float w = floor(wavelength); + float dw = wavelength - w; + uint64_t i = static_cast(w - spectrum::kShortestWavelength); + uint64_t j = min(i + 1, spectrum::WavelengthCount - 1llu); + float3 xyz0 = spectrum::spectral_xyz(i); + float3 xyz1 = spectrum::spectral_xyz(j); + return lerp(xyz0, xyz1, dw) * (components.x / spectrum::kYIntegral); + } else { + return spectrum::rgb_to_xyz({components.x, components.y, components.z}); + } + } + + ETX_GPU_CODE float maximum() const { + if constexpr (spectrum::kSpectralRendering) { + return components.x; + } else { + return max(components.x, max(components.y, components.z)); + } + } + + ETX_GPU_CODE float monochromatic() const { + if constexpr (spectrum::kSpectralRendering) { + return components.x; + } else { + return 0.2627f * components.x + 0.678f * components.y + 0.0593f * components.z; + } + } + + ETX_GPU_CODE float average() const { + if constexpr (spectrum::kSpectralRendering) { + return components.x; + } else { + return (components.x + components.y + components.z) / 3.0f; + } + } + + ETX_GPU_CODE bool valid() const { + return true; + // TODO : fix + // return valid_value(components); + } + + ETX_GPU_CODE bool is_zero() const { + return (components.x <= kEpsilon) && (components.y <= kEpsilon) && (components.z <= kEpsilon); + } + + ETX_GPU_CODE SpectralResponse& operator*=(const SpectralResponse& other) { + ETX_ASSERT(wavelength == other.wavelength); + components *= other.components; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator/=(const SpectralResponse& other) { + ETX_ASSERT(wavelength == other.wavelength); + components /= other.components; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator+=(const SpectralResponse& other) { + ETX_ASSERT(wavelength == other.wavelength); + components += other.components; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator-=(const SpectralResponse& other) { + ETX_ASSERT(wavelength == other.wavelength); + components -= other.components; + return *this; + } + ETX_GPU_CODE SpectralResponse operator*(const SpectralResponse& other) const { + ETX_ASSERT(wavelength == other.wavelength); + return {wavelength, components * other.components}; + } + ETX_GPU_CODE SpectralResponse operator/(const SpectralResponse& other) const { + ETX_ASSERT(wavelength == other.wavelength); + return {wavelength, components / other.components}; + } + ETX_GPU_CODE SpectralResponse operator+(const SpectralResponse& other) const { + ETX_ASSERT(wavelength == other.wavelength); + return {wavelength, components + other.components}; + } + ETX_GPU_CODE SpectralResponse operator-(const SpectralResponse& other) const { + ETX_ASSERT(wavelength == other.wavelength); + return {wavelength, components - other.components}; + } + ETX_GPU_CODE SpectralResponse& operator*=(float other) { + components *= other; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator/=(float other) { + components /= other; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator+=(float other) { + components += other; + return *this; + } + ETX_GPU_CODE SpectralResponse& operator-=(float other) { + components -= other; + return *this; + } + ETX_GPU_CODE SpectralResponse operator*(float other) const { + return {wavelength, components * other}; + } + ETX_GPU_CODE SpectralResponse operator/(float other) const { + return {wavelength, components / other}; + } + ETX_GPU_CODE SpectralResponse operator+(float other) const { + return {wavelength, components + other}; + } + ETX_GPU_CODE SpectralResponse operator-(float other) const { + return {wavelength, components - other}; + } +}; + +ETX_GPU_CODE bool valid_value(const SpectralResponse& v) { + return v.valid(); +} +ETX_GPU_CODE SpectralResponse operator*(float other, const SpectralResponse& s) { + return s * other; +} +ETX_GPU_CODE SpectralResponse operator/(float other, const SpectralResponse& s) { + return {s.wavelength, other / s.components}; +} +ETX_GPU_CODE SpectralResponse operator+(float other, const SpectralResponse& s) { + return s + other; +} +ETX_GPU_CODE SpectralResponse operator-(float other, const SpectralResponse& s) { + return {s.wavelength, other - s.components}; +} +ETX_GPU_CODE SpectralResponse exp(const SpectralResponse& v) { + return {v.wavelength, exp(v.components)}; +} +ETX_GPU_CODE SpectralResponse sqrt(const SpectralResponse& v) { + return {v.wavelength, sqrt(v.components)}; +} +ETX_GPU_CODE SpectralResponse cos(const SpectralResponse& v) { + return {v.wavelength, cos(v.components)}; +} +ETX_GPU_CODE SpectralResponse abs(const SpectralResponse& v) { + return {v.wavelength, abs(v.components)}; +} +ETX_GPU_CODE void print_value(const char* name, const char* tag, const SpectralResponse& v) { + printf("%s : %s (%f : %f %f %f)\n", name, tag, v.wavelength, v.components.x, v.components.y, v.components.z); +} + +struct alignas(16) SpectralDistribution { + enum Class { + Reflectance, + Illuminant, + }; + + struct { + float wavelength = 0.0f; + float power = 0.0f; + } entries[spectrum::WavelengthCount] = {}; + + uint64_t count = 0; + + public: // device + ETX_GPU_CODE SpectralResponse query(const SpectralQuery q) const { + if constexpr (spectrum::kSpectralRendering) { + if ((q.wavelength < spectrum::kShortestWavelength) || (q.wavelength > spectrum::kLongestWavelength)) { + return {q.wavelength, -1.0f}; + } + + uint64_t i = lower_bound(q.wavelength); + if (i >= count) { + return {q.wavelength, 0.0f}; + } + + if ((i == 0) && (q.wavelength < entries[i].wavelength)) { + return {q.wavelength, entries[i].power}; + } + + if (i + 1 == count) { + return {q.wavelength, entries[i].power}; + } + + uint64_t j = min(i + 1, count - 1); + float t = (q.wavelength - entries[i].wavelength) / (entries[j].wavelength - entries[i].wavelength); + float p = lerp(entries[i].power, entries[j].power, t); + return SpectralResponse{q.wavelength, p}; + } else { + return SpectralResponse{q.wavelength, {entries[0].power, entries[1].power, entries[2].power}}; + } + } + + ETX_GPU_CODE SpectralResponse operator()(const SpectralQuery q) const { + return query(q); + } + + ETX_GPU_CODE float random_entry_power(float rnd) const { + uint64_t i = static_cast(rnd * float(count)); + return entries[i].power; + } + + ETX_GPU_CODE uint64_t lower_bound(float wavelength) const { + uint64_t b = 0; + uint64_t e = count; + do { + uint64_t m = b + (e - b) / 2; + if (entries[m].wavelength > wavelength) { + e = m; + } else { + b = m; + } + } while ((e - b) > 1); + return b; + } + + ETX_GPU_CODE void make_constant(float power) { + for (uint64_t i = 0; i < count; ++i) { + entries[i].power = power; + } + } + + ETX_GPU_CODE bool empty() const { + return count == 0; + } + + public: + SpectralDistribution& operator*=(float other) { + for (uint64_t i = 0; i < count; ++i) { + entries[i].power *= other; + } + return *this; + } + SpectralDistribution& operator/=(float other) { + for (uint64_t i = 0; i < count; ++i) { + entries[i].power /= other; + } + return *this; + } + SpectralDistribution& operator+=(float other) { + for (uint64_t i = 0; i < count; ++i) { + entries[i].power += other; + } + return *this; + } + SpectralDistribution& operator-=(float other) { + for (uint64_t i = 0; i < count; ++i) { + entries[i].power -= other; + } + return *this; + } + SpectralDistribution operator*(float other) const { + SpectralDistribution result = *this; + result *= other; + return result; + } + SpectralDistribution operator/(float other) const { + SpectralDistribution result = *this; + result /= other; + return result; + } + SpectralDistribution operator+(float other) const { + SpectralDistribution result = *this; + result += other; + return result; + } + SpectralDistribution operator-(float other) const { + SpectralDistribution result = *this; + result -= other; + return result; + } + + public: + float3 integrate_to_xyz() const; + float3 to_xyz() const; + + float total_power() const; + float maximum_power() const; + + bool valid() const; + bool is_zero() const; + + static SpectralDistribution from_constant(float value); + static SpectralDistribution from_samples(const float wavelengths[], const float power[], uint64_t count); + static SpectralDistribution from_samples(const float wavelengths[], const float power[], uint64_t count, Class cls, struct Spectrums*); + static SpectralDistribution from_samples(const float2 wavelengths_power[], uint64_t count, Class cls, struct Spectrums*); + static SpectralDistribution from_black_body(float temperature, Class cls, struct Spectrums*); + static void load_from_file(const char* file_name, SpectralDistribution& values0, SpectralDistribution* values1, Class cls, struct Spectrums*); +}; + +struct RefractiveIndex { + SpectralDistribution eta; + SpectralDistribution k; + + struct Sample { + float wavelength = 0.0f; + SpectralResponse eta; + SpectralResponse k; + + ETX_GPU_CODE Sample operator/(const Sample& other) const { + return {wavelength, eta / other.eta, k / other.eta}; + } + }; + + ETX_GPU_CODE Sample at(SpectralQuery q) const { + Sample result = {q.wavelength}; + result.eta = eta.empty() ? SpectralResponse(q.wavelength, 1.0f) : eta(q); + result.k = k.empty() ? SpectralResponse(q.wavelength, 0.0f) : k(q); + return result; + } + + ETX_GPU_CODE Sample operator()(const SpectralQuery q) const { + return at(q); + } + + void make_constant(float a_eta, float a_k) { + eta.make_constant(a_eta); + k.make_constant(a_k); + } +}; + +namespace rgb { +enum Color : uint32_t { + Red, + Green, + Blue, + Yellow, + Magenta, + Cyan, + White, + Count, +}; + +enum : uint32_t { + SampleCount = 32u, +}; + +struct SpectrumSet { + using ValueSet = float[SampleCount]; + ValueSet values[Color::Count] = {}; +}; +} // namespace rgb + +struct alignas(16) Spectrums { + RefractiveIndex thinfilm = {}; + RefractiveIndex conductor = {}; + RefractiveIndex dielectric = {}; + rgb::SpectrumSet rgb_reflection = {}; + rgb::SpectrumSet rgb_illuminant = {}; +}; + +namespace rgb { + +ETX_GPU_CODE void compute_weights(const float3& rgb, float weights[Color::Count]) { + if ((rgb.x < rgb.y) && (rgb.x < rgb.z)) { + weights[Color::White] = rgb.x; + if (rgb.y < rgb.z) { + weights[Color::Cyan] = (rgb.y - rgb.x); + weights[Color::Blue] = (rgb.z - rgb.y); + } else { + weights[Color::Cyan] = (rgb.z - rgb.x); + weights[Color::Green] = (rgb.y - rgb.z); + } + } else if ((rgb.y < rgb.x) && (rgb.y < rgb.z)) { + weights[Color::White] = rgb.y; + if (rgb.x < rgb.z) { + weights[Color::Magenta] = (rgb.x - rgb.y); + weights[Color::Blue] = (rgb.z - rgb.x); + } else { + weights[Color::Magenta] = (rgb.z - rgb.y); + weights[Color::Red] = (rgb.x - rgb.z); + } + } else { + weights[Color::White] = rgb.z; + if (rgb.x < rgb.y) { + weights[Color::Yellow] = (rgb.x - rgb.z); + weights[Color::Green] = (rgb.y - rgb.x); + } else { + weights[Color::Yellow] = (rgb.y - rgb.z); + weights[Color::Red] = (rgb.x - rgb.y); + } + } +} + +ETX_GPU_CODE SpectralDistribution make_spd(const float3& rgb, const SpectrumSet& spectrums) { + SpectralDistribution r; + if constexpr (spectrum::kSpectralRendering == false) { + r.count = 3; + r.entries[0] = {spectrum::kUndefinedWavelength, rgb.x}; + r.entries[1] = {spectrum::kUndefinedWavelength, rgb.y}; + r.entries[2] = {spectrum::kUndefinedWavelength, rgb.z}; + } else { + constexpr float wavelengths[SampleCount] = {380.000000f, 390.967743f, 401.935486f, 412.903229f, 423.870972f, 434.838715f, 445.806458f, 456.774200f, 467.741943f, 478.709686f, + 489.677429f, 500.645172f, 511.612915f, 522.580627f, 533.548340f, 544.516052f, 555.483765f, 566.451477f, 577.419189f, 588.386902f, 599.354614f, 610.322327f, 621.290039f, + 632.257751f, 643.225464f, 654.193176f, 665.160889f, 676.128601f, 687.096313f, 698.064026f, 709.031738f, 720.000000f}; + + float weights[Color::Count] = {}; + compute_weights(rgb, weights); + + r.count = SampleCount; + for (uint32_t i = 0; i < SampleCount; ++i) { + r.entries[i].wavelength = wavelengths[i]; + r.entries[i].power = weights[0] * spectrums.values[0][i] + // + weights[1] * spectrums.values[1][i] + // + weights[2] * spectrums.values[2][i] + // + weights[3] * spectrums.values[3][i] + // + weights[4] * spectrums.values[4][i] + // + weights[5] * spectrums.values[5][i] + // + weights[6] * spectrums.values[6][i]; + } + for (uint64_t i = 0; i < r.count; ++i) { + r.entries[i].power = max(0.0f, r.entries[i].power); + } + } + return r; +} + +ETX_GPU_CODE SpectralDistribution make_reflectance_spd(const float3& rgb, const Spectrums* spectrums) { + return make_spd(rgb, spectrums->rgb_reflection); +} + +ETX_GPU_CODE SpectralDistribution make_illuminant_spd(const float3& rgb, const Spectrums* spectrums) { + return make_spd(rgb, spectrums->rgb_illuminant); +} + +ETX_GPU_CODE SpectralResponse query_spd(const SpectralQuery spect, const float3& rgb, const SpectrumSet& spectrums) { + if constexpr (spectrum::kSpectralRendering == false) { + return SpectralResponse(spect.wavelength, rgb); + } else { + constexpr float wavelengths[SampleCount] = {380.000000f, 390.967743f, 401.935486f, 412.903229f, 423.870972f, 434.838715f, 445.806458f, 456.774200f, 467.741943f, 478.709686f, + 489.677429f, 500.645172f, 511.612915f, 522.580627f, 533.548340f, 544.516052f, 555.483765f, 566.451477f, 577.419189f, 588.386902f, 599.354614f, 610.322327f, 621.290039f, + 632.257751f, 643.225464f, 654.193176f, 665.160889f, 676.128601f, 687.096313f, 698.064026f, 709.031738f, 720.000000f}; + + uint32_t i = 0; + uint32_t e = SampleCount; + do { + uint32_t m = i + (e - i) / 2; + if (wavelengths[m] > spect.wavelength) { + e = m; + } else { + i = m; + } + } while ((e - i) > 1); + + if (i >= SampleCount) { + return {spect.wavelength, 0.0f}; + } + + uint64_t j = min(i + 1llu, SampleCount - 1llu); + + float t; + if ((i == 0) && (spect.wavelength < wavelengths[0])) { + t = 0.0f; + } else if (i + 1 == SampleCount) { + t = 1.0f; + } else { + t = (spect.wavelength - wavelengths[i]) / (wavelengths[j] - wavelengths[i]); + } + + float weights[Color::Count] = {}; + compute_weights(rgb, weights); + + float p = weights[0] * lerp(spectrums.values[0][i], spectrums.values[0][j], t) + // + weights[1] * lerp(spectrums.values[1][i], spectrums.values[1][j], t) + // + weights[2] * lerp(spectrums.values[2][i], spectrums.values[2][j], t) + // + weights[3] * lerp(spectrums.values[3][i], spectrums.values[3][j], t) + // + weights[4] * lerp(spectrums.values[4][i], spectrums.values[4][j], t) + // + weights[5] * lerp(spectrums.values[5][i], spectrums.values[5][j], t) + // + weights[6] * lerp(spectrums.values[6][i], spectrums.values[6][j], t); + + return SpectralResponse{spect.wavelength, max(0.0f, p)}; + } +} + +void init_spectrums(Spectrums&); + +} // namespace rgb + +} // namespace etx diff --git a/sources/etx/rt/integrators/integrator.hxx b/sources/etx/rt/integrators/integrator.hxx new file mode 100644 index 0000000..387217c --- /dev/null +++ b/sources/etx/rt/integrators/integrator.hxx @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +#include + +namespace etx { + +struct Integrator { + enum class State { + Stopped, + Preview, + Running, + WaitingForCompletion, + }; + + Integrator(Raytracing& r) + : rt(r) { + } + + virtual ~Integrator() = default; + + virtual const char* name() { + return "Basic Integrator"; + } + + virtual Options options() const { + Options result = {}; + result.set("desc", "No options available"); + return result; + } + + virtual void set_output_size(const uint2&) { + } + + virtual State state() const { + return current_state.load(); + } + + virtual void preview() { + } + + virtual void run(const Options&) { + } + + virtual void update() { + } + + virtual void stop(bool /* wait for completion */) { + } + + virtual float4* get_updated_camera_image() { + return nullptr; + } + + virtual float4* get_updated_light_image() { + return nullptr; + } + + virtual const char* status() const { + return "Test Integrator"; + } + + virtual bool can_run() const { + return rt.has_scene(); + } + + protected: + Raytracing& rt; + std::atomic current_state = {State::Stopped}; +}; + +} // namespace etx diff --git a/sources/etx/rt/integrators/path_tracing.cxx b/sources/etx/rt/integrators/path_tracing.cxx new file mode 100644 index 0000000..5160d9a --- /dev/null +++ b/sources/etx/rt/integrators/path_tracing.cxx @@ -0,0 +1,398 @@ +#include +#include +#include +#include +#include +#include + +namespace etx { + +struct CPUPathTracingImpl : public Task { + Raytracing& rt; + std::vector camera_image; + std::vector samplers; + uint2 film_dimensions = {}; + uint2 current_dimensions = {}; + char status[2048] = {}; + + TimeMeasure total_time = {}; + TimeMeasure iteration_time = {}; + Task::Handle current_task = {}; + uint32_t iteration = 0u; + uint32_t max_iterations = ~0u; + uint32_t max_depth = ~0u; + uint32_t rr_start = ~0u; + uint32_t preview_scale = 1u; + std::atomic* state = nullptr; + + CPUPathTracingImpl(Raytracing& a_rt, std::atomic* st) + : rt(a_rt) + , samplers(rt.scheduler().max_thread_count()) + , state(st) { + } + + void start() { + iteration = 0; + film_dimensions = {rt.scene().camera.image_size.x, rt.scene().camera.image_size.y}; + snprintf(status, sizeof(status), "[%u] %s ...", iteration, (state->load() == Integrator::State::Running ? "Running" : "Preview")); + + preview_scale = (state->load() == Integrator::State::Running) ? 1u : max(1u, uint32_t(exp2(3.0f - iteration))); + current_dimensions = film_dimensions / preview_scale; + + total_time = {}; + iteration_time = {}; + current_task = rt.scheduler().schedule(this, current_dimensions.x * current_dimensions.y); + } + + void execute_range(uint32_t begin, uint32_t end, uint32_t thread_id) override { + auto& smp = samplers[thread_id]; + auto mode = state->load(); + if (mode == Integrator::State::Preview) { + for (uint32_t i = begin; (state->load() != Integrator::State::Stopped) && (i < end); ++i) { + uint32_t x = i % current_dimensions.x; + uint32_t y = i / current_dimensions.x; + float4 xyz = {preview_pixel(smp, x, y), 1.0f}; + + for (uint32_t ay = 0; ay < preview_scale; ++ay) { + for (uint32_t ax = 0; ax < preview_scale; ++ax) { + uint32_t rx = x * preview_scale + ax; + uint32_t ry = y * preview_scale + ay; + uint32_t j = rx + (film_dimensions.y - 1 - ry) * film_dimensions.x; + camera_image[j] = (preview_scale > 1) ? xyz : lerp(xyz, camera_image[j], float(iteration) / (float(iteration + 1))); + } + } + } + } else { + for (uint32_t i = begin; (state->load() != Integrator::State::Stopped) && (i < end); ++i) { + uint32_t x = i % film_dimensions.x; + uint32_t y = i / film_dimensions.x; + float4 xyz = {trace_pixel(smp, x, y), 1.0f}; + ETX_VALIDATE(xyz); + uint32_t j = x + (film_dimensions.y - 1 - y) * film_dimensions.x; + camera_image[j] = (iteration == 0) ? xyz : lerp(xyz, camera_image[j], float(iteration) / (float(iteration + 1))); + } + } + } + + float3 trace_pixel(RNDSampler& smp, uint32_t x, uint32_t y) { + auto& scene = rt.scene(); + auto spect = spectrum::sample(smp.next()); + SpectralResponse result = {spect.wavelength, 0.0f}; + SpectralResponse throughput = {spect.wavelength, 1.0f}; + + uint32_t path_length = 1; + uint32_t medium_index = scene.camera_medium_index; + + float eta = 1.0f; + float sampled_bsdf_pdf = 0.0f; + bool sampled_delta_bsdf = false; + + Intersection intersection = {}; + Medium::Sample medium_sample = {}; + auto ray = generate_ray(smp, rt.scene(), get_jittered_uv(smp, {x, y}, current_dimensions)); + while ((state->load() != Integrator::State::Stopped) && (path_length <= max_depth)) { + bool found_intersection = rt.trace(ray, intersection, smp); + + if (medium_index != kInvalidIndex) { + medium_sample = scene.mediums[medium_index].sample(spect, smp, ray.o, ray.d, found_intersection ? intersection.t : std::numeric_limits::max()); + throughput *= medium_sample.weight; + ETX_VALIDATE(throughput); + } else { + medium_sample.sampled_medium = 0; + } + + if (medium_sample.sampled_medium) { + const auto& medium = scene.mediums[medium_index]; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * direct light sampling from medium + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + if (path_length + 1 <= max_depth) { + auto emitter_sample = sample_emitter(spect, smp, medium_sample.pos, scene); + if (emitter_sample.pdf_dir > 0) { + auto tr = transmittance(spect, smp, medium_sample.pos, emitter_sample.origin, medium_index); + float phase_function = medium.phase_function(spect, medium_sample.pos, ray.d, emitter_sample.direction); + auto weight = emitter_sample.is_delta ? 1.0f : power_heuristic(emitter_sample.pdf_dir * emitter_sample.pdf_sample, phase_function); + result += throughput * emitter_sample.value * tr * (phase_function * weight / (emitter_sample.pdf_dir * emitter_sample.pdf_sample)); + ETX_VALIDATE(result); + } + } + + float3 w_o = medium.sample_phase_function(spect, smp, medium_sample.pos, ray.d); + sampled_bsdf_pdf = medium.phase_function(spect, medium_sample.pos, ray.d, w_o); + sampled_delta_bsdf = false; + + ray.o = medium_sample.pos; + ray.d = w_o; + + } else if (found_intersection) { + const auto& tri = scene.triangles[intersection.triangle_index]; + const auto& mat = scene.materials[tri.material_index]; + + if (mat.cls == Material::Class::Boundary) { + medium_index = (dot(intersection.nrm, ray.d) < 0.0f) ? mat.int_medium : mat.ext_medium; + ray.o = shading_pos(scene.vertices, tri, intersection.barycentric, ray.d); + continue; + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * direct light sampling + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + if (path_length + 1 <= max_depth) { + auto emitter_sample = sample_emitter(spect, smp, intersection.pos, scene); + if (emitter_sample.pdf_dir > 0) { + BSDFEval bsdf_eval = bsdf::evaluate({spect, medium_index, mat, PathSource::Camera, intersection, ray.d, emitter_sample.direction}, scene); + if (bsdf_eval.valid()) { + auto pos = shading_pos(scene.vertices, tri, intersection.barycentric, emitter_sample.direction); + auto tr = transmittance(spect, smp, pos, emitter_sample.origin, medium_index); + auto weight = emitter_sample.is_delta ? 1.0f : power_heuristic(emitter_sample.pdf_dir * emitter_sample.pdf_sample, bsdf_eval.pdf); + result += throughput * bsdf_eval.bsdf * emitter_sample.value * tr * (weight / (emitter_sample.pdf_dir * emitter_sample.pdf_sample)); + ETX_VALIDATE(result); + } + } + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * directly visible emitters + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + if (tri.emitter_index != kInvalidIndex) { + const auto& emitter = scene.emitters[tri.emitter_index]; + float pdf_emitter_area = 0.0f; + float pdf_emitter_dir = 0.0f; + float pdf_emitter_dir_out = 0.0f; + auto e = + emitter_evaluate_in_local(emitter, spect, intersection.tex, ray.o, intersection.pos, pdf_emitter_area, pdf_emitter_dir, pdf_emitter_dir_out, scene, (path_length == 0)); + if (pdf_emitter_dir > 0.0f) { + auto tr = transmittance(spect, smp, ray.o, intersection.pos, medium_index); + float pdf_emitter_discrete = emitter_discrete_pdf(emitter, scene.emitters_distribution); + auto weight = ((path_length == 1) || sampled_delta_bsdf) ? 1.0f : power_heuristic(sampled_bsdf_pdf, pdf_emitter_discrete * pdf_emitter_dir); + result += throughput * e * tr * weight; + ETX_VALIDATE(result); + } + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * bsdf sampling + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + auto bsdf_sample = bsdf::sample({spect, medium_index, mat, PathSource::Camera, intersection, ray.d, {}}, scene, smp); + if (bsdf_sample.valid() == false) { + break; + } + + if (bsdf_sample.properties & BSDFSample::MediumChanged) { + medium_index = bsdf_sample.medium_index; + } + + ETX_VALIDATE(throughput); + throughput *= bsdf_sample.weight; + ETX_VALIDATE(throughput); + + if (throughput.is_zero()) { + break; + } + + sampled_bsdf_pdf = bsdf_sample.pdf; + sampled_delta_bsdf = bsdf_sample.is_delta(); + eta *= bsdf_sample.eta; + + ray.d = bsdf_sample.w_o; + ray.o = shading_pos(scene.vertices, tri, intersection.barycentric, bsdf_sample.w_o); + + } else { + for (uint32_t ie = 0; ie < scene.environment_emitters.count; ++ie) { + const auto& emitter = scene.emitters[scene.environment_emitters.emitters[ie]]; + float pdf_emitter_area = 0.0f; + float pdf_emitter_dir = 0.0f; + float pdf_emitter_dir_out = 0.0f; + auto e = emitter_evaluate_in_dist(emitter, spect, ray.d, pdf_emitter_area, pdf_emitter_dir, pdf_emitter_dir_out, scene); + ETX_VALIDATE(e); + if ((pdf_emitter_dir > 0) && (e.is_zero() == false)) { + float pdf_emitter_discrete = emitter_discrete_pdf(emitter, scene.emitters_distribution); + auto weight = ((path_length == 1) || sampled_delta_bsdf) ? 1.0f : power_heuristic(sampled_bsdf_pdf, pdf_emitter_discrete * pdf_emitter_dir); + result += throughput * e * weight; + ETX_VALIDATE(result); + } + } + break; + } + + if ((path_length >= rr_start) && (apply_rr(eta, smp.next(), throughput) == false)) { + break; + } + + ++path_length; + } + + ETX_VALIDATE(result); + result /= spectrum::sample_pdf(); + ETX_VALIDATE(result); + + return result.to_xyz(); + } + + float3 preview_pixel(RNDSampler& smp, uint32_t x, uint32_t y) { + auto ray = generate_ray(smp, rt.scene(), get_jittered_uv(smp, {x, y}, current_dimensions)); + + float3 xyz = {0.1f, 0.1f, 0.1f}; + + Intersection intersection; + if (rt.trace(ray, intersection, smp)) { + float d = fabsf(dot(intersection.nrm, ray.d)); + xyz = spectrum::rgb_to_xyz({d, d, d}); + } + return xyz; + } + + SpectralResponse transmittance(SpectralQuery spect, Sampler& smp, const float3& p0, const float3& p1, uint32_t medium_index) { + const auto& scene = rt.scene(); + float3 w_o = p1 - p0; + float max_t = length(w_o); + w_o /= max_t; + max_t -= kRayEpsilon; + + float3 origin = p0; + + SpectralResponse result = {spect.wavelength, 1.0f}; + + for (;;) { + Intersection intersection; + if (rt.trace({origin, w_o, kRayEpsilon, max_t}, intersection, smp) == false) { + if (medium_index != kInvalidIndex) { + result *= scene.mediums[medium_index].transmittance(spect, smp, origin, w_o, max_t); + } + break; + } + + const auto& tri = scene.triangles[intersection.triangle_index]; + const auto& mat = scene.materials[tri.material_index]; + if (mat.cls != Material::Class::Boundary) { + result = {spect.wavelength, 0.0f}; + break; + } + + if (medium_index != kInvalidIndex) { + result *= scene.mediums[medium_index].transmittance(spect, smp, origin, w_o, intersection.t); + } + + medium_index = (dot(intersection.nrm, w_o) < 0.0f) ? mat.int_medium : mat.ext_medium; + origin = intersection.pos; + max_t -= intersection.t; + } + + return result; + } +}; + +CPUPathTracing::CPUPathTracing(CPUPathTracing&& other) noexcept + : Integrator(other.rt) { + if (_private) { + _private->~CPUPathTracingImpl(); + } + memcpy(_private_storage, other._private_storage, sizeof(_private_storage)); + _private = reinterpret_cast(_private_storage); + memset(other._private_storage, 0, sizeof(_private_storage)); + other._private = nullptr; +} + +CPUPathTracing& CPUPathTracing::operator=(CPUPathTracing&& other) noexcept { + if (_private) { + _private->~CPUPathTracingImpl(); + } + memcpy(_private_storage, other._private_storage, sizeof(_private_storage)); + _private = reinterpret_cast(_private_storage); + memset(other._private_storage, 0, sizeof(_private_storage)); + other._private = nullptr; + return *this; +} + +CPUPathTracing::CPUPathTracing(Raytracing& rt) + : Integrator(rt) { + ETX_PIMPL_INIT(CPUPathTracing, rt, ¤t_state); +} + +CPUPathTracing::~CPUPathTracing() { + if (current_state != State::Stopped) { + stop(false); + } + + ETX_PIMPL_CLEANUP(CPUPathTracing); +} + +void CPUPathTracing::set_output_size(const uint2& dim) { + _private->film_dimensions = dim; + _private->camera_image.resize(1llu * dim.x * dim.y); +} + +float4* CPUPathTracing::get_updated_camera_image() { + return _private->camera_image.data(); +} + +float4* CPUPathTracing::get_updated_light_image() { + return nullptr; +} + +const char* CPUPathTracing::status() const { + return _private->status; +} + +void CPUPathTracing::preview() { + stop(false); + + if (rt.has_scene()) { + current_state = State::Preview; + _private->start(); + } +} + +void CPUPathTracing::run(const Options& opt) { + stop(false); + + _private->max_iterations = opt.get("spp", _private->max_iterations).to_integer(); + _private->max_depth = opt.get("pathlen", _private->max_depth).to_integer(); + _private->rr_start = opt.get("rrstart", _private->rr_start).to_integer(); + + if (rt.has_scene()) { + current_state = State::Running; + _private->start(); + } +} + +void CPUPathTracing::update() { + bool should_stop = (current_state != State::Stopped) || (current_state == State::WaitingForCompletion); + + if (should_stop && rt.scheduler().completed(_private->current_task)) { + if ((current_state == State::WaitingForCompletion) || (_private->iteration >= _private->max_iterations)) { + rt.scheduler().wait(_private->current_task); + snprintf(_private->status, sizeof(_private->status), "[%u] Completed in %.2f seconds", _private->iteration, _private->total_time.measure()); + _private->current_task = {}; + current_state = Integrator::State::Stopped; + } else { + snprintf(_private->status, sizeof(_private->status), "[%u] %s... (%.3fms per iteration)", _private->iteration, + (current_state == Integrator::State::Running ? "Running" : "Preview"), _private->iteration_time.measure_ms()); + _private->iteration_time = {}; + _private->iteration += 1; + + _private->preview_scale = (current_state == Integrator::State::Running) ? 1u : max(1u, uint32_t(exp2(3.0f - _private->iteration))); + _private->current_dimensions = _private->film_dimensions / _private->preview_scale; + + rt.scheduler().restart(_private->current_task, _private->current_dimensions.x * _private->current_dimensions.y); + } + } +} + +void CPUPathTracing::stop(bool wait_for_completion) { + if (current_state == State::Stopped) { + return; + } + + if (wait_for_completion) { + current_state = State::WaitingForCompletion; + snprintf(_private->status, sizeof(_private->status), "[%u] Waiting for completion", _private->iteration); + } else { + current_state = State::Stopped; + rt.scheduler().wait(_private->current_task); + _private->current_task = {}; + snprintf(_private->status, sizeof(_private->status), "[%u] Stopped", _private->iteration); + } +} + +} // namespace etx diff --git a/sources/etx/rt/integrators/path_tracing.hxx b/sources/etx/rt/integrators/path_tracing.hxx new file mode 100644 index 0000000..f039fe5 --- /dev/null +++ b/sources/etx/rt/integrators/path_tracing.hxx @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +namespace etx { + +struct CPUPathTracing : public Integrator { + CPUPathTracing(Raytracing&); + ~CPUPathTracing() override; + + const char* name() override { + return "Path Tracing (CPU)"; + } + + Options options() const override { + Options result = {}; + result.set(1u, 0x7fffu, 0xffffu, "spp", "Samples per Pixel"); + result.set(1u, 0x7fffu, 65536u, "pathlen", "Maximal Path Length"); + result.set(1u, 5u, 65536u, "rrstart", "Start Russian Roulette at"); + return result; + } + + void set_output_size(const uint2&) override; + float4* get_updated_camera_image() override; + float4* get_updated_light_image() override; + const char* status() const override; + + void preview() override; + void run(const Options&) override; + void update() override; + void stop(bool wait_for_completion) override; + + ETX_DECLARE_PIMPL(CPUPathTracing, 4096); +}; + +} // namespace etx diff --git a/sources/etx/rt/rt.cxx b/sources/etx/rt/rt.cxx new file mode 100644 index 0000000..f358f53 --- /dev/null +++ b/sources/etx/rt/rt.cxx @@ -0,0 +1,297 @@ +#include + +#define ETX_RT_API_BVH 1 +#define ETX_RT_API_NANORT 2 +#define ETX_RT_API_EMBREE 3 + +#define ETX_RT_API ETX_RT_API_EMBREE + +#if (ETX_RT_API == ETX_RT_API_NANORT) + +#define NANORT_USE_CPP11_FEATURE 1 +#include + +#elif (ETX_RT_API == ETX_RT_API_BVH) + +#include +#include +#include +#include +#include + +#elif (ETX_RT_API == ETX_RT_API_EMBREE) + +#include + +#else + +#error No raytracing API defined + +#endif + +namespace etx { + +struct RaytracingImpl { + TaskScheduler scheduler; + const Scene* scene = nullptr; + +#if (ETX_RT_API == ETX_RT_API_NANORT) + + using Ray = nanort::Ray; + std::vector linear_indices; + std::vector linear_vertex_data; + float* v_ptr = nullptr; + uint32_t* i_ptr = nullptr; + + nanort::BVHAccel bvh = {}; + +#elif (ETX_RT_API == ETX_RT_API_BVH) + + using Bvh = bvh::Bvh; + using Builder = bvh::SweepSahBuilder; + using Traverser = bvh::SingleRayTraverser >; + using Triangle = bvh::Triangle; + using BVHVector = bvh::Vector3; + using Intersection = bvh::AlphaTestClosestPrimitiveIntersector; + using Ray = bvh::Ray; + + std::vector triangles; + bvh::Bvh bvh = {}; + +#elif (ETX_RT_API == ETX_RT_API_EMBREE) + + RTCDevice rt_device = {}; + RTCScene rt_scene = {}; + +#endif + + RaytracingImpl() = default; + + ~RaytracingImpl() { + release_scene(); + } + + void set_scene(const Scene& s) { + scene = &s; + release_scene(); + +#if (ETX_RT_API == ETX_RT_API_NANORT) + linear_vertex_data.reserve(scene.vertices.count); + for (uint32_t i = 0; i < scene.vertices.count; ++i) { + linear_vertex_data.emplace_back(scene.vertices[i].pos.x); + linear_vertex_data.emplace_back(scene.vertices[i].pos.y); + linear_vertex_data.emplace_back(scene.vertices[i].pos.z); + } + v_ptr = linear_vertex_data.data(); + + linear_indices.reserve(3llu * scene.triangles.count); + for (uint32_t i = 0; i < scene.triangles.count; ++i) { + const auto& tri = scene.triangles[i]; + linear_indices.emplace_back(tri.i[0]); + linear_indices.emplace_back(tri.i[1]); + linear_indices.emplace_back(tri.i[2]); + } + i_ptr = linear_indices.data(); + + auto mesh = nanort::TriangleMesh(v_ptr, i_ptr, sizeof(float) * 3llu); + auto sah = nanort::TriangleSAHPred(v_ptr, i_ptr, sizeof(float) * 3llu); + auto succeed = bvh.Build(uint32_t(scene.triangles.count), mesh, sah, {}); + ETX_ASSERT(succeed); + +#elif (ETX_RT_API == ETX_RT_API_BVH) + + triangles.clear(); + triangles.reserve(scene.triangles.count); + for (uint64_t i = 0, e = scene.triangles.count; i < e; ++i) { + const auto& tri = scene.triangles[i]; + const auto& v0 = scene.vertices[tri.i[0]]; + const auto& v1 = scene.vertices[tri.i[1]]; + const auto& v2 = scene.vertices[tri.i[2]]; + triangles.emplace_back(BVHVector{v0.pos.x, v0.pos.y, v0.pos.z}, BVHVector{v1.pos.x, v1.pos.y, v1.pos.z}, BVHVector{v2.pos.x, v2.pos.y, v2.pos.z}); + } + + auto [boxes, centers] = bvh::compute_bounding_boxes_and_centers(triangles.data(), triangles.size()); + auto global_bbox = bvh::compute_bounding_boxes_union(boxes.get(), triangles.size()); + + Builder bvh_builder(bvh); + bvh_builder.build(global_bbox, boxes.get(), centers.get(), triangles.size()); + +#elif (ETX_RT_API == ETX_RT_API_EMBREE) + + rt_device = rtcNewDevice(nullptr); + rtcSetDeviceErrorFunction( + rt_device, + [](void* userPtr, enum RTCError code, const char* str) { + printf("Embree error: %u (%s)\n", code, str); + }, + nullptr); + + rt_scene = rtcNewScene(rt_device); + auto geometry = rtcNewGeometry(rt_device, RTCGeometryType::RTC_GEOMETRY_TYPE_TRIANGLE); + + rtcSetSharedGeometryBuffer(geometry, RTCBufferType::RTC_BUFFER_TYPE_VERTEX, 0, RTCFormat::RTC_FORMAT_FLOAT3, // + scene->vertices.a, 0, sizeof(Vertex), scene->vertices.count); + + rtcSetSharedGeometryBuffer(geometry, RTCBufferType::RTC_BUFFER_TYPE_INDEX, 0, RTCFormat::RTC_FORMAT_UINT3, // + scene->triangles.a, 0, sizeof(Triangle), scene->triangles.count); + + rtcCommitGeometry(geometry); + rtcAttachGeometry(rt_scene, geometry); + rtcReleaseGeometry(geometry); + rtcCommitScene(rt_scene); + +#endif + } + + void release_scene() { +#if (ETX_RT_API == ETX_RT_API_EMBREE) + if (rt_scene) { + rtcReleaseScene(rt_scene); + rt_scene = {}; + } + if (rt_device) { + rtcReleaseDevice(rt_device); + rt_device = {}; + } +#endif + } +}; + +ETX_PIMPL_IMPLEMENT(Raytracing, Impl); + +Raytracing::Raytracing() { + ETX_PIMPL_INIT(Raytracing); +} + +Raytracing::~Raytracing() { + ETX_PIMPL_CLEANUP(Raytracing); +} + +TaskScheduler& Raytracing::scheduler() { + return _private->scheduler; +} + +void Raytracing::set_scene(const Scene& scene) { + _private->set_scene(scene); +} + +bool Raytracing::has_scene() const { + return (_private->scene != nullptr) && _private->scene->valid(); +} + +const Scene& Raytracing::scene() const { + ETX_ASSERT(has_scene()); + return *(_private->scene); +} + +bool Raytracing::trace(const Ray& r, Intersection& result_intersection, Sampler& smp) const { + ETX_ASSERT(_private != nullptr); + + bool intersection_found = false; + float2 barycentric = {}; + uint32_t triangle_index = kInvalidIndex; + float t = -kMaxFloat; + +#if (ETX_RT_API == ETX_RT_API_NANORT) + + RaytracerPrivate::Ray rr = RaytracerPrivate::Ray{{r.o.x, r.o.y, r.o.z}, {r.d.x, r.d.y, r.d.z}, r.min_t, r.max_t}; + nanort::TriangleIntersector traverser(_private->v_ptr, _private->i_ptr, 3llu * sizeof(float)); + nanort::TriangleIntersection isect; + if (_private->bvh.Traverse(rr, traverser, &isect, {})) { + intersection_found = true; + barycentric = {isect.u, isect.v}; + triangle_index = isect.prim_id; + t = isect.t; + } + +#elif (ETX_RT_API == ETX_RT_API_BVH) + + RaytracerPrivate::Ray rr = {{r.o.x, r.o.y, r.o.z}, {r.d.x, r.d.y, r.d.z}, r.min_t, r.max_t}; + RaytracerPrivate::Traverser traverser(_private->bvh); + RaytracerPrivate::Intersection isect(_private->bvh, _private->triangles.data(), _private->scene, smp); + if (result_intersection = traverser.traverse(rr, isect)) { + intersection_found = true; + barycentric = {result_intersection.barycentric.y, result_intersection.barycentric.z}; + triangle_index = result_intersection.triangle_index; + t = result_intersection.t; + } + +#elif (ETX_RT_API == ETX_RT_API_EMBREE) + + RTCIntersectContext context = {}; + rtcInitIntersectContext(&context); + + RTCRayHit ray_hit = {}; + ray_hit.ray.dir_x = r.d.x; + ray_hit.ray.dir_y = r.d.y; + ray_hit.ray.dir_z = r.d.z; + ray_hit.ray.org_x = r.o.x; + ray_hit.ray.org_y = r.o.y; + ray_hit.ray.org_z = r.o.z; + ray_hit.ray.tnear = r.min_t; + ray_hit.ray.tfar = r.max_t; + ray_hit.ray.mask = kInvalidIndex; + ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID; + ray_hit.hit.primID = RTC_INVALID_GEOMETRY_ID; + ray_hit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; + + for (;;) { + rtcIntersect1(_private->rt_scene, &context, &ray_hit); + if ((ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID)) { + intersection_found = false; + break; + } + + const auto& tri = _private->scene->triangles[ray_hit.hit.primID]; + const auto& mat = _private->scene->materials[tri.material_index]; + /* + float3 bc = {1.0f - ray_hit.hit.u - ray_hit.hit.v, ray_hit.hit.u, ray_hit.hit.v}; + if (bsdf::continue_tracing(mat, lerp_uv(_private->scene.vertices, tri, bc), _private->scene, smp)) { + auto p = lerp_pos(_private->scene.vertices, tri, bc); + ray_hit.ray.org_x = p.x + r.d.x * kRayEpsilon; + ray_hit.ray.org_y = p.y + r.d.y * kRayEpsilon; + ray_hit.ray.org_z = p.z + r.d.z * kRayEpsilon; + ray_hit.ray.tfar = r.max_t - ray_hit.ray.tfar; + ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID; + ray_hit.hit.primID = RTC_INVALID_GEOMETRY_ID; + ray_hit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; + } else + // */ + { + intersection_found = true; + barycentric = {ray_hit.hit.u, ray_hit.hit.v}; + triangle_index = ray_hit.hit.primID; + t = ray_hit.ray.tfar; + break; + } + } + +#endif + + if (intersection_found) { + float3 bc = {1.0f - barycentric.x - barycentric.y, barycentric.x, barycentric.y}; + const auto& tri = _private->scene->triangles[triangle_index]; + result_intersection = lerp_vertex(_private->scene->vertices, tri, bc); + result_intersection.barycentric = bc; + result_intersection.triangle_index = static_cast(triangle_index); + result_intersection.w_i = r.d; + result_intersection.t = t; + + const auto& mat = _private->scene->materials[tri.material_index]; + if ((mat.normal_image_index != kInvalidIndex) && (mat.normal_scale > 0.0f)) { + auto sampled_normal = _private->scene->images[mat.normal_image_index].evaluate_normal(result_intersection.tex, mat.normal_scale); + float3x3 from_local = { + {result_intersection.tan.x, result_intersection.tan.y, result_intersection.tan.z}, + {result_intersection.btn.x, result_intersection.btn.y, result_intersection.btn.z}, + {result_intersection.nrm.x, result_intersection.nrm.y, result_intersection.nrm.z}, + }; + result_intersection.nrm = normalize(from_local * sampled_normal); + result_intersection.tan = normalize(result_intersection.tan - result_intersection.nrm * dot(result_intersection.tan, result_intersection.nrm)); + result_intersection.btn = normalize(cross(result_intersection.nrm, result_intersection.tan)); + } + } + + return intersection_found; +} + +} // namespace etx \ No newline at end of file diff --git a/sources/etx/rt/rt.hxx b/sources/etx/rt/rt.hxx new file mode 100644 index 0000000..7f090b3 --- /dev/null +++ b/sources/etx/rt/rt.hxx @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace etx { + +struct Raytracing { + Raytracing(); + ~Raytracing(); + + TaskScheduler& scheduler(); + + const Scene& scene() const; + bool has_scene() const; + void set_scene(const Scene&); + + bool trace(const Ray&, Intersection&, Sampler& smp) const; + + private: + ETX_DECLARE_PIMPL(Raytracing, 512); +}; + +} // namespace etx \ No newline at end of file diff --git a/sources/raytracer/CMakeLists.txt b/sources/raytracer/CMakeLists.txt index 4f5a89c..e04214a 100644 --- a/sources/raytracer/CMakeLists.txt +++ b/sources/raytracer/CMakeLists.txt @@ -1,6 +1,21 @@ add_executable(raytracer main.cxx + app.hxx + app.cxx + ui.hxx + ui.cxx + render.hxx + render.cxx + options.hxx + camera_controller.hxx +) + +target_link_libraries(raytracer sokol_imgui glm etx-core etx-log etx-render etx-rt) + +set_target_properties(raytracer PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${root_folder}/bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${root_folder}/bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${root_folder}/bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${root_folder}/bin" ) -set_target_properties(raytracer PROPERTIES WIN32_EXECUTABLE YES) -target_link_libraries(raytracer sokol_app) diff --git a/sources/raytracer/app.cxx b/sources/raytracer/app.cxx new file mode 100644 index 0000000..24f2869 --- /dev/null +++ b/sources/raytracer/app.cxx @@ -0,0 +1,181 @@ +#include +#include + +#include + +#include + +#include "app.hxx" + +namespace etx { + +RTApplication::RTApplication() + : camera_controller(scene.camera()) { +} + +void RTApplication::init() { + render.init(); + ui.initialize(); + ui.set_integrator_list(_integrator_array, std::size(_integrator_array)); + ui.callbacks.reference_image_selected = std::bind(&RTApplication::on_referenece_image_selected, this, std::placeholders::_1); + ui.callbacks.scene_file_selected = std::bind(&RTApplication::on_scene_file_selected, this, std::placeholders::_1); + ui.callbacks.integrator_selected = std::bind(&RTApplication::on_integrator_selected, this, std::placeholders::_1); + ui.callbacks.preview_selected = std::bind(&RTApplication::on_preview_selected, this); + ui.callbacks.run_selected = std::bind(&RTApplication::on_run_selected, this); + ui.callbacks.stop_selected = std::bind(&RTApplication::on_stop_selected, this, std::placeholders::_1); + ui.callbacks.reload_scene_selected = std::bind(&RTApplication::on_reload_scene_selected, this); + ui.callbacks.reload_geometry_selected = std::bind(&RTApplication::on_reload_geometry_selected, this); + + _options.load_from_file(env().file_in_data("options.json")); + + auto integrator = _options.get("integrator", std::string{}).name; + for (uint64_t i = 0; (integrator.empty() == false) && (i < std::size(_integrator_array)); ++i) { + if (integrator == _integrator_array[i]->name()) { + _current_integrator = _integrator_array[i]; + break; + } + } + + ui.set_current_integrator(_current_integrator); + + _current_scene_file = _options.get("scene", std::string{}).name; + if (_current_scene_file.empty() == false) { + on_scene_file_selected(_current_scene_file); + } +} + +void RTApplication::save_options() { + _options.save_to_file(env().file_in_data("options.json")); +} + +void RTApplication::frame() { + float4* c_image = nullptr; + float4* l_image = nullptr; + const char* status = "Not running"; + + bool can_change_camera = true; + if (_current_integrator != nullptr) { + _current_integrator->update(); + status = _current_integrator->status(); + c_image = _current_integrator->get_updated_camera_image(); + l_image = _current_integrator->get_updated_light_image(); + can_change_camera = _current_integrator->state() == Integrator::State::Preview; + } + + auto dt = time_measure.lap(); + if (can_change_camera) { + if (camera_controller.update(dt)) { + _current_integrator->preview(); + } + } + + render.set_view_options(ui.view_options()); + render.start_frame(); + render.update_output_images(c_image, l_image); + ui.build(dt, status); + render.end_frame(); +} + +void RTApplication::cleanup() { + render.cleanup(); +} + +void RTApplication::process_event(const sapp_event* e) { + if (ui.handle_event(e) || (raytracing.has_scene() == false)) { + return; + } + camera_controller.handle_event(e); +} + +void RTApplication::load_scene_file(const std::string& file_name, uint32_t options, bool start_rendering) { + _current_scene_file = file_name; + + log::warning("Loading scene %s...", _current_scene_file.c_str()); + if (_current_integrator) { + _current_integrator->stop(false); + } + + _options.set("scene", _current_scene_file); + save_options(); + + if (scene.load_from_file(_current_scene_file.c_str(), options) == false) { + log::error("Failed to load scene from file: %s", _current_scene_file.c_str()); + return; + } + + raytracing.set_scene(scene.scene()); + + if (scene) { + render.set_output_dimensions(scene.scene().camera.image_size); + + if (_current_integrator != nullptr) { + if (start_rendering) { + _current_integrator->run(ui.integrator_options()); + } else { + _current_integrator->set_output_size(scene.scene().camera.image_size); + _current_integrator->preview(); + } + } + } +} + +void RTApplication::on_referenece_image_selected(std::string file_name) { + log::warning("Loading reference image %s...", file_name.c_str()); + render.set_reference_image(file_name.c_str()); +} + +void RTApplication::on_scene_file_selected(std::string file_name) { + load_scene_file(file_name, SceneRepresentation::LoadEverything, false); +} + +void RTApplication::on_integrator_selected(Integrator* i) { + if (_current_integrator == i) { + return; + } + + _options.set("integrator", i->name()); + save_options(); + + if (_current_integrator != nullptr) { + _current_integrator->stop(false); + } + + _current_integrator = i; + ui.set_current_integrator(_current_integrator); + + if (scene) { + _current_integrator->set_output_size(scene.scene().camera.image_size); + _current_integrator->preview(); + } +} + +void RTApplication::on_preview_selected() { + ETX_ASSERT(_current_integrator != nullptr); + _current_integrator->preview(); +} + +void RTApplication::on_run_selected() { + ETX_ASSERT(_current_integrator != nullptr); + _current_integrator->run(ui.integrator_options()); +} + +void RTApplication::on_stop_selected(bool wait_for_completion) { + ETX_ASSERT(_current_integrator != nullptr); + _current_integrator->stop(wait_for_completion); +} + +void RTApplication::on_reload_scene_selected() { + if (_current_scene_file.empty() == false) { + bool start_render = (_current_integrator != nullptr) && (_current_integrator->state() == Integrator::State::Running); + load_scene_file(_current_scene_file, SceneRepresentation::LoadEverything, start_render); + } +} + +void RTApplication::on_reload_geometry_selected() { + if (_current_scene_file.empty() == false) { + bool start_render = (_current_integrator != nullptr) && (_current_integrator->state() == Integrator::State::Running); + load_scene_file(_current_scene_file, SceneRepresentation::LoadGeometry, start_render); + } +} + +} // namespace etx \ No newline at end of file diff --git a/sources/raytracer/app.hxx b/sources/raytracer/app.hxx new file mode 100644 index 0000000..fd4fa0b --- /dev/null +++ b/sources/raytracer/app.hxx @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "ui.hxx" +#include "render.hxx" +#include "camera_controller.hxx" + +namespace etx { + +struct RTApplication { + RTApplication(); + + void init(); + void frame(); + void cleanup(); + void process_event(const sapp_event*); + void load_scene_file(const std::string&, uint32_t options, bool start_rendering); + + private: + void on_referenece_image_selected(std::string); + void on_scene_file_selected(std::string); + void on_integrator_selected(Integrator*); + void on_preview_selected(); + void on_run_selected(); + void on_stop_selected(bool wait_for_completion); + void on_reload_scene_selected(); + void on_reload_geometry_selected(); + + private: + void save_options(); + + private: + RenderContext render; + UI ui; + TimeMeasure time_measure; + SceneRepresentation scene; + Raytracing raytracing; + CameraController camera_controller; + + Integrator _test = {raytracing}; + CPUPathTracing _cpu_pt = {raytracing}; + + Integrator* _integrator_array[2] = { + &_test, + &_cpu_pt, + }; + + Integrator* _current_integrator = nullptr; + std::string _current_scene_file = {}; + Options _options; +}; + +} // namespace etx diff --git a/sources/raytracer/camera_controller.hxx b/sources/raytracer/camera_controller.hxx new file mode 100644 index 0000000..40d3ac0 --- /dev/null +++ b/sources/raytracer/camera_controller.hxx @@ -0,0 +1,88 @@ +#include + +#include +#include + +#include + +namespace etx { + +struct CameraController { + CameraController(Camera& cam) + : _camera(cam) { + } + + void handle_event(const sapp_event* e) { + switch (e->type) { + case SAPP_EVENTTYPE_MOUSE_SCROLL: { + _move_speed = clamp(_move_speed + e->scroll_y / 256.0f, 1.0f / 1000.0f, 1000.0f); + break; + } + case SAPP_EVENTTYPE_KEY_DOWN: { + _keys.insert(e->key_code); + break; + } + case SAPP_EVENTTYPE_KEY_UP: { + _keys.erase(e->key_code); + break; + } + case SAPP_EVENTTYPE_MOUSE_DOWN: { + if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) { + _mouse_control = true; + _mouse_delta = {}; + } + break; + } + case SAPP_EVENTTYPE_MOUSE_UP: { + if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) { + _mouse_control = false; + } + break; + } + case SAPP_EVENTTYPE_MOUSE_MOVE: { + _mouse_delta = {e->mouse_dx, e->mouse_dy}; + break; + } + default: + break; + } + } + + bool update(double dt) { + float move_fwd = float(_keys.count(SAPP_KEYCODE_W)) - float(_keys.count(SAPP_KEYCODE_S)); + float move_side = float(_keys.count(SAPP_KEYCODE_D)) - float(_keys.count(SAPP_KEYCODE_A)); + + bool changed = (move_fwd != 0.0f) || (move_side != 0.0f); + + float3 direction = _camera.direction; + float3 side = _camera.side; + float3 up = {0.0f, 1.0f, 0.0f}; + + if (_mouse_control && ((_mouse_delta.x != 0.0f) || (_mouse_delta.y != 0.0f))) { + float2 pt = direction_to_phi_theta(_camera.direction); + pt.x += _rotation_speed * (_mouse_delta.x * kPi / 180.0f); + pt.y = clamp(pt.y - _rotation_speed * (_mouse_delta.y * kDoublePi / 180.0f), -kHalfPi + kPi / 180.0f, kHalfPi - kPi / 180.0f); + direction = phi_theta_to_direction(pt.x, pt.y); + side = cross(direction, up); + changed = true; + _mouse_delta = {}; + } + + if (changed) { + _camera.position += (move_fwd * direction + move_side * side) * _move_speed; + update_camera(_camera, _camera.position, _camera.position + direction, up, _camera.image_size, get_camera_fov(_camera)); + } + + return changed; + } + + private: + Camera& _camera; + std::unordered_set _keys; + float2 _mouse_delta = {}; + float _move_speed = 1.0f / 100.0f; + float _rotation_speed = 1.0f / 32.0f; + bool _mouse_control = false; +}; + +} // namespace etx \ No newline at end of file diff --git a/sources/raytracer/main.cxx b/sources/raytracer/main.cxx index cdf058f..1ec8eaa 100644 --- a/sources/raytracer/main.cxx +++ b/sources/raytracer/main.cxx @@ -1,30 +1,38 @@ -#include - -void init_application() { -} +#include +#include "app.hxx" -void frame() { -} +#include -void cleanup_application() { -} +namespace etx { -void handle_event(const sapp_event*) { -} +extern "C" int main(int argc, char* argv[]) { + env().setup(argv[0]); -sapp_desc sokol_main(int argc, char* argv[]) { - sapp_desc result = {}; + RTApplication app; + sapp_desc desc = {}; { - result.init_cb = init_application; - result.frame_cb = frame; - result.cleanup_cb = cleanup_application; - result.event_cb = handle_event; - result.width = 1280; - result.height = 720; - result.window_title = "etx-tracer"; - result.high_dpi = true; - result.win32_console_utf8 = true; - result.win32_console_create = true; + desc.init_userdata_cb = [](void* data) { + reinterpret_cast(data)->init(); + }; + desc.frame_userdata_cb = [](void* data) { + reinterpret_cast(data)->frame(); + }; + desc.cleanup_userdata_cb = [](void* data) { + reinterpret_cast(data)->cleanup(); + }; + desc.event_userdata_cb = [](const sapp_event* e, void* data) { + reinterpret_cast(data)->process_event(e); + }; + desc.width = 1600; + desc.height = 900; + desc.window_title = "etx-tracer"; + desc.high_dpi = true; + desc.win32_console_utf8 = true; + desc.win32_console_create = true; + desc.user_data = &app; }; - return result; + sapp_run(desc); + return 0; } + +} // namespace etx diff --git a/sources/raytracer/options.hxx b/sources/raytracer/options.hxx new file mode 100644 index 0000000..b0b8519 --- /dev/null +++ b/sources/raytracer/options.hxx @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace etx { + +enum class OutputView : uint32_t { + Result, + CameraImage, + LightImage, + ReferenceImage, + RelativeDifference, + AbsoluteDifference, + Count, +}; + +inline std::string output_view_to_string(uint32_t i) { + switch (OutputView(i)) { + case OutputView::Result: + return "Result Image"; + case OutputView::CameraImage: + return "Camera Image"; + case OutputView::LightImage: + return "Light Image"; + case OutputView::ReferenceImage: + return "Reference Image"; + case OutputView::RelativeDifference: + return "Relative Difference"; + case OutputView::AbsoluteDifference: + return "Absolute Differenec"; + default: + return "???"; + } +} + +struct ViewOptions { + enum : uint32_t { + ToneMapping = 1u << 0u, + sRGB = 1u << 1u, + }; + + OutputView view = OutputView::Result; + uint32_t options = ToneMapping | sRGB; + float exposure = 0.0f; +}; + +} // namespace etx diff --git a/sources/raytracer/render.cxx b/sources/raytracer/render.cxx new file mode 100644 index 0000000..65ee7a7 --- /dev/null +++ b/sources/raytracer/render.cxx @@ -0,0 +1,351 @@ +#include + +#include "render.hxx" + +#include +#include + +namespace etx { + +extern const char* shader_source; + +struct ShaderConstants { + float4 dimensions = {}; + uint32_t image_view = 0; + uint32_t options = ViewOptions::ToneMapping; + float exposure = 1.0f; + float pad = 0.0f; +}; + +struct RenderContextImpl { + sg_shader output_shader = {}; + sg_pipeline output_pipeline = {}; + sg_image sample_image = {}; + sg_image light_image = {}; + sg_image reference_image = {}; + ShaderConstants constants; + uint32_t def_image_handle = kInvalidIndex; + uint32_t ref_image_handle = kInvalidIndex; + ViewOptions view_options = {}; + uint2 output_dimensions = {}; + ImagePool image_pool = {}; +}; + +ETX_PIMPL_IMPLEMENT_ALL(RenderContext, Impl); + +void RenderContext::init() { + _private->image_pool.init(1024u); + _private->def_image_handle = _private->image_pool.add_from_file("##default", Image::RepeatU | Image::RepeatV); + + sg_desc context = {}; + context.context.d3d11.device = sapp_d3d11_get_device(); + context.context.d3d11.device_context = sapp_d3d11_get_device_context(); + context.context.d3d11.depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view; + context.context.d3d11.render_target_view_cb = sapp_d3d11_get_render_target_view; + context.context.depth_format = SG_PIXELFORMAT_NONE; + sg_setup(context); + + sg_shader_desc shader_desc = {}; + shader_desc.vs.source = shader_source; + shader_desc.vs.entry = "vertex_main"; + shader_desc.vs.uniform_blocks[0].size = sizeof(ShaderConstants); + + shader_desc.fs.source = shader_source; + shader_desc.fs.entry = "fragment_main"; + shader_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; + shader_desc.fs.images[0].name = "sample_image"; + shader_desc.fs.images[0].sampler_type = SG_SAMPLERTYPE_FLOAT; + shader_desc.fs.images[1].image_type = SG_IMAGETYPE_2D; + shader_desc.fs.images[1].name = "light_image"; + shader_desc.fs.images[1].sampler_type = SG_SAMPLERTYPE_FLOAT; + shader_desc.fs.images[2].image_type = SG_IMAGETYPE_2D; + shader_desc.fs.images[2].name = "reference_image"; + shader_desc.fs.images[2].sampler_type = SG_SAMPLERTYPE_FLOAT; + shader_desc.fs.uniform_blocks[0].size = sizeof(ShaderConstants); + _private->output_shader = sg_make_shader(shader_desc); + + sg_pipeline_desc pipeline_desc = {}; + pipeline_desc.shader = _private->output_shader; + _private->output_pipeline = sg_make_pipeline(pipeline_desc); + + apply_reference_image(_private->def_image_handle); + + set_output_dimensions({16, 16}); + float4 c_image[256] = {}; + float4 l_image[256] = {}; + for (uint32_t y = 0; y < 16u; ++y) { + for (uint32_t x = 0; x < 16u; ++x) { + uint32_t i = x + y * 16u; + c_image[i] = {1.0f, 0.5f, 0.25f, 1.0f}; + l_image[i] = {0.0f, 0.5f, 0.75f, 1.0f}; + } + } + update_output_images(c_image, l_image); +} + +void RenderContext::cleanup() { + sg_destroy_pipeline(_private->output_pipeline); + sg_destroy_shader(_private->output_shader); + sg_destroy_image(_private->sample_image); + sg_destroy_image(_private->light_image); + sg_destroy_image(_private->reference_image); + sg_shutdown(); + + _private->image_pool.remove(_private->ref_image_handle); + _private->image_pool.remove(_private->def_image_handle); + _private->image_pool.cleanup(); +} + +void RenderContext::start_frame() { + sg_pass_action pass_action = {}; + pass_action.colors[0].action = SG_ACTION_CLEAR; + pass_action.colors[0].value = {0.05f, 0.07f, 0.1f, 1.0f}; + sg_apply_viewport(0, 0, sapp_width(), sapp_height(), sg_features().origin_top_left); + sg_begin_default_pass(&pass_action, sapp_width(), sapp_height()); + + _private->constants = { + {sapp_widthf(), sapp_heightf(), float(_private->output_dimensions.x), float(_private->output_dimensions.y)}, + uint32_t(_private->view_options.view), + _private->view_options.options, + _private->view_options.exposure, + }; + + sg_range uniform_data = { + .ptr = &_private->constants, + .size = sizeof(ShaderConstants), + }; + + sg_bindings bindings = {}; + bindings.fs_images[0] = _private->sample_image; + bindings.fs_images[1] = _private->light_image; + bindings.fs_images[2] = _private->reference_image; + + sg_apply_pipeline(_private->output_pipeline); + sg_apply_bindings(bindings); + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, uniform_data); + sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, uniform_data); + sg_draw(0, 3, 1); +} + +void RenderContext::end_frame() { + sg_end_pass(); + sg_commit(); +} + +void RenderContext::apply_reference_image(uint32_t handle) { + auto img = _private->image_pool.get(handle); + + sg_destroy_image(_private->reference_image); + + sg_image_desc ref_image_desc = {}; + ref_image_desc.type = SG_IMAGETYPE_2D; + ref_image_desc.pixel_format = SG_PIXELFORMAT_RGBA32F; + ref_image_desc.width = img.isize.x; + ref_image_desc.height = img.isize.y; + ref_image_desc.mag_filter = SG_FILTER_NEAREST; + ref_image_desc.min_filter = SG_FILTER_NEAREST; + ref_image_desc.num_mipmaps = 1; + ref_image_desc.usage = SG_USAGE_STREAM; + _private->reference_image = sg_make_image(ref_image_desc); + + ref_image_desc.data.subimage[0][0].ptr = img.pixels; + ref_image_desc.data.subimage[0][0].size = sizeof(float4) * img.isize.x * img.isize.y; + sg_update_image(_private->reference_image, ref_image_desc.data); +} + +void RenderContext::set_reference_image(const char* file_name) { + _private->image_pool.remove(_private->ref_image_handle); + _private->ref_image_handle = _private->image_pool.add_from_file(file_name, 0); + apply_reference_image(_private->ref_image_handle); +} + +void RenderContext::set_view_options(const ViewOptions& o) { + _private->view_options = o; +} + +void RenderContext::set_output_dimensions(const uint2& dim) { + if ((_private->sample_image.id != 0) && (_private->light_image.id != 0) && (_private->output_dimensions == dim)) { + return; + } + + _private->output_dimensions = dim; + sg_destroy_image(_private->sample_image); + sg_destroy_image(_private->light_image); + + sg_image_desc desc = {}; + desc.type = SG_IMAGETYPE_2D; + desc.pixel_format = SG_PIXELFORMAT_RGBA32F; + desc.width = _private->output_dimensions.x; + desc.height = _private->output_dimensions.y; + desc.mag_filter = SG_FILTER_NEAREST; + desc.min_filter = SG_FILTER_NEAREST; + desc.num_mipmaps = 1; + desc.usage = SG_USAGE_STREAM; + _private->sample_image = sg_make_image(desc); + _private->light_image = sg_make_image(desc); +} + +void RenderContext::update_output_images(const float4* camera, const float4* light) { + ETX_ASSERT((_private->sample_image.id != 0) && (_private->light_image.id != 0)); + + sg_image_data data = {}; + data.subimage[0][0].size = sizeof(float4) * _private->output_dimensions.x * _private->output_dimensions.y; + + if (camera != nullptr) { + data.subimage[0][0].ptr = camera; + sg_update_image(_private->sample_image, data); + } + + if (light != nullptr) { + data.subimage[0][0].ptr = light; + sg_update_image(_private->light_image, data); + } +} + +const char* shader_source = R"( + +cbuffer Constants : register(b0) { + float4 dimensions; + uint image_view; + uint options; + float exposure; + float pad; +} + +Texture2D sample_image : register(t0); +Texture2D light_image : register(t1); +Texture2D reference_image : register(t2); + +struct VSOutput { + float4 pos : SV_Position; + float2 uv : TEXCOORD0; +}; + +VSOutput vertex_main(uint vertexIndex : SV_VertexID) { + float2 pos = float2((vertexIndex << 1u) & 2u, vertexIndex & 2u); + float2 scale = dimensions.zw / dimensions.xy; + float2 snapped_pos = floor(pos * 2.0f * dimensions.zw - dimensions.zw) / dimensions.xy; + + VSOutput output = (VSOutput)0; + output.pos = float4(snapped_pos, 0.0f, 1.0f); + output.uv = pos; + return output; +} + +static const uint kViewResult = 0; +static const uint kViewCameraImage = 1; +static const uint kViewLightImage = 2; +static const uint kViewReferenceImage = 3; +static const uint kViewRelativeDifference = 4; +static const uint kViewAbsoluteDifference = 5; + +static const uint ToneMapping = 1u << 0u; +static const uint sRGB = 1u << 1u; + +static const float3 lum = float3(0.2627, 0.6780, 0.0593); + +float4 to_rgb(in float4 xyz) { + float4 rgb; + rgb[0] = max(0.0, 3.240479f * xyz[0] - 1.537150f * xyz[1] - 0.498535f * xyz[2]); + rgb[1] = max(0.0, -0.969256f * xyz[0] + 1.875991f * xyz[1] + 0.041556f * xyz[2]); + rgb[2] = max(0.0, 0.055648f * xyz[0] - 0.204043f * xyz[1] + 1.057311f * xyz[2]); + rgb[3] = 1.0f; + return rgb; +} + +float4 validate(in float4 xyz) { + if (any(isnan(xyz))) { + return float4(123456.0, 0.0, 123456.0, 1.0); + } + if (any(isinf(xyz))) { + return float4(0.0, 123456.0, 123456.0, 1.0); + } + if (any(xyz < 0.0)) { + return float4(0.0, 0.0, 123456.0, 1.0); + } + return xyz; +} + +float4 tonemap(float4 value) { + if (options & ToneMapping) { + value = 1.0f - exp(-exposure * value); + } + + if (options & sRGB) { + value = pow(max(0.0f, value), 1.0f / 2.2f); + } + + return value; +} + +float4 fragment_main(in VSOutput input) : SV_Target0 { + float2 offset = 0.5f * (dimensions.xy - dimensions.zw); + + int2 coord = int2(floor(input.pos.xy - offset)); + int2 clamped = clamp(coord.xy, int2(0, 0), int2(dimensions.zw) - 1); + clip(any(clamped != coord.xy) ? -1 : 1); + + if (any(clamped != coord.xy)) { + return float4(1.0f, 0.0f, 1.0f, 1.0f); + } + + int3 load_coord = int3(clamped, 0); + + float4 c_image = sample_image.Load(load_coord); + float c_lum = dot(c_image.xyz, lum); + + float4 l_image = light_image.Load(load_coord); + float l_lum = dot(l_image.xyz, lum); + + float4 r_image = reference_image.Load(load_coord); + float r_lum = dot(r_image.xyz, lum); + + float4 t_image = c_image + l_image; + float4 v_image = validate(t_image); + if (any(v_image != t_image)) { + return v_image; + } + + c_image = to_rgb(c_image); + l_image = to_rgb(l_image); + v_image = to_rgb(v_image); + float v_lum = dot(v_image.xyz, lum); + + float4 result = float4(0.0f, 0.0f, 0.0f, 0.0f); + switch (image_view) { + case kViewResult: { + result = tonemap(v_image); + break; + } + case kViewCameraImage: { + result = tonemap(c_image); + break; + } + case kViewLightImage: { + result = tonemap(l_image); + break; + } + case kViewReferenceImage: { + result = tonemap(r_image); + break; + } + case kViewRelativeDifference: { + result.x = max(0.0f, r_lum - v_lum); + result.y = max(0.0f, v_lum - r_lum); + break; + } + case kViewAbsoluteDifference: { + result.x = float(r_lum > v_lum); + result.y = float(v_lum > r_lum); + break; + } + default: + break; + }; + + return result; +} + +)"; + +} // namespace etx diff --git a/sources/raytracer/render.hxx b/sources/raytracer/render.hxx new file mode 100644 index 0000000..6a2700e --- /dev/null +++ b/sources/raytracer/render.hxx @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "options.hxx" + +namespace etx { + +struct RenderContext { + RenderContext(); + ~RenderContext(); + + void init(); + void cleanup(); + + void start_frame(); + void end_frame(); + + void set_output_dimensions(const uint2&); + void update_output_images(const float4* camera, const float4* ligth); + void set_view_options(const ViewOptions&); + void set_reference_image(const char*); + + ETX_DECLARE_PIMPL(RenderContext, 512); + + private: + void apply_reference_image(uint32_t); +}; + +} // namespace etx diff --git a/sources/raytracer/ui.cxx b/sources/raytracer/ui.cxx new file mode 100644 index 0000000..efd6669 --- /dev/null +++ b/sources/raytracer/ui.cxx @@ -0,0 +1,235 @@ +#include +#include + +#include "ui.hxx" + +#include +#include + +#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS +#include +#include + +namespace etx { + +void UI::initialize() { + simgui_desc_t imggui_desc = {}; + imggui_desc.depth_format = SG_PIXELFORMAT_NONE; + simgui_setup(imggui_desc); + + _view_options = Options{{ + {OutputView::Result, OutputView::Count, output_view_to_string, "out_view", "View Image"}, + {0.001f, 1.0f, +10.0f, "exp", "Exposure"}, + }}; +} + +void UI::build_options(Options& options) { + for (auto& option : options.values) { + switch (option.cls) { + case OptionalValue::Class::InfoString: { + igTextColored({1.0f, 0.5f, 0.25f, 1.0f}, option.name.c_str()); + break; + }; + + case OptionalValue::Class::Boolean: { + bool value = option.to_bool(); + if (igCheckbox(option.name.c_str(), &value)) { + option.set(value); + } + break; + } + + case OptionalValue::Class::Float: { + float value = option.to_float(); + igSetNextItemWidth(4.0f * igGetFontSize()); + if (igDragFloat(option.name.c_str(), &value, 0.001f, option.min_value.flt, option.max_value.flt, "%.3f", ImGuiSliderFlags_AlwaysClamp)) { + option.set(value); + } + break; + } + + case OptionalValue::Class::Integer: { + int value = option.to_integer(); + igSetNextItemWidth(4.0f * igGetFontSize()); + if (igDragInt(option.name.c_str(), &value, 1.0f, option.min_value.integer, option.max_value.integer, "%u", ImGuiSliderFlags_AlwaysClamp)) { + option.set(uint32_t(value)); + } + break; + } + + case OptionalValue::Class::Enum: { + int value = option.to_integer(); + igSetNextItemWidth(4.0f * igGetFontSize()); + if (igTreeNodeEx_Str(option.name.c_str(), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) { + for (uint32_t i = 0; i <= option.max_value.integer; ++i) { + if (igRadioButton_IntPtr(option.name_func(i).c_str(), &value, i)) { + value = i; + } + } + if (value != option.to_integer()) { + option.set(uint32_t(value)); + } + igTreePop(); + } + break; + } + + default: + ETX_FAIL("Invalid option"); + } + } +} + +void UI::build(double dt, const char* status) { + simgui_new_frame(simgui_frame_desc_t{sapp_width(), sapp_height(), dt, sapp_dpi_scale()}); + + igSetNextWindowPos({sapp_widthf() - igGetFontSize(), 2.0f * igGetFontSize()}, ImGuiCond_Always, {1.0f, 0.0f}); + igBegin("View", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove); + igText("View options"); + build_options(_view_options); + + char status_buffer[2048] = {}; + float dy = igGetStyle()->FramePadding.y; + snprintf(status_buffer, sizeof(status_buffer), "%.2fms | %.2ffps | %s", 1000.0 * dt, 1.0f / dt, status ? status : ""); + igBeginViewportSideBar("Sidebar", igGetMainViewport(), ImGuiDir_Down, dy + 2.0f * igGetFontSize(), ImGuiWindowFlags_NoDecoration); + igText(status_buffer); + igEnd(); + + if (igBeginMainMenuBar()) { + if (igBeginMenu("Raytracer", true)) { + for (uint64_t i = 0; i < _integrators.count; ++i) { + if (igMenuItemEx(_integrators[i]->name(), nullptr, nullptr, false, true)) { + if (callbacks.integrator_selected) { + callbacks.integrator_selected(_integrators[i]); + } + } + } + igSeparator(); + if (igMenuItemEx("Exit", nullptr, "Ctrl+Q", false, true)) { + } + igEndMenu(); + } + + if (igBeginMenu("Scene", true)) { + if (igMenuItemEx("Open...", nullptr, "Ctrl+O", false, true)) { + select_scene_file(); + } + if (igMenuItemEx("Reload Scene", nullptr, "Ctrl+R", false, true)) { + if (callbacks.reload_scene_selected) { + callbacks.reload_scene_selected(); + } + } + if (igMenuItemEx("Reload Geometry and Materials", nullptr, "Ctrl+G", false, true)) { + if (callbacks.reload_geometry_selected) { + callbacks.reload_geometry_selected(); + } + } + if (igMenuItemEx("Reload Materials", nullptr, "Ctrl+M", false, false)) { + } + igSeparator(); + if (igMenuItemEx("Save...", nullptr, "Ctrl+S", false, false)) { + } + igEndMenu(); + } + + if (igBeginMenu("Reference image", true)) { + if (igMenuItemEx("Open...", nullptr, nullptr, false, true)) { + auto selected_file = open_file({"Supported images", "*.exr;*.png;*.hdr;*.pfm;*.jpg;*.bmp;*.tga"}); + if ((selected_file.empty() == false) && callbacks.reference_image_selected) { + callbacks.reference_image_selected(selected_file); + } + } + igEndMenu(); + } + igEndMainMenuBar(); + } + igEnd(); + + if ((_current_integrator != nullptr) && (_integrator_options.values.empty() == false)) { + igSetNextWindowPos({igGetFontSize(), 2.0f * igGetFontSize()}, ImGuiCond_Always, {0.0f, 0.0f}); + igBegin(_integrator_name, nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize); + igText("Integrator options"); + build_options(_integrator_options); + + if (_current_integrator->can_run()) { + igSeparator(); + igNewLine(); + + auto state = _current_integrator->state(); + bool has_complete = (state == Integrator::State::Running); + bool has_stop = (state != Integrator::State::Stopped); + bool has_preview = (state == Integrator::State::Stopped); + bool has_run = (state == Integrator::State::Stopped) || (state == Integrator::State::Preview); + + igPushStyleColor_Vec4(ImGuiCol_Button, {0.33f, 0.22f, 0.11f, 1.0f}); + if (has_complete && igButton("[ Complete iteration and stop ]", {}) && callbacks.stop_selected) { + callbacks.stop_selected(true); + } + + igPushStyleColor_Vec4(ImGuiCol_Button, {0.33f, 0.1f, 0.1f, 1.0f}); + if (has_stop && igButton("[ Break Immediately ]", {}) && callbacks.stop_selected) { + callbacks.stop_selected(false); + } + + igPushStyleColor_Vec4(ImGuiCol_Button, {0.1f, 0.1f, 0.33f, 1.0f}); + if (has_preview && igButton("[ Preview ]", {}) && callbacks.preview_selected) { + callbacks.preview_selected(); + } + + igPushStyleColor_Vec4(ImGuiCol_Button, {0.1f, 0.33f, 0.1f, 1.0f}); + if (has_run && igButton("[ Launch ]", {}) && callbacks.run_selected) { + callbacks.run_selected(); + } + + igPopStyleColor(4); + igNewLine(); + } + igEnd(); + } + simgui_render(); +} + +bool UI::handle_event(const sapp_event* e) { + if ((e->modifiers & SAPP_MODIFIER_CTRL) && (e->type == SAPP_EVENTTYPE_KEY_DOWN)) { + switch (e->key_code) { + case SAPP_KEYCODE_O: { + select_scene_file(); + break; + } + case SAPP_KEYCODE_R: { + if (callbacks.reload_scene_selected) + callbacks.reload_scene_selected(); + break; + } + case SAPP_KEYCODE_G: { + if (callbacks.reload_geometry_selected) + callbacks.reload_geometry_selected(); + break; + } + } + } + return simgui_handle_event(e); +} + +ViewOptions UI::view_options() const { + return { + _view_options.get("out_view", uint32_t(OutputView::Result)).to_enum(), + ViewOptions::ToneMapping | ViewOptions::sRGB, + _view_options.get("exp", 1.0f).to_float(), + }; +} + +void UI::set_current_integrator(Integrator* i) { + _current_integrator = i; + _integrator_name = _current_integrator ? _current_integrator->name() : ""; + _integrator_options = _current_integrator ? _current_integrator->options() : Options{}; +} + +void UI::select_scene_file() { + auto selected_file = open_file({"Supported formats", "*.json;*.obj"}); // TODO : add *.gltf;*.pbrt + if ((selected_file.empty() == false) && callbacks.scene_file_selected) { + callbacks.scene_file_selected(selected_file); + } +} + +} // namespace etx diff --git a/sources/raytracer/ui.hxx b/sources/raytracer/ui.hxx new file mode 100644 index 0000000..82d2511 --- /dev/null +++ b/sources/raytracer/ui.hxx @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include +#include + +#include + +#include "options.hxx" + +struct sapp_event; + +namespace etx { + +struct UI { + void initialize(); + void build(double dt, const char* status); + + void set_integrator_list(Integrator* i[], uint64_t count) { + _integrators = {i, count}; + } + + void set_current_integrator(Integrator*); + + const Options& integrator_options() const { + return _integrator_options; + } + + bool handle_event(const sapp_event*); + + ViewOptions view_options() const; + + struct { + std::function reference_image_selected; + std::function scene_file_selected; + std::function integrator_selected; + std::function stop_selected; + std::function preview_selected; + std::function run_selected; + std::function reload_scene_selected; + std::function reload_geometry_selected; + } callbacks; + + private: + void build_options(Options&); + void select_scene_file(); + + private: + Integrator* _current_integrator = {}; + ArrayView _integrators = {}; + Options _view_options = {}; + Options _integrator_options = {}; + const char* _integrator_name = {}; +}; + +} // namespace etx diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 8b18202..4419947 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1 +1,18 @@ add_subdirectory(sokol_app) +add_subdirectory(sokol_gfx) +add_subdirectory(imgui) + +add_subdirectory(sokol_imgui) + +add_subdirectory(glm) + +add_subdirectory(stb_image) +add_subdirectory(tinyexr) + +add_subdirectory(jansson) + +add_subdirectory(tinyobjloader) +add_subdirectory(mikktspace) + +add_subdirectory(enkits) + diff --git a/thirdparty/enkits/CMakeLists.txt b/thirdparty/enkits/CMakeLists.txt new file mode 100644 index 0000000..ae77283 --- /dev/null +++ b/thirdparty/enkits/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.0) + +project( enkiTS ) + +set( ENKITS_TASK_PRIORITIES_NUM "3" CACHE STRING "Number of task priorities, 1-5, 0 for defined by defaults in source" ) + +set( ENKITS_SRC + LockLessMultiReadPipe.hxx + TaskScheduler.hxx + TaskScheduler.cxx + ) + +list( APPEND ENKITS_SRC ${ENKITS_HEADERS} ) + +add_library( enkiTS STATIC ${ENKITS_SRC} ) +target_include_directories( enkiTS PUBLIC "${CMAKE_CURRENT_LIST_DIR}" ) +set_target_properties(enkiTS PROPERTIES FOLDER "thirdparty") + +if( ENKITS_TASK_PRIORITIES_NUM GREATER "0" ) + target_compile_definitions( enkiTS PUBLIC "ENKITS_TASK_PRIORITIES_NUM=${ENKITS_TASK_PRIORITIES_NUM}" ) +endif() + +if( UNIX ) + set( CMAKE_THREAD_PREFER_PTHREAD TRUE ) + find_package( Threads REQUIRED ) + if( CMAKE_USE_PTHREADS_INIT ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" ) + endif() + target_link_libraries( enkiTS ${CMAKE_THREAD_LIBS_INIT} ) + + SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) +endif() + +if( APPLE ) + SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++" ) +endif() diff --git a/thirdparty/enkits/LockLessMultiReadPipe.hxx b/thirdparty/enkits/LockLessMultiReadPipe.hxx new file mode 100644 index 0000000..339c8bd --- /dev/null +++ b/thirdparty/enkits/LockLessMultiReadPipe.hxx @@ -0,0 +1,283 @@ +// Copyright (c) 2013 Doug Binks +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#pragma once + +#include +#include +#include + +#ifndef ENKI_ASSERT +#include +#define ENKI_ASSERT(x) assert(x) +#endif + +namespace enki +{ + // LockLessMultiReadPipe - Single writer, multiple reader thread safe pipe using (semi) lockless programming + // Readers can only read from the back of the pipe + // The single writer can write to the front of the pipe, and read from both ends (a writer can be a reader) + // for many of the principles used here, see http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650(v=vs.85).aspx + // Note: using log2 sizes so we do not need to clamp (multi-operation) + // T is the contained type + // Note this is not true lockless as the use of flags as a form of lock state. + template class LockLessMultiReadPipe + { + public: + LockLessMultiReadPipe(); + ~LockLessMultiReadPipe() {} + + // ReaderTryReadBack returns false if we were unable to read + // This is thread safe for both multiple readers and the writer + bool ReaderTryReadBack( T* pOut ); + + // WriterTryReadFront returns false if we were unable to read + // This is thread safe for the single writer, but should not be called by readers + bool WriterTryReadFront( T* pOut ); + + // WriterTryWriteFront returns false if we were unable to write + // This is thread safe for the single writer, but should not be called by readers + bool WriterTryWriteFront( const T& in ); + + // IsPipeEmpty() is a utility function, not intended for general use + // Should only be used very prudently. + bool IsPipeEmpty() const + { + return 0 == m_WriteIndex.load( std::memory_order_relaxed ) - m_ReadCount.load( std::memory_order_relaxed ); + } + + void Clear() + { + m_WriteIndex = 0; + m_ReadIndex = 0; + m_ReadCount = 0; + memset( (void*)m_Flags, 0, sizeof( m_Flags ) ); + } + + private: + const static uint32_t ms_cSize = ( 1 << cSizeLog2 ); + const static uint32_t ms_cIndexMask = ms_cSize - 1; + const static uint32_t FLAG_INVALID = 0xFFFFFFFF; // 32bit for CAS + const static uint32_t FLAG_CAN_WRITE = 0x00000000; // 32bit for CAS + const static uint32_t FLAG_CAN_READ = 0x11111111; // 32bit for CAS + + T m_Buffer[ ms_cSize ]; + + // read and write indexes allow fast access to the pipe, but actual access + // controlled by the access flags. + std::atomic m_WriteIndex; + std::atomic m_ReadCount; + std::atomic m_Flags[ ms_cSize ]; + std::atomic m_ReadIndex; + }; + + template inline + LockLessMultiReadPipe::LockLessMultiReadPipe() + : m_WriteIndex(0) + , m_ReadCount(0) + , m_ReadIndex(0) + { + ENKI_ASSERT( cSizeLog2 < 32 ); + memset( (void*)m_Flags, 0, sizeof( m_Flags ) ); + } + + template inline + bool LockLessMultiReadPipe::ReaderTryReadBack( T* pOut ) + { + + uint32_t actualReadIndex; + uint32_t readCount = m_ReadCount.load( std::memory_order_relaxed ); + + // We get hold of read index for consistency + // and do first pass starting at read count + uint32_t readIndexToUse = readCount; + while(true) + { + + uint32_t writeIndex = m_WriteIndex.load( std::memory_order_relaxed ); + // power of two sizes ensures we can use a simple calc without modulus + uint32_t numInPipe = writeIndex - readCount; + if( 0 == numInPipe ) + { + return false; + } + if( readIndexToUse >= writeIndex ) + { + readIndexToUse = m_ReadIndex.load( std::memory_order_relaxed ); + } + + // power of two sizes ensures we can perform AND for a modulus + actualReadIndex = readIndexToUse & ms_cIndexMask; + + // Multiple potential readers mean we should check if the data is valid, + // using an atomic compare exchange + uint32_t previous = FLAG_CAN_READ; + bool bSuccess = m_Flags[ actualReadIndex ].compare_exchange_strong( previous, FLAG_INVALID, std::memory_order_acq_rel, std::memory_order_relaxed ); + if( bSuccess ) + { + break; + } + ++readIndexToUse; + + // Update read count + readCount = m_ReadCount.load( std::memory_order_relaxed ); + } + + // we update the read index using an atomic add, as we've only read one piece of data. + // this ensure consistency of the read index, and the above loop ensures readers + // only read from unread data + m_ReadCount.fetch_add(1, std::memory_order_relaxed ); + + // now read data, ensuring we do so after above reads & CAS + *pOut = m_Buffer[ actualReadIndex ]; + + m_Flags[ actualReadIndex ].store( FLAG_CAN_WRITE, std::memory_order_release ); + + return true; + } + + template inline + bool LockLessMultiReadPipe::WriterTryReadFront( T* pOut ) + { + uint32_t writeIndex = m_WriteIndex.load( std::memory_order_relaxed ); + uint32_t frontReadIndex = writeIndex; + + // Multiple potential readers mean we should check if the data is valid, + // using an atomic compare exchange - which acts as a form of lock (so not quite lockless really). + uint32_t actualReadIndex = 0; + while(true) + { + uint32_t readCount = m_ReadCount.load( std::memory_order_relaxed ); + // power of two sizes ensures we can use a simple calc without modulus + uint32_t numInPipe = writeIndex - readCount; + if( 0 == numInPipe ) + { + m_ReadIndex.store( readCount, std::memory_order_release ); + return false; + } + --frontReadIndex; + actualReadIndex = frontReadIndex & ms_cIndexMask; + uint32_t previous = FLAG_CAN_READ; + bool success = m_Flags[ actualReadIndex ].compare_exchange_strong( previous, FLAG_INVALID, std::memory_order_acq_rel, std::memory_order_relaxed ); + if( success ) + { + break; + } + else if( m_ReadIndex.load( std::memory_order_acquire ) >= frontReadIndex ) + { + return false; + } + } + + // now read data, ensuring we do so after above reads & CAS + *pOut = m_Buffer[ actualReadIndex ]; + + m_Flags[ actualReadIndex ].store( FLAG_CAN_WRITE, std::memory_order_relaxed ); + + m_WriteIndex.store(writeIndex-1, std::memory_order_relaxed); + return true; + } + + + template inline + bool LockLessMultiReadPipe::WriterTryWriteFront( const T& in ) + { + // The writer 'owns' the write index, and readers can only reduce + // the amount of data in the pipe. + // We get hold of both values for consistency and to reduce false sharing + // impacting more than one access + uint32_t writeIndex = m_WriteIndex; + + // power of two sizes ensures we can perform AND for a modulus + uint32_t actualWriteIndex = writeIndex & ms_cIndexMask; + + // a reader may still be reading this item, as there are multiple readers + if( m_Flags[ actualWriteIndex ].load(std::memory_order_acquire) != FLAG_CAN_WRITE ) + { + return false; // still being read, so have caught up with tail. + } + + // as we are the only writer we can update the data without atomics + // whilst the write index has not been updated + m_Buffer[ actualWriteIndex ] = in; + m_Flags[ actualWriteIndex ].store( FLAG_CAN_READ, std::memory_order_release ); + + m_WriteIndex.fetch_add(1, std::memory_order_relaxed); + return true; + } + + + // Lockless multiwriter intrusive list + // Type T must implement T* volatile pNext; + template class LocklessMultiWriteIntrusiveList + { + + std::atomic pHead; + T tail; + public: + LocklessMultiWriteIntrusiveList() : pHead( &tail ) + { + tail.pNext = NULL; + } + + bool IsListEmpty() const + { + return pHead == &tail; + } + + // Add - safe to perform from any thread + void WriterWriteFront( T* pNode_ ) + { + ENKI_ASSERT( pNode_ ); + pNode_->pNext = NULL; + T* pPrev = pHead.exchange( pNode_ ); + pPrev->pNext = pNode_; + } + + // Remove - only thread safe for owner + T* ReaderReadBack() + { + T* pTailPlus1 = tail.pNext; + if( pTailPlus1 ) + { + T* pTailPlus2 = pTailPlus1->pNext; + if( pTailPlus2 ) + { + //not head + tail.pNext = pTailPlus2; + } + else + { + tail.pNext = NULL; + T* pCompare = pTailPlus1; // we need preserve pTailPlus1 as compare will alter it on failure + // pTailPlus1 is the head, attempt swap with tail + if( !pHead.compare_exchange_strong( pCompare, &tail ) ) + { + // pCompare receives the revised pHead on failure. + // pTailPlus1 is no longer the head, so pTailPlus1->pNext should be non NULL + while( (T*)NULL == pTailPlus1->pNext ) {;} // wait for pNext to be updated as head may have just changed. + tail.pNext = pTailPlus1->pNext.load(); + pTailPlus1->pNext = NULL; + } + } + } + return pTailPlus1; + } + }; + +} diff --git a/thirdparty/enkits/TaskScheduler.cxx b/thirdparty/enkits/TaskScheduler.cxx new file mode 100644 index 0000000..095e982 --- /dev/null +++ b/thirdparty/enkits/TaskScheduler.cxx @@ -0,0 +1,1199 @@ +// Copyright (c) 2013 Doug Binks +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "TaskScheduler.hxx" +#include "LockLessMultiReadPipe.hxx" + +#include + +#if defined __i386__ || defined __x86_64__ +#include "x86intrin.h" +#elif defined _WIN32 +#include +#endif + +using namespace enki; + +#if defined(ENKI_CUSTOM_ALLOC_FILE_AND_LINE) +#define ENKI_FILE_AND_LINE __FILE__, __LINE__ +#else +namespace { +const char* gc_File = ""; +const uint32_t gc_Line = 0; +} // namespace +#define ENKI_FILE_AND_LINE gc_File, gc_Line +#endif + +namespace enki { +static const int32_t gc_TaskStartCount = 2; +static const int32_t gc_TaskAlmostCompleteCount = 1; // GetIsComplete() will return false, but execution is done and about to complete +static const uint32_t gc_PipeSizeLog2 = 8; +static const uint32_t gc_SpinCount = 10; +static const uint32_t gc_SpinBackOffMulitplier = 100; +static const uint32_t gc_MaxNumInitialPartitions = 8; +static const uint32_t gc_CacheLineSize = 64; +// awaiting std::hardware_constructive_interference_size +}; // namespace enki + +// thread_local not well supported yet by C++11 compilers. +#ifdef _MSC_VER +#if _MSC_VER <= 1800 +#define thread_local __declspec(thread) +#endif +#elif __APPLE__ + // Apple thread_local currently not implemented despite it being in Clang. +#define thread_local __thread +#endif + +// each software thread gets it's own copy of gtl_threadNum, so this is safe to use as a static variable +static thread_local uint32_t gtl_threadNum = 0; + +namespace enki { +struct SubTaskSet { + ITaskSet* pTask; + TaskSetPartition partition; +}; + +// we derive class TaskPipe rather than typedef to get forward declaration working easily +class TaskPipe : public LockLessMultiReadPipe {}; + +enum ThreadState : int32_t { + ENKI_THREAD_STATE_NONE, // shouldn't get this value + ENKI_THREAD_STATE_NOT_LAUNCHED, // for debug purposes - indicates enki task thread not yet launched + ENKI_THREAD_STATE_RUNNING, + ENKI_THREAD_STATE_PRIMARY_REGISTERED, // primary thread is the one enkiTS was initialized on + ENKI_THREAD_STATE_EXTERNAL_REGISTERED, + ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED, + ENKI_THREAD_STATE_WAIT_TASK_COMPLETION, + ENKI_THREAD_STATE_WAIT_NEW_TASKS, + ENKI_THREAD_STATE_WAIT_NEW_PINNED_TASKS, + ENKI_THREAD_STATE_STOPPED, +}; + +struct ThreadArgs { + uint32_t threadNum; + TaskScheduler* pTaskScheduler; +}; + +struct alignas(enki::gc_CacheLineSize) ThreadDataStore { + std::atomic threadState = {ENKI_THREAD_STATE_NONE}; + semaphoreid_t* pWaitNewPinnedTaskSemaphore = nullptr; + char prevent_false_Share[enki::gc_CacheLineSize - sizeof(std::atomic)]; +}; +static_assert(sizeof(ThreadDataStore) >= enki::gc_CacheLineSize, "ThreadDataStore may exhibit false sharing"); + +class PinnedTaskList : public LocklessMultiWriteIntrusiveList {}; + +semaphoreid_t* SemaphoreCreate(); +void SemaphoreDelete(semaphoreid_t* pSemaphore_); +void SemaphoreWait(semaphoreid_t& semaphoreid); +void SemaphoreSignal(semaphoreid_t& semaphoreid, int32_t countWaiting); +} // namespace enki + +namespace { +SubTaskSet SplitTask(SubTaskSet& subTask_, uint32_t rangeToSplit_) { + SubTaskSet splitTask = subTask_; + uint32_t rangeLeft = subTask_.partition.end - subTask_.partition.start; + + if (rangeToSplit_ > rangeLeft) { + rangeToSplit_ = rangeLeft; + } + splitTask.partition.end = subTask_.partition.start + rangeToSplit_; + subTask_.partition.start = splitTask.partition.end; + return splitTask; +} + +#if (defined _WIN32 && (defined _M_IX86 || defined _M_X64)) || (defined __i386__ || defined __x86_64__) +// Note: see https://software.intel.com/en-us/articles/a-common-construct-to-avoid-the-contention-of-threads-architecture-agnostic-spin-wait-loops +static void SpinWait(uint32_t spinCount_) { + uint64_t end = __rdtsc() + spinCount_; + while (__rdtsc() < end) { + _mm_pause(); + } +} +#else +static void SpinWait(uint32_t spinCount_) { + while (spinCount_) { + // TODO: may have NOP or yield equiv + --spinCount_; + } +} +#endif +} // namespace + +static void SafeCallback(ProfilerCallbackFunc func_, uint32_t threadnum_) { + if (func_ != nullptr) { + func_(threadnum_); + } +} + +ENKITS_API void* enki::DefaultAllocFunc(size_t align_, size_t size_, void* userData_, const char* file_, int line_) { + (void)userData_; + (void)file_; + (void)line_; + void* pRet; +#ifdef _WIN32 + pRet = (void*)_aligned_malloc(size_, align_); +#else + pRet = nullptr; + if (align_ <= size_ && align_ <= alignof(int64_t)) { + // no need for alignment, use malloc + pRet = malloc(size_); + } else { + int retval = posix_memalign(&pRet, align_, size_); + (void)retval; // unused + } +#endif + return pRet; +}; + +ENKITS_API void enki::DefaultFreeFunc(void* ptr_, size_t size_, void* userData_, const char* file_, int line_) { + (void)size_; + (void)userData_; + (void)file_; + (void)line_; +#ifdef _WIN32 + _aligned_free(ptr_); +#else + free(ptr_); +#endif +}; + +bool TaskScheduler::RegisterExternalTaskThread() { + bool bRegistered = false; + while (!bRegistered && m_NumExternalTaskThreadsRegistered < (int32_t)m_Config.numExternalTaskThreads) { + for (uint32_t thread = GetNumFirstExternalTaskThread(); thread < GetNumFirstExternalTaskThread() + m_Config.numExternalTaskThreads; ++thread) { + ThreadState threadStateExpected = ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED; + if (m_pThreadDataStore[thread].threadState.compare_exchange_strong(threadStateExpected, ENKI_THREAD_STATE_EXTERNAL_REGISTERED)) { + ++m_NumExternalTaskThreadsRegistered; + gtl_threadNum = thread; + bRegistered = true; + break; + } + } + } + return bRegistered; +} + +bool TaskScheduler::RegisterExternalTaskThread(uint32_t threadNumToRegister_) { + ENKI_ASSERT(threadNumToRegister_ >= GetNumFirstExternalTaskThread()); + ENKI_ASSERT(threadNumToRegister_ < (GetNumFirstExternalTaskThread() + m_Config.numExternalTaskThreads)); + ThreadState threadStateExpected = ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED; + if (m_pThreadDataStore[threadNumToRegister_].threadState.compare_exchange_strong(threadStateExpected, ENKI_THREAD_STATE_EXTERNAL_REGISTERED)) { + ++m_NumExternalTaskThreadsRegistered; + gtl_threadNum = threadNumToRegister_; + return true; + } + return false; +} + +void TaskScheduler::DeRegisterExternalTaskThread() { + ENKI_ASSERT(gtl_threadNum); + ThreadState threadState = m_pThreadDataStore[gtl_threadNum].threadState.load(std::memory_order_acquire); + ENKI_ASSERT(threadState == ENKI_THREAD_STATE_EXTERNAL_REGISTERED); + if (threadState == ENKI_THREAD_STATE_EXTERNAL_REGISTERED) { + --m_NumExternalTaskThreadsRegistered; + m_pThreadDataStore[gtl_threadNum].threadState.store(ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED, std::memory_order_release); + gtl_threadNum = 0; + } +} + +uint32_t TaskScheduler::GetNumRegisteredExternalTaskThreads() { + return m_NumExternalTaskThreadsRegistered; +} + +void TaskScheduler::TaskingThreadFunction(const ThreadArgs& args_) { + uint32_t threadNum = args_.threadNum; + TaskScheduler* pTS = args_.pTaskScheduler; + gtl_threadNum = threadNum; + + pTS->m_pThreadDataStore[threadNum].threadState.store(ENKI_THREAD_STATE_RUNNING, std::memory_order_release); + SafeCallback(pTS->m_Config.profilerCallbacks.threadStart, threadNum); + + uint32_t spinCount = 0; + uint32_t hintPipeToCheck_io = threadNum + 1; // does not need to be clamped. + while (pTS->GetIsRunning()) { + if (!pTS->TryRunTask(threadNum, hintPipeToCheck_io)) { + // no tasks, will spin then wait + ++spinCount; + if (spinCount > gc_SpinCount) { + pTS->WaitForNewTasks(threadNum); + } else { + uint32_t spinBackoffCount = spinCount * gc_SpinBackOffMulitplier; + SpinWait(spinBackoffCount); + } + } else { + spinCount = 0; // have run a task so reset spin count. + } + } + + pTS->m_NumInternalTaskThreadsRunning.fetch_sub(1, std::memory_order_release); + pTS->m_pThreadDataStore[threadNum].threadState.store(ENKI_THREAD_STATE_STOPPED, std::memory_order_release); + SafeCallback(pTS->m_Config.profilerCallbacks.threadStop, threadNum); + return; +} + +void SetThreadName(std::thread& thread, const std::string& threadName); + +void TaskScheduler::StartThreads() { + if (m_bHaveThreads) { + return; + } + + m_NumThreads = m_Config.numTaskThreadsToCreate + m_Config.numExternalTaskThreads + 1; + + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + m_pPipesPerThread[priority] = NewArray(m_NumThreads, ENKI_FILE_AND_LINE); + m_pPinnedTaskListPerThread[priority] = NewArray(m_NumThreads, ENKI_FILE_AND_LINE); + } + + m_pNewTaskSemaphore = SemaphoreNew(); + m_pTaskCompleteSemaphore = SemaphoreNew(); + + // we create one less thread than m_NumThreads as the main thread counts as one + m_pThreadDataStore = NewArray(m_NumThreads, ENKI_FILE_AND_LINE); + m_pThreads = NewArray(m_NumThreads, ENKI_FILE_AND_LINE); + m_bRunning = true; + m_bWaitforAllCalled = false; + + // current thread is primary enkiTS thread + m_pThreadDataStore[0].threadState = ENKI_THREAD_STATE_PRIMARY_REGISTERED; + gtl_threadNum = 0; + + for (uint32_t thread = GetNumFirstExternalTaskThread(); thread < m_Config.numExternalTaskThreads + GetNumFirstExternalTaskThread(); ++thread) { + m_pThreadDataStore[thread].threadState = ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED; + } + for (uint32_t thread = m_Config.numExternalTaskThreads + GetNumFirstExternalTaskThread(); thread < m_NumThreads; ++thread) { + m_pThreadDataStore[thread].threadState = ENKI_THREAD_STATE_NOT_LAUNCHED; + } + // only launch threads once all thread states are set + for (uint32_t thread = m_Config.numExternalTaskThreads + GetNumFirstExternalTaskThread(); thread < m_NumThreads; ++thread) { + m_pThreads[thread] = std::thread(TaskingThreadFunction, ThreadArgs{thread, this}); + SetThreadName(m_pThreads[thread], "TaskThread" + std::to_string(thread)); + ++m_NumInternalTaskThreadsRunning; + } + + // Create Wait New Pinned Task Semaphores + for (uint32_t threadNum = 0; threadNum < m_NumThreads; ++threadNum) { + m_pThreadDataStore[threadNum].pWaitNewPinnedTaskSemaphore = SemaphoreNew(); + } + + // ensure we have sufficient tasks to equally fill either all threads including main + // or just the threads we've launched, this is outside the firstinit as we want to be able + // to runtime change it + if (1 == m_NumThreads) { + m_NumPartitions = 1; + m_NumInitialPartitions = 1; + } else { + // There could be more threads than hardware threads if external threads are + // being intended for blocking functionality such as io etc. + // We only need to partition for a maximum of the available processor parallelism. + uint32_t numThreadsToPartitionFor = std::min(m_NumThreads, GetNumHardwareThreads()); + m_NumPartitions = numThreadsToPartitionFor * (numThreadsToPartitionFor - 1); + // ensure m_NumPartitions, m_NumInitialPartitions non zero, can happen if m_NumThreads > 1 && GetNumHardwareThreads() == 1 + m_NumPartitions = std::max(m_NumPartitions, (uint32_t)1); + m_NumInitialPartitions = std::max(numThreadsToPartitionFor - 1, (uint32_t)1); + if (m_NumInitialPartitions > gc_MaxNumInitialPartitions) { + m_NumInitialPartitions = gc_MaxNumInitialPartitions; + } + } + + m_bHaveThreads = true; +} + +void TaskScheduler::StopThreads(bool bWait_) { + if (m_bHaveThreads) { + // wait for them threads quit before deleting data + m_bRunning.store(false, std::memory_order_release); + m_bWaitforAllCalled.store(false, std::memory_order_release); + + while (bWait_ && m_NumInternalTaskThreadsRunning) { + // keep firing event to ensure all threads pick up state of m_bRunning + WakeThreadsForNewTasks(); + + for (uint32_t threadId = 0; threadId < m_NumThreads; ++threadId) { + // send wait for new pinned tasks signal to ensure any waiting are awoken + SemaphoreSignal(*m_pThreadDataStore[threadId].pWaitNewPinnedTaskSemaphore, 1); + } + } + + // detach threads starting with thread GetNumFirstExternalTaskThread() (as 0 is initialization thread). + for (uint32_t thread = m_Config.numExternalTaskThreads + GetNumFirstExternalTaskThread(); thread < m_NumThreads; ++thread) { + ENKI_ASSERT(m_pThreads[thread].joinable()); + m_pThreads[thread].join(); + } + + // delete any Wait New Pinned Task Semaphores + for (uint32_t threadNum = 0; threadNum < m_NumThreads; ++threadNum) { + SemaphoreDelete(m_pThreadDataStore[threadNum].pWaitNewPinnedTaskSemaphore); + } + + DeleteArray(m_pThreadDataStore, m_NumThreads, ENKI_FILE_AND_LINE); + DeleteArray(m_pThreads, m_NumThreads, ENKI_FILE_AND_LINE); + m_pThreadDataStore = 0; + m_pThreads = 0; + + SemaphoreDelete(m_pNewTaskSemaphore); + m_pNewTaskSemaphore = 0; + SemaphoreDelete(m_pTaskCompleteSemaphore); + m_pTaskCompleteSemaphore = 0; + + m_bHaveThreads = false; + m_NumThreadsWaitingForNewTasks = 0; + m_NumThreadsWaitingForTaskCompletion = 0; + m_NumInternalTaskThreadsRunning = 0; + m_NumExternalTaskThreadsRegistered = 0; + + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + DeleteArray(m_pPipesPerThread[priority], m_NumThreads, ENKI_FILE_AND_LINE); + m_pPipesPerThread[priority] = NULL; + DeleteArray(m_pPinnedTaskListPerThread[priority], m_NumThreads, ENKI_FILE_AND_LINE); + m_pPinnedTaskListPerThread[priority] = NULL; + } + m_NumThreads = 0; + } +} + +bool TaskScheduler::TryRunTask(uint32_t threadNum_, uint32_t& hintPipeToCheck_io_) { + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + if (TryRunTask(threadNum_, priority, hintPipeToCheck_io_)) { + return true; + } + } + return false; +} + +bool TaskScheduler::TryRunTask(uint32_t threadNum_, uint32_t priority_, uint32_t& hintPipeToCheck_io_) { + // Run any tasks for this thread + RunPinnedTasks(threadNum_, priority_); + + // check for tasks + SubTaskSet subTask; + bool bHaveTask = m_pPipesPerThread[priority_][threadNum_].WriterTryReadFront(&subTask); + + uint32_t threadToCheck = hintPipeToCheck_io_; + uint32_t checkCount = 0; + while (!bHaveTask && checkCount < m_NumThreads) { + threadToCheck = (hintPipeToCheck_io_ + checkCount) % m_NumThreads; + if (threadToCheck != threadNum_) { + bHaveTask = m_pPipesPerThread[priority_][threadToCheck].ReaderTryReadBack(&subTask); + } + ++checkCount; + } + + if (bHaveTask) { + // update hint, will preserve value unless actually got task from another thread. + hintPipeToCheck_io_ = threadToCheck; + + uint32_t partitionSize = subTask.partition.end - subTask.partition.start; + if (subTask.pTask->m_RangeToRun < partitionSize) { + SubTaskSet taskToRun = SplitTask(subTask, subTask.pTask->m_RangeToRun); + SplitAndAddTask(threadNum_, subTask, subTask.pTask->m_RangeToRun); + taskToRun.pTask->ExecuteRange(taskToRun.partition, threadNum_); + int prevCount = taskToRun.pTask->m_RunningCount.fetch_sub(1, std::memory_order_release); + if (gc_TaskStartCount == prevCount) { + TaskComplete(taskToRun.pTask, true, threadNum_); + } + } else { + // the task has already been divided up by AddTaskSetToPipe, so just run it + subTask.pTask->ExecuteRange(subTask.partition, threadNum_); + int prevCount = subTask.pTask->m_RunningCount.fetch_sub(1, std::memory_order_release); + if (gc_TaskStartCount == prevCount) { + TaskComplete(subTask.pTask, true, threadNum_); + } + } + } + + return bHaveTask; +} + +void TaskScheduler::TaskComplete(ICompletable* pTask_, bool bWakeThreads_, uint32_t threadNum_) { + // It must be impossible for a thread to enter the sleeping wait prior to the load of m_WaitingForTaskCount + // in this function, so we introduce an gc_TaskAlmostCompleteCount to prevent this. + ENKI_ASSERT(gc_TaskAlmostCompleteCount == pTask_->m_RunningCount.load(std::memory_order_acquire)); + bool bCallWakeThreads = bWakeThreads_ && pTask_->m_WaitingForTaskCount.load(std::memory_order_acquire); + + Dependency* pDependent = pTask_->m_pDependents; + + // Do not access pTask_ below this line unless we have dependencies. + pTask_->m_RunningCount.store(0, std::memory_order_release); + + if (bCallWakeThreads) { + WakeThreadsForTaskCompletion(); + } + + while (pDependent) { + int prevDeps = pDependent->pTaskToRunOnCompletion->m_DependenciesCompletedCount.fetch_add(1, std::memory_order_release); + ENKI_ASSERT(prevDeps < pDependent->pTaskToRunOnCompletion->m_DependenciesCount); + if (pDependent->pTaskToRunOnCompletion->m_DependenciesCount == (prevDeps + 1)) { + // get temp copy of pDependent so OnDependenciesComplete can delete task if needed. + Dependency* pDependentCurr = pDependent; + pDependent = pDependent->pNext; + // reset dependencies + pDependentCurr->pTaskToRunOnCompletion->m_DependenciesCompletedCount.store(0, std::memory_order_release); + pDependentCurr->pTaskToRunOnCompletion->OnDependenciesComplete(this, threadNum_); + } else { + pDependent = pDependent->pNext; + } + } +} + +bool TaskScheduler::HaveTasks(uint32_t threadNum_) { + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + for (uint32_t thread = 0; thread < m_NumThreads; ++thread) { + if (!m_pPipesPerThread[priority][thread].IsPipeEmpty()) { + return true; + } + } + if (!m_pPinnedTaskListPerThread[priority][threadNum_].IsListEmpty()) { + return true; + } + } + return false; +} + +void TaskScheduler::WaitForNewTasks(uint32_t threadNum_) { + // We don't want to suspend this thread if there are task threads + // with pinned tasks suspended, as it could result in this thread + // being unsuspended and not the thread with pinned tasks + if (WakeSuspendedThreadsWithPinnedTasks()) { + return; + } + + // We incrememt the number of threads waiting here in order + // to ensure that the check for tasks occurs after the increment + // to prevent a task being added after a check, then the thread waiting. + // This will occasionally result in threads being mistakenly awoken, + // but they will then go back to sleep. + m_NumThreadsWaitingForNewTasks.fetch_add(1, std::memory_order_acquire); + ThreadState prevThreadState = m_pThreadDataStore[threadNum_].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum_].threadState.store(ENKI_THREAD_STATE_WAIT_NEW_TASKS, std::memory_order_seq_cst); + + if (HaveTasks(threadNum_)) { + m_NumThreadsWaitingForNewTasks.fetch_sub(1, std::memory_order_release); + } else { + SafeCallback(m_Config.profilerCallbacks.waitForNewTaskSuspendStart, threadNum_); + SemaphoreWait(*m_pNewTaskSemaphore); + SafeCallback(m_Config.profilerCallbacks.waitForNewTaskSuspendStop, threadNum_); + } + + m_pThreadDataStore[threadNum_].threadState.store(prevThreadState, std::memory_order_release); +} + +void TaskScheduler::WaitForTaskCompletion(const ICompletable* pCompletable_, uint32_t threadNum_) { + // We don't want to suspend this thread if there are task threads + // with pinned tasks suspended, as the completable could be a pinned task + // or it could be waiting on one. + if (WakeSuspendedThreadsWithPinnedTasks()) { + return; + } + + m_NumThreadsWaitingForTaskCompletion.fetch_add(1, std::memory_order_acquire); + pCompletable_->m_WaitingForTaskCount.fetch_add(1, std::memory_order_acquire); + ThreadState prevThreadState = m_pThreadDataStore[threadNum_].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum_].threadState.store(ENKI_THREAD_STATE_WAIT_TASK_COMPLETION, std::memory_order_seq_cst); + + // do not wait on semaphore if task in gc_TaskAlmostCompleteCount state. + if (gc_TaskAlmostCompleteCount >= pCompletable_->m_RunningCount.load(std::memory_order_acquire) || HaveTasks(threadNum_)) { + m_NumThreadsWaitingForTaskCompletion.fetch_sub(1, std::memory_order_release); + } else { + SafeCallback(m_Config.profilerCallbacks.waitForTaskCompleteSuspendStart, threadNum_); + std::atomic_thread_fence(std::memory_order_acquire); + + SemaphoreWait(*m_pTaskCompleteSemaphore); + if (!pCompletable_->GetIsComplete()) { + // This thread which may not the one which was supposed to be awoken + WakeThreadsForTaskCompletion(); + } + SafeCallback(m_Config.profilerCallbacks.waitForTaskCompleteSuspendStop, threadNum_); + } + + m_pThreadDataStore[threadNum_].threadState.store(prevThreadState, std::memory_order_release); + pCompletable_->m_WaitingForTaskCount.fetch_sub(1, std::memory_order_release); +} + +void TaskScheduler::WakeThreadsForNewTasks() { + int32_t waiting = m_NumThreadsWaitingForNewTasks.load(std::memory_order_relaxed); + while (waiting > 0 && !m_NumThreadsWaitingForNewTasks.compare_exchange_weak(waiting, 0, std::memory_order_release, std::memory_order_relaxed)) { + } + + if (waiting > 0) { + SemaphoreSignal(*m_pNewTaskSemaphore, waiting); + } + + // We also wake tasks waiting for completion as they can run tasks + WakeThreadsForTaskCompletion(); +} + +void TaskScheduler::WakeThreadsForTaskCompletion() { + // m_NumThreadsWaitingForTaskCompletion can go negative as this indicates that + // we signalled more threads than the number which ended up waiting + int32_t waiting = m_NumThreadsWaitingForTaskCompletion.load(std::memory_order_relaxed); + while (waiting > 0 && !m_NumThreadsWaitingForTaskCompletion.compare_exchange_weak(waiting, 0, std::memory_order_release, std::memory_order_relaxed)) { + } + + if (waiting > 0) { + SemaphoreSignal(*m_pTaskCompleteSemaphore, waiting); + } +} + +bool TaskScheduler::WakeSuspendedThreadsWithPinnedTasks() { + uint32_t threadNum = gtl_threadNum; + for (uint32_t t = 1; t < m_NumThreads; ++t) { + // distribute thread checks more evenly by starting at our thread number rather than 0. + uint32_t thread = (threadNum + t) % m_NumThreads; + + ThreadState state = m_pThreadDataStore[thread].threadState.load(std::memory_order_acquire); + + ENKI_ASSERT(state != ENKI_THREAD_STATE_NONE); + + if (state == ENKI_THREAD_STATE_WAIT_NEW_TASKS || state == ENKI_THREAD_STATE_WAIT_TASK_COMPLETION) { + // thread is suspended, check if it has pinned tasks + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + if (!m_pPinnedTaskListPerThread[priority][thread].IsListEmpty()) { + WakeThreadsForNewTasks(); + return true; + } + } + } + } + return false; +} + +void TaskScheduler::SplitAndAddTask(uint32_t threadNum_, SubTaskSet subTask_, uint32_t rangeToSplit_) { + int32_t numAdded = 0; + int32_t numRun = 0; + // ensure that an artificial completion is not registered whilst adding tasks by incrementing count + subTask_.pTask->m_RunningCount.fetch_add(1, std::memory_order_acquire); + while (subTask_.partition.start != subTask_.partition.end) { + SubTaskSet taskToAdd = SplitTask(subTask_, rangeToSplit_); + + // add the partition to the pipe + ++numAdded; + subTask_.pTask->m_RunningCount.fetch_add(1, std::memory_order_acquire); + if (!m_pPipesPerThread[subTask_.pTask->m_Priority][threadNum_].WriterTryWriteFront(taskToAdd)) { + if (numAdded > 1) { + WakeThreadsForNewTasks(); + } + numAdded = 0; + // alter range to run the appropriate fraction + if (taskToAdd.pTask->m_RangeToRun < taskToAdd.partition.end - taskToAdd.partition.start) { + taskToAdd.partition.end = taskToAdd.partition.start + taskToAdd.pTask->m_RangeToRun; + ENKI_ASSERT(taskToAdd.partition.end <= taskToAdd.pTask->m_SetSize); + subTask_.partition.start = taskToAdd.partition.end; + } + taskToAdd.pTask->ExecuteRange(taskToAdd.partition, threadNum_); + ++numRun; + } + } + int prevCount = subTask_.pTask->m_RunningCount.fetch_sub(numRun + 1, std::memory_order_release); + if (numRun + gc_TaskStartCount == prevCount) { + TaskComplete(subTask_.pTask, false, threadNum_); + } + + // WakeThreadsForNewTasks also calls WakeThreadsForTaskCompletion() so do not need to do so above + WakeThreadsForNewTasks(); +} + +TaskSchedulerConfig TaskScheduler::GetConfig() const { + return m_Config; +} + +void TaskScheduler::AddTaskSetToPipeInt(ITaskSet* pTaskSet_, uint32_t threadNum_) { + ENKI_ASSERT(pTaskSet_->m_RunningCount == gc_TaskStartCount); + ThreadState prevThreadState = m_pThreadDataStore[threadNum_].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum_].threadState.store(ENKI_THREAD_STATE_RUNNING, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + // divide task up and add to pipe + pTaskSet_->m_RangeToRun = pTaskSet_->m_SetSize / m_NumPartitions; + if (pTaskSet_->m_RangeToRun < pTaskSet_->m_MinRange) { + pTaskSet_->m_RangeToRun = pTaskSet_->m_MinRange; + } + + uint32_t rangeToSplit = pTaskSet_->m_SetSize / m_NumInitialPartitions; + if (rangeToSplit < pTaskSet_->m_MinRange) { + rangeToSplit = pTaskSet_->m_MinRange; + } + + SubTaskSet subTask; + subTask.pTask = pTaskSet_; + subTask.partition.start = 0; + subTask.partition.end = pTaskSet_->m_SetSize; + SplitAndAddTask(threadNum_, subTask, rangeToSplit); + int prevCount = pTaskSet_->m_RunningCount.fetch_sub(1, std::memory_order_release); + if (gc_TaskStartCount == prevCount) { + TaskComplete(pTaskSet_, true, threadNum_); + } + + m_pThreadDataStore[threadNum_].threadState.store(prevThreadState, std::memory_order_release); +} + +void TaskScheduler::AddTaskSetToPipe(ITaskSet* pTaskSet_) { + ENKI_ASSERT(pTaskSet_->m_RunningCount == 0); + InitDependencies(pTaskSet_); + pTaskSet_->m_RunningCount.store(gc_TaskStartCount, std::memory_order_relaxed); + AddTaskSetToPipeInt(pTaskSet_, gtl_threadNum); +} + +void TaskScheduler::AddPinnedTaskInt(IPinnedTask* pTask_) { + ENKI_ASSERT(pTask_->m_RunningCount == gc_TaskStartCount); + m_pPinnedTaskListPerThread[pTask_->m_Priority][pTask_->threadNum].WriterWriteFront(pTask_); + + ThreadState statePinnedTaskThread = m_pThreadDataStore[pTask_->threadNum].threadState.load(std::memory_order_acquire); + if (statePinnedTaskThread == ENKI_THREAD_STATE_WAIT_NEW_PINNED_TASKS) { + SemaphoreSignal(*m_pThreadDataStore[pTask_->threadNum].pWaitNewPinnedTaskSemaphore, 1); + } else { + WakeThreadsForNewTasks(); + } +} + +void TaskScheduler::AddPinnedTask(IPinnedTask* pTask_) { + ENKI_ASSERT(pTask_->m_RunningCount == 0); + InitDependencies(pTask_); + pTask_->m_RunningCount = gc_TaskStartCount; + AddPinnedTaskInt(pTask_); +} + +void TaskScheduler::InitDependencies(ICompletable* pCompletable_) { + // go through any dependencies and set thier running count so they show as not complete + // and increment depedency count + if (pCompletable_->m_RunningCount.load(std::memory_order_relaxed)) { + // already initialized + return; + } + Dependency* pDependent = pCompletable_->m_pDependents; + while (pDependent) { + InitDependencies(pDependent->pTaskToRunOnCompletion); + pDependent->pTaskToRunOnCompletion->m_RunningCount.store(gc_TaskStartCount, std::memory_order_relaxed); + pDependent = pDependent->pNext; + } +} + +void TaskScheduler::RunPinnedTasks() { + uint32_t threadNum = gtl_threadNum; + ThreadState prevThreadState = m_pThreadDataStore[threadNum].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum].threadState.store(ENKI_THREAD_STATE_RUNNING, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + RunPinnedTasks(threadNum, priority); + } + m_pThreadDataStore[threadNum].threadState.store(prevThreadState, std::memory_order_release); +} + +void TaskScheduler::RunPinnedTasks(uint32_t threadNum_, uint32_t priority_) { + IPinnedTask* pPinnedTaskSet = NULL; + do { + pPinnedTaskSet = m_pPinnedTaskListPerThread[priority_][threadNum_].ReaderReadBack(); + if (pPinnedTaskSet) { + pPinnedTaskSet->Execute(); + pPinnedTaskSet->m_RunningCount.fetch_sub(1, std::memory_order_release); + TaskComplete(pPinnedTaskSet, true, threadNum_); + } + } while (pPinnedTaskSet); +} + +void TaskScheduler::WaitforTask(const ICompletable* pCompletable_, enki::TaskPriority priorityOfLowestToRun_) { + uint32_t threadNum = gtl_threadNum; + uint32_t hintPipeToCheck_io = threadNum + 1; // does not need to be clamped. + + // waiting for a task is equivalent to 'running' for thread state purpose as we may run tasks whilst waiting + ThreadState prevThreadState = m_pThreadDataStore[threadNum].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum].threadState.store(ENKI_THREAD_STATE_RUNNING, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (pCompletable_ && !pCompletable_->GetIsComplete()) { + SafeCallback(m_Config.profilerCallbacks.waitForTaskCompleteStart, threadNum); + // We need to ensure that the task we're waiting on can complete even if we're the only thread, + // so we clamp the priorityOfLowestToRun_ to no smaller than the task we're waiting for + priorityOfLowestToRun_ = std::max(priorityOfLowestToRun_, pCompletable_->m_Priority); + uint32_t spinCount = 0; + while (!pCompletable_->GetIsComplete()) { + ++spinCount; + for (int priority = 0; priority <= priorityOfLowestToRun_; ++priority) { + if (TryRunTask(threadNum, priority, hintPipeToCheck_io)) { + spinCount = 0; // reset spin as ran a task + break; + } + } + if (spinCount > gc_SpinCount) { + WaitForTaskCompletion(pCompletable_, threadNum); + spinCount = 0; + } else { + uint32_t spinBackoffCount = spinCount * gc_SpinBackOffMulitplier; + SpinWait(spinBackoffCount); + } + } + SafeCallback(m_Config.profilerCallbacks.waitForTaskCompleteStop, threadNum); + } else { + for (int priority = 0; priority <= priorityOfLowestToRun_; ++priority) { + if (TryRunTask(gtl_threadNum, priority, hintPipeToCheck_io)) { + break; + } + } + } + + m_pThreadDataStore[threadNum].threadState.store(prevThreadState, std::memory_order_release); +} + +class TaskSchedulerWaitTask : public IPinnedTask { + void Execute() override { + // do nothing + } +}; + +void TaskScheduler::WaitforAll() { + m_bWaitforAllCalled.store(true, std::memory_order_release); + + bool bHaveTasks = true; + uint32_t ourThreadNum = gtl_threadNum; + uint32_t hintPipeToCheck_io = ourThreadNum + 1; // does not need to be clamped. + bool otherThreadsRunning = false; // account for this thread + uint32_t spinCount = 0; + TaskSchedulerWaitTask dummyWaitTask; + dummyWaitTask.threadNum = 0; + while (bHaveTasks || otherThreadsRunning) { + bHaveTasks = TryRunTask(ourThreadNum, hintPipeToCheck_io); + ++spinCount; + if (bHaveTasks) { + spinCount = 0; // reset spin as ran a task + } + if (spinCount > gc_SpinCount) { + // find a running thread and add a dummy wait task + int32_t countThreadsToCheck = m_NumThreads - 1; + bool bHaveThreadToWaitOn = false; + do { + --countThreadsToCheck; + dummyWaitTask.threadNum = (dummyWaitTask.threadNum + 1) % m_NumThreads; + + // We can only add a pinned task to wait on if we find an enki Task Thread which isn't this thread. + // Otherwise we have to busy wait. + if (dummyWaitTask.threadNum != ourThreadNum && dummyWaitTask.threadNum > m_Config.numExternalTaskThreads) { + ThreadState state = m_pThreadDataStore[dummyWaitTask.threadNum].threadState.load(std::memory_order_acquire); + if (state == ENKI_THREAD_STATE_RUNNING || state == ENKI_THREAD_STATE_WAIT_TASK_COMPLETION) { + bHaveThreadToWaitOn = true; + break; + } + } + } while (countThreadsToCheck); + + if (bHaveThreadToWaitOn) { + ENKI_ASSERT(dummyWaitTask.threadNum != ourThreadNum); + AddPinnedTask(&dummyWaitTask); + WaitforTask(&dummyWaitTask); + } + spinCount = 0; + } else { + uint32_t spinBackoffCount = spinCount * gc_SpinBackOffMulitplier; + SpinWait(spinBackoffCount); + } + + // count threads running + otherThreadsRunning = false; + for (uint32_t thread = 0; thread < m_NumThreads && !otherThreadsRunning; ++thread) { + // ignore our thread + if (thread != ourThreadNum) { + switch (m_pThreadDataStore[thread].threadState.load(std::memory_order_acquire)) { + case ENKI_THREAD_STATE_NONE: + ENKI_ASSERT(false); + break; + case ENKI_THREAD_STATE_NOT_LAUNCHED: + case ENKI_THREAD_STATE_RUNNING: + case ENKI_THREAD_STATE_WAIT_TASK_COMPLETION: + otherThreadsRunning = true; + break; + case ENKI_THREAD_STATE_WAIT_NEW_PINNED_TASKS: + otherThreadsRunning = true; + SemaphoreSignal(*m_pThreadDataStore[thread].pWaitNewPinnedTaskSemaphore, 1); + break; + case ENKI_THREAD_STATE_PRIMARY_REGISTERED: + case ENKI_THREAD_STATE_EXTERNAL_REGISTERED: + case ENKI_THREAD_STATE_EXTERNAL_UNREGISTERED: + case ENKI_THREAD_STATE_WAIT_NEW_TASKS: + case ENKI_THREAD_STATE_STOPPED: + break; + }; + } + } + if (!otherThreadsRunning) { + // check there are no tasks + for (uint32_t thread = 0; thread < m_NumThreads && !otherThreadsRunning; ++thread) { + // ignore our thread + if (thread != ourThreadNum) { + otherThreadsRunning = HaveTasks(thread); + } + } + } + } + + m_bWaitforAllCalled.store(false, std::memory_order_release); +} + +void TaskScheduler::WaitforAllAndShutdown() { + if (m_bHaveThreads) { + WaitforAll(); + StopThreads(true); + } +} + +void TaskScheduler::WaitForNewPinnedTasks() { + uint32_t threadNum = gtl_threadNum; + ThreadState prevThreadState = m_pThreadDataStore[threadNum].threadState.load(std::memory_order_relaxed); + m_pThreadDataStore[threadNum].threadState.store(ENKI_THREAD_STATE_WAIT_NEW_PINNED_TASKS, std::memory_order_seq_cst); + + // check if have tasks inside threadState change but before waiting + bool bHavePinnedTasks = false; + for (int priority = 0; priority < TASK_PRIORITY_NUM; ++priority) { + if (!m_pPinnedTaskListPerThread[priority][threadNum].IsListEmpty()) { + bHavePinnedTasks = true; + break; + } + } + + if (!bHavePinnedTasks) { + SafeCallback(m_Config.profilerCallbacks.waitForNewTaskSuspendStart, threadNum); + SemaphoreWait(*m_pThreadDataStore[threadNum].pWaitNewPinnedTaskSemaphore); + SafeCallback(m_Config.profilerCallbacks.waitForNewTaskSuspendStop, threadNum); + } + + m_pThreadDataStore[threadNum].threadState.store(prevThreadState, std::memory_order_release); +} + +uint32_t TaskScheduler::GetNumTaskThreads() const { + return m_NumThreads; +} + +uint32_t TaskScheduler::GetThreadNum() const { + return gtl_threadNum; +} + +template +T* TaskScheduler::NewArray(size_t num_, const char* file_, int line_) { + T* pRet = (T*)m_Config.customAllocator.alloc(alignof(T), num_ * sizeof(T), m_Config.customAllocator.userData, file_, line_); + if (!std::is_trivial::value) { + T* pCurr = pRet; + for (size_t i = 0; i < num_; ++i) { + void* pBuffer = pCurr; + pCurr = new (pBuffer) T; + ++pCurr; + } + } + return pRet; +} + +template +void TaskScheduler::DeleteArray(T* p_, size_t num_, const char* file_, int line_) { + if (!std::is_trivial::value) { + size_t i = num_; + while (i) { + p_[--i].~T(); + } + } + m_Config.customAllocator.free(p_, sizeof(T) * num_, m_Config.customAllocator.userData, file_, line_); +} + +template +T* TaskScheduler::New(const char* file_, int line_, Args&&... args_) { + T* pRet = this->Alloc(file_, line_); + return new (pRet) T(std::forward(args_)...); +} + +template +void TaskScheduler::Delete(T* p_, const char* file_, int line_) { + p_->~T(); + this->Free(p_, file_, line_); +} + +template +T* TaskScheduler::Alloc(const char* file_, int line_) { + T* pRet = (T*)m_Config.customAllocator.alloc(alignof(T), sizeof(T), m_Config.customAllocator.userData, file_, line_); + return pRet; +} + +template +void TaskScheduler::Free(T* p_, const char* file_, int line_) { + m_Config.customAllocator.free(p_, sizeof(T), m_Config.customAllocator.userData, file_, line_); +} + +TaskScheduler::TaskScheduler() + : m_pPipesPerThread() + , m_pPinnedTaskListPerThread() + , m_NumThreads(0) + , m_pThreadDataStore(NULL) + , m_pThreads(NULL) + , m_bRunning(0) + , m_NumInternalTaskThreadsRunning(0) + , m_NumThreadsWaitingForNewTasks(0) + , m_NumThreadsWaitingForTaskCompletion(0) + , m_NumPartitions(0) + , m_pNewTaskSemaphore(NULL) + , m_pTaskCompleteSemaphore(NULL) + , m_NumInitialPartitions(0) + , m_bHaveThreads(false) + , m_NumExternalTaskThreadsRegistered(0) { +} + +TaskScheduler::~TaskScheduler() { + StopThreads(true); // Stops threads, waiting for them. +} + +void TaskScheduler::Initialize(uint32_t numThreadsTotal_) { + ENKI_ASSERT(numThreadsTotal_ >= 1); + StopThreads(true); // Stops threads, waiting for them. + m_Config.numTaskThreadsToCreate = numThreadsTotal_ - 1; + m_Config.numExternalTaskThreads = 0; + StartThreads(); +} + +void TaskScheduler::Initialize(TaskSchedulerConfig config_) { + StopThreads(true); // Stops threads, waiting for them. + m_Config = config_; + StartThreads(); +} + +void TaskScheduler::Initialize() { + Initialize(std::thread::hardware_concurrency()); +} + +// Semaphore implementation +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +#pragma pack(push, 8) +typedef struct tagTHREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(uint32_t dwThreadID, const std::string& threadName) { + THREADNAME_INFO info = { + info.dwType = 0x1000, + info.szName = threadName.c_str(), + info.dwThreadID = dwThreadID, + info.dwFlags = 0, + }; + __try { + const DWORD MS_VC_EXCEPTION = 0x406D1388; + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +} +void SetThreadName(const std::string& threadName) { + SetThreadName(GetCurrentThreadId(), threadName); +} + +void SetThreadName(std::thread& thread, const std::string& threadName) { + DWORD threadId = ::GetThreadId(static_cast(thread.native_handle())); + SetThreadName(threadId, threadName); +} + +namespace enki { + +struct semaphoreid_t { + HANDLE sem; +}; + +inline void SemaphoreCreate(semaphoreid_t& semaphoreid) { +#ifdef _XBOX_ONE + semaphoreid.sem = CreateSemaphoreExW(NULL, 0, MAXLONG, NULL, 0, SEMAPHORE_ALL_ACCESS); +#else + semaphoreid.sem = CreateSemaphore(NULL, 0, MAXLONG, NULL); +#endif +} + +inline void SemaphoreClose(semaphoreid_t& semaphoreid) { + CloseHandle(semaphoreid.sem); +} + +inline void SemaphoreWait(semaphoreid_t& semaphoreid) { + DWORD retval = WaitForSingleObject(semaphoreid.sem, INFINITE); + ENKI_ASSERT(retval != WAIT_FAILED); + (void)retval; // only needed for ENKI_ASSERT +} + +inline void SemaphoreSignal(semaphoreid_t& semaphoreid, int32_t countWaiting) { + if (countWaiting) { + ReleaseSemaphore(semaphoreid.sem, countWaiting, NULL); + } +} +} // namespace enki +#elif defined(__MACH__) + +// OS X does not have POSIX semaphores +// Mach semaphores can now only be created by the kernel +// Named sempahores work, but would require unique name construction to ensure +// they are isolated to this process. +// Dispatch semaphores appear to be the way other developers use OSX Semaphores, e.g. Boost +// However the API could change +// OSX below 10.6 does not support dispatch, but I do not have an earlier OSX version +// to test alternatives +#include + +namespace enki { + +struct semaphoreid_t { + dispatch_semaphore_t sem; +}; + +inline void SemaphoreCreate(semaphoreid_t& semaphoreid) { + semaphoreid.sem = dispatch_semaphore_create(0); +} + +inline void SemaphoreClose(semaphoreid_t& semaphoreid) { + dispatch_release(semaphoreid.sem); +} + +inline void SemaphoreWait(semaphoreid_t& semaphoreid) { + dispatch_semaphore_wait(semaphoreid.sem, DISPATCH_TIME_FOREVER); +} + +inline void SemaphoreSignal(semaphoreid_t& semaphoreid, int32_t countWaiting) { + while (countWaiting-- > 0) { + dispatch_semaphore_signal(semaphoreid.sem); + } +} +} // namespace enki + +#else // POSIX + +#include +#include + +namespace enki { + +struct semaphoreid_t { + sem_t sem; +}; + +inline void SemaphoreCreate(semaphoreid_t& semaphoreid) { + int err = sem_init(&semaphoreid.sem, 0, 0); + ENKI_ASSERT(err == 0); + (void)err; +} + +inline void SemaphoreClose(semaphoreid_t& semaphoreid) { + sem_destroy(&semaphoreid.sem); +} + +inline void SemaphoreWait(semaphoreid_t& semaphoreid) { + while (sem_wait(&semaphoreid.sem) == -1 && errno == EINTR) { + } +} + +inline void SemaphoreSignal(semaphoreid_t& semaphoreid, int32_t countWaiting) { + while (countWaiting-- > 0) { + sem_post(&semaphoreid.sem); + } +} +} // namespace enki +#endif + +semaphoreid_t* TaskScheduler::SemaphoreNew() { + semaphoreid_t* pSemaphore = this->Alloc(ENKI_FILE_AND_LINE); + SemaphoreCreate(*pSemaphore); + return pSemaphore; +} + +void TaskScheduler::SemaphoreDelete(semaphoreid_t* pSemaphore_) { + SemaphoreClose(*pSemaphore_); + this->Free(pSemaphore_, ENKI_FILE_AND_LINE); +} + +void TaskScheduler::SetCustomAllocator(CustomAllocator customAllocator_) { + m_Config.customAllocator = customAllocator_; +} + +Dependency::Dependency(const ICompletable* pDependencyTask_, ICompletable* pTaskToRunOnCompletion_) + : pDependencyTask(pDependencyTask_) + , pTaskToRunOnCompletion(pTaskToRunOnCompletion_) + , pNext(pDependencyTask->m_pDependents) { + ENKI_ASSERT(pDependencyTask->GetIsComplete()); + ENKI_ASSERT(pTaskToRunOnCompletion->GetIsComplete()); + pDependencyTask->m_pDependents = this; + ++pTaskToRunOnCompletion->m_DependenciesCount; +} + +Dependency::Dependency(Dependency&& rhs_) noexcept { + pDependencyTask = rhs_.pDependencyTask; + pTaskToRunOnCompletion = rhs_.pTaskToRunOnCompletion; + pNext = rhs_.pNext; + if (rhs_.pDependencyTask) { + ENKI_ASSERT(rhs_.pTaskToRunOnCompletion); + ENKI_ASSERT(rhs_.pDependencyTask->GetIsComplete()); + ENKI_ASSERT(rhs_.pTaskToRunOnCompletion->GetIsComplete()); + Dependency** ppDependent = &(pDependencyTask->m_pDependents); + while (*ppDependent) { + if (&rhs_ == *ppDependent) { + *ppDependent = this; + break; + } + ppDependent = &((*ppDependent)->pNext); + } + } +} + +Dependency::~Dependency() { + ClearDependency(); +} + +void Dependency::SetDependency(const ICompletable* pDependencyTask_, ICompletable* pTaskToRunOnCompletion_) { + ClearDependency(); + ENKI_ASSERT(pDependencyTask_->GetIsComplete()); + ENKI_ASSERT(pTaskToRunOnCompletion_->GetIsComplete()); + pDependencyTask = pDependencyTask_; + pTaskToRunOnCompletion = pTaskToRunOnCompletion_; + pNext = pDependencyTask->m_pDependents; + pDependencyTask->m_pDependents = this; + ++pTaskToRunOnCompletion->m_DependenciesCount; +} + +void Dependency::ClearDependency() { + if (pDependencyTask) { + ENKI_ASSERT(pTaskToRunOnCompletion); + ENKI_ASSERT(pDependencyTask->GetIsComplete()); + ENKI_ASSERT(pTaskToRunOnCompletion->GetIsComplete()); + ENKI_ASSERT(pTaskToRunOnCompletion->m_DependenciesCount > 0); + Dependency* pDependent = pDependencyTask->m_pDependents; + --pTaskToRunOnCompletion->m_DependenciesCount; + if (this == pDependent) { + pDependencyTask->m_pDependents = pDependent->pNext; + } else { + while (pDependent) { + Dependency* pPrev = pDependent; + pDependent = pDependent->pNext; + if (this == pDependent) { + pPrev->pNext = pDependent->pNext; + break; + } + } + } + } + pDependencyTask = NULL; + pDependencyTask = NULL; + pNext = NULL; +} diff --git a/thirdparty/enkits/TaskScheduler.hxx b/thirdparty/enkits/TaskScheduler.hxx new file mode 100644 index 0000000..9c1149c --- /dev/null +++ b/thirdparty/enkits/TaskScheduler.hxx @@ -0,0 +1,559 @@ +// Copyright (c) 2013 Doug Binks +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#pragma once + +#include +#include +#include +#include +#include + +// ENKITS_TASK_PRIORITIES_NUM can be set from 1 to 5. +// 1 corresponds to effectively no priorities. +#ifndef ENKITS_TASK_PRIORITIES_NUM + #define ENKITS_TASK_PRIORITIES_NUM 3 +#endif + +#if defined(_WIN32) && defined(ENKITS_BUILD_DLL) + // Building enkiTS as a DLL + #define ENKITS_API __declspec(dllexport) +#elif defined(_WIN32) && defined(ENKITS_DLL) + // Using enkiTS as a DLL + #define ENKITS_API __declspec(dllimport) +#elif defined(__GNUC__) && defined(ENKITS_BUILD_DLL) + // Building enkiTS as a shared library + #define ENKITS_API __attribute__((visibility("default"))) +#else + #define ENKITS_API +#endif + +// Define ENKI_CUSTOM_ALLOC_FILE_AND_LINE (at project level) to get file and line report in custom allocators, +// this is default in Debug - to turn off define ENKI_CUSTOM_ALLOC_NO_FILE_AND_LINE +#ifndef ENKI_CUSTOM_ALLOC_FILE_AND_LINE +#if defined(_DEBUG ) && !defined(ENKI_CUSTOM_ALLOC_NO_FILE_AND_LINE) +#define ENKI_CUSTOM_ALLOC_FILE_AND_LINE +#endif +#endif + +#ifndef ENKI_ASSERT +#include +#define ENKI_ASSERT(x) assert(x) +#endif + +namespace enki +{ + + struct TaskSetPartition + { + uint32_t start; + uint32_t end; + }; + + class TaskScheduler; + class TaskPipe; + class PinnedTaskList; + class Dependency; + struct ThreadArgs; + struct ThreadDataStore; + struct SubTaskSet; + struct semaphoreid_t; + + uint32_t GetNumHardwareThreads(); + + enum TaskPriority + { + TASK_PRIORITY_HIGH = 0, +#if ( ENKITS_TASK_PRIORITIES_NUM > 3 ) + TASK_PRIORITY_MED_HI, +#endif +#if ( ENKITS_TASK_PRIORITIES_NUM > 2 ) + TASK_PRIORITY_MED, +#endif +#if ( ENKITS_TASK_PRIORITIES_NUM > 4 ) + TASK_PRIORITY_MED_LO, +#endif +#if ( ENKITS_TASK_PRIORITIES_NUM > 1 ) + TASK_PRIORITY_LOW, +#endif + TASK_PRIORITY_NUM + }; + + // ICompletable is a base class used to check for completion. + // Can be used with dependencies to wait for their completion. + // Derive from ITaskSet or IPinnedTask for running parallel tasks. + class ICompletable + { + public: + bool GetIsComplete() const { + return 0 == m_RunningCount.load( std::memory_order_acquire ); + } + + virtual ~ICompletable(); + + // Dependency helpers, see Dependencies.cpp + void SetDependency( Dependency& dependency_, const ICompletable* pDependencyTask_ ); + template void SetDependenciesArr( D& dependencyArray_ , const T(&taskArray_)[SIZE] ); + template void SetDependenciesArr( D& dependencyArray_, std::initializer_list taskpList_ ); + template void SetDependenciesArr( D(&dependencyArray_)[SIZE], const T(&taskArray_)[SIZE] ); + template void SetDependenciesArr( D(&dependencyArray_)[SIZE], std::initializer_list taskpList_ ); + template void SetDependenciesVec( D& dependencyVec_, const T(&taskArray_)[SIZE] ); + template void SetDependenciesVec( D& dependencyVec_, std::initializer_list taskpList_ ); + + TaskPriority m_Priority = TASK_PRIORITY_HIGH; + protected: + // Deriving from an ICompletable and overriding OnDependenciesComplete is advanced use. + // If you do override OnDependenciesComplete() call: + // ICompletable::OnDependenciesComplete( pTaskScheduler_, threadNum_ ); + // in your implementation. + virtual void OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ); + private: + friend class TaskScheduler; + friend class Dependency; + std::atomic m_RunningCount = {0}; + std::atomic m_DependenciesCompletedCount = {0}; + int32_t m_DependenciesCount = 0; + mutable std::atomic m_WaitingForTaskCount = {0}; + mutable Dependency* m_pDependents = NULL; + }; + + // Subclass ITaskSet to create tasks. + // TaskSets can be re-used, but check completion first. + class ITaskSet : public ICompletable + { + public: + ITaskSet() = default; + ITaskSet( uint32_t setSize_ ) + : m_SetSize( setSize_ ) + {} + + ITaskSet( uint32_t setSize_, uint32_t minRange_ ) + : m_SetSize( setSize_ ) + , m_MinRange( minRange_ ) + , m_RangeToRun(minRange_) + {} + + // Execute range should be overloaded to process tasks. It will be called with a + // range_ where range.start >= 0; range.start < range.end; and range.end < m_SetSize; + // The range values should be mapped so that linearly processing them in order is cache friendly + // i.e. neighbouring values should be close together. + // threadnum should not be used for changing processing of data, it's intended purpose + // is to allow per-thread data buckets for output. + virtual void ExecuteRange( TaskSetPartition range_, uint32_t threadnum_ ) = 0; + + // Set Size - usually the number of data items to be processed, see ExecuteRange. Defaults to 1 + uint32_t m_SetSize = 1; + + // Min Range - Minimum size of of TaskSetPartition range when splitting a task set into partitions. + // Designed for reducing scheduling overhead by preventing set being + // divided up too small. Ranges passed to ExecuteRange will *not* be a mulitple of this, + // only attempts to deliver range sizes larger than this most of the time. + // This should be set to a value which results in computation effort of at least 10k + // clock cycles to minimize task scheduler overhead. + // NOTE: The last partition will be smaller than m_MinRange if m_SetSize is not a multiple + // of m_MinRange. + // Also known as grain size in literature. + uint32_t m_MinRange = 1; + + private: + friend class TaskScheduler; + void OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ) override final; + uint32_t m_RangeToRun = 1; + }; + + // Subclass IPinnedTask to create tasks which can be run on a given thread only. + class IPinnedTask : public ICompletable + { + public: + IPinnedTask() = default; + IPinnedTask( uint32_t threadNum_ ) : threadNum(threadNum_) {} // default is to run a task on main thread + + // IPinnedTask needs to be non abstract for intrusive list functionality. + // Should never be called as should be overridden. + virtual void Execute() { ENKI_ASSERT(false); } + + uint32_t threadNum = 0; // thread to run this pinned task on + std::atomic pNext = {NULL}; + private: + void OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ) override final; + }; + + // TaskSet - a utility task set for creating tasks based on std::func. + typedef std::function TaskSetFunction; + class TaskSet : public ITaskSet + { + public: + TaskSet() = default; + TaskSet( TaskSetFunction func_ ) : m_Function( func_ ) {} + TaskSet( uint32_t setSize_, TaskSetFunction func_ ) : ITaskSet( setSize_ ), m_Function( func_ ) {} + + void ExecuteRange( TaskSetPartition range_, uint32_t threadnum_ ) override { m_Function( range_, threadnum_ ); } + TaskSetFunction m_Function; + }; + + // LambdaPinnedTask - a utility pinned task for creating tasks based on std::func. + typedef std::function PinnedTaskFunction; + class LambdaPinnedTask : public IPinnedTask + { + public: + LambdaPinnedTask() = default; + LambdaPinnedTask( PinnedTaskFunction func_ ) : m_Function( func_ ) {} + LambdaPinnedTask( uint32_t threadNum_, PinnedTaskFunction func_ ) : IPinnedTask( threadNum_ ), m_Function( func_ ) {} + + void Execute() override { m_Function(); } + PinnedTaskFunction m_Function; + }; + + class Dependency + { + public: + Dependency() = default; + Dependency( const Dependency& ) = delete; + ENKITS_API Dependency( Dependency&& ) noexcept; + ENKITS_API Dependency( const ICompletable* pDependencyTask_, ICompletable* pTaskToRunOnCompletion_ ); + ENKITS_API ~Dependency(); + + ENKITS_API void SetDependency( const ICompletable* pDependencyTask_, ICompletable* pTaskToRunOnCompletion_ ); + ENKITS_API void ClearDependency(); + ICompletable* GetTaskToRunOnCompletion() { return pTaskToRunOnCompletion; } + const ICompletable* GetDependencyTask() { return pDependencyTask; } + private: + friend class TaskScheduler; friend class ICompletable; + ICompletable* pTaskToRunOnCompletion = NULL; + const ICompletable* pDependencyTask = NULL; + Dependency* pNext = NULL; + }; + + // TaskScheduler implements several callbacks intended for profilers + typedef void (*ProfilerCallbackFunc)( uint32_t threadnum_ ); + struct ProfilerCallbacks + { + ProfilerCallbackFunc threadStart; + ProfilerCallbackFunc threadStop; + ProfilerCallbackFunc waitForNewTaskSuspendStart; // thread suspended waiting for new tasks + ProfilerCallbackFunc waitForNewTaskSuspendStop; // thread unsuspended + ProfilerCallbackFunc waitForTaskCompleteStart; // thread waiting for task completion + ProfilerCallbackFunc waitForTaskCompleteStop; // thread stopped waiting + ProfilerCallbackFunc waitForTaskCompleteSuspendStart; // thread suspended waiting task completion + ProfilerCallbackFunc waitForTaskCompleteSuspendStop; // thread unsuspended + }; + + // Custom allocator, set in TaskSchedulerConfig. Also see ENKI_CUSTOM_ALLOC_FILE_AND_LINE for file_ and line_ + typedef void* (*AllocFunc)( size_t align_, size_t size_, void* userData_, const char* file_, int line_ ); + typedef void (*FreeFunc)( void* ptr_, size_t size_, void* userData_, const char* file_, int line_ ); + ENKITS_API void* DefaultAllocFunc( size_t align_, size_t size_, void* userData_, const char* file_, int line_ ); + ENKITS_API void DefaultFreeFunc( void* ptr_, size_t size_, void* userData_, const char* file_, int line_ ); + struct CustomAllocator + { + AllocFunc alloc = DefaultAllocFunc; + FreeFunc free = DefaultFreeFunc; + void* userData = nullptr; + }; + + // TaskSchedulerConfig - configuration struct for advanced Initialize + struct TaskSchedulerConfig + { + // numTaskThreadsToCreate - Number of tasking threads the task scheduler will create. Must be > 0. + // Defaults to GetNumHardwareThreads()-1 threads as thread which calls initialize is thread 0. + uint32_t numTaskThreadsToCreate = GetNumHardwareThreads()-1; + + // numExternalTaskThreads - Advanced use. Number of external threads which need to use TaskScheduler API. + // See TaskScheduler::RegisterExternalTaskThread() for usage. + // Defaults to 0. The thread used to initialize the TaskScheduler can also use the TaskScheduler API. + // Thus there are (numTaskThreadsToCreate + numExternalTaskThreads + 1) able to use the API, with this + // defaulting to the number of harware threads available to the system. + uint32_t numExternalTaskThreads = 0; + + ProfilerCallbacks profilerCallbacks = {}; + + CustomAllocator customAllocator; + }; + + class TaskScheduler + { + public: + ENKITS_API TaskScheduler(); + ENKITS_API ~TaskScheduler(); + + // Call an Initialize function before adding tasks. + + // Initialize() will create GetNumHardwareThreads()-1 tasking threads, which is + // sufficient to fill the system when including the main thread. + // Initialize can be called multiple times - it will wait for completion + // before re-initializing. + ENKITS_API void Initialize(); + + // Initialize( numThreadsTotal_ ) + // will create numThreadsTotal_-1 threads, as thread 0 is + // the thread on which the initialize was called. + // numThreadsTotal_ must be > 0 + ENKITS_API void Initialize( uint32_t numThreadsTotal_ ); + + // Initialize with advanced TaskSchedulerConfig settings. See TaskSchedulerConfig. + ENKITS_API void Initialize( TaskSchedulerConfig config_ ); + + // Get config. Can be called before Initialize to get the defaults. + ENKITS_API TaskSchedulerConfig GetConfig() const; + + // while( GetIsRunning() ) {} can be used in tasks which loop, to check if enkiTS has been shutdown. + // If GetIsRunning() returns false should then exit. Not required for finite tasks + inline bool GetIsRunning() const { return m_bRunning.load( std::memory_order_acquire ); } + + // while( !GetIsWaitforAllCalled() ) {} can be used in tasks which loop, to check if WaitforAll() has been called. + // If GetIsWaitforAllCalled() returns false should then exit. Not required for finite tasks + // This is intended to be used with code which calls WaitforAll() with flag WAITFORALLFLAGS_INC_WAIT_NEW_PINNED_TASKS set. + // This is also set when the the task manager is shutting down, so no need to have an additional check for GetIsRunning() + inline bool GetIsWaitforAllCalled() const { return m_bWaitforAllCalled.load( std::memory_order_acquire ); } + + // Adds the TaskSet to pipe and returns if the pipe is not full. + // If the pipe is full, pTaskSet is run. + // should only be called from main thread, or within a task + ENKITS_API void AddTaskSetToPipe( ITaskSet* pTaskSet_ ); + + // Thread 0 is main thread, otherwise use threadNum + // Pinned tasks can be added from any thread + ENKITS_API void AddPinnedTask( IPinnedTask* pTask_ ); + + // This function will run any IPinnedTask* for current thread, but not run other + // Main thread should call this or use a wait to ensure it's tasks are run. + ENKITS_API void RunPinnedTasks(); + + // Runs the TaskSets in pipe until true == pTaskSet->GetIsComplete(); + // should only be called from thread which created the taskscheduler , or within a task + // if called with 0 it will try to run tasks, and return if none available. + // To run only a subset of tasks, set priorityOfLowestToRun_ to a high priority. + // Default is lowest priority available. + // Only wait for child tasks of the current task otherwise a deadlock could occur. + ENKITS_API void WaitforTask( const ICompletable* pCompletable_, enki::TaskPriority priorityOfLowestToRun_ = TaskPriority(TASK_PRIORITY_NUM - 1) ); + + // Waits for all task sets to complete - not guaranteed to work unless we know we + // are in a situation where tasks aren't being continuously added. + // If you are running tasks which loop, make sure to check GetIsWaitforAllCalled() and exit + ENKITS_API void WaitforAll(); + + // Waits for all task sets to complete and shutdown threads - not guaranteed to work unless we know we + // are in a situation where tasks aren't being continuously added. + // This function can be safely called even if TaskScheduler::Initialize() has not been called. + ENKITS_API void WaitforAllAndShutdown(); + + // Waits for the current thread to receive a PinnedTask + // Will not run any tasks - use with RunPinnedTasks() + // Can be used with both ExternalTaskThreads or with an enkiTS tasking thread to create + // a thread which only runs pinned tasks. If enkiTS threads are used can create + // extra enkiTS task threads to handle non blocking computation via normal tasks. + ENKITS_API void WaitForNewPinnedTasks(); + + // Returns the number of threads created for running tasks + number of external threads + // plus 1 to account for the thread used to initialize the task scheduler. + // Equivalent to config values: numTaskThreadsToCreate + numExternalTaskThreads + 1. + // It is guaranteed that GetThreadNum() < GetNumTaskThreads() + ENKITS_API uint32_t GetNumTaskThreads() const; + + // Returns the current task threadNum + // Will return 0 for thread which initialized the task scheduler, + // and all other non-enkiTS threads which have not been registered ( see RegisterExternalTaskThread() ), + // and < GetNumTaskThreads() for all threads. + // It is guaranteed that GetThreadNum() < GetNumTaskThreads() + ENKITS_API uint32_t GetThreadNum() const; + + // Call on a thread to register the thread to use the TaskScheduling API. + // This is implicitly done for the thread which initializes the TaskScheduler + // Intended for developers who have threads who need to call the TaskScheduler API + // Returns true if successfull, false if not. + // Can only have numExternalTaskThreads registered at any one time, which must be set + // at initialization time. + ENKITS_API bool RegisterExternalTaskThread(); + + // As RegisterExternalTaskThread() but explicitly requests a given thread number. + // threadNumToRegister_ must be >= GetNumFirstExternalTaskThread() + // and < ( GetNumFirstExternalTaskThread() + numExternalTaskThreads ) + ENKITS_API bool RegisterExternalTaskThread( uint32_t threadNumToRegister_ ); + + // Call on a thread on which RegisterExternalTaskThread has been called to deregister that thread. + ENKITS_API void DeRegisterExternalTaskThread(); + + // Get the number of registered external task threads. + ENKITS_API uint32_t GetNumRegisteredExternalTaskThreads(); + + // Get the thread number of the first external task thread. This thread + // is not guaranteed to be registered, but threads are registered in order + // from GetNumFirstExternalTaskThread() up to ( GetNumFirstExternalTaskThread() + numExternalTaskThreads ) + // Note that if numExternalTaskThreads == 0 a for loop using this will be valid: + // for( uint32_t externalThreadNum = GetNumFirstExternalTaskThread(); + // externalThreadNum < ( GetNumFirstExternalTaskThread() + numExternalTaskThreads + // ++externalThreadNum ) { // do something with externalThreadNum } + inline static constexpr uint32_t GetNumFirstExternalTaskThread() { return 1; } + + // ------------- Start DEPRECATED Functions ------------- + // DEPRECATED - WaitforTaskSet, deprecated interface use WaitforTask + inline void WaitforTaskSet( const ICompletable* pCompletable_ ) { WaitforTask( pCompletable_ ); } + + // DEPRECATED - GetProfilerCallbacks. Use TaskSchedulerConfig instead + // Returns the ProfilerCallbacks structure so that it can be modified to + // set the callbacks. Should be set prior to initialization. + inline ProfilerCallbacks* GetProfilerCallbacks() { return &m_Config.profilerCallbacks; } + // ------------- End DEPRECATED Functions ------------- + + private: + friend class ICompletable; friend class ITaskSet; friend class IPinnedTask; + static void TaskingThreadFunction( const ThreadArgs& args_ ); + bool HaveTasks( uint32_t threadNum_ ); + void WaitForNewTasks( uint32_t threadNum_ ); + void WaitForTaskCompletion( const ICompletable* pCompletable_, uint32_t threadNum_ ); + void RunPinnedTasks( uint32_t threadNum_, uint32_t priority_ ); + bool TryRunTask( uint32_t threadNum_, uint32_t& hintPipeToCheck_io_ ); + bool TryRunTask( uint32_t threadNum_, uint32_t priority_, uint32_t& hintPipeToCheck_io_ ); + void StartThreads(); + void StopThreads( bool bWait_ ); + void SplitAndAddTask( uint32_t threadNum_, SubTaskSet subTask_, uint32_t rangeToSplit_ ); + void WakeThreadsForNewTasks(); + void WakeThreadsForTaskCompletion(); + bool WakeSuspendedThreadsWithPinnedTasks(); + void InitDependencies( ICompletable* pCompletable_ ); + ENKITS_API void TaskComplete( ICompletable* pTask_, bool bWakeThreads_, uint32_t threadNum_ ); + ENKITS_API void AddTaskSetToPipeInt( ITaskSet* pTaskSet_, uint32_t threadNum_ ); + ENKITS_API void AddPinnedTaskInt( IPinnedTask* pTask_ ); + + template< typename T > T* NewArray( size_t num_, const char* file_, int line_ ); + template< typename T > void DeleteArray( T* p_, size_t num_, const char* file_, int line_ ); + template T* New( const char* file_, int line_, Args&&... args_ ); + template< typename T > void Delete( T* p_, const char* file_, int line_ ); + template< typename T > T* Alloc( const char* file_, int line_ ); + template< typename T > void Free( T* p_, const char* file_, int line_ ); + semaphoreid_t* SemaphoreNew(); + void SemaphoreDelete( semaphoreid_t* pSemaphore_ ); + + TaskPipe* m_pPipesPerThread[ TASK_PRIORITY_NUM ]; + PinnedTaskList* m_pPinnedTaskListPerThread[ TASK_PRIORITY_NUM ]; + + uint32_t m_NumThreads; + ThreadDataStore* m_pThreadDataStore; + std::thread* m_pThreads; + std::atomic m_bRunning; + std::atomic m_bWaitforAllCalled; + std::atomic m_NumInternalTaskThreadsRunning; + std::atomic m_NumThreadsWaitingForNewTasks; + std::atomic m_NumThreadsWaitingForTaskCompletion; + uint32_t m_NumPartitions; + semaphoreid_t* m_pNewTaskSemaphore; + semaphoreid_t* m_pTaskCompleteSemaphore; + uint32_t m_NumInitialPartitions; + bool m_bHaveThreads; + TaskSchedulerConfig m_Config; + std::atomic m_NumExternalTaskThreadsRegistered; + + TaskScheduler( const TaskScheduler& nocopy_ ); + TaskScheduler& operator=( const TaskScheduler& nocopy_ ); + + protected: + void SetCustomAllocator( CustomAllocator customAllocator_ ); // for C interface + }; + + inline uint32_t GetNumHardwareThreads() + { + return std::thread::hardware_concurrency(); + } + + inline void ICompletable::OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ) + { + m_RunningCount.fetch_sub( 1, std::memory_order_release ); + pTaskScheduler_->TaskComplete( this, true, threadNum_ ); + } + + inline void ITaskSet::OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ) + { + pTaskScheduler_->AddTaskSetToPipeInt( this, threadNum_ ); + } + + inline void IPinnedTask::OnDependenciesComplete( TaskScheduler* pTaskScheduler_, uint32_t threadNum_ ) + { + (void)threadNum_; + pTaskScheduler_->AddPinnedTaskInt( this ); + } + + inline ICompletable::~ICompletable() + { + ENKI_ASSERT( GetIsComplete() ); // this task is still waiting to run + Dependency* pDependency = m_pDependents; + while( pDependency ) + { + Dependency* pNext = pDependency->pNext; + pDependency->pDependencyTask = NULL; + pDependency->pNext = NULL; + pDependency = pNext; + } + } + + inline void ICompletable::SetDependency( Dependency& dependency_, const ICompletable* pDependencyTask_ ) + { + ENKI_ASSERT( pDependencyTask_ != this ); + dependency_.SetDependency( pDependencyTask_, this ); + } + + template + void ICompletable::SetDependenciesArr( D& dependencyArray_ , const T(&taskArray_)[SIZE] ) { + static_assert( std::tuple_size::value >= SIZE, "Size of dependency array too small" ); + for( int i = 0; i < SIZE; ++i ) + { + dependencyArray_[i].SetDependency( &taskArray_[i], this ); + } + } + template + void ICompletable::SetDependenciesArr( D& dependencyArray_, std::initializer_list taskpList_ ) { + ENKI_ASSERT( std::tuple_size::value >= taskpList_.size() ); + int i = 0; + for( auto pTask : taskpList_ ) + { + dependencyArray_[i++].SetDependency( pTask, this ); + } + } + template + void ICompletable::SetDependenciesArr( D(&dependencyArray_)[SIZE], const T(&taskArray_)[SIZE] ) { + for( int i = 0; i < SIZE; ++i ) + { + dependencyArray_[i].SetDependency( &taskArray_[i], this ); + } + } + template + void ICompletable::SetDependenciesArr( D(&dependencyArray_)[SIZE], std::initializer_list taskpList_ ) { + ENKI_ASSERT( SIZE >= taskpList_.size() ); + int i = 0; + for( auto pTask : taskpList_ ) + { + dependencyArray_[i++].SetDependency( pTask, this ); + } + } + template + void ICompletable::SetDependenciesVec( D& dependencyVec_, const T(&taskArray_)[SIZE] ) { + dependencyVec_.resize( SIZE ); + for( int i = 0; i < SIZE; ++i ) + { + dependencyVec_[i].SetDependency( &taskArray_[i], this ); + } + } + + template + void ICompletable::SetDependenciesVec( D& dependencyVec_, std::initializer_list taskpList_ ) { + dependencyVec_.resize( taskpList_.size() ); + int i = 0; + for( auto pTask : taskpList_ ) + { + dependencyVec_[i++].SetDependency( pTask, this ); + } + } +} diff --git a/thirdparty/glm/CMakeLists.txt b/thirdparty/glm/CMakeLists.txt new file mode 100644 index 0000000..545a226 --- /dev/null +++ b/thirdparty/glm/CMakeLists.txt @@ -0,0 +1,47 @@ +file(GLOB ROOT_SOURCE *.cpp) +file(GLOB ROOT_INLINE *.inl) +file(GLOB ROOT_HEADER *.hpp) +file(GLOB ROOT_TEXT ../*.txt) +file(GLOB ROOT_MD ../*.md) +file(GLOB ROOT_NAT ../util/glm.natvis) + +file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp) +file(GLOB_RECURSE CORE_INLINE ./detail/*.inl) +file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp) + +file(GLOB_RECURSE EXT_SOURCE ./ext/*.cpp) +file(GLOB_RECURSE EXT_INLINE ./ext/*.inl) +file(GLOB_RECURSE EXT_HEADER ./ext/*.hpp) + +file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp) +file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl) +file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp) + +file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp) +file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl) +file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp) + +file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp) +file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl) +file(GLOB_RECURSE SIMD_HEADER ./simd/*.h) + +source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD}) +source_group("Core Files" FILES ${CORE_SOURCE}) +source_group("Core Files" FILES ${CORE_INLINE}) +source_group("Core Files" FILES ${CORE_HEADER}) +source_group("EXT Files" FILES ${EXT_SOURCE}) +source_group("EXT Files" FILES ${EXT_INLINE}) +source_group("EXT Files" FILES ${EXT_HEADER}) +source_group("GTC Files" FILES ${GTC_SOURCE}) +source_group("GTC Files" FILES ${GTC_INLINE}) +source_group("GTC Files" FILES ${GTC_HEADER}) +source_group("GTX Files" FILES ${GTX_SOURCE}) +source_group("GTX Files" FILES ${GTX_INLINE}) +source_group("GTX Files" FILES ${GTX_HEADER}) +source_group("SIMD Files" FILES ${SIMD_SOURCE}) +source_group("SIMD Files" FILES ${SIMD_INLINE}) +source_group("SIMD Files" FILES ${SIMD_HEADER}) + +add_library(glm INTERFACE) +target_include_directories(glm INTERFACE "${CMAKE_CURRENT_LIST_DIR}/../") + diff --git a/thirdparty/glm/common.hpp b/thirdparty/glm/common.hpp new file mode 100644 index 0000000..0328dc9 --- /dev/null +++ b/thirdparty/glm/common.hpp @@ -0,0 +1,539 @@ +/// @ref core +/// @file glm/common.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.3 Common Functions +/// +/// @defgroup core_func_common Common functions +/// @ingroup core +/// +/// Provides GLSL common functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/_fixes.hpp" + +namespace glm +{ + /// @addtogroup core_func_common + /// @{ + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam genType floating-point or signed integer; scalar or vector types. + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType abs(genType x); + + /// Returns x if x >= 0; otherwise, it returns -x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL abs man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec abs(vec const& x); + + /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sign man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec sign(vec const& x); + + /// Returns a value equal to the nearest integer that is less then or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floor man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floor(vec const& x); + + /// Returns a value equal to the nearest integer to x + /// whose absolute value is not larger than the absolute value of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL trunc man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec trunc(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// This includes the possibility that round(x) returns the + /// same value as roundEven(x) for all values of x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL round man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec round(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// A fractional part of 0.5 will round toward the nearest even + /// integer. (Both 3.5 and 4.5 for x will return 4.0.) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL roundEven man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// @see New round to even technique + template + GLM_FUNC_DECL vec roundEven(vec const& x); + + /// Returns a value equal to the nearest integer + /// that is greater than or equal to x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL ceil man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec ceil(vec const& x); + + /// Return x - floor(x). + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fract(genType x); + + /// Return x - floor(x). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL fract man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec fract(vec const& x); + + template + GLM_FUNC_DECL genType mod(genType x, genType y); + + template + GLM_FUNC_DECL vec mod(vec const& x, T y); + + /// Modulus. Returns x - y * floor(x / y) + /// for each component in x using the floating point value y. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types, include glm/gtc/integer for integer scalar types support + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL mod man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec mod(vec const& x, vec const& y); + + /// Returns the fractional part of x and sets i to the integer + /// part (as a whole number floating point value). Both the + /// return value and the output parameter will have the same + /// sign as x. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL modf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType modf(genType x, genType& i); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType min(genType x, genType y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL min man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, vec const& y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType max(genType x, genType y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, T y); + + /// Returns y if x < y; otherwise, it returns x. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL max man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam genType Floating-point or integer; scalar or vector types. + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x + /// using the floating-point values minVal and maxVal. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL clamp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal); + + /// If genTypeU is a floating scalar or vector: + /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of + /// x and y using the floating-point value a. + /// The value for a is not restricted to the range [0, 1]. + /// + /// If genTypeU is a boolean scalar or vector: + /// Selects which vector each returned component comes + /// from. For a component of 'a' that is false, the + /// corresponding component of 'x' is returned. For a + /// component of 'a' that is true, the corresponding + /// component of 'y' is returned. Components of 'x' and 'y' that + /// are not selected are allowed to be invalid floating point + /// values and will have no effect on the results. Thus, this + /// provides different functionality than + /// genType mix(genType x, genType y, genType(a)) + /// where a is a Boolean vector. + /// + /// @see GLSL mix man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + /// + /// @param[in] x Value to interpolate. + /// @param[in] y Value to interpolate. + /// @param[in] a Interpolant. + /// + /// @tparam genTypeT Floating point scalar or vector. + /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT. + /// + /// @code + /// #include + /// ... + /// float a; + /// bool b; + /// glm::dvec3 e; + /// glm::dvec3 f; + /// glm::vec4 g; + /// glm::vec4 h; + /// ... + /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. + /// glm::vec4 s = glm::mix(g, h, b); // Returns g or h; + /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second. + /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter. + /// @endcode + template + GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, vec const& a); + + template + GLM_FUNC_DECL vec mix(vec const& x, vec const& y, U a); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType. + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType step(genType edge, genType x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(T edge, vec const& x); + + /// Returns 0.0 if x < edge, otherwise it returns 1.0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL step man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec step(vec const& edge, vec const& x); + + /// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and + /// performs smooth Hermite interpolation between 0 and 1 + /// when edge0 < x < edge1. This is useful in cases where + /// you would want a threshold function with a smooth + /// transition. This is equivalent to: + /// genType t; + /// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1); + /// return t * t * (3 - 2 * t); + /// Results are undefined if edge0 >= edge1. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL smoothstep man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x); + + template + GLM_FUNC_DECL vec smoothstep(T edge0, T edge1, vec const& x); + + template + GLM_FUNC_DECL vec smoothstep(vec const& edge0, vec const& edge1, vec const& x); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isnan(vec const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL isinf man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec isinf(vec const& x); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floating-point + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL int floatBitsToInt(float const& v); + + /// Returns a signed integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToInt man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToInt(vec const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL uint floatBitsToUint(float const& v); + + /// Returns a unsigned integer value representing + /// the encoding of a floating-point value. The floatingpoint + /// value's bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL floatBitsToUint man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec floatBitsToUint(vec const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float intBitsToFloat(int const& v); + + /// Returns a floating-point value corresponding to a signed + /// integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL intBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec intBitsToFloat(vec const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + GLM_FUNC_DECL float uintBitsToFloat(uint const& v); + + /// Returns a floating-point value corresponding to a + /// unsigned integer encoding of a floating-point value. + /// If an inf or NaN is passed in, it will not signal, and the + /// resulting floating point value is unspecified. Otherwise, + /// the bit-level representation is preserved. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL uintBitsToFloat man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL vec uintBitsToFloat(vec const& v); + + /// Computes and returns a * b + c. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL fma man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType fma(genType const& a, genType const& b, genType const& c); + + /// Splits x into a floating-point significand in the range + /// [0.5, 1.0) and an integral exponent of two, such that: + /// x = significand * exp(2, exponent) + /// + /// The significand is returned by the function and the + /// exponent is returned in the parameter exp. For a + /// floating-point value of zero, the significant and exponent + /// are both zero. For a floating-point value that is an + /// infinity or is not a number, the results are undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL frexp man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType frexp(genType x, int& exp); + + template + GLM_FUNC_DECL vec frexp(vec const& v, vec& exp); + + /// Builds a floating-point number from x and the + /// corresponding integral exponent of two in exp, returning: + /// significand * exp(2, exponent) + /// + /// If this product is too large to be represented in the + /// floating-point type, the result is undefined. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL ldexp man page; + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL genType ldexp(genType const& x, int const& exp); + + template + GLM_FUNC_DECL vec ldexp(vec const& v, vec const& exp); + + /// @} +}//namespace glm + +#include "detail/func_common.inl" + diff --git a/thirdparty/glm/detail/_features.hpp b/thirdparty/glm/detail/_features.hpp new file mode 100644 index 0000000..b0cbe9f --- /dev/null +++ b/thirdparty/glm/detail/_features.hpp @@ -0,0 +1,394 @@ +#pragma once + +// #define GLM_CXX98_EXCEPTIONS +// #define GLM_CXX98_RTTI + +// #define GLM_CXX11_RVALUE_REFERENCES +// Rvalue references - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html + +// GLM_CXX11_TRAILING_RETURN +// Rvalue references for *this - GCC not supported +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Initialization of class objects by rvalues - GCC any +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html + +// GLM_CXX11_NONSTATIC_MEMBER_INIT +// Non-static data member initializers - GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm + +// #define GLM_CXX11_VARIADIC_TEMPLATE +// Variadic templates - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf + +// +// Extending variadic template template parameters - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf + +// #define GLM_CXX11_GENERALIZED_INITIALIZERS +// Initializer lists - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm + +// #define GLM_CXX11_STATIC_ASSERT +// Static assertions - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html + +// #define GLM_CXX11_AUTO_TYPE +// auto-typed variables - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Multi-declarator auto - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf + +// #define GLM_CXX11_AUTO_TYPE +// Removal of auto as a storage-class specifier - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm + +// #define GLM_CXX11_AUTO_TYPE +// New function declarator syntax - GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm + +// #define GLM_CXX11_LAMBDAS +// New wording for C++0x lambdas - GCC 4.5 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf + +// #define GLM_CXX11_DECLTYPE +// Declared type of an expression - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf + +// +// Right angle brackets - GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html + +// +// Default template arguments for function templates DR226 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226 + +// +// Solving the SFINAE problem for expressions DR339 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html + +// #define GLM_CXX11_ALIAS_TEMPLATE +// Template aliases N2258 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf + +// +// Extern templates N1987 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm + +// #define GLM_CXX11_NULLPTR +// Null pointer constant N2431 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf + +// #define GLM_CXX11_STRONG_ENUMS +// Strongly-typed enums N2347 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf + +// +// Forward declarations for enums N2764 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf + +// +// Generalized attributes N2761 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf + +// +// Generalized constant expressions N2235 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf + +// +// Alignment support N2341 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf + +// #define GLM_CXX11_DELEGATING_CONSTRUCTORS +// Delegating constructors N1986 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf + +// +// Inheriting constructors N2540 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm + +// #define GLM_CXX11_EXPLICIT_CONVERSIONS +// Explicit conversion operators N2437 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf + +// +// New character types N2249 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html + +// +// Unicode string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Raw string literals N2442 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm + +// +// Universal character name literals N2170 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html + +// #define GLM_CXX11_USER_LITERALS +// User-defined literals N2765 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf + +// +// Standard Layout Types N2342 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm + +// #define GLM_CXX11_DEFAULTED_FUNCTIONS +// #define GLM_CXX11_DELETED_FUNCTIONS +// Defaulted and deleted functions N2346 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm + +// +// Extended friend declarations N1791 GCC 4.7 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf + +// +// Extending sizeof N2253 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html + +// #define GLM_CXX11_INLINE_NAMESPACES +// Inline namespaces N2535 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm + +// #define GLM_CXX11_UNRESTRICTED_UNIONS +// Unrestricted unions N2544 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + +// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +// Local and unnamed types as template arguments N2657 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm + +// #define GLM_CXX11_RANGE_FOR +// Range-based for N2930 GCC 4.6 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html + +// #define GLM_CXX11_OVERRIDE_CONTROL +// Explicit virtual overrides N2928 N3206 N3272 GCC 4.7 +// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm + +// +// Minimal support for garbage collection and reachability-based leak detection N2670 No +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm + +// #define GLM_CXX11_NOEXCEPT +// Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only) +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html + +// +// Defining move special member functions N3053 GCC 4.6 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html + +// +// Sequence points N2239 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Atomic operations N2427 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html + +// +// Strong Compare and Exchange N2748 GCC 4.5 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html + +// +// Bidirectional Fences N2752 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm + +// +// Memory model N2429 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm + +// +// Data-dependency ordering: atomics and memory model N2664 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm + +// +// Propagating exceptions N2179 GCC 4.4 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html + +// +// Abandoning a process and at_quick_exit N2440 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm + +// +// Allow atomics use in signal handlers N2547 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm + +// +// Thread-local storage N2659 GCC 4.8 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm + +// +// Dynamic initialization and destruction with concurrency N2660 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm + +// +// __func__ predefined identifier N2340 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm + +// +// C99 preprocessor N1653 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm + +// +// long long N1811 GCC 4.3 +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf + +// +// Extended integral types N1988 Yes +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf + +#if(GLM_COMPILER & GLM_COMPILER_GCC) + +# define GLM_CXX11_STATIC_ASSERT + +#elif(GLM_COMPILER & GLM_COMPILER_CLANG) +# if(__has_feature(cxx_exceptions)) +# define GLM_CXX98_EXCEPTIONS +# endif + +# if(__has_feature(cxx_rtti)) +# define GLM_CXX98_RTTI +# endif + +# if(__has_feature(cxx_access_control_sfinae)) +# define GLM_CXX11_ACCESS_CONTROL_SFINAE +# endif + +# if(__has_feature(cxx_alias_templates)) +# define GLM_CXX11_ALIAS_TEMPLATE +# endif + +# if(__has_feature(cxx_alignas)) +# define GLM_CXX11_ALIGNAS +# endif + +# if(__has_feature(cxx_attributes)) +# define GLM_CXX11_ATTRIBUTES +# endif + +# if(__has_feature(cxx_constexpr)) +# define GLM_CXX11_CONSTEXPR +# endif + +# if(__has_feature(cxx_decltype)) +# define GLM_CXX11_DECLTYPE +# endif + +# if(__has_feature(cxx_default_function_template_args)) +# define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_defaulted_functions)) +# define GLM_CXX11_DEFAULTED_FUNCTIONS +# endif + +# if(__has_feature(cxx_delegating_constructors)) +# define GLM_CXX11_DELEGATING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_deleted_functions)) +# define GLM_CXX11_DELETED_FUNCTIONS +# endif + +# if(__has_feature(cxx_explicit_conversions)) +# define GLM_CXX11_EXPLICIT_CONVERSIONS +# endif + +# if(__has_feature(cxx_generalized_initializers)) +# define GLM_CXX11_GENERALIZED_INITIALIZERS +# endif + +# if(__has_feature(cxx_implicit_moves)) +# define GLM_CXX11_IMPLICIT_MOVES +# endif + +# if(__has_feature(cxx_inheriting_constructors)) +# define GLM_CXX11_INHERITING_CONSTRUCTORS +# endif + +# if(__has_feature(cxx_inline_namespaces)) +# define GLM_CXX11_INLINE_NAMESPACES +# endif + +# if(__has_feature(cxx_lambdas)) +# define GLM_CXX11_LAMBDAS +# endif + +# if(__has_feature(cxx_local_type_template_args)) +# define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS +# endif + +# if(__has_feature(cxx_noexcept)) +# define GLM_CXX11_NOEXCEPT +# endif + +# if(__has_feature(cxx_nonstatic_member_init)) +# define GLM_CXX11_NONSTATIC_MEMBER_INIT +# endif + +# if(__has_feature(cxx_nullptr)) +# define GLM_CXX11_NULLPTR +# endif + +# if(__has_feature(cxx_override_control)) +# define GLM_CXX11_OVERRIDE_CONTROL +# endif + +# if(__has_feature(cxx_reference_qualified_functions)) +# define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS +# endif + +# if(__has_feature(cxx_range_for)) +# define GLM_CXX11_RANGE_FOR +# endif + +# if(__has_feature(cxx_raw_string_literals)) +# define GLM_CXX11_RAW_STRING_LITERALS +# endif + +# if(__has_feature(cxx_rvalue_references)) +# define GLM_CXX11_RVALUE_REFERENCES +# endif + +# if(__has_feature(cxx_static_assert)) +# define GLM_CXX11_STATIC_ASSERT +# endif + +# if(__has_feature(cxx_auto_type)) +# define GLM_CXX11_AUTO_TYPE +# endif + +# if(__has_feature(cxx_strong_enums)) +# define GLM_CXX11_STRONG_ENUMS +# endif + +# if(__has_feature(cxx_trailing_return)) +# define GLM_CXX11_TRAILING_RETURN +# endif + +# if(__has_feature(cxx_unicode_literals)) +# define GLM_CXX11_UNICODE_LITERALS +# endif + +# if(__has_feature(cxx_unrestricted_unions)) +# define GLM_CXX11_UNRESTRICTED_UNIONS +# endif + +# if(__has_feature(cxx_user_literals)) +# define GLM_CXX11_USER_LITERALS +# endif + +# if(__has_feature(cxx_variadic_templates)) +# define GLM_CXX11_VARIADIC_TEMPLATES +# endif + +#endif//(GLM_COMPILER & GLM_COMPILER_CLANG) diff --git a/thirdparty/glm/detail/_fixes.hpp b/thirdparty/glm/detail/_fixes.hpp new file mode 100644 index 0000000..a503c7c --- /dev/null +++ b/thirdparty/glm/detail/_fixes.hpp @@ -0,0 +1,27 @@ +#include + +//! Workaround for compatibility with other libraries +#ifdef max +#undef max +#endif + +//! Workaround for compatibility with other libraries +#ifdef min +#undef min +#endif + +//! Workaround for Android +#ifdef isnan +#undef isnan +#endif + +//! Workaround for Android +#ifdef isinf +#undef isinf +#endif + +//! Workaround for Chrone Native Client +#ifdef log2 +#undef log2 +#endif + diff --git a/thirdparty/glm/detail/_noise.hpp b/thirdparty/glm/detail/_noise.hpp new file mode 100644 index 0000000..5a874a0 --- /dev/null +++ b/thirdparty/glm/detail/_noise.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mod289(T const& x) + { + return x - floor(x * (static_cast(1.0) / static_cast(289.0))) * static_cast(289.0); + } + + template + GLM_FUNC_QUALIFIER T permute(T const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> permute(vec<2, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> permute(vec<3, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> permute(vec<4, T, Q> const& x) + { + return mod289(((x * static_cast(34)) + static_cast(1)) * x); + } + + template + GLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> taylorInvSqrt(vec<2, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> taylorInvSqrt(vec<3, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> taylorInvSqrt(vec<4, T, Q> const& r) + { + return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> fade(vec<2, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> fade(vec<3, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> fade(vec<4, T, Q> const& t) + { + return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); + } +}//namespace detail +}//namespace glm + diff --git a/thirdparty/glm/detail/_swizzle.hpp b/thirdparty/glm/detail/_swizzle.hpp new file mode 100644 index 0000000..87896ef --- /dev/null +++ b/thirdparty/glm/detail/_swizzle.hpp @@ -0,0 +1,804 @@ +#pragma once + +namespace glm{ +namespace detail +{ + // Internal class for implementing swizzle operators + template + struct _swizzle_base0 + { + protected: + GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast(_buffer))[i]; } + GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast(_buffer))[i]; } + + // Use an opaque buffer to *ensure* the compiler doesn't call a constructor. + // The size 1 buffer is assumed to aligned to the actual members so that the + // elem() + char _buffer[1]; + }; + + template + struct _swizzle_base1 : public _swizzle_base0 + { + }; + + template + struct _swizzle_base1<2, T, Q, E0,E1,-1,-2, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<2, T, Q> operator ()() const { return vec<2, T, Q>(this->elem(E0), this->elem(E1)); } + }; + + template + struct _swizzle_base1<3, T, Q, E0,E1,E2,-1, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<3, T, Q> operator ()() const { return vec<3, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2)); } + }; + + template + struct _swizzle_base1<4, T, Q, E0,E1,E2,E3, Aligned> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, T, Q> operator ()() const { return vec<4, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); } + }; + + // Internal class for implementing swizzle operators + /* + Template parameters: + + T = type of scalar values (e.g. float, double) + N = number of components in the vector (e.g. 3) + E0...3 = what index the n-th element of this swizzle refers to in the unswizzled vec + + DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles + containing duplicate elements so that they cannot be used as r-values). + */ + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct op_equal + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e = t; } + }; + + struct op_minus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e -= t; } + }; + + struct op_plus + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e += t; } + }; + + struct op_mul + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e *= t; } + }; + + struct op_div + { + GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e /= t; } + }; + + public: + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t) + { + for (int i = 0; i < N; ++i) + (*this)[i] = t; + return *this; + } + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vec const& that) + { + _apply_op(that, op_equal()); + return *this; + } + + GLM_FUNC_QUALIFIER void operator -= (vec const& that) + { + _apply_op(that, op_minus()); + } + + GLM_FUNC_QUALIFIER void operator += (vec const& that) + { + _apply_op(that, op_plus()); + } + + GLM_FUNC_QUALIFIER void operator *= (vec const& that) + { + _apply_op(that, op_mul()); + } + + GLM_FUNC_QUALIFIER void operator /= (vec const& that) + { + _apply_op(that, op_div()); + } + + GLM_FUNC_QUALIFIER T& operator[](size_t i) + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + GLM_FUNC_QUALIFIER T operator[](size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + + protected: + template + GLM_FUNC_QUALIFIER void _apply_op(vec const& that, const U& op) + { + // Make a copy of the data in this == &that. + // The copier should optimize out the copy in cases where the function is + // properly inlined and the copy is not necessary. + T t[N]; + for (int i = 0; i < N; ++i) + t[i] = that[i]; + for (int i = 0; i < N; ++i) + op( (*this)[i], t[i] ); + } + }; + + // Specialization for swizzles containing duplicate elements. These cannot be modified. + template + struct _swizzle_base2 : public _swizzle_base1::value> + { + struct Stub {}; + + GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const&) { return *this; } + + GLM_FUNC_QUALIFIER T operator[] (size_t i) const + { + const int offset_dst[4] = { E0, E1, E2, E3 }; + return this->elem(offset_dst[i]); + } + }; + + template + struct _swizzle : public _swizzle_base2 + { + typedef _swizzle_base2 base_type; + + using base_type::operator=; + + GLM_FUNC_QUALIFIER operator vec () const { return (*this)(); } + }; + +// +// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros +// +#define GLM_SWIZZLE_TEMPLATE1 template +#define GLM_SWIZZLE_TEMPLATE2 template +#define GLM_SWIZZLE_TYPE1 _swizzle +#define GLM_SWIZZLE_TYPE2 _swizzle + +// +// Wrapper for a binary operator (e.g. u.yy + v.zy) +// +#define GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return a() OPERAND b(); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const vec& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const vec& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz) +// +#define GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const T& b) \ + { \ + return a() OPERAND b; \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER vec operator OPERAND ( const T& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return a OPERAND b(); \ + } + +// +// Macro for wrapping a function taking one argument (e.g. abs()) +// +#define GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a) \ + { \ + return FUNCTION(a()); \ + } + +// +// Macro for wrapping a function taking two vector arguments (e.g. dot()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a(), b()); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename V& b) \ + { \ + return FUNCTION(a(), b); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const GLM_SWIZZLE_TYPE1& b) \ + { \ + return FUNCTION(a, b()); \ + } + +// +// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()). +// +#define GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION) \ + GLM_SWIZZLE_TEMPLATE2 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a(), b(), c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\ + { \ + return FUNCTION(a(), b, c); \ + } \ + GLM_SWIZZLE_TEMPLATE1 \ + GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ + { \ + return FUNCTION(a, b(), c); \ + } + +}//namespace detail +}//namespace glm + +namespace glm +{ + namespace detail + { + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*) + GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/) + } + + // + // Swizzles are distinct types from the unswizzled type. The below macros will + // provide template specializations for the swizzle types for the given functions + // so that the compiler does not have any ambiguity to choosing how to handle + // the function. + // + // The alternative is to use the operator()() when calling the function in order + // to explicitly convert the swizzled type to the unswizzled type. + // + + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, abs); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acos); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acosh); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, all); + //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, any); + + //GLM_SWIZZLE_FUNCTION_2_ARGS(value_type, dot); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, cross); + //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, step); + //GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix); +} + +#define GLM_SWIZZLE2_2_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<2, T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2, T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2, T, Q, 1,1,-1,-2> E1 ## E1; }; + +#define GLM_SWIZZLE2_3_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<3,T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3,T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE2_4_MEMBERS(T, Q, E0,E1) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; + +#define GLM_SWIZZLE3_2_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; + +#define GLM_SWIZZLE3_3_MEMBERS(T, Q ,E0,E1,E2) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE3_4_MEMBERS(T, Q, E0,E1,E2) \ + struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4,T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; + +#define GLM_SWIZZLE4_2_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 0,3,-1,-2> E0 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 1,3,-1,-2> E1 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 2,3,-1,-2> E2 ## E3; }; \ + struct { detail::_swizzle<2,T, Q, 3,0,-1,-2> E3 ## E0; }; \ + struct { detail::_swizzle<2,T, Q, 3,1,-1,-2> E3 ## E1; }; \ + struct { detail::_swizzle<2,T, Q, 3,2,-1,-2> E3 ## E2; }; \ + struct { detail::_swizzle<2,T, Q, 3,3,-1,-2> E3 ## E3; }; + +#define GLM_SWIZZLE4_3_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,0,3,-1> E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,1,3,-1> E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,2,3,-1> E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,0,-1> E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,1,-1> E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,2,-1> E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 0,3,3,-1> E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,0,3,-1> E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,1,3,-1> E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,2,3,-1> E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,0,-1> E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,1,-1> E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,2,-1> E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 1,3,3,-1> E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,0,3,-1> E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,1,3,-1> E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,2,3,-1> E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,0,-1> E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,1,-1> E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,2,-1> E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 2,3,3,-1> E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,0,-1> E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,1,-1> E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,2,-1> E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,0,3,-1> E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,0,-1> E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,1,-1> E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,2,-1> E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,1,3,-1> E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,0,-1> E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,1,-1> E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,2,-1> E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,2,3,-1> E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,0,-1> E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,1,-1> E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,2,-1> E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<3, T, Q, 3,3,3,-1> E3 ## E3 ## E3; }; + +#define GLM_SWIZZLE4_4_MEMBERS(T, Q, E0,E1,E2,E3) \ + struct { detail::_swizzle<4, T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \ + struct { detail::_swizzle<4, T, Q, 3,3,3,3> E3 ## E3 ## E3 ## E3; }; diff --git a/thirdparty/glm/detail/_swizzle_func.hpp b/thirdparty/glm/detail/_swizzle_func.hpp new file mode 100644 index 0000000..d93c6af --- /dev/null +++ b/thirdparty/glm/detail/_swizzle_func.hpp @@ -0,0 +1,682 @@ +#pragma once + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, CONST, A, B) \ + vec<2, T, Q> A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, CONST, A, B, C) \ + vec<3, T, Q> A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, CONST, A, B, C, D) \ + vec<4, T, Q> A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(T, P, L, CONST, A, B) \ + template \ + vec vec::A ## B() CONST \ + { \ + return vec<2, T, Q>(this->A, this->B); \ + } + +#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(T, P, L, CONST, A, B, C) \ + template \ + vec<3, T, Q> vec::A ## B ## C() CONST \ + { \ + return vec<3, T, Q>(this->A, this->B, this->C); \ + } + +#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(T, P, L, CONST, A, B, C, D) \ + template \ + vec<4, T, Q> vec::A ## B ## C ## D() CONST \ + { \ + return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ + } + +#define GLM_MUTABLE + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, x, y) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, r, g) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, s, t) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, B, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, C) + +#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, B) + +#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, C, A) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, s, t, p, q) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, x, y) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, r, g) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, s, t) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, x, y, z) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, r, g, b) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, s, t, p) + +#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, D) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, A) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, B) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, C) \ + GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, D) + +#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, D) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, A) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, B) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, C) \ + GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, D) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, A) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, B) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, C) \ + GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ + GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) + +#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, x, y, z, w) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, r, g, b, a) \ + GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, s, t, p, q) + diff --git a/thirdparty/glm/detail/_vectorize.hpp b/thirdparty/glm/detail/_vectorize.hpp new file mode 100644 index 0000000..1fcaec3 --- /dev/null +++ b/thirdparty/glm/detail/_vectorize.hpp @@ -0,0 +1,162 @@ +#pragma once + +namespace glm{ +namespace detail +{ + template class vec, length_t L, typename R, typename T, qualifier Q> + struct functor1{}; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<1, R, Q> call(R (*Func) (T x), vec<1, T, Q> const& v) + { + return vec<1, R, Q>(Func(v.x)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<2, R, Q> call(R (*Func) (T x), vec<2, T, Q> const& v) + { + return vec<2, R, Q>(Func(v.x), Func(v.y)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, R, Q> call(R (*Func) (T x), vec<3, T, Q> const& v) + { + return vec<3, R, Q>(Func(v.x), Func(v.y), Func(v.z)); + } + }; + + template class vec, typename R, typename T, qualifier Q> + struct functor1 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, R, Q> call(R (*Func) (T x), vec<4, T, Q> const& v) + { + return vec<4, R, Q>(Func(v.x), Func(v.y), Func(v.z), Func(v.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2{}; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return vec<1, T, Q>(Func(a.x, b.x)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + return vec<2, T, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return vec<3, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2 + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; + + template class vec, length_t L, typename T, qualifier Q> + struct functor2_vec_sca{}; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, T b) + { + return vec<1, T, Q>(Func(a.x, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, T b) + { + return vec<2, T, Q>(Func(a.x, b), Func(a.y, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, T b) + { + return vec<3, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b)); + } + }; + + template class vec, typename T, qualifier Q> + struct functor2_vec_sca + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, T b) + { + return vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); + } + }; + + template + struct functor2_vec_int {}; + + template + struct functor2_vec_int<1, T, Q> + { + GLM_FUNC_QUALIFIER static vec<1, int, Q> call(int (*Func) (T x, int y), vec<1, T, Q> const& a, vec<1, int, Q> const& b) + { + return vec<1, int, Q>(Func(a.x, b.x)); + } + }; + + template + struct functor2_vec_int<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, int, Q> call(int (*Func) (T x, int y), vec<2, T, Q> const& a, vec<2, int, Q> const& b) + { + return vec<2, int, Q>(Func(a.x, b.x), Func(a.y, b.y)); + } + }; + + template + struct functor2_vec_int<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, int, Q> call(int (*Func) (T x, int y), vec<3, T, Q> const& a, vec<3, int, Q> const& b) + { + return vec<3, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); + } + }; + + template + struct functor2_vec_int<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(int (*Func) (T x, int y), vec<4, T, Q> const& a, vec<4, int, Q> const& b) + { + return vec<4, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); + } + }; +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/compute_common.hpp b/thirdparty/glm/detail/compute_common.hpp new file mode 100644 index 0000000..cc24b9e --- /dev/null +++ b/thirdparty/glm/detail/compute_common.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs + {}; + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || std::numeric_limits::is_signed, + "'abs' only accept floating-point and integer scalar or vector inputs"); + + return x >= genFIType(0) ? x : -x; + // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff; + } + }; + +#if GLM_COMPILER & GLM_COMPILER_CUDA + template<> + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static float call(float x) + { + return fabsf(x); + } + }; +#endif + + template + struct compute_abs + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) + { + GLM_STATIC_ASSERT( + (!std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'abs' only accept floating-point and integer scalar or vector inputs"); + return x; + } + }; +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/compute_vector_relational.hpp b/thirdparty/glm/detail/compute_vector_relational.hpp new file mode 100644 index 0000000..167b634 --- /dev/null +++ b/thirdparty/glm/detail/compute_vector_relational.hpp @@ -0,0 +1,30 @@ +#pragma once + +//#include "compute_common.hpp" +#include "setup.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return a == b; + } + }; +/* + template + struct compute_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) + { + return detail::compute_abs::is_signed>::call(b - a) <= static_cast(0); + //return std::memcmp(&a, &b, sizeof(T)) == 0; + } + }; +*/ +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/func_common.inl b/thirdparty/glm/detail/func_common.inl new file mode 100644 index 0000000..4b5f144 --- /dev/null +++ b/thirdparty/glm/detail/func_common.inl @@ -0,0 +1,792 @@ +/// @ref core +/// @file glm/detail/func_common.inl + +#include "../vector_relational.hpp" +#include "compute_common.hpp" +#include "type_vec1.hpp" +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include "_vectorize.hpp" +#include + +namespace glm +{ + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType min(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return (y < x) ? y : x; + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType max(genType x, genType y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + + return (x < y) ? y : x; + } + + // abs + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR int abs(int x) + { + int const y = x >> (sizeof(int) * 8 - 1); + return (x ^ y) - y; + } + + // round +# if GLM_HAS_CXX11_STL + using ::std::round; +# else + template + GLM_FUNC_QUALIFIER genType round(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + + return x < static_cast(0) ? static_cast(int(x - static_cast(0.5))) : static_cast(int(x + static_cast(0.5))); + } +# endif + + // trunc +# if GLM_HAS_CXX11_STL + using ::std::trunc; +# else + template + GLM_FUNC_QUALIFIER genType trunc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + + return x < static_cast(0) ? -std::floor(-x) : std::floor(x); + } +# endif + +}//namespace glm + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec call(vec const& x) + { + return detail::functor1::call(abs, x); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) + { + vec Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = a[i] ? y[i] : x[i]; + return Result; + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); + } + }; + + template + struct compute_mix_scalar + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, U const& a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); + + return static_cast(static_cast(x) * (static_cast(1) - a) + static_cast(y) * a); + } + }; + + template + struct compute_mix + { + GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, bool const& a) + { + return a ? y : x; + } + }; + + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return vec(glm::lessThan(vec(0), x)) - vec(glm::lessThan(x, vec(0))); + } + }; + +# if GLM_ARCH == GLM_ARCH_X86 + template + struct compute_sign + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + T const Shift(static_cast(sizeof(T) * 8 - 1)); + vec const y(vec::type, Q>(-x) >> typename detail::make_unsigned::type(Shift)); + + return (x >> Shift) | y; + } + }; +# endif + + template + struct compute_floor + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::floor, x); + } + }; + + template + struct compute_ceil + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::ceil, x); + } + }; + + template + struct compute_fract + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return x - floor(x); + } + }; + + template + struct compute_trunc + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(trunc, x); + } + }; + + template + struct compute_round + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(round, x); + } + }; + + template + struct compute_mod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mod' only accept floating-point inputs. Include for integer inputs."); + return a - b * floor(a / b); + } + }; + + template + struct compute_min_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(min, x, y); + } + }; + + template + struct compute_max_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) + { + return detail::functor2::call(max, x, y); + } + }; + + template + struct compute_clamp_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& minVal, vec const& maxVal) + { + return min(max(x, minVal), maxVal); + } + }; + + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge, vec const& x) + { + return mix(vec(1), vec(0), glm::lessThan(x, edge)); + } + }; + + template + struct compute_smoothstep_vector + { + GLM_FUNC_QUALIFIER static vec call(vec const& edge0, vec const& edge1, vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); + vec const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast(0), static_cast(1))); + return tmp * tmp * (static_cast(3) - static_cast(2) * tmp); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genFIType abs(genFIType x) + { + return detail::compute_abs::is_signed>::call(x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec abs(vec const& x) + { + return detail::compute_abs_vector::value>::call(x); + } + + // sign + // fast and works for any type + template + GLM_FUNC_QUALIFIER genFIType sign(genFIType x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign<1, genFIType, defaultp, + std::numeric_limits::is_iec559, detail::is_aligned::value>::call(vec<1, genFIType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec sign(vec const& x) + { + GLM_STATIC_ASSERT( + std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), + "'sign' only accept signed inputs"); + + return detail::compute_sign::is_iec559, detail::is_aligned::value>::call(x); + } + + // floor + using ::std::floor; + template + GLM_FUNC_QUALIFIER vec floor(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'floor' only accept floating-point inputs."); + return detail::compute_floor::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec trunc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); + return detail::compute_trunc::value>::call(x); + } + + template + GLM_FUNC_QUALIFIER vec round(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); + return detail::compute_round::value>::call(x); + } + +/* + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + return genType(int(x + genType(int(x) % 2))); + } +*/ + + // roundEven + template + GLM_FUNC_QUALIFIER genType roundEven(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + + int Integer = static_cast(x); + genType IntegerPart = static_cast(Integer); + genType FractionalPart = fract(x); + + if(FractionalPart > static_cast(0.5) || FractionalPart < static_cast(0.5)) + { + return round(x); + } + else if((Integer % 2) == 0) + { + return IntegerPart; + } + else if(x <= static_cast(0)) // Work around... + { + return IntegerPart - static_cast(1); + } + else + { + return IntegerPart + static_cast(1); + } + //else // Bug on MinGW 4.5.2 + //{ + // return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0)); + //} + } + + template + GLM_FUNC_QUALIFIER vec roundEven(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); + return detail::functor1::call(roundEven, x); + } + + // ceil + using ::std::ceil; + template + GLM_FUNC_QUALIFIER vec ceil(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ceil' only accept floating-point inputs"); + return detail::compute_ceil::value>::call(x); + } + + // fract + template + GLM_FUNC_QUALIFIER genType fract(genType x) + { + return fract(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec fract(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fract' only accept floating-point inputs"); + return detail::compute_fract::value>::call(x); + } + + // mod + template + GLM_FUNC_QUALIFIER genType mod(genType x, genType y) + { +# if GLM_COMPILER & GLM_COMPILER_CUDA + // Another Cuda compiler bug https://github.com/g-truc/glm/issues/530 + vec<1, genType, defaultp> Result(mod(vec<1, genType, defaultp>(x), y)); + return Result.x; +# else + return mod(vec<1, genType, defaultp>(x), y).x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, T y) + { + return detail::compute_mod::value>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec mod(vec const& x, vec const& y) + { + return detail::compute_mod::value>::call(x, y); + } + + // modf + template + GLM_FUNC_QUALIFIER genType modf(genType x, genType & i) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'modf' only accept floating-point inputs"); + return std::modf(x, &i); + } + + template + GLM_FUNC_QUALIFIER vec<1, T, Q> modf(vec<1, T, Q> const& x, vec<1, T, Q> & i) + { + return vec<1, T, Q>( + modf(x.x, i.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> modf(vec<2, T, Q> const& x, vec<2, T, Q> & i) + { + return vec<2, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> modf(vec<3, T, Q> const& x, vec<3, T, Q> & i) + { + return vec<3, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> modf(vec<4, T, Q> const& x, vec<4, T, Q> & i) + { + return vec<4, T, Q>( + modf(x.x, i.x), + modf(x.y, i.y), + modf(x.z, i.z), + modf(x.w, i.w)); + } + + //// Only valid if (INT_MIN <= x-y <= INT_MAX) + //// min(x,y) + //r = y + ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + //// max(x,y) + //r = x - ((x - y) & ((x - y) >> (sizeof(int) * + //CHAR_BIT - 1))); + + // min + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); + return detail::compute_min_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, vec const& b) + { + return detail::compute_min_vector::value>::call(a, b); + } + + // max + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); + return detail::compute_max_vector::value>::call(a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, vec const& b) + { + return detail::compute_max_vector::value>::call(a, b); + } + + // clamp + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return min(max(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, vec(minVal), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); + return detail::compute_clamp_vector::value>::call(x, minVal, maxVal); + } + + template + GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a) + { + return detail::compute_mix::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, U a) + { + return detail::compute_mix_scalar::value>::call(x, y, a); + } + + template + GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, vec const& a) + { + return detail::compute_mix_vector::value>::call(x, y, a); + } + + // step + template + GLM_FUNC_QUALIFIER genType step(genType edge, genType x) + { + return mix(static_cast(1), static_cast(0), x < edge); + } + + template + GLM_FUNC_QUALIFIER vec step(T edge, vec const& x) + { + return detail::compute_step_vector::value>::call(vec(edge), x); + } + + template + GLM_FUNC_QUALIFIER vec step(vec const& edge, vec const& x) + { + return detail::compute_step_vector::value>::call(edge, x); + } + + // smoothstep + template + GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); + + genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1))); + return tmp * tmp * (genType(3) - genType(2) * tmp); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(T edge0, T edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(vec(edge0), vec(edge1), x); + } + + template + GLM_FUNC_QUALIFIER vec smoothstep(vec const& edge0, vec const& edge1, vec const& x) + { + return detail::compute_smoothstep_vector::value>::call(edge0, edge1, x); + } + +# if GLM_HAS_CXX11_STL + using std::isnan; +# else + template + GLM_FUNC_QUALIFIER bool isnan(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isnan(x); +# elif GLM_COMPILER & GLM_COMPILER_VC + return _isnan(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_PLATFORM & GLM_PLATFORM_WINDOWS + return _isnan(x) != 0; +# else + return ::isnan(x) != 0; +# endif +# elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L + return _isnan(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_CUDA + return ::isnan(x) != 0; +# else + return std::isnan(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isnan(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isnan(v[l]); + return Result; + } + +# if GLM_HAS_CXX11_STL + using std::isinf; +# else + template + GLM_FUNC_QUALIFIER bool isinf(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::isinf(x); +# elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC) +# if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) + return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF; +# else + return ::isinf(x); +# endif +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L) + return _isinf(x) != 0; +# else + return std::isinf(x); +# endif +# elif GLM_COMPILER & GLM_COMPILER_CUDA + // http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab + return ::isinf(double(x)) != 0; +# else + return std::isinf(x); +# endif + } +# endif + + template + GLM_FUNC_QUALIFIER vec isinf(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = glm::isinf(v[l]); + return Result; + } + + GLM_FUNC_QUALIFIER int floatBitsToInt(float const& v) + { + union + { + float in; + int out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToInt(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER uint floatBitsToUint(float const& v) + { + union + { + float in; + uint out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec floatBitsToUint(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float intBitsToFloat(int const& v) + { + union + { + int in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec intBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + + GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const& v) + { + union + { + uint in; + float out; + } u; + + u.in = v; + + return u.out; + } + + template + GLM_FUNC_QUALIFIER vec uintBitsToFloat(vec const& v) + { + return reinterpret_cast&>(const_cast&>(v)); + } + +# if GLM_HAS_CXX11_STL + using std::fma; +# else + template + GLM_FUNC_QUALIFIER genType fma(genType const& a, genType const& b, genType const& c) + { + return a * b + c; + } +# endif + + template + GLM_FUNC_QUALIFIER genType frexp(genType x, int& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + return std::frexp(x, &exp); + } + + template + GLM_FUNC_QUALIFIER vec frexp(vec const& v, vec& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::frexp(v[l], &exp[l]); + return Result; + } + + template + GLM_FUNC_QUALIFIER genType ldexp(genType const& x, int const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + return std::ldexp(x, exp); + } + + template + GLM_FUNC_QUALIFIER vec ldexp(vec const& v, vec const& exp) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); + + vec Result; + for (length_t l = 0; l < v.length(); ++l) + Result[l] = std::ldexp(v[l], exp[l]); + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_common_simd.inl" +#endif diff --git a/thirdparty/glm/detail/func_common_simd.inl b/thirdparty/glm/detail/func_common_simd.inl new file mode 100644 index 0000000..ce0032d --- /dev/null +++ b/thirdparty/glm/detail/func_common_simd.inl @@ -0,0 +1,231 @@ +/// @ref core +/// @file glm/detail/func_common_simd.inl + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "../simd/common.h" + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_abs_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_abs(v.data); + return result; + } + }; + + template + struct compute_abs_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> result; + result.data = glm_ivec4_abs(v.data); + return result; + } + }; + + template + struct compute_floor<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_floor(v.data); + return result; + } + }; + + template + struct compute_ceil<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_ceil(v.data); + return result; + } + }; + + template + struct compute_fract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_fract(v.data); + return result; + } + }; + + template + struct compute_round<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> result; + result.data = glm_vec4_round(v.data); + return result; + } + }; + + template + struct compute_mod<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + vec<4, float, Q> result; + result.data = glm_vec4_mod(x.data, y.data); + return result; + } + }; + + template + struct compute_min_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_min_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + vec<4, float, Q> result; + result.data = _mm_max_ps(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + vec<4, int, Q> result; + result.data = _mm_max_epi32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_max_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + vec<4, uint, Q> result; + result.data = _mm_max_epu32(v1.data, v2.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal) + { + vec<4, float, Q> result; + result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, int, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal) + { + vec<4, int, Q> result; + result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_clamp_vector<4, uint, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal) + { + vec<4, uint, Q> result; + result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data); + return result; + } + }; + + template + struct compute_mix_vector<4, float, bool, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a) + { + __m128i const Load = _mm_set_epi32(-static_cast(a.w), -static_cast(a.z), -static_cast(a.y), -static_cast(a.x)); + __m128 const Mask = _mm_castsi128_ps(Load); + + vec<4, float, Q> Result; +# if 0 && GLM_ARCH & GLM_ARCH_AVX + Result.data = _mm_blendv_ps(x.data, y.data, Mask); +# else + Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data)); +# endif + return Result; + } + }; +/* FIXME + template + struct compute_step_vector + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + result.data = glm_vec4_step(edge.data, x.data); + return result; + } + }; +*/ + template + struct compute_smoothstep_vector<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/detail/func_exponential.inl b/thirdparty/glm/detail/func_exponential.inl new file mode 100644 index 0000000..2040d41 --- /dev/null +++ b/thirdparty/glm/detail/func_exponential.inl @@ -0,0 +1,152 @@ +/// @ref core +/// @file glm/detail/func_exponential.inl + +#include "../vector_relational.hpp" +#include "_vectorize.hpp" +#include +#include +#include + +namespace glm{ +namespace detail +{ +# if GLM_HAS_CXX11_STL + using std::log2; +# else + template + genType log2(genType Value) + { + return std::log(Value) * static_cast(1.4426950408889634073599246810019); + } +# endif + + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'log2' only accept floating-point inputs. Include for integer inputs."); + + return detail::functor1::call(log2, v); + } + }; + + template + struct compute_sqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(std::sqrt, x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return static_cast(1) / sqrt(x); + } + }; + + template + struct compute_inversesqrt + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + vec tmp(x); + vec xhalf(tmp * 0.5f); + vec* p = reinterpret_cast*>(const_cast*>(&x)); + vec i = vec(0x5f375a86) - (*p >> vec(1)); + vec* ptmp = reinterpret_cast*>(&i); + tmp = *ptmp; + tmp = tmp * (1.5f - xhalf * tmp * tmp); + return tmp; + } + }; +}//namespace detail + + // pow + using std::pow; + template + GLM_FUNC_QUALIFIER vec pow(vec const& base, vec const& exponent) + { + return detail::functor2::call(pow, base, exponent); + } + + // exp + using std::exp; + template + GLM_FUNC_QUALIFIER vec exp(vec const& x) + { + return detail::functor1::call(exp, x); + } + + // log + using std::log; + template + GLM_FUNC_QUALIFIER vec log(vec const& x) + { + return detail::functor1::call(log, x); + } + +# if GLM_HAS_CXX11_STL + using std::exp2; +# else + //exp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType exp2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'exp2' only accept floating-point inputs"); + + return std::exp(static_cast(0.69314718055994530941723212145818) * x); + } +# endif + + template + GLM_FUNC_QUALIFIER vec exp2(vec const& x) + { + return detail::functor1::call(exp2, x); + } + + // log2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType log2(genType x) + { + return log2(vec<1, genType>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec log2(vec const& x) + { + return detail::compute_log2::is_iec559, detail::is_aligned::value>::call(x); + } + + // sqrt + using std::sqrt; + template + GLM_FUNC_QUALIFIER vec sqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sqrt' only accept floating-point inputs"); + return detail::compute_sqrt::value>::call(x); + } + + // inversesqrt + template + GLM_FUNC_QUALIFIER genType inversesqrt(genType x) + { + return static_cast(1) / sqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec inversesqrt(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'inversesqrt' only accept floating-point inputs"); + return detail::compute_inversesqrt::value>::call(x); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_exponential_simd.inl" +#endif + diff --git a/thirdparty/glm/detail/func_exponential_simd.inl b/thirdparty/glm/detail/func_exponential_simd.inl new file mode 100644 index 0000000..fb78951 --- /dev/null +++ b/thirdparty/glm/detail/func_exponential_simd.inl @@ -0,0 +1,37 @@ +/// @ref core +/// @file glm/detail/func_exponential_simd.inl + +#include "../simd/exponential.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_sqrt<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = _mm_sqrt_ps(v.data); + return Result; + } + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct compute_sqrt<4, float, aligned_lowp, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& v) + { + vec<4, float, aligned_lowp> Result; + Result.data = glm_vec4_sqrt_lowp(v.data); + return Result; + } + }; +# endif +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/detail/func_geometric.inl b/thirdparty/glm/detail/func_geometric.inl new file mode 100644 index 0000000..9cde28f --- /dev/null +++ b/thirdparty/glm/detail/func_geometric.inl @@ -0,0 +1,243 @@ +#include "../exponential.hpp" +#include "../common.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return sqrt(dot(v, v)); + } + }; + + template + struct compute_distance + { + GLM_FUNC_QUALIFIER static T call(vec const& p0, vec const& p1) + { + return length(p1 - p0); + } + }; + + template + struct compute_dot{}; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<1, T, Q> const& a, vec<1, T, Q> const& b) + { + return a.x * b.x; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& a, vec<2, T, Q> const& b) + { + vec<2, T, Q> tmp(a * b); + return tmp.x + tmp.y; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + vec<3, T, Q> tmp(a * b); + return tmp.x + tmp.y + tmp.z; + } + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER static T call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> tmp(a * b); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER static vec<3, T, Q> call(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return vec<3, T, Q>( + x.y * y.z - y.y * x.z, + x.z * y.x - y.z * x.x, + x.x * y.y - y.x * x.y); + } + }; + + template + struct compute_normalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return v * inversesqrt(dot(v, v)); + } + }; + + template + struct compute_faceforward + { + GLM_FUNC_QUALIFIER static vec call(vec const& N, vec const& I, vec const& Nref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return dot(Nref, I) < static_cast(0) ? N : -N; + } + }; + + template + struct compute_reflect + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N) + { + return I - N * dot(N, I) * static_cast(2); + } + }; + + template + struct compute_refract + { + GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N, T eta) + { + T const dotValue(dot(N, I)); + T const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + vec const Result = + (k >= static_cast(0)) ? (eta * I - (eta * dotValue + std::sqrt(k)) * N) : vec(0); + return Result; + } + }; +}//namespace detail + + // length + template + GLM_FUNC_QUALIFIER genType length(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T length(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); + + return detail::compute_length::value>::call(v); + } + + // distance + template + GLM_FUNC_QUALIFIER genType distance(genType const& p0, genType const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance' accepts only floating-point inputs"); + + return length(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance(vec const& p0, vec const& p1) + { + return detail::compute_distance::value>::call(p0, p1); + } + + // dot + template + GLM_FUNC_QUALIFIER T dot(T x, T y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return x * y; + } + + template + GLM_FUNC_QUALIFIER T dot(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + // cross + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return detail::compute_cross::value>::call(x, y); + } +/* + // normalize + template + GLM_FUNC_QUALIFIER genType normalize(genType const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return x < genType(0) ? genType(-1) : genType(1); + } +*/ + template + GLM_FUNC_QUALIFIER vec normalize(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); + + return detail::compute_normalize::value>::call(x); + } + + // faceforward + template + GLM_FUNC_QUALIFIER genType faceforward(genType const& N, genType const& I, genType const& Nref) + { + return dot(Nref, I) < static_cast(0) ? N : -N; + } + + template + GLM_FUNC_QUALIFIER vec faceforward(vec const& N, vec const& I, vec const& Nref) + { + return detail::compute_faceforward::value>::call(N, I, Nref); + } + + // reflect + template + GLM_FUNC_QUALIFIER genType reflect(genType const& I, genType const& N) + { + return I - N * dot(N, I) * genType(2); + } + + template + GLM_FUNC_QUALIFIER vec reflect(vec const& I, vec const& N) + { + return detail::compute_reflect::value>::call(I, N); + } + + // refract + template + GLM_FUNC_QUALIFIER genType refract(genType const& I, genType const& N, genType eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + genType const dotValue(dot(N, I)); + genType const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); + return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast(k >= static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec refract(vec const& I, vec const& N, T eta) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); + return detail::compute_refract::value>::call(I, N, eta); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_geometric_simd.inl" +#endif diff --git a/thirdparty/glm/detail/func_geometric_simd.inl b/thirdparty/glm/detail/func_geometric_simd.inl new file mode 100644 index 0000000..2076dae --- /dev/null +++ b/thirdparty/glm/detail/func_geometric_simd.inl @@ -0,0 +1,163 @@ +/// @ref core +/// @file glm/detail/func_geometric_simd.inl + +#include "../simd/geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_length<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) + { + return _mm_cvtss_f32(glm_vec4_length(v.data)); + } + }; + + template + struct compute_distance<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) + { + return _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data)); + } + }; + + template + struct compute_dot, float, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; + + template + struct compute_cross + { + GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b) + { + __m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x); + __m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x); + __m128 const xpd0 = glm_vec4_cross(set0, set1); + + vec<4, float, Q> Result; + Result.data = xpd0; + return vec<3, float, Q>(Result); + } + }; + + template + struct compute_normalize<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_normalize(v.data); + return Result; + } + }; + + template + struct compute_faceforward<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& N, vec<4, float, Q> const& I, vec<4, float, Q> const& Nref) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_faceforward(N.data, I.data, Nref.data); + return Result; + } + }; + + template + struct compute_reflect<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_reflect(I.data, N.data); + return Result; + } + }; + + template + struct compute_refract<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N, float eta) + { + vec<4, float, Q> Result; + Result.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#elif GLM_ARCH & GLM_ARCH_NEON_BIT +namespace glm{ +namespace detail +{ + template + struct compute_length<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) + { + return sqrt(compute_dot, float, true>::call(v, v)); + } + }; + + template + struct compute_distance<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) + { + return compute_length<4, float, Q, true>::call(p1 - p0); + } + }; + + + template + struct compute_dot, float, true> + { + GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) + { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + float32x4_t v = vmulq_f32(x.data, y.data); + return vaddvq_f32(v); +#else // Armv7a with Neon + float32x4_t p = vmulq_f32(x.data, y.data); + float32x2_t v = vpadd_f32(vget_low_f32(p), vget_high_f32(p)); + v = vpadd_f32(v, v); + return vget_lane_f32(v, 0); +#endif + } + }; + + template + struct compute_normalize<4, float, Q, true> + { + GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) + { + float32x4_t p = vmulq_f32(v.data, v.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + p = vpaddq_f32(p, p); + p = vpaddq_f32(p, p); +#else + float32x2_t t = vpadd_f32(vget_low_f32(p), vget_high_f32(p)); + t = vpadd_f32(t, t); + p = vcombine_f32(t, t); +#endif + + float32x4_t vd = vrsqrteq_f32(p); + vec<4, float, Q> Result; + Result.data = vmulq_f32(v.data, vd); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/detail/func_integer.inl b/thirdparty/glm/detail/func_integer.inl new file mode 100644 index 0000000..091e1e0 --- /dev/null +++ b/thirdparty/glm/detail/func_integer.inl @@ -0,0 +1,372 @@ +/// @ref core + +#include "_vectorize.hpp" +#if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +# include +# pragma intrinsic(_BitScanReverse) +#endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) +#include + +#if !GLM_HAS_EXTENDED_INTEGER_TYPE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" +# endif +#endif + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER T mask(T Bits) + { + return Bits >= static_cast(sizeof(T) * 8) ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldReverseStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) << Shift | (v & (~Mask)) >> Shift; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) + { + return v; + } + }; + + template + struct compute_bitfieldBitCountStep + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) + { + return (v & Mask) + ((v >> Shift) & Mask); + } + }; + + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + if(Value == 0) + return -1; + + return glm::bitCount(~Value & (Value - static_cast(1))); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + struct compute_findLSB + { + GLM_FUNC_QUALIFIER static int call(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T Shift) + { + return x | (x >> Shift); + } + }; + + template + struct compute_findMSB_step_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x, T) + { + return x; + } + }; + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + vec x(v); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 1)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 2)); + x = compute_findMSB_step_vec= 8>::call(x, static_cast( 4)); + x = compute_findMSB_step_vec= 16>::call(x, static_cast( 8)); + x = compute_findMSB_step_vec= 32>::call(x, static_cast(16)); + x = compute_findMSB_step_vec= 64>::call(x, static_cast(32)); + return vec(sizeof(T) * 8 - 1) - glm::bitCount(~x); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + GLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_32, x); + } + }; + +# if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) + template + GLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value) + { + unsigned long Result(0); + unsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast(&Value)); + return IsNotNull ? int(Result) : -1; + } + + template + struct compute_findMSB_vec + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + return detail::functor1::call(compute_findMSB_64, x); + } + }; +# endif +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail + + // uaddCarry + GLM_FUNC_QUALIFIER uint uaddCarry(uint const& x, uint const& y, uint & Carry) + { + detail::uint64 const Value64(static_cast(x) + static_cast(y)); + detail::uint64 const Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = Value64 > Max32 ? 1u : 0u; + return static_cast(Value64 % (Max32 + static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER vec uaddCarry(vec const& x, vec const& y, vec& Carry) + { + vec Value64(vec(x) + vec(y)); + vec Max32((static_cast(1) << static_cast(32)) - static_cast(1)); + Carry = mix(vec(0), vec(1), greaterThan(Value64, Max32)); + return vec(Value64 % (Max32 + static_cast(1))); + } + + // usubBorrow + GLM_FUNC_QUALIFIER uint usubBorrow(uint const& x, uint const& y, uint & Borrow) + { + Borrow = x >= y ? static_cast(0) : static_cast(1); + if(y >= x) + return y - x; + else + return static_cast((static_cast(1) << static_cast(32)) + (static_cast(y) - static_cast(x))); + } + + template + GLM_FUNC_QUALIFIER vec usubBorrow(vec const& x, vec const& y, vec& Borrow) + { + Borrow = mix(vec(1), vec(0), greaterThanEqual(x, y)); + vec const YgeX(y - x); + vec const XgeY(vec((static_cast(1) << static_cast(32)) + (vec(y) - vec(x)))); + return mix(XgeY, YgeX, greaterThanEqual(y, x)); + } + + // umulExtended + GLM_FUNC_QUALIFIER void umulExtended(uint const& x, uint const& y, uint & msb, uint & lsb) + { + detail::uint64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void umulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + msb = vec(Value64 >> static_cast(32)); + lsb = vec(Value64); + } + + // imulExtended + GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int& msb, int& lsb) + { + detail::int64 Value64 = static_cast(x) * static_cast(y); + msb = static_cast(Value64 >> static_cast(32)); + lsb = static_cast(Value64); + } + + template + GLM_FUNC_QUALIFIER void imulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) + { + vec Value64(vec(x) * vec(y)); + lsb = vec(Value64 & static_cast(0xFFFFFFFF)); + msb = vec((Value64 >> static_cast(32)) & static_cast(0xFFFFFFFF)); + } + + // bitfieldExtract + template + GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits) + { + return bitfieldExtract(vec<1, genIUType>(Value), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldExtract(vec const& Value, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); + + return (Value >> static_cast(Offset)) & static_cast(detail::mask(Bits)); + } + + // bitfieldInsert + template + GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); + + return bitfieldInsert(vec<1, genIUType>(Base), vec<1, genIUType>(Insert), Offset, Bits).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldInsert(vec const& Base, vec const& Insert, int Offset, int Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); + + T const Mask = static_cast(detail::mask(Bits) << Offset); + return (Base & ~Mask) | ((Insert << static_cast(Offset)) & Mask); + } + + // bitfieldReverse + template + GLM_FUNC_QUALIFIER genIUType bitfieldReverse(genIUType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); + + return bitfieldReverse(glm::vec<1, genIUType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitfieldReverse(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); + + vec x(v); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 2>::call(x, static_cast(0x5555555555555555ull), static_cast( 1)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 4>::call(x, static_cast(0x3333333333333333ull), static_cast( 2)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 8>::call(x, static_cast(0x0F0F0F0F0F0F0F0Full), static_cast( 4)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 16>::call(x, static_cast(0x00FF00FF00FF00FFull), static_cast( 8)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 32>::call(x, static_cast(0x0000FFFF0000FFFFull), static_cast(16)); + x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 64>::call(x, static_cast(0x00000000FFFFFFFFull), static_cast(32)); + return x; + } + + // bitCount + template + GLM_FUNC_QUALIFIER int bitCount(genIUType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + + return bitCount(glm::vec<1, genIUType, glm::defaultp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec bitCount(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4310) //cast truncates constant value +# endif + + vec::type, Q> x(*reinterpret_cast::type, Q> const *>(&v)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 2>::call(x, typename detail::make_unsigned::type(0x5555555555555555ull), typename detail::make_unsigned::type( 1)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 4>::call(x, typename detail::make_unsigned::type(0x3333333333333333ull), typename detail::make_unsigned::type( 2)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 8>::call(x, typename detail::make_unsigned::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned::type( 4)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned::type( 8)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned::type(16)); + x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned::type(0x00000000FFFFFFFFull), typename detail::make_unsigned::type(32)); + return vec(x); + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + } + + // findLSB + template + GLM_FUNC_QUALIFIER int findLSB(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::compute_findLSB::call(Value); + } + + template + GLM_FUNC_QUALIFIER vec findLSB(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); + + return detail::functor1::call(findLSB, x); + } + + // findMSB + template + GLM_FUNC_QUALIFIER int findMSB(genIUType v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return findMSB(vec<1, genIUType>(v)).x; + } + + template + GLM_FUNC_QUALIFIER vec findMSB(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); + + return detail::compute_findMSB_vec::call(v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_integer_simd.inl" +#endif + diff --git a/thirdparty/glm/detail/func_integer_simd.inl b/thirdparty/glm/detail/func_integer_simd.inl new file mode 100644 index 0000000..8be6c9c --- /dev/null +++ b/thirdparty/glm/detail/func_integer_simd.inl @@ -0,0 +1,65 @@ +#include "../simd/integer.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_bitfieldReverseStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and1 = _mm_and_si128(set0, set1); + __m128i const sft1 = _mm_slli_epi32(and1, Shift); + + __m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1)); + __m128i const and2 = _mm_and_si128(set0, set2); + __m128i const sft2 = _mm_srai_epi32(and2, Shift); + + __m128i const or0 = _mm_or_si128(sft1, sft2); + + return or0; + } + }; + + template + struct compute_bitfieldBitCountStep<4, uint, Q, true, true> + { + GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) + { + __m128i const set0 = v.data; + + __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); + __m128i const and0 = _mm_and_si128(set0, set1); + __m128i const sft0 = _mm_slli_epi32(set0, Shift); + __m128i const and1 = _mm_and_si128(sft0, set1); + __m128i const add0 = _mm_add_epi32(and0, and1); + + return add0; + } + }; +}//namespace detail + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER int bitCount(uint x) + { + return _mm_popcnt_u32(x); + } + +# if(GLM_MODEL == GLM_MODEL_64) + template<> + GLM_FUNC_QUALIFIER int bitCount(detail::uint64 x) + { + return static_cast(_mm_popcnt_u64(x)); + } +# endif//GLM_MODEL +# endif//GLM_ARCH + +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/detail/func_matrix.inl b/thirdparty/glm/detail/func_matrix.inl new file mode 100644 index 0000000..d980c6d --- /dev/null +++ b/thirdparty/glm/detail/func_matrix.inl @@ -0,0 +1,398 @@ +#include "../geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct compute_matrixCompMult + { + GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) + { + mat Result; + for(length_t i = 0; i < Result.length(); ++i) + Result[i] = x[i] * y[i]; + return Result; + } + }; + + template + struct compute_transpose{}; + + template + struct compute_transpose<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + }; + + template + struct compute_transpose<2, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 2, T, Q> call(mat<2, 3, T, Q> const& m) + { + mat<3,2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + return Result; + } + }; + + template + struct compute_transpose<2, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 2, T, Q> call(mat<2, 4, T, Q> const& m) + { + mat<4, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + return Result; + } + }; + + template + struct compute_transpose<3, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 3, T, Q> call(mat<3, 2, T, Q> const& m) + { + mat<2, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + return Result; + } + }; + + template + struct compute_transpose<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + }; + + template + struct compute_transpose<3, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 3, T, Q> call(mat<3, 4, T, Q> const& m) + { + mat<4, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + return Result; + } + }; + + template + struct compute_transpose<4, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 4, T, Q> call(mat<4, 2, T, Q> const& m) + { + mat<2, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + return Result; + } + }; + + template + struct compute_transpose<4, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 4, T, Q> call(mat<4, 3, T, Q> const& m) + { + mat<3, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + return Result; + } + }; + + template + struct compute_transpose<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + }; + + template + struct compute_determinant{}; + + template + struct compute_determinant<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<2, 2, T, Q> const& m) + { + return m[0][0] * m[1][1] - m[1][0] * m[0][1]; + } + }; + + template + struct compute_determinant<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<3, 3, T, Q> const& m) + { + return + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + } + }; + + template + struct compute_determinant<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static T call(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + vec<4, T, Q> DetCof( + + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + return + m[0][0] * DetCof[0] + m[0][1] * DetCof[1] + + m[0][2] * DetCof[2] + m[0][3] * DetCof[3]; + } + }; + + template + struct compute_inverse{}; + + template + struct compute_inverse<2, 2, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * m[1][1] + - m[1][0] * m[0][1]); + + mat<2, 2, T, Q> Inverse( + + m[1][1] * OneOverDeterminant, + - m[0][1] * OneOverDeterminant, + - m[1][0] * OneOverDeterminant, + + m[0][0] * OneOverDeterminant); + + return Inverse; + } + }; + + template + struct compute_inverse<3, 3, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) + { + T OneOverDeterminant = static_cast(1) / ( + + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant; + Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant; + Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant; + Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant; + Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant; + Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant; + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant; + + return Inverse; + } + }; + + template + struct compute_inverse<4, 4, T, Q, Aligned> + { + GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) + { + T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + vec<4, T, Q> Fac0(Coef00, Coef00, Coef02, Coef03); + vec<4, T, Q> Fac1(Coef04, Coef04, Coef06, Coef07); + vec<4, T, Q> Fac2(Coef08, Coef08, Coef10, Coef11); + vec<4, T, Q> Fac3(Coef12, Coef12, Coef14, Coef15); + vec<4, T, Q> Fac4(Coef16, Coef16, Coef18, Coef19); + vec<4, T, Q> Fac5(Coef20, Coef20, Coef22, Coef23); + + vec<4, T, Q> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]); + vec<4, T, Q> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]); + vec<4, T, Q> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]); + vec<4, T, Q> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]); + + vec<4, T, Q> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2); + vec<4, T, Q> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4); + vec<4, T, Q> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5); + vec<4, T, Q> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5); + + vec<4, T, Q> SignA(+1, -1, +1, -1); + vec<4, T, Q> SignB(-1, +1, -1, +1); + mat<4, 4, T, Q> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB); + + vec<4, T, Q> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]); + + vec<4, T, Q> Dot0(m[0] * Row0); + T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w); + + T OneOverDeterminant = static_cast(1) / Dot1; + + return Inverse * OneOverDeterminant; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER mat matrixCompMult(mat const& x, mat const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'matrixCompMult' only accept floating-point inputs"); + return detail::compute_matrixCompMult::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'outerProduct' only accept floating-point inputs"); + + typename detail::outerProduct_trait::type m; + for(length_t i = 0; i < m.length(); ++i) + m[i] = c * r[i]; + return m; + } + + template + GLM_FUNC_QUALIFIER typename mat::transpose_type transpose(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'transpose' only accept floating-point inputs"); + return detail::compute_transpose::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER T determinant(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'determinant' only accept floating-point inputs"); + return detail::compute_determinant::value>::call(m); + } + + template + GLM_FUNC_QUALIFIER mat inverse(mat const& m) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs"); + return detail::compute_inverse::value>::call(m); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_matrix_simd.inl" +#endif + diff --git a/thirdparty/glm/detail/func_matrix_simd.inl b/thirdparty/glm/detail/func_matrix_simd.inl new file mode 100644 index 0000000..f67ac66 --- /dev/null +++ b/thirdparty/glm/detail/func_matrix_simd.inl @@ -0,0 +1,249 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#include "type_mat4x4.hpp" +#include "../geometric.hpp" +#include "../simd/matrix.h" +#include + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template + struct compute_matrixCompMult<4, 4, float, Q, true> + { + GLM_STATIC_ASSERT(detail::is_aligned::value, "Specialization requires aligned"); + + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& x, mat<4, 4, float, Q> const& y) + { + mat<4, 4, float, Q> Result; + glm_mat4_matrixCompMult( + *static_cast(&x[0].data), + *static_cast(&y[0].data), + *static_cast(&Result[0].data)); + return Result; + } + }; +# endif + + template + struct compute_transpose<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_transpose(&m[0].data, &Result[0].data); + return Result; + } + }; + + template + struct compute_determinant<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static float call(mat<4, 4, float, Q> const& m) + { + return _mm_cvtss_f32(glm_mat4_determinant(&m[0].data)); + } + }; + + template + struct compute_inverse<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + mat<4, 4, float, Q> Result; + glm_mat4_inverse(&m[0].data, &Result[0].data); + return Result; + } + }; +}//namespace detail + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_lowp> outerProduct<4, 4, float, aligned_lowp>(vec<4, float, aligned_lowp> const& c, vec<4, float, aligned_lowp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_lowp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_mediump> outerProduct<4, 4, float, aligned_mediump>(vec<4, float, aligned_mediump> const& c, vec<4, float, aligned_mediump> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_mediump> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } + + template<> + GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_highp> outerProduct<4, 4, float, aligned_highp>(vec<4, float, aligned_highp> const& c, vec<4, float, aligned_highp> const& r) + { + __m128 NativeResult[4]; + glm_mat4_outerProduct(c.data, r.data, NativeResult); + mat<4, 4, float, aligned_highp> Result; + std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); + return Result; + } +# endif +}//namespace glm + +#elif GLM_ARCH & GLM_ARCH_NEON_BIT + +namespace glm { +#if GLM_LANG & GLM_LANG_CXX11_FLAG + template + GLM_FUNC_QUALIFIER + typename std::enable_if::value, mat<4, 4, float, Q>>::type + operator*(mat<4, 4, float, Q> const & m1, mat<4, 4, float, Q> const & m2) + { + auto MulRow = [&](int l) { + float32x4_t const SrcA = m2[l].data; + + float32x4_t r = neon::mul_lane(m1[0].data, SrcA, 0); + r = neon::madd_lane(r, m1[1].data, SrcA, 1); + r = neon::madd_lane(r, m1[2].data, SrcA, 2); + r = neon::madd_lane(r, m1[3].data, SrcA, 3); + + return r; + }; + + mat<4, 4, float, aligned_highp> Result; + Result[0].data = MulRow(0); + Result[1].data = MulRow(1); + Result[2].data = MulRow(2); + Result[3].data = MulRow(3); + + return Result; + } +#endif // CXX11 + + template + struct detail::compute_inverse<4, 4, float, Q, true> + { + GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) + { + float32x4_t const& m0 = m[0].data; + float32x4_t const& m1 = m[1].data; + float32x4_t const& m2 = m[2].data; + float32x4_t const& m3 = m[3].data; + + // m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + float32x4_t Fac0; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac0 = w0 * w1 - w2 * w3; + } + + // m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + float32x4_t Fac1; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac1 = w0 * w1 - w2 * w3; + } + + // m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + float32x4_t Fac2; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + Fac2 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + float32x4_t Fac3; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3)); + Fac3 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + float32x4_t Fac4; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2)); + Fac4 = w0 * w1 - w2 * w3; + } + + // m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + float32x4_t Fac5; + { + float32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0)); + float32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1); + float32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0); + float32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1)); + Fac5 = w0 * w1 - w2 * w3; + } + + float32x4_t Vec0 = neon::copy_lane(neon::dupq_lane(m0, 0), 0, m1, 0); // (m[1][0], m[0][0], m[0][0], m[0][0]); + float32x4_t Vec1 = neon::copy_lane(neon::dupq_lane(m0, 1), 0, m1, 1); // (m[1][1], m[0][1], m[0][1], m[0][1]); + float32x4_t Vec2 = neon::copy_lane(neon::dupq_lane(m0, 2), 0, m1, 2); // (m[1][2], m[0][2], m[0][2], m[0][2]); + float32x4_t Vec3 = neon::copy_lane(neon::dupq_lane(m0, 3), 0, m1, 3); // (m[1][3], m[0][3], m[0][3], m[0][3]); + + float32x4_t Inv0 = Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2; + float32x4_t Inv1 = Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4; + float32x4_t Inv2 = Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5; + float32x4_t Inv3 = Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5; + + float32x4_t r0 = float32x4_t{-1, +1, -1, +1} * Inv0; + float32x4_t r1 = float32x4_t{+1, -1, +1, -1} * Inv1; + float32x4_t r2 = float32x4_t{-1, +1, -1, +1} * Inv2; + float32x4_t r3 = float32x4_t{+1, -1, +1, -1} * Inv3; + + float32x4_t det = neon::mul_lane(r0, m0, 0); + det = neon::madd_lane(det, r1, m0, 1); + det = neon::madd_lane(det, r2, m0, 2); + det = neon::madd_lane(det, r3, m0, 3); + + float32x4_t rdet = vdupq_n_f32(1 / vgetq_lane_f32(det, 0)); + + mat<4, 4, float, Q> r; + r[0].data = vmulq_f32(r0, rdet); + r[1].data = vmulq_f32(r1, rdet); + r[2].data = vmulq_f32(r2, rdet); + r[3].data = vmulq_f32(r3, rdet); + return r; + } + }; +}//namespace glm +#endif diff --git a/thirdparty/glm/detail/func_packing.inl b/thirdparty/glm/detail/func_packing.inl new file mode 100644 index 0000000..234b093 --- /dev/null +++ b/thirdparty/glm/detail/func_packing.inl @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/func_packing.inl + +#include "../common.hpp" +#include "type_half.hpp" + +namespace glm +{ + GLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const& v) + { + union + { + unsigned short in[2]; + uint out; + } u; + + vec<2, unsigned short, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 65535.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p) + { + union + { + uint in; + unsigned short out[2]; + } u; + + u.in = p; + + return vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f; + } + + GLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + vec<2, short, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 32767.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = p; + + return clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const& v) + { + union + { + unsigned char in[4]; + uint out; + } u; + + vec<4, unsigned char, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p) + { + union + { + uint in; + unsigned char out[4]; + } u; + + u.in = p; + + return vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f; + } + + GLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const& v) + { + union + { + signed char in[4]; + uint out; + } u; + + vec<4, signed char, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + + u.in[0] = result[0]; + u.in[1] = result[1]; + u.in[2] = result[2]; + u.in[3] = result[3]; + + return u.out; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p) + { + union + { + uint in; + signed char out[4]; + } u; + + u.in = p; + + return clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const& v) + { + union + { + uint in[2]; + double out; + } u; + + u.in[0] = v[0]; + u.in[1] = v[1]; + + return u.out; + } + + GLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v) + { + union + { + double in; + uint out[2]; + } u; + + u.in = v; + + return uvec2(u.out[0], u.out[1]); + } + + GLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const& v) + { + union + { + signed short in[2]; + uint out; + } u; + + u.in[0] = detail::toFloat16(v.x); + u.in[1] = detail::toFloat16(v.y); + + return u.out; + } + + GLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v) + { + union + { + uint in; + signed short out[2]; + } u; + + u.in = v; + + return vec2( + detail::toFloat32(u.out[0]), + detail::toFloat32(u.out[1])); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_packing_simd.inl" +#endif + diff --git a/thirdparty/glm/detail/func_packing_simd.inl b/thirdparty/glm/detail/func_packing_simd.inl new file mode 100644 index 0000000..fd0fe8b --- /dev/null +++ b/thirdparty/glm/detail/func_packing_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/func_trigonometric.inl b/thirdparty/glm/detail/func_trigonometric.inl new file mode 100644 index 0000000..e129dce --- /dev/null +++ b/thirdparty/glm/detail/func_trigonometric.inl @@ -0,0 +1,197 @@ +#include "_vectorize.hpp" +#include +#include + +namespace glm +{ + // radians + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'radians' only accept floating-point input"); + + return degrees * static_cast(0.01745329251994329576923690768489); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec radians(vec const& v) + { + return detail::functor1::call(radians, v); + } + + // degrees + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'degrees' only accept floating-point input"); + + return radians * static_cast(57.295779513082320876798154814105); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec degrees(vec const& v) + { + return detail::functor1::call(degrees, v); + } + + // sin + using ::std::sin; + + template + GLM_FUNC_QUALIFIER vec sin(vec const& v) + { + return detail::functor1::call(sin, v); + } + + // cos + using std::cos; + + template + GLM_FUNC_QUALIFIER vec cos(vec const& v) + { + return detail::functor1::call(cos, v); + } + + // tan + using std::tan; + + template + GLM_FUNC_QUALIFIER vec tan(vec const& v) + { + return detail::functor1::call(tan, v); + } + + // asin + using std::asin; + + template + GLM_FUNC_QUALIFIER vec asin(vec const& v) + { + return detail::functor1::call(asin, v); + } + + // acos + using std::acos; + + template + GLM_FUNC_QUALIFIER vec acos(vec const& v) + { + return detail::functor1::call(acos, v); + } + + // atan + template + GLM_FUNC_QUALIFIER genType atan(genType y, genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atan' only accept floating-point input"); + + return ::std::atan2(y, x); + } + + template + GLM_FUNC_QUALIFIER vec atan(vec const& a, vec const& b) + { + return detail::functor2::call(::std::atan2, a, b); + } + + using std::atan; + + template + GLM_FUNC_QUALIFIER vec atan(vec const& v) + { + return detail::functor1::call(atan, v); + } + + // sinh + using std::sinh; + + template + GLM_FUNC_QUALIFIER vec sinh(vec const& v) + { + return detail::functor1::call(sinh, v); + } + + // cosh + using std::cosh; + + template + GLM_FUNC_QUALIFIER vec cosh(vec const& v) + { + return detail::functor1::call(cosh, v); + } + + // tanh + using std::tanh; + + template + GLM_FUNC_QUALIFIER vec tanh(vec const& v) + { + return detail::functor1::call(tanh, v); + } + + // asinh +# if GLM_HAS_CXX11_STL + using std::asinh; +# else + template + GLM_FUNC_QUALIFIER genType asinh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asinh' only accept floating-point input"); + + return (x < static_cast(0) ? static_cast(-1) : (x > static_cast(0) ? static_cast(1) : static_cast(0))) * log(std::abs(x) + sqrt(static_cast(1) + x * x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec asinh(vec const& v) + { + return detail::functor1::call(asinh, v); + } + + // acosh +# if GLM_HAS_CXX11_STL + using std::acosh; +# else + template + GLM_FUNC_QUALIFIER genType acosh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acosh' only accept floating-point input"); + + if(x < static_cast(1)) + return static_cast(0); + return log(x + sqrt(x * x - static_cast(1))); + } +# endif + + template + GLM_FUNC_QUALIFIER vec acosh(vec const& v) + { + return detail::functor1::call(acosh, v); + } + + // atanh +# if GLM_HAS_CXX11_STL + using std::atanh; +# else + template + GLM_FUNC_QUALIFIER genType atanh(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atanh' only accept floating-point input"); + + if(std::abs(x) >= static_cast(1)) + return 0; + return static_cast(0.5) * log((static_cast(1) + x) / (static_cast(1) - x)); + } +# endif + + template + GLM_FUNC_QUALIFIER vec atanh(vec const& v) + { + return detail::functor1::call(atanh, v); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_trigonometric_simd.inl" +#endif + diff --git a/sources/rt-api/CMakeLists.txt b/thirdparty/glm/detail/func_trigonometric_simd.inl similarity index 100% rename from sources/rt-api/CMakeLists.txt rename to thirdparty/glm/detail/func_trigonometric_simd.inl diff --git a/thirdparty/glm/detail/func_vector_relational.inl b/thirdparty/glm/detail/func_vector_relational.inl new file mode 100644 index 0000000..80c9e87 --- /dev/null +++ b/thirdparty/glm/detail/func_vector_relational.inl @@ -0,0 +1,87 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool any(vec const& v) + { + bool Result = false; + for(length_t i = 0; i < L; ++i) + Result = Result || v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool all(vec const& v) + { + bool Result = true; + for(length_t i = 0; i < L; ++i) + Result = Result && v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec not_(vec const& v) + { + vec Result(true); + for(length_t i = 0; i < L; ++i) + Result[i] = !v[i]; + return Result; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "func_vector_relational_simd.inl" +#endif diff --git a/thirdparty/glm/detail/func_vector_relational_simd.inl b/thirdparty/glm/detail/func_vector_relational_simd.inl new file mode 100644 index 0000000..fd0fe8b --- /dev/null +++ b/thirdparty/glm/detail/func_vector_relational_simd.inl @@ -0,0 +1,6 @@ +namespace glm{ +namespace detail +{ + +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/glm.cpp b/thirdparty/glm/detail/glm.cpp new file mode 100644 index 0000000..e0755bd --- /dev/null +++ b/thirdparty/glm/detail/glm.cpp @@ -0,0 +1,263 @@ +/// @ref core +/// @file glm/glm.cpp + +#ifndef GLM_ENABLE_EXPERIMENTAL +#define GLM_ENABLE_EXPERIMENTAL +#endif +#include +#include +#include +#include +#include +#include + +namespace glm +{ +// tvec1 type explicit instantiation +template struct vec<1, uint8, lowp>; +template struct vec<1, uint16, lowp>; +template struct vec<1, uint32, lowp>; +template struct vec<1, uint64, lowp>; +template struct vec<1, int8, lowp>; +template struct vec<1, int16, lowp>; +template struct vec<1, int32, lowp>; +template struct vec<1, int64, lowp>; +template struct vec<1, float32, lowp>; +template struct vec<1, float64, lowp>; + +template struct vec<1, uint8, mediump>; +template struct vec<1, uint16, mediump>; +template struct vec<1, uint32, mediump>; +template struct vec<1, uint64, mediump>; +template struct vec<1, int8, mediump>; +template struct vec<1, int16, mediump>; +template struct vec<1, int32, mediump>; +template struct vec<1, int64, mediump>; +template struct vec<1, float32, mediump>; +template struct vec<1, float64, mediump>; + +template struct vec<1, uint8, highp>; +template struct vec<1, uint16, highp>; +template struct vec<1, uint32, highp>; +template struct vec<1, uint64, highp>; +template struct vec<1, int8, highp>; +template struct vec<1, int16, highp>; +template struct vec<1, int32, highp>; +template struct vec<1, int64, highp>; +template struct vec<1, float32, highp>; +template struct vec<1, float64, highp>; + +// tvec2 type explicit instantiation +template struct vec<2, uint8, lowp>; +template struct vec<2, uint16, lowp>; +template struct vec<2, uint32, lowp>; +template struct vec<2, uint64, lowp>; +template struct vec<2, int8, lowp>; +template struct vec<2, int16, lowp>; +template struct vec<2, int32, lowp>; +template struct vec<2, int64, lowp>; +template struct vec<2, float32, lowp>; +template struct vec<2, float64, lowp>; + +template struct vec<2, uint8, mediump>; +template struct vec<2, uint16, mediump>; +template struct vec<2, uint32, mediump>; +template struct vec<2, uint64, mediump>; +template struct vec<2, int8, mediump>; +template struct vec<2, int16, mediump>; +template struct vec<2, int32, mediump>; +template struct vec<2, int64, mediump>; +template struct vec<2, float32, mediump>; +template struct vec<2, float64, mediump>; + +template struct vec<2, uint8, highp>; +template struct vec<2, uint16, highp>; +template struct vec<2, uint32, highp>; +template struct vec<2, uint64, highp>; +template struct vec<2, int8, highp>; +template struct vec<2, int16, highp>; +template struct vec<2, int32, highp>; +template struct vec<2, int64, highp>; +template struct vec<2, float32, highp>; +template struct vec<2, float64, highp>; + +// tvec3 type explicit instantiation +template struct vec<3, uint8, lowp>; +template struct vec<3, uint16, lowp>; +template struct vec<3, uint32, lowp>; +template struct vec<3, uint64, lowp>; +template struct vec<3, int8, lowp>; +template struct vec<3, int16, lowp>; +template struct vec<3, int32, lowp>; +template struct vec<3, int64, lowp>; +template struct vec<3, float32, lowp>; +template struct vec<3, float64, lowp>; + +template struct vec<3, uint8, mediump>; +template struct vec<3, uint16, mediump>; +template struct vec<3, uint32, mediump>; +template struct vec<3, uint64, mediump>; +template struct vec<3, int8, mediump>; +template struct vec<3, int16, mediump>; +template struct vec<3, int32, mediump>; +template struct vec<3, int64, mediump>; +template struct vec<3, float32, mediump>; +template struct vec<3, float64, mediump>; + +template struct vec<3, uint8, highp>; +template struct vec<3, uint16, highp>; +template struct vec<3, uint32, highp>; +template struct vec<3, uint64, highp>; +template struct vec<3, int8, highp>; +template struct vec<3, int16, highp>; +template struct vec<3, int32, highp>; +template struct vec<3, int64, highp>; +template struct vec<3, float32, highp>; +template struct vec<3, float64, highp>; + +// tvec4 type explicit instantiation +template struct vec<4, uint8, lowp>; +template struct vec<4, uint16, lowp>; +template struct vec<4, uint32, lowp>; +template struct vec<4, uint64, lowp>; +template struct vec<4, int8, lowp>; +template struct vec<4, int16, lowp>; +template struct vec<4, int32, lowp>; +template struct vec<4, int64, lowp>; +template struct vec<4, float32, lowp>; +template struct vec<4, float64, lowp>; + +template struct vec<4, uint8, mediump>; +template struct vec<4, uint16, mediump>; +template struct vec<4, uint32, mediump>; +template struct vec<4, uint64, mediump>; +template struct vec<4, int8, mediump>; +template struct vec<4, int16, mediump>; +template struct vec<4, int32, mediump>; +template struct vec<4, int64, mediump>; +template struct vec<4, float32, mediump>; +template struct vec<4, float64, mediump>; + +template struct vec<4, uint8, highp>; +template struct vec<4, uint16, highp>; +template struct vec<4, uint32, highp>; +template struct vec<4, uint64, highp>; +template struct vec<4, int8, highp>; +template struct vec<4, int16, highp>; +template struct vec<4, int32, highp>; +template struct vec<4, int64, highp>; +template struct vec<4, float32, highp>; +template struct vec<4, float64, highp>; + +// tmat2x2 type explicit instantiation +template struct mat<2, 2, float32, lowp>; +template struct mat<2, 2, float64, lowp>; + +template struct mat<2, 2, float32, mediump>; +template struct mat<2, 2, float64, mediump>; + +template struct mat<2, 2, float32, highp>; +template struct mat<2, 2, float64, highp>; + +// tmat2x3 type explicit instantiation +template struct mat<2, 3, float32, lowp>; +template struct mat<2, 3, float64, lowp>; + +template struct mat<2, 3, float32, mediump>; +template struct mat<2, 3, float64, mediump>; + +template struct mat<2, 3, float32, highp>; +template struct mat<2, 3, float64, highp>; + +// tmat2x4 type explicit instantiation +template struct mat<2, 4, float32, lowp>; +template struct mat<2, 4, float64, lowp>; + +template struct mat<2, 4, float32, mediump>; +template struct mat<2, 4, float64, mediump>; + +template struct mat<2, 4, float32, highp>; +template struct mat<2, 4, float64, highp>; + +// tmat3x2 type explicit instantiation +template struct mat<3, 2, float32, lowp>; +template struct mat<3, 2, float64, lowp>; + +template struct mat<3, 2, float32, mediump>; +template struct mat<3, 2, float64, mediump>; + +template struct mat<3, 2, float32, highp>; +template struct mat<3, 2, float64, highp>; + +// tmat3x3 type explicit instantiation +template struct mat<3, 3, float32, lowp>; +template struct mat<3, 3, float64, lowp>; + +template struct mat<3, 3, float32, mediump>; +template struct mat<3, 3, float64, mediump>; + +template struct mat<3, 3, float32, highp>; +template struct mat<3, 3, float64, highp>; + +// tmat3x4 type explicit instantiation +template struct mat<3, 4, float32, lowp>; +template struct mat<3, 4, float64, lowp>; + +template struct mat<3, 4, float32, mediump>; +template struct mat<3, 4, float64, mediump>; + +template struct mat<3, 4, float32, highp>; +template struct mat<3, 4, float64, highp>; + +// tmat4x2 type explicit instantiation +template struct mat<4, 2, float32, lowp>; +template struct mat<4, 2, float64, lowp>; + +template struct mat<4, 2, float32, mediump>; +template struct mat<4, 2, float64, mediump>; + +template struct mat<4, 2, float32, highp>; +template struct mat<4, 2, float64, highp>; + +// tmat4x3 type explicit instantiation +template struct mat<4, 3, float32, lowp>; +template struct mat<4, 3, float64, lowp>; + +template struct mat<4, 3, float32, mediump>; +template struct mat<4, 3, float64, mediump>; + +template struct mat<4, 3, float32, highp>; +template struct mat<4, 3, float64, highp>; + +// tmat4x4 type explicit instantiation +template struct mat<4, 4, float32, lowp>; +template struct mat<4, 4, float64, lowp>; + +template struct mat<4, 4, float32, mediump>; +template struct mat<4, 4, float64, mediump>; + +template struct mat<4, 4, float32, highp>; +template struct mat<4, 4, float64, highp>; + +// tquat type explicit instantiation +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +template struct qua; +template struct qua; + +//tdualquat type explicit instantiation +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +template struct tdualquat; +template struct tdualquat; + +}//namespace glm + diff --git a/thirdparty/glm/detail/qualifier.hpp b/thirdparty/glm/detail/qualifier.hpp new file mode 100644 index 0000000..b6c9df0 --- /dev/null +++ b/thirdparty/glm/detail/qualifier.hpp @@ -0,0 +1,230 @@ +#pragma once + +#include "setup.hpp" + +namespace glm +{ + /// Qualify GLM types in term of alignment (packed, aligned) and precision in term of ULPs (lowp, mediump, highp) + enum qualifier + { + packed_highp, ///< Typed data is tightly packed in memory and operations are executed with high precision in term of ULPs + packed_mediump, ///< Typed data is tightly packed in memory and operations are executed with medium precision in term of ULPs for higher performance + packed_lowp, ///< Typed data is tightly packed in memory and operations are executed with low precision in term of ULPs to maximize performance + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + aligned_highp, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs + aligned_mediump, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs for higher performance + aligned_lowp, // ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs to maximize performance + aligned = aligned_highp, ///< By default aligned qualifier is also high precision +# endif + + highp = packed_highp, ///< By default highp qualifier is also packed + mediump = packed_mediump, ///< By default mediump qualifier is also packed + lowp = packed_lowp, ///< By default lowp qualifier is also packed + packed = packed_highp, ///< By default packed qualifier is also high precision + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE && defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) + defaultp = aligned_highp +# else + defaultp = highp +# endif + }; + + typedef qualifier precision; + + template struct vec; + template struct mat; + template struct qua; + +# if GLM_HAS_TEMPLATE_ALIASES + template using tvec1 = vec<1, T, Q>; + template using tvec2 = vec<2, T, Q>; + template using tvec3 = vec<3, T, Q>; + template using tvec4 = vec<4, T, Q>; + template using tmat2x2 = mat<2, 2, T, Q>; + template using tmat2x3 = mat<2, 3, T, Q>; + template using tmat2x4 = mat<2, 4, T, Q>; + template using tmat3x2 = mat<3, 2, T, Q>; + template using tmat3x3 = mat<3, 3, T, Q>; + template using tmat3x4 = mat<3, 4, T, Q>; + template using tmat4x2 = mat<4, 2, T, Q>; + template using tmat4x3 = mat<4, 3, T, Q>; + template using tmat4x4 = mat<4, 4, T, Q>; + template using tquat = qua; +# endif + +namespace detail +{ + template + struct is_aligned + { + static const bool value = false; + }; + +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; + + template<> + struct is_aligned + { + static const bool value = true; + }; +# endif + + template + struct storage + { + typedef struct type { + T data[L]; + } type; + }; + +# if GLM_HAS_ALIGNOF + template + struct storage + { + typedef struct alignas(L * sizeof(T)) type { + T data[L]; + } type; + }; + + template + struct storage<3, T, true> + { + typedef struct alignas(4 * sizeof(T)) type { + T data[4]; + } type; + }; +# endif + +# if GLM_ARCH & GLM_ARCH_SSE2_BIT + template<> + struct storage<4, float, true> + { + typedef glm_f32vec4 type; + }; + + template<> + struct storage<4, int, true> + { + typedef glm_i32vec4 type; + }; + + template<> + struct storage<4, unsigned int, true> + { + typedef glm_u32vec4 type; + }; + + template<> + struct storage<2, double, true> + { + typedef glm_f64vec2 type; + }; + + template<> + struct storage<2, detail::int64, true> + { + typedef glm_i64vec2 type; + }; + + template<> + struct storage<2, detail::uint64, true> + { + typedef glm_u64vec2 type; + }; +# endif + +# if (GLM_ARCH & GLM_ARCH_AVX_BIT) + template<> + struct storage<4, double, true> + { + typedef glm_f64vec4 type; + }; +# endif + +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) + template<> + struct storage<4, detail::int64, true> + { + typedef glm_i64vec4 type; + }; + + template<> + struct storage<4, detail::uint64, true> + { + typedef glm_u64vec4 type; + }; +# endif + +# if GLM_ARCH & GLM_ARCH_NEON_BIT + template<> + struct storage<4, float, true> + { + typedef glm_f32vec4 type; + }; + + template<> + struct storage<4, int, true> + { + typedef glm_i32vec4 type; + }; + + template<> + struct storage<4, unsigned int, true> + { + typedef glm_u32vec4 type; + }; +# endif + + enum genTypeEnum + { + GENTYPE_VEC, + GENTYPE_MAT, + GENTYPE_QUAT + }; + + template + struct genTypeTrait + {}; + + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_MAT; + }; + + template + struct init_gentype + { + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1, 0, 0, 0); + } + }; + + template + struct init_gentype + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() + { + return genType(1); + } + }; +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/setup.hpp b/thirdparty/glm/detail/setup.hpp new file mode 100644 index 0000000..2c01e02 --- /dev/null +++ b/thirdparty/glm/detail/setup.hpp @@ -0,0 +1,1135 @@ +#ifndef GLM_SETUP_INCLUDED + +#include +#include + +#define GLM_VERSION_MAJOR 0 +#define GLM_VERSION_MINOR 9 +#define GLM_VERSION_PATCH 9 +#define GLM_VERSION_REVISION 8 +#define GLM_VERSION 998 +#define GLM_VERSION_MESSAGE "GLM: version 0.9.9.8" + +#define GLM_SETUP_INCLUDED GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Active states + +#define GLM_DISABLE 0 +#define GLM_ENABLE 1 + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if defined(GLM_FORCE_MESSAGES) +# define GLM_MESSAGES GLM_ENABLE +#else +# define GLM_MESSAGES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Detect the platform + +#include "../simd/platform.h" + +/////////////////////////////////////////////////////////////////////////////////// +// Build model + +#if defined(_M_ARM64) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__) +# define GLM_MODEL GLM_MODEL_64 +#elif defined(__i386__) || defined(__ppc__) || defined(__ILP32__) || defined(_M_ARM) +# define GLM_MODEL GLM_MODEL_32 +#else +# define GLM_MODEL GLM_MODEL_32 +#endif// + +#if !defined(GLM_MODEL) && GLM_COMPILER != 0 +# error "GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message." +#endif//GLM_MODEL + +/////////////////////////////////////////////////////////////////////////////////// +// C++ Version + +// User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14, GLM_FORCE_CXX17, GLM_FORCE_CXX2A + +#define GLM_LANG_CXX98_FLAG (1 << 1) +#define GLM_LANG_CXX03_FLAG (1 << 2) +#define GLM_LANG_CXX0X_FLAG (1 << 3) +#define GLM_LANG_CXX11_FLAG (1 << 4) +#define GLM_LANG_CXX14_FLAG (1 << 5) +#define GLM_LANG_CXX17_FLAG (1 << 6) +#define GLM_LANG_CXX2A_FLAG (1 << 7) +#define GLM_LANG_CXXMS_FLAG (1 << 8) +#define GLM_LANG_CXXGNU_FLAG (1 << 9) + +#define GLM_LANG_CXX98 GLM_LANG_CXX98_FLAG +#define GLM_LANG_CXX03 (GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG) +#define GLM_LANG_CXX0X (GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG) +#define GLM_LANG_CXX11 (GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG) +#define GLM_LANG_CXX14 (GLM_LANG_CXX11 | GLM_LANG_CXX14_FLAG) +#define GLM_LANG_CXX17 (GLM_LANG_CXX14 | GLM_LANG_CXX17_FLAG) +#define GLM_LANG_CXX2A (GLM_LANG_CXX17 | GLM_LANG_CXX2A_FLAG) +#define GLM_LANG_CXXMS GLM_LANG_CXXMS_FLAG +#define GLM_LANG_CXXGNU GLM_LANG_CXXGNU_FLAG + +#if (defined(_MSC_EXTENSIONS)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#elif ((GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) && (GLM_ARCH & GLM_ARCH_SIMD_BIT)) +# define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG +#else +# define GLM_LANG_EXT 0 +#endif + +#if (defined(GLM_FORCE_CXX_UNKNOWN)) +# define GLM_LANG 0 +#elif defined(GLM_FORCE_CXX2A) +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX17) +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX14) +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX11) +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# define GLM_LANG_STL11_FORCED +#elif defined(GLM_FORCE_CXX03) +# define GLM_LANG (GLM_LANG_CXX03 | GLM_LANG_EXT) +#elif defined(GLM_FORCE_CXX98) +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +#else +# if GLM_COMPILER & GLM_COMPILER_VC && defined(_MSVC_LANG) +# if GLM_COMPILER >= GLM_COMPILER_VC15_7 +# define GLM_LANG_PLATFORM _MSVC_LANG +# elif GLM_COMPILER >= GLM_COMPILER_VC15 +# if _MSVC_LANG > 201402L +# define GLM_LANG_PLATFORM 201402L +# else +# define GLM_LANG_PLATFORM _MSVC_LANG +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif +# else +# define GLM_LANG_PLATFORM 0 +# endif + +# if __cplusplus > 201703L || GLM_LANG_PLATFORM > 201703L +# define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) +# elif __cplusplus == 201703L || GLM_LANG_PLATFORM == 201703L +# define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) +# elif __cplusplus == 201402L || __cplusplus == 201500L || GLM_LANG_PLATFORM == 201402L +# define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) +# elif __cplusplus == 201103L || GLM_LANG_PLATFORM == 201103L +# define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) +# elif defined(__INTEL_CXX11_MODE__) || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_EXT) +# elif __cplusplus == 199711L +# define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) +# else +# define GLM_LANG (0 | GLM_LANG_EXT) +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Has of C++ features + +// http://clang.llvm.org/cxx_status.html +// http://gcc.gnu.org/projects/cxx0x.html +// http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx + +// Android has multiple STLs but C++11 STL detection doesn't always work #284 #564 +#if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED) +# define GLM_HAS_CXX11_STL 0 +#elif GLM_COMPILER & GLM_COMPILER_CLANG +# if (defined(_LIBCPP_VERSION) || (GLM_LANG & GLM_LANG_CXX11_FLAG) || defined(GLM_LANG_STL11_FORCED)) +# define GLM_HAS_CXX11_STL 1 +# else +# define GLM_HAS_CXX11_STL 0 +# endif +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_CXX11_STL 1 +#else +# define GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)))) +#endif + +// N1720 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_STATIC_ASSERT 1 +#else +# define GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)))) +#endif + +// N1988 +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXTENDED_INTEGER_TYPE 1 +#else +# define GLM_HAS_EXTENDED_INTEGER_TYPE (\ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \ + ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG))) +#endif + +// N2672 Initializer lists http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_INITIALIZER_LISTS 1 +#else +# define GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_UNRESTRICTED_UNIONS 1 +#else +# define GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + (GLM_COMPILER & GLM_COMPILER_VC) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA))) +#endif + +// N2346 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_DEFAULTED_FUNCTIONS 1 +#else +# define GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + (GLM_COMPILER & GLM_COMPILER_CUDA))) +#endif + +// N2118 +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RVALUE_REFERENCES 1 +#else +# define GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1 +#else +# define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_TEMPLATE_ALIASES 1 +#else +# define GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_RANGE_FOR __has_feature(cxx_range_for) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_RANGE_FOR 1 +#else +# define GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf +#if GLM_COMPILER & GLM_COMPILER_CLANG +# define GLM_HAS_ALIGNOF __has_feature(cxx_alignas) +#elif GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ALIGNOF 1 +#else +# define GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf +// N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html +#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr... +# define GLM_HAS_CONSTEXPR 0 +#elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) +#elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# define GLM_HAS_CONSTEXPR 1 +#else +# define GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && GLM_HAS_INITIALIZER_LISTS && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL17)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)))) +#endif + +#if GLM_HAS_CONSTEXPR +# define GLM_CONSTEXPR constexpr +#else +# define GLM_CONSTEXPR +#endif + +// +#if GLM_HAS_CONSTEXPR +# if (GLM_COMPILER & GLM_COMPILER_CLANG) +# if __has_feature(cxx_if_constexpr) +# define GLM_HAS_IF_CONSTEXPR 1 +# else +# define GLM_HAS_IF_CONSTEXPR 0 +# endif +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# define GLM_HAS_IF_CONSTEXPR 1 +# else +# define GLM_HAS_IF_CONSTEXPR 0 +# endif +#else +# define GLM_HAS_IF_CONSTEXPR 0 +#endif + +#if GLM_HAS_IF_CONSTEXPR +# define GLM_IF_CONSTEXPR if constexpr +#else +# define GLM_IF_CONSTEXPR if +#endif + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_ASSIGNABLE 1 +#else +# define GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ + ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49)))) +#endif + +// +#define GLM_HAS_TRIVIAL_QUERIES 0 + +// +#if GLM_LANG & GLM_LANG_CXX11_FLAG +# define GLM_HAS_MAKE_SIGNED 1 +#else +# define GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ + ((GLM_COMPILER & GLM_COMPILER_CUDA)))) +#endif + +// +#if defined(GLM_FORCE_INTRINSICS) +# define GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\ + ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ + ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT)))) +#else +# define GLM_HAS_BITSCAN_WINDOWS 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// OpenMP +#ifdef _OPENMP +# if GLM_COMPILER & GLM_COMPILER_GCC +# if GLM_COMPILER >= GLM_COMPILER_GCC61 +# define GLM_HAS_OPENMP 45 +# elif GLM_COMPILER >= GLM_COMPILER_GCC49 +# define GLM_HAS_OPENMP 40 +# elif GLM_COMPILER >= GLM_COMPILER_GCC47 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# if GLM_COMPILER >= GLM_COMPILER_CLANG38 +# define GLM_HAS_OPENMP 31 +# else +# define GLM_HAS_OPENMP 0 +# endif +# elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_HAS_OPENMP 20 +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# if GLM_COMPILER >= GLM_COMPILER_INTEL16 +# define GLM_HAS_OPENMP 40 +# else +# define GLM_HAS_OPENMP 0 +# endif +# else +# define GLM_HAS_OPENMP 0 +# endif +#else +# define GLM_HAS_OPENMP 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// nullptr + +#if GLM_LANG & GLM_LANG_CXX0X_FLAG +# define GLM_CONFIG_NULLPTR GLM_ENABLE +#else +# define GLM_CONFIG_NULLPTR GLM_DISABLE +#endif + +#if GLM_CONFIG_NULLPTR == GLM_ENABLE +# define GLM_NULLPTR nullptr +#else +# define GLM_NULLPTR 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Static assert + +#if GLM_HAS_STATIC_ASSERT +# define GLM_STATIC_ASSERT(x, message) static_assert(x, message) +#elif GLM_COMPILER & GLM_COMPILER_VC +# define GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1] +#else +# define GLM_STATIC_ASSERT(x, message) assert(x) +#endif//GLM_LANG + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +#if GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_CUDA_FUNC_DEF __device__ __host__ +# define GLM_CUDA_FUNC_DECL __device__ __host__ +#else +# define GLM_CUDA_FUNC_DEF +# define GLM_CUDA_FUNC_DECL +#endif + +#if defined(GLM_FORCE_INLINE) +# if GLM_COMPILER & GLM_COMPILER_VC +# define GLM_INLINE __forceinline +# define GLM_NEVER_INLINE __declspec((noinline)) +# elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) +# define GLM_INLINE inline __attribute__((__always_inline__)) +# define GLM_NEVER_INLINE __attribute__((__noinline__)) +# elif GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_INLINE __forceinline__ +# define GLM_NEVER_INLINE __noinline__ +# else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +# endif//GLM_COMPILER +#else +# define GLM_INLINE inline +# define GLM_NEVER_INLINE +#endif//defined(GLM_FORCE_INLINE) + +#define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL +#define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE + +/////////////////////////////////////////////////////////////////////////////////// +// Swizzle operators + +// User defines: GLM_FORCE_SWIZZLE + +#define GLM_SWIZZLE_DISABLED 0 +#define GLM_SWIZZLE_OPERATOR 1 +#define GLM_SWIZZLE_FUNCTION 2 + +#if defined(GLM_FORCE_XYZW_ONLY) +# undef GLM_FORCE_SWIZZLE +#endif + +#if defined(GLM_SWIZZLE) +# pragma message("GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead.") +# define GLM_FORCE_SWIZZLE +#endif + +#if defined(GLM_FORCE_SWIZZLE) && (GLM_LANG & GLM_LANG_CXXMS_FLAG) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_OPERATOR +#elif defined(GLM_FORCE_SWIZZLE) +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_FUNCTION +#else +# define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_DISABLED +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Allows using not basic types as genType + +// #define GLM_FORCE_UNRESTRICTED_GENTYPE + +#ifdef GLM_FORCE_UNRESTRICTED_GENTYPE +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_ENABLE +#else +# define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Clip control, define GLM_FORCE_DEPTH_ZERO_TO_ONE before including GLM +// to use a clip space between 0 to 1. +// Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM +// to use left handed coordinate system by default. + +#define GLM_CLIP_CONTROL_ZO_BIT (1 << 0) // ZERO_TO_ONE +#define GLM_CLIP_CONTROL_NO_BIT (1 << 1) // NEGATIVE_ONE_TO_ONE +#define GLM_CLIP_CONTROL_LH_BIT (1 << 2) // LEFT_HANDED, For DirectX, Metal, Vulkan +#define GLM_CLIP_CONTROL_RH_BIT (1 << 3) // RIGHT_HANDED, For OpenGL, default in GLM + +#define GLM_CLIP_CONTROL_LH_ZO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_LH_NO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_NO_BIT) +#define GLM_CLIP_CONTROL_RH_ZO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_ZO_BIT) +#define GLM_CLIP_CONTROL_RH_NO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_NO_BIT) + +#ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_ZO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_ZO +# endif +#else +# ifdef GLM_FORCE_LEFT_HANDED +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_NO +# else +# define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_NO +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Qualifiers + +#if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)) +# define GLM_DEPRECATED __declspec(deprecated) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name +#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL) +# define GLM_DEPRECATED __attribute__((__deprecated__)) +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment))) +#elif GLM_COMPILER & GLM_COMPILER_CUDA +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x) +#else +# define GLM_DEPRECATED +# define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name +#endif + +/////////////////////////////////////////////////////////////////////////////////// + +#ifdef GLM_FORCE_EXPLICIT_CTOR +# define GLM_EXPLICIT explicit +#else +# define GLM_EXPLICIT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// SYCL + +#if GLM_COMPILER==GLM_COMPILER_SYCL + +#include +#include + +namespace glm { +namespace std { + // Import SYCL's functions into the namespace glm::std to force their usages. + // It's important to use the math built-in function (sin, exp, ...) + // of SYCL instead the std ones. + using namespace cl::sycl; + + /////////////////////////////////////////////////////////////////////////////// + // Import some "harmless" std's stuffs used by glm into + // the new glm::std namespace. + template + using numeric_limits = ::std::numeric_limits; + + using ::std::size_t; + + using ::std::uint8_t; + using ::std::uint16_t; + using ::std::uint32_t; + using ::std::uint64_t; + + using ::std::int8_t; + using ::std::int16_t; + using ::std::int32_t; + using ::std::int64_t; + + using ::std::make_unsigned; + /////////////////////////////////////////////////////////////////////////////// +} //namespace std +} //namespace glm + +#endif + +/////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////// +// Length type: all length functions returns a length_t type. +// When GLM_FORCE_SIZE_T_LENGTH is defined, length_t is a typedef of size_t otherwise +// length_t is a typedef of int like GLSL defines it. + +#define GLM_LENGTH_INT 1 +#define GLM_LENGTH_SIZE_T 2 + +#ifdef GLM_FORCE_SIZE_T_LENGTH +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_SIZE_T +#else +# define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_INT +#endif + +namespace glm +{ + using std::size_t; +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T + typedef size_t length_t; +# else + typedef int length_t; +# endif +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// constexpr + +#if GLM_HAS_CONSTEXPR +# define GLM_CONFIG_CONSTEXP GLM_ENABLE + + namespace glm + { + template + constexpr std::size_t countof(T const (&)[N]) + { + return N; + } + }//namespace glm +# define GLM_COUNTOF(arr) glm::countof(arr) +#elif defined(_MSC_VER) +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) _countof(arr) +#else +# define GLM_CONFIG_CONSTEXP GLM_DISABLE + +# define GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0]) +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// uint + +namespace glm{ +namespace detail +{ + template + struct is_int + { + enum test {value = 0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + typedef unsigned int uint; +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// 64-bit int + +#if GLM_HAS_EXTENDED_INTEGER_TYPE +# include +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint64_t uint64; + typedef std::int64_t int64; +# elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available + typedef uint64_t uint64; + typedef int64_t int64; +# elif GLM_COMPILER & GLM_COMPILER_VC + typedef unsigned __int64 uint64; + typedef signed __int64 int64; +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic ignored "-Wlong-long" + __extension__ typedef unsigned long long uint64; + __extension__ typedef signed long long int64; +# elif (GLM_COMPILER & GLM_COMPILER_CLANG) +# pragma clang diagnostic ignored "-Wc++11-long-long" + typedef unsigned long long uint64; + typedef signed long long int64; +# else//unknown compiler + typedef unsigned long long uint64; + typedef signed long long int64; +# endif +}//namespace detail +}//namespace glm + +/////////////////////////////////////////////////////////////////////////////////// +// make_unsigned + +#if GLM_HAS_MAKE_SIGNED +# include + +namespace glm{ +namespace detail +{ + using std::make_unsigned; +}//namespace detail +}//namespace glm + +#else + +namespace glm{ +namespace detail +{ + template + struct make_unsigned + {}; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; + + template<> + struct make_unsigned + { + typedef unsigned char type; + }; + + template<> + struct make_unsigned + { + typedef unsigned short type; + }; + + template<> + struct make_unsigned + { + typedef unsigned int type; + }; + + template<> + struct make_unsigned + { + typedef unsigned long type; + }; + + template<> + struct make_unsigned + { + typedef uint64 type; + }; +}//namespace detail +}//namespace glm +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Only use x, y, z, w as vector type components + +#ifdef GLM_FORCE_XYZW_ONLY +# define GLM_CONFIG_XYZW_ONLY GLM_ENABLE +#else +# define GLM_CONFIG_XYZW_ONLY GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted initialized types + +#define GLM_CTOR_INIT_DISABLE 0 +#define GLM_CTOR_INITIALIZER_LIST 1 +#define GLM_CTOR_INITIALISATION 2 + +#if defined(GLM_FORCE_CTOR_INIT) && GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALIZER_LIST +#elif defined(GLM_FORCE_CTOR_INIT) && !GLM_HAS_INITIALIZER_LISTS +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALISATION +#else +# define GLM_CONFIG_CTOR_INIT GLM_CTOR_INIT_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Use SIMD instruction sets + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (GLM_ARCH & GLM_ARCH_SIMD_BIT) +# define GLM_CONFIG_SIMD GLM_ENABLE +#else +# define GLM_CONFIG_SIMD GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of defaulted function + +#if GLM_HAS_DEFAULTED_FUNCTIONS && GLM_CONFIG_CTOR_INIT == GLM_CTOR_INIT_DISABLE +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_ENABLE +# define GLM_DEFAULT = default +#else +# define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_DISABLE +# define GLM_DEFAULT +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of aligned gentypes + +#ifdef GLM_FORCE_ALIGNED // Legacy define +# define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +#endif + +#ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# define GLM_FORCE_ALIGNED_GENTYPES +#endif + +#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (defined(GLM_FORCE_ALIGNED_GENTYPES) || (GLM_CONFIG_SIMD == GLM_ENABLE)) +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_ENABLE +#else +# define GLM_CONFIG_ALIGNED_GENTYPES GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Configure the use of anonymous structure as implementation detail + +#if ((GLM_CONFIG_SIMD == GLM_ENABLE) || (GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR) || (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE)) +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_ENABLE +#else +# define GLM_CONFIG_ANONYMOUS_STRUCT GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Silent warnings + +#ifdef GLM_FORCE_SILENT_WARNINGS +# define GLM_SILENT_WARNINGS GLM_ENABLE +#else +# define GLM_SILENT_WARNINGS GLM_DISABLE +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Precision + +#define GLM_HIGHP 1 +#define GLM_MEDIUMP 2 +#define GLM_LOWP 3 + +#if defined(GLM_FORCE_PRECISION_HIGHP_BOOL) || defined(GLM_PRECISION_HIGHP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_BOOL) || defined(GLM_PRECISION_MEDIUMP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_BOOL) || defined(GLM_PRECISION_LOWP_BOOL) +# define GLM_CONFIG_PRECISION_BOOL GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_INT) || defined(GLM_PRECISION_HIGHP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_INT) || defined(GLM_PRECISION_MEDIUMP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_INT) || defined(GLM_PRECISION_LOWP_INT) +# define GLM_CONFIG_PRECISION_INT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_INT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_UINT) || defined(GLM_PRECISION_HIGHP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_UINT) || defined(GLM_PRECISION_MEDIUMP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_UINT) || defined(GLM_PRECISION_LOWP_UINT) +# define GLM_CONFIG_PRECISION_UINT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_UINT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_FLOAT) || defined(GLM_PRECISION_HIGHP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_FLOAT) || defined(GLM_PRECISION_MEDIUMP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_FLOAT) || defined(GLM_PRECISION_LOWP_FLOAT) +# define GLM_CONFIG_PRECISION_FLOAT GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP +#endif + +#if defined(GLM_FORCE_PRECISION_HIGHP_DOUBLE) || defined(GLM_PRECISION_HIGHP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#elif defined(GLM_FORCE_PRECISION_MEDIUMP_DOUBLE) || defined(GLM_PRECISION_MEDIUMP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_MEDIUMP +#elif defined(GLM_FORCE_PRECISION_LOWP_DOUBLE) || defined(GLM_PRECISION_LOWP_DOUBLE) +# define GLM_CONFIG_PRECISION_DOUBLE GLM_LOWP +#else +# define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP +#endif + +/////////////////////////////////////////////////////////////////////////////////// +// Check inclusions of different versions of GLM + +#elif ((GLM_SETUP_INCLUDED != GLM_VERSION) && !defined(GLM_FORCE_IGNORE_VERSION)) +# error "GLM error: A different version of GLM is already included. Define GLM_FORCE_IGNORE_VERSION before including GLM headers to ignore this error." +#elif GLM_SETUP_INCLUDED == GLM_VERSION + +/////////////////////////////////////////////////////////////////////////////////// +// Messages + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_DISPLAYED) +# define GLM_MESSAGE_DISPLAYED +# define GLM_STR_HELPER(x) #x +# define GLM_STR(x) GLM_STR_HELPER(x) + + // Report GLM version +# pragma message (GLM_STR(GLM_VERSION_MESSAGE)) + + // Report C++ language +# if (GLM_LANG & GLM_LANG_CXX2A_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 2A with extensions") +# elif (GLM_LANG & GLM_LANG_CXX2A_FLAG) +# pragma message("GLM: C++ 2A") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 17 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX17_FLAG) +# pragma message("GLM: C++ 17") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 14 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX14_FLAG) +# pragma message("GLM: C++ 14") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 11 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX11_FLAG) +# pragma message("GLM: C++ 11") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 0x with extensions") +# elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) +# pragma message("GLM: C++ 0x") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 03 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX03_FLAG) +# pragma message("GLM: C++ 03") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) && (GLM_LANG & GLM_LANG_EXT) +# pragma message("GLM: C++ 98 with extensions") +# elif (GLM_LANG & GLM_LANG_CXX98_FLAG) +# pragma message("GLM: C++ 98") +# else +# pragma message("GLM: C++ language undetected") +# endif//GLM_LANG + + // Report compiler detection +# if GLM_COMPILER & GLM_COMPILER_CUDA +# pragma message("GLM: CUDA compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma message("GLM: Visual C++ compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma message("GLM: Clang compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_INTEL +# pragma message("GLM: Intel Compiler detected") +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma message("GLM: GCC compiler detected") +# else +# pragma message("GLM: Compiler not detected") +# endif + + // Report build target +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with AVX instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with AVX instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE4.1 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE4.1 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE3 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE3 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits with SSE2 instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits with SSE2 instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: x86 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: x86 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits with Neon instruction set build target") +# elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits with Neon instruction set build target") + +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: ARM 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: ARM 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: MIPS 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: MIPS 32 bits build target") + +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_64) +# pragma message("GLM: PowerPC 64 bits build target") +# elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_32) +# pragma message("GLM: PowerPC 32 bits build target") +# else +# pragma message("GLM: Unknown build target") +# endif//GLM_ARCH + + // Report platform name +# if(GLM_PLATFORM & GLM_PLATFORM_QNXNTO) +# pragma message("GLM: QNX platform detected") +//# elif(GLM_PLATFORM & GLM_PLATFORM_IOS) +//# pragma message("GLM: iOS platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_APPLE) +# pragma message("GLM: Apple platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINCE) +# pragma message("GLM: WinCE platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) +# pragma message("GLM: Windows platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL) +# pragma message("GLM: Native Client detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# pragma message("GLM: Android platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_LINUX) +# pragma message("GLM: Linux platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNIX) +# pragma message("GLM: UNIX platform detected") +# elif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN) +# pragma message("GLM: platform unknown") +# else +# pragma message("GLM: platform not detected") +# endif + + // Report whether only xyzw component are used +# if defined GLM_FORCE_XYZW_ONLY +# pragma message("GLM: GLM_FORCE_XYZW_ONLY is defined. Only x, y, z and w component are available in vector type. This define disables swizzle operators and SIMD instruction sets.") +# endif + + // Report swizzle operator support +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling operators enabled.") +# elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling functions enabled. Enable compiler C++ language extensions to enable swizzle operators.") +# else +# pragma message("GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled.") +# endif + + // Report .length() type +# if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is defined. .length() returns a glm::length_t, a typedef of std::size_t.") +# else +# pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL.") +# endif + +# if GLM_CONFIG_UNRESTRICTED_GENTYPE == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is defined. Removes GLSL restrictions on valid function genTypes.") +# else +# pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes.") +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is defined. Ignores C++ warnings from using C++ language extensions.") +# else +# pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is undefined. Shows C++ warnings from using C++ language extensions.") +# endif + +# ifdef GLM_FORCE_SINGLE_ONLY +# pragma message("GLM: GLM_FORCE_SINGLE_ONLY is defined. Using only single precision floating-point types.") +# endif + +# if defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined, allowing aligned types. This prevents the use of C++ constexpr.") +# elif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# undef GLM_FORCE_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# endif + +# if defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE +# undef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") +# elif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined. All gentypes (e.g. vec3) will be aligned and padded by default.") +# endif +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is defined. Using zero to one depth clip space.") +# else +# pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space.") +# endif + +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is defined. Using left handed coordinate system.") +# else +# pragma message("GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system.") +# endif +#endif//GLM_MESSAGES + +#endif//GLM_SETUP_INCLUDED diff --git a/thirdparty/glm/detail/type_float.hpp b/thirdparty/glm/detail/type_float.hpp new file mode 100644 index 0000000..c8037eb --- /dev/null +++ b/thirdparty/glm/detail/type_float.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "setup.hpp" + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(push) +# pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace glm{ +namespace detail +{ + template + union float_t + {}; + + // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + template <> + union float_t + { + typedef int int_type; + typedef float float_type; + + GLM_CONSTEXPR float_t(float_type Num = 0.0f) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((1 << 23) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 23) & ((1 << 8) - 1); } + + int_type i; + float_type f; + }; + + template <> + union float_t + { + typedef detail::int64 int_type; + typedef double float_type; + + GLM_CONSTEXPR float_t(float_type Num = static_cast(0)) : f(Num) {} + + GLM_CONSTEXPR float_t& operator=(float_t const& x) + { + f = x.f; + return *this; + } + + // Portable extraction of components. + GLM_CONSTEXPR bool negative() const { return i < 0; } + GLM_CONSTEXPR int_type mantissa() const { return i & ((int_type(1) << 52) - 1); } + GLM_CONSTEXPR int_type exponent() const { return (i >> 52) & ((int_type(1) << 11) - 1); } + + int_type i; + float_type f; + }; +}//namespace detail +}//namespace glm + +#if GLM_COMPILER == GLM_COMPILER_VC12 +# pragma warning(pop) +#endif diff --git a/thirdparty/glm/detail/type_half.hpp b/thirdparty/glm/detail/type_half.hpp new file mode 100644 index 0000000..40b8bec --- /dev/null +++ b/thirdparty/glm/detail/type_half.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "setup.hpp" + +namespace glm{ +namespace detail +{ + typedef short hdata; + + GLM_FUNC_DECL float toFloat32(hdata value); + GLM_FUNC_DECL hdata toFloat16(float const& value); + +}//namespace detail +}//namespace glm + +#include "type_half.inl" diff --git a/thirdparty/glm/detail/type_half.inl b/thirdparty/glm/detail/type_half.inl new file mode 100644 index 0000000..b0723e3 --- /dev/null +++ b/thirdparty/glm/detail/type_half.inl @@ -0,0 +1,241 @@ +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float overflow() + { + volatile float f = 1e10; + + for(int i = 0; i < 10; ++i) + f *= f; // this will overflow before the for loop terminates + return f; + } + + union uif32 + { + GLM_FUNC_QUALIFIER uif32() : + i(0) + {} + + GLM_FUNC_QUALIFIER uif32(float f_) : + f(f_) + {} + + GLM_FUNC_QUALIFIER uif32(unsigned int i_) : + i(i_) + {} + + float f; + unsigned int i; + }; + + GLM_FUNC_QUALIFIER float toFloat32(hdata value) + { + int s = (value >> 15) & 0x00000001; + int e = (value >> 10) & 0x0000001f; + int m = value & 0x000003ff; + + if(e == 0) + { + if(m == 0) + { + // + // Plus or minus zero + // + + detail::uif32 result; + result.i = static_cast(s << 31); + return result.f; + } + else + { + // + // Denormalized number -- renormalize it + // + + while(!(m & 0x00000400)) + { + m <<= 1; + e -= 1; + } + + e += 1; + m &= ~0x00000400; + } + } + else if(e == 31) + { + if(m == 0) + { + // + // Positive or negative infinity + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000); + return result.f; + } + else + { + // + // Nan -- preserve sign and significand bits + // + + uif32 result; + result.i = static_cast((s << 31) | 0x7f800000 | (m << 13)); + return result.f; + } + } + + // + // Normalized number + // + + e = e + (127 - 15); + m = m << 13; + + // + // Assemble s, e and m. + // + + uif32 Result; + Result.i = static_cast((s << 31) | (e << 23) | m); + return Result.f; + } + + GLM_FUNC_QUALIFIER hdata toFloat16(float const& f) + { + uif32 Entry; + Entry.f = f; + int i = static_cast(Entry.i); + + // + // Our floating point number, f, is represented by the bit + // pattern in integer i. Disassemble that bit pattern into + // the sign, s, the exponent, e, and the significand, m. + // Shift s into the position where it will go in the + // resulting half number. + // Adjust e, accounting for the different exponent bias + // of float and half (127 versus 15). + // + + int s = (i >> 16) & 0x00008000; + int e = ((i >> 23) & 0x000000ff) - (127 - 15); + int m = i & 0x007fffff; + + // + // Now reassemble s, e and m into a half: + // + + if(e <= 0) + { + if(e < -10) + { + // + // E is less than -10. The absolute value of f is + // less than half_MIN (f may be a small normalized + // float, a denormalized float or a zero). + // + // We convert f to a half zero. + // + + return hdata(s); + } + + // + // E is between -10 and 0. F is a normalized float, + // whose magnitude is less than __half_NRM_MIN. + // + // We convert f to a denormalized half. + // + + m = (m | 0x00800000) >> (1 - e); + + // + // Round to nearest, round "0.5" up. + // + // Rounding may cause the significand to overflow and make + // our number normalized. Because of the way a half's bits + // are laid out, we don't have to treat this case separately; + // the code below will handle it correctly. + // + + if(m & 0x00001000) + m += 0x00002000; + + // + // Assemble the half from s, e (zero) and m. + // + + return hdata(s | (m >> 13)); + } + else if(e == 0xff - (127 - 15)) + { + if(m == 0) + { + // + // F is an infinity; convert f to a half + // infinity with the same sign as f. + // + + return hdata(s | 0x7c00); + } + else + { + // + // F is a NAN; we produce a half NAN that preserves + // the sign bit and the 10 leftmost bits of the + // significand of f, with one exception: If the 10 + // leftmost bits are all zero, the NAN would turn + // into an infinity, so we have to set at least one + // bit in the significand. + // + + m >>= 13; + + return hdata(s | 0x7c00 | m | (m == 0)); + } + } + else + { + // + // E is greater than zero. F is a normalized float. + // We try to convert f to a normalized half. + // + + // + // Round to nearest, round "0.5" up + // + + if(m & 0x00001000) + { + m += 0x00002000; + + if(m & 0x00800000) + { + m = 0; // overflow in significand, + e += 1; // adjust exponent + } + } + + // + // Handle exponent overflow + // + + if (e > 30) + { + overflow(); // Cause a hardware floating point overflow; + + return hdata(s | 0x7c00); + // if this returns, the half becomes an + } // infinity with the same sign as f. + + // + // Assemble the half from s, e and m. + // + + return hdata(s | (e << 10) | (m >> 13)); + } + } + +}//namespace detail +}//namespace glm diff --git a/thirdparty/glm/detail/type_mat2x2.hpp b/thirdparty/glm/detail/type_mat2x2.hpp new file mode 100644 index 0000000..939524b --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x2.hpp @@ -0,0 +1,177 @@ +/// @ref core +/// @file glm/detail/type_mat2x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 2, T, Q> type; + typedef mat<2, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x1, T const& y1, + T const& x2, T const& y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + U const& x1, V const& y1, + M const& x2, N const& y2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, U, Q> const& v1, + vec<2, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(mat<2, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(mat<2, 2, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator*(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator*(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); +} //namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x2.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat2x2.inl b/thirdparty/glm/detail/type_mat2x2.inl new file mode 100644 index 0000000..fe5d1aa --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x2.inl @@ -0,0 +1,536 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m[0], m[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0), col_type(0, scalar)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0); + this->value[1] = col_type(0, scalar); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + T const& x0, T const& y0, + T const& x1, T const& y1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{v0, v1} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, + X2 const& x2, Y2 const& y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(static_cast(x1), value_type(y1)), col_type(static_cast(x2), value_type(y2)) } +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(static_cast(x1), value_type(y1)); + this->value[1] = col_type(static_cast(x2), value_type(y2)); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- mat2x2 matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 2, T, Q>::col_type const& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator=(mat<2, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(U scalar) + { + this->value[0] += scalar; + this->value[1] += scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(mat<2, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(U scalar) + { + this->value[0] -= scalar; + this->value[1] -= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(mat<2, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(U scalar) + { + this->value[0] *= scalar; + this->value[1] *= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(mat<2, 2, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(U scalar) + { + this->value[0] /= scalar; + this->value[1] /= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(mat<2, 2, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator++(int) + { + mat<2, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator--(int) + { + mat<2, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar - m[0], + scalar - m[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator* + ( + mat<2, 2, T, Q> const& m, + typename mat<2, 2, T, Q>::row_type const& v + ) + { + return vec<2, T, Q>( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator* + ( + typename mat<2, 2, T, Q>::col_type const& v, + mat<2, 2, T, Q> const& m + ) + { + return vec<2, T, Q>( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar) + { + return mat<2, 2, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + mat<2, 2, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat2x3.hpp b/thirdparty/glm/detail/type_mat2x3.hpp new file mode 100644 index 0000000..e002a85 --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x3.hpp @@ -0,0 +1,159 @@ +/// @ref core +/// @file glm/detail/type_mat2x3.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 3, T, Q> type; + typedef mat<3, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, U, Q> const& v1, + vec<3, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(mat<2, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 3, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 3, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::col_type operator*(mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 3, T, Q>::row_type operator*(typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x3.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat2x3.inl b/thirdparty/glm/detail/type_mat2x3.inl new file mode 100644 index 0000000..5fec17e --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x3.inl @@ -0,0 +1,510 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m.value[0], m.value[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m.value[0]; + this->value[1] = m.value[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(T scalar) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(scalar, 0, 0), col_type(0, scalar, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(scalar, 0, 0); + this->value[1] = col_type(0, scalar, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type & mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 3, T, Q>::col_type const& mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator=(mat<2, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator+=(mat<2, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(mat<2, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator++(int) + { + mat<2, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator--(int) + { + mat<2, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type operator* + ( + mat<2, 3, T, Q> const& m, + typename mat<2, 3, T, Q>::row_type const& v) + { + return typename mat<2, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::row_type operator* + ( + typename mat<2, 3, T, Q>::col_type const& v, + mat<2, 3, T, Q> const& m) + { + return typename mat<2, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar) + { + return mat<2, 3, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m) + { + return mat<2, 3, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat2x4.hpp b/thirdparty/glm/detail/type_mat2x4.hpp new file mode 100644 index 0000000..0d2a9aa --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x4.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/detail/type_mat2x4.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<2, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<2, T, Q> row_type; + typedef mat<2, 4, T, Q> type; + typedef mat<4, 2, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[2]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, U, Q> const& v1, + vec<4, V, Q> const& v2); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(mat<2, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<2, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<2, 4, T, Q> & operator++ (); + GLM_FUNC_DECL mat<2, 4, T, Q> & operator-- (); + GLM_FUNC_DECL mat<2, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<2, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat2x4.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat2x4.inl b/thirdparty/glm/detail/type_mat2x4.inl new file mode 100644 index 0000000..b6d2b9d --- /dev/null +++ b/thirdparty/glm/detail/type_mat2x4.inl @@ -0,0 +1,520 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{m[0], m[1]} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(col_type const& v0, col_type const& v1) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type & mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 4, T, Q>::col_type const& mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator=(mat<2, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(mat<2, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(mat<2, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> & mat<2, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator++(int) + { + mat<2, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator--(int) + { + mat<2, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + -m[0], + -m[1]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] + scalar, + m[1] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] - scalar, + m[1] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + m[0] * scalar, + m[1] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v) + { + return typename mat<2, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y, + m[0][1] * v.x + m[1][1] * v.y, + m[0][2] * v.x + m[1][2] * v.y, + m[0][3] * v.x + m[1][3] * v.y); + } + + template + GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m) + { + return typename mat<2, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + T SrcA00 = m1[0][0]; + T SrcA01 = m1[0][1]; + T SrcA02 = m1[0][2]; + T SrcA03 = m1[0][3]; + T SrcA10 = m1[1][0]; + T SrcA11 = m1[1][1]; + T SrcA12 = m1[1][2]; + T SrcA13 = m1[1][3]; + + T SrcB00 = m2[0][0]; + T SrcB01 = m2[0][1]; + T SrcB10 = m2[1][0]; + T SrcB11 = m2[1][1]; + T SrcB20 = m2[2][0]; + T SrcB21 = m2[2][1]; + T SrcB30 = m2[3][0]; + T SrcB31 = m2[3][1]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar) + { + return mat<2, 4, T, Q>( + m[0] / scalar, + m[1] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m) + { + return mat<2, 4, T, Q>( + scalar / m[0], + scalar / m[1]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat3x2.hpp b/thirdparty/glm/detail/type_mat3x2.hpp new file mode 100644 index 0000000..c3ffae8 --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x2.hpp @@ -0,0 +1,167 @@ +/// @ref core +/// @file glm/detail/type_mat3x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 2, T, Q> type; + typedef mat<2, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(mat<3, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<3, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<3, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); + +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x2.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat3x2.inl b/thirdparty/glm/detail/type_mat3x2.inl new file mode 100644 index 0000000..b4b948b --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x2.inl @@ -0,0 +1,532 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type & mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 2, T, Q>::col_type const& mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator=(mat<3, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(mat<3, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(mat<3, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> & mat<3, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator++(int) + { + mat<3, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator--(int) + { + mat<3, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v) + { + return typename mat<3, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m) + { + return typename mat<3, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar) + { + return mat<3, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m) + { + return mat<3, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat3x3.hpp b/thirdparty/glm/detail/type_mat3x3.hpp new file mode 100644 index 0000000..b1e4741 --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x3.hpp @@ -0,0 +1,184 @@ +/// @ref core +/// @file glm/detail/type_mat3x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 3, T, Q> type; + typedef mat<3, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(mat<3, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(mat<3, 3, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 3, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 3, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x3.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat3x3.inl b/thirdparty/glm/detail/type_mat3x3.inl new file mode 100644 index 0000000..1ddaf99 --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x3.inl @@ -0,0 +1,601 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + T x0, T y0, T z0, + T x1, T y1, T z1, + T x2, T y2, T z2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat + ( + X1 x1, Y1 y1, Z1 z1, + X2 x2, Y2 y2, Z2 z2, + X3 x3, Y3 y3, Z3 z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1); + this->value[1] = col_type(x2, y2, z2); + this->value[2] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type & mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 3, T, Q>::col_type const& mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator=(mat<3, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(mat<3, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(mat<3, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(mat<3, 3, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(mat<3, 3, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator++(int) + { + mat<3, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator--(int) + { + mat<3, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar - m[0], + scalar - m[1], + scalar - m[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return typename mat<3, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return typename mat<3, 3, T, Q>::row_type( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar) + { + return mat<3, 3, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m) + { + return mat<3, 3, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + mat<3, 3, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat3x4.hpp b/thirdparty/glm/detail/type_mat3x4.hpp new file mode 100644 index 0000000..0929dcc --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x4.hpp @@ -0,0 +1,166 @@ +/// @ref core +/// @file glm/detail/type_mat3x4.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<3, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<3, T, Q> row_type; + typedef mat<3, 4, T, Q> type; + typedef mat<4, 3, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[3]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2, + X3 x3, Y3 y3, Z3 z3, W3 w3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(mat<3, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<3, 4, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<3, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<3, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<3, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<3, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::col_type operator*(mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<3, 4, T, Q>::row_type operator*(typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat3x4.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat3x4.inl b/thirdparty/glm/detail/type_mat3x4.inl new file mode 100644 index 0000000..6ee416c --- /dev/null +++ b/thirdparty/glm/detail/type_mat3x4.inl @@ -0,0 +1,578 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + T x0, T y0, T z0, T w0, + T x1, T y1, T z1, T w1, + T x2, T y2, T z2, T w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, typename W0, + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat + ( + X0 x0, Y0 y0, Z0 z0, W0 w0, + X1 x1, Y1 y1, Z1 z1, W1 w1, + X2 x2, Y2 y2, Z2 z2, W2 w2 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(vec<4, V1, Q> const& v0, vec<4, V2, Q> const& v1, vec<4, V3, Q> const& v2) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type & mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 4, T, Q>::col_type const& mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator=(mat<3, 4, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(mat<3, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(mat<3, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> & mat<3, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator++(int) + { + mat<3, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator--(int) + { + mat<3, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + -m[0], + -m[1], + -m[2]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type operator* + ( + mat<3, 4, T, Q> const& m, + typename mat<3, 4, T, Q>::row_type const& v + ) + { + return typename mat<3, 4, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z, + m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z); + } + + template + GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::row_type operator* + ( + typename mat<3, 4, T, Q>::col_type const& v, + mat<3, 4, T, Q> const& m + ) + { + return typename mat<3, 4, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + const T SrcA00 = m1[0][0]; + const T SrcA01 = m1[0][1]; + const T SrcA02 = m1[0][2]; + const T SrcA03 = m1[0][3]; + const T SrcA10 = m1[1][0]; + const T SrcA11 = m1[1][1]; + const T SrcA12 = m1[1][2]; + const T SrcA13 = m1[1][3]; + const T SrcA20 = m1[2][0]; + const T SrcA21 = m1[2][1]; + const T SrcA22 = m1[2][2]; + const T SrcA23 = m1[2][3]; + + const T SrcB00 = m2[0][0]; + const T SrcB01 = m2[0][1]; + const T SrcB02 = m2[0][2]; + const T SrcB10 = m2[1][0]; + const T SrcB11 = m2[1][1]; + const T SrcB12 = m2[1][2]; + const T SrcB20 = m2[2][0]; + const T SrcB21 = m2[2][1]; + const T SrcB22 = m2[2][2]; + const T SrcB30 = m2[3][0]; + const T SrcB31 = m2[3][1]; + const T SrcB32 = m2[3][2]; + + mat<4, 4, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; + Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; + Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; + Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22; + Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32; + Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32; + Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32; + Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar) + { + return mat<3, 4, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m) + { + return mat<3, 4, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat4x2.hpp b/thirdparty/glm/detail/type_mat4x2.hpp new file mode 100644 index 0000000..65ca270 --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x2.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x2.hpp + +#pragma once + +#include "type_vec2.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 2, T, Q> + { + typedef vec<2, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 2, T, Q> type; + typedef mat<2, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 2, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<2, V1, Q> const& v1, + vec<2, V2, Q> const& v2, + vec<2, V3, Q> const& v3, + vec<2, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(mat<4, 2, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 2, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 2, T, Q> & operator++ (); + GLM_FUNC_DECL mat<4, 2, T, Q> & operator-- (); + GLM_FUNC_DECL mat<4, 2, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 2, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar); + + template + GLM_FUNC_DECL mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x2.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat4x2.inl b/thirdparty/glm/detail/type_mat4x2.inl new file mode 100644 index 0000000..419c80c --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x2.inl @@ -0,0 +1,574 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0), col_type(0, 1), col_type(0, 0), col_type(0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0); + this->value[1] = col_type(0, 1); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(T s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0), col_type(0, s), col_type(0, 0), col_type(0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0); + this->value[1] = col_type(0, s); + this->value[2] = col_type(0, 0); + this->value[3] = col_type(0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + T x0, T y0, + T x1, T y1, + T x2, T y2, + T x3, T y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, + typename X1, typename Y1, + typename X2, typename Y2, + typename X3, typename Y3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat + ( + X0 x0, Y0 y0, + X1 x1, Y1 y1, + X2 x2, Y2 y2, + X3 x3, Y3 y3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0); + this->value[1] = col_type(x1, y1); + this->value[2] = col_type(x2, y2); + this->value[3] = col_type(x3, y3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v0); + this->value[1] = col_type(v1); + this->value[2] = col_type(v2); + this->value[3] = col_type(v3); +# endif + } + + // -- Conversion -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type & mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 2, T, Q>::col_type const& mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q>& mat<4, 2, T, Q>::operator=(mat<4, 2, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(mat<4, 2, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(mat<4, 2, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator++(int) + { + mat<4, 2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator--(int) + { + mat<4, 2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] + scalar, + m[1] + scalar, + m[2] + scalar, + m[3] + scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] - scalar, + m[1] - scalar, + m[2] - scalar, + m[3] - scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + m[0] * scalar, + m[1] * scalar, + m[2] * scalar, + m[3] * scalar); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v) + { + return typename mat<4, 2, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m) + { + return typename mat<4, 2, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1], + v.x * m[1][0] + v.y * m[1][1], + v.x * m[2][0] + v.y * m[2][1], + v.x * m[3][0] + v.y * m[3][1]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + + mat<2, 2, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 2, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar) + { + return mat<4, 2, T, Q>( + m[0] / scalar, + m[1] / scalar, + m[2] / scalar, + m[3] / scalar); + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m) + { + return mat<4, 2, T, Q>( + scalar / m[0], + scalar / m[1], + scalar / m[2], + scalar / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat4x3.hpp b/thirdparty/glm/detail/type_mat4x3.hpp new file mode 100644 index 0000000..beafa4f --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x3.hpp @@ -0,0 +1,171 @@ +/// @ref core +/// @file glm/detail/type_mat4x3.hpp + +#pragma once + +#include "type_vec3.hpp" +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 3, T, Q> + { + typedef vec<3, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 3, T, Q> type; + typedef mat<3, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 3, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3, + typename X4, typename Y4, typename Z4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3, + X4 const& x4, Y4 const& y4, Z4 const& z4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<3, V1, Q> const& v1, + vec<3, V2, Q> const& v2, + vec<3, V3, Q> const& v3, + vec<3, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(mat<4, 3, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 3, T, Q> & operator/=(U s); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 3, T, Q>& operator++(); + GLM_FUNC_DECL mat<4, 3, T, Q>& operator--(); + GLM_FUNC_DECL mat<4, 3, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 3, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::col_type operator*(mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 3, T, Q>::row_type operator*(typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x3.inl" +#endif //GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_mat4x3.inl b/thirdparty/glm/detail/type_mat4x3.inl new file mode 100644 index 0000000..11b1ee3 --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x3.inl @@ -0,0 +1,598 @@ +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1), col_type(0, 0, 0)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0); + this->value[1] = col_type(0, 1, 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0, 0, 0); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s), col_type(0, 0, 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0); + this->value[1] = col_type(0, s, 0); + this->value[2] = col_type(0, 0, s); + this->value[3] = col_type(0, 0, 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, + T const& x1, T const& y1, T const& z1, + T const& x2, T const& y2, T const& z2, + T const& x3, T const& y3, T const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + // -- Conversion constructors -- + + template + template< + typename X0, typename Y0, typename Z0, + typename X1, typename Y1, typename Z1, + typename X2, typename Y2, typename Z2, + typename X3, typename Y3, typename Z3> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat + ( + X0 const& x0, Y0 const& y0, Z0 const& z0, + X1 const& x1, Y1 const& y1, Z1 const& z1, + X2 const& x2, Y2 const& y2, Z2 const& z2, + X3 const& x3, Y3 const& y3, Z3 const& z3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0); + this->value[1] = col_type(x1, y1, z1); + this->value[2] = col_type(x2, y2, z2); + this->value[3] = col_type(x3, y3, z3); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(0, 0, 1); + this->value[3] = col_type(0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(m[3], 0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 1); + this->value[3] = col_type(m[3], 0); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(0); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type & mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 3, T, Q>::col_type const& mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary updatable operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q>& mat<4, 3, T, Q>::operator=(mat<4, 3, U, Q> const& m) + { + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(mat<4, 3, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(mat<4, 3, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator++(int) + { + mat<4, 3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator--(int) + { + mat<4, 3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type operator* + ( + mat<4, 3, T, Q> const& m, + typename mat<4, 3, T, Q>::row_type const& v) + { + return typename mat<4, 3, T, Q>::col_type( + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w, + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::row_type operator* + ( + typename mat<4, 3, T, Q>::col_type const& v, + mat<4, 3, T, Q> const& m) + { + return typename mat<4, 3, T, Q>::row_type( + v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], + v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2], + v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2], + v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + T const SrcA00 = m1[0][0]; + T const SrcA01 = m1[0][1]; + T const SrcA02 = m1[0][2]; + T const SrcA10 = m1[1][0]; + T const SrcA11 = m1[1][1]; + T const SrcA12 = m1[1][2]; + T const SrcA20 = m1[2][0]; + T const SrcA21 = m1[2][1]; + T const SrcA22 = m1[2][2]; + T const SrcA30 = m1[3][0]; + T const SrcA31 = m1[3][1]; + T const SrcA32 = m1[3][2]; + + T const SrcB00 = m2[0][0]; + T const SrcB01 = m2[0][1]; + T const SrcB02 = m2[0][2]; + T const SrcB03 = m2[0][3]; + T const SrcB10 = m2[1][0]; + T const SrcB11 = m2[1][1]; + T const SrcB12 = m2[1][2]; + T const SrcB13 = m2[1][3]; + T const SrcB20 = m2[2][0]; + T const SrcB21 = m2[2][1]; + T const SrcB22 = m2[2][2]; + T const SrcB23 = m2[2][3]; + + mat<3, 3, T, Q> Result; + Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; + Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; + Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03; + Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; + Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; + Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13; + Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23; + Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23; + Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 3, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], + m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3], + m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s) + { + return mat<4, 3, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m) + { + return mat<4, 3, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +} //namespace glm diff --git a/thirdparty/glm/detail/type_mat4x4.hpp b/thirdparty/glm/detail/type_mat4x4.hpp new file mode 100644 index 0000000..5ea880d --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x4.hpp @@ -0,0 +1,189 @@ +/// @ref core +/// @file glm/detail/type_mat4x4.hpp + +#pragma once + +#include "type_vec4.hpp" +#include +#include + +namespace glm +{ + template + struct mat<4, 4, T, Q> + { + typedef vec<4, T, Q> col_type; + typedef vec<4, T, Q> row_type; + typedef mat<4, 4, T, Q> type; + typedef mat<4, 4, T, Q> transpose_type; + typedef T value_type; + + private: + col_type value[4]; + + public: + // -- Accesses -- + + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL col_type & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; + + // -- Constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR mat() GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 4, T, P> const& m); + + GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3); + GLM_FUNC_DECL GLM_CONSTEXPR mat( + col_type const& v0, + col_type const& v1, + col_type const& v2, + col_type const& v3); + + // -- Conversions -- + + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_DECL GLM_CONSTEXPR mat( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4); + + template + GLM_FUNC_DECL GLM_CONSTEXPR mat( + vec<4, V1, Q> const& v1, + vec<4, V2, Q> const& v2, + vec<4, V3, Q> const& v3, + vec<4, V4, Q> const& v4); + + // -- Matrix conversions -- + + template + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, U, P> const& m); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(mat<4, 4, U, Q> const& m); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(U s); + template + GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(mat<4, 4, U, Q> const& m); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL mat<4, 4, T, Q> & operator++(); + GLM_FUNC_DECL mat<4, 4, T, Q> & operator--(); + GLM_FUNC_DECL mat<4, 4, T, Q> operator++(int); + GLM_FUNC_DECL mat<4, 4, T, Q> operator--(int); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m); + + // -- Binary operators -- + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator*(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator*(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); + + template + GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); + + template + GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); + + template + GLM_FUNC_DECL bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_mat4x4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_mat4x4.inl b/thirdparty/glm/detail/type_mat4x4.inl new file mode 100644 index 0000000..e38b87f --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x4.inl @@ -0,0 +1,706 @@ +#include "../matrix.hpp" + +namespace glm +{ + // -- Constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat() +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST + : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION + this->value[0] = col_type(1, 0, 0, 0); + this->value[1] = col_type(0, 1, 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, T, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(T const& s) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0), col_type(0, 0, 0, s)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(s, 0, 0, 0); + this->value[1] = col_type(0, s, 0, 0); + this->value[2] = col_type(0, 0, s, 0); + this->value[3] = col_type(0, 0, 0, s); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + T const& x0, T const& y0, T const& z0, T const& w0, + T const& x1, T const& y1, T const& z1, T const& w1, + T const& x2, T const& y2, T const& z2, T const& w2, + T const& x3, T const& y3, T const& z3, T const& w3 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{ + col_type(x0, y0, z0, w0), + col_type(x1, y1, z1, w1), + col_type(x2, y2, z2, w2), + col_type(x3, y3, z3, w3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x0, y0, z0, w0); + this->value[1] = col_type(x1, y1, z1, w1); + this->value[2] = col_type(x2, y2, z2, w2); + this->value[3] = col_type(x3, y3, z3, w3); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = v0; + this->value[1] = v1; + this->value[2] = v2; + this->value[3] = v3; +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, U, P> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0]); + this->value[1] = col_type(m[1]); + this->value[2] = col_type(m[2]); + this->value[3] = col_type(m[3]); +# endif + } + + // -- Conversions -- + + template + template< + typename X1, typename Y1, typename Z1, typename W1, + typename X2, typename Y2, typename Z2, typename W2, + typename X3, typename Y3, typename Z3, typename W3, + typename X4, typename Y4, typename Z4, typename W4> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat + ( + X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, + X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, + X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, + X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4 + ) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3), col_type(x4, y4, z4, w4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 5th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 6th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 7th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 8th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 9th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 10th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 11th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 12th parameter type invalid."); + + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 13th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 14th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 15th parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 16th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(x1, y1, z1, w1); + this->value[1] = col_type(x2, y2, z2, w2); + this->value[2] = col_type(x3, y3, z3, w3); + this->value[3] = col_type(x4, y4, z4, w4); +# endif + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} +# endif + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); + +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(v1); + this->value[1] = col_type(v2); + this->value[2] = col_type(v3); + this->value[3] = col_type(v4); +# endif + } + + // -- Matrix conversions -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(m[2], 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0, 0); + this->value[1] = col_type(m[1], 0, 0); + this->value[2] = col_type(0, 0, 1, 0); + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0, 0, 0, 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = col_type(0, 0, 0, 1); +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) +# if GLM_HAS_INITIALIZER_LISTS + : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(m[3], 1)} +# endif + { +# if !GLM_HAS_INITIALIZER_LISTS + this->value[0] = col_type(m[0], 0); + this->value[1] = col_type(m[1], 0); + this->value[2] = col_type(m[2], 0); + this->value[3] = col_type(m[3], 1); +# endif + } + + // -- Accesses -- + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type & mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) + { + assert(i < this->length()); + return this->value[i]; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 4, T, Q>::col_type const& mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) const + { + assert(i < this->length()); + return this->value[i]; + } + + // -- Unary arithmetic operators -- + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator=(mat<4, 4, U, Q> const& m) + { + //memcpy could be faster + //memcpy(&this->value, &m.value, 16 * sizeof(valType)); + this->value[0] = m[0]; + this->value[1] = m[1]; + this->value[2] = m[2]; + this->value[3] = m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(U s) + { + this->value[0] += s; + this->value[1] += s; + this->value[2] += s; + this->value[3] += s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(mat<4, 4, U, Q> const& m) + { + this->value[0] += m[0]; + this->value[1] += m[1]; + this->value[2] += m[2]; + this->value[3] += m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(U s) + { + this->value[0] -= s; + this->value[1] -= s; + this->value[2] -= s; + this->value[3] -= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(mat<4, 4, U, Q> const& m) + { + this->value[0] -= m[0]; + this->value[1] -= m[1]; + this->value[2] -= m[2]; + this->value[3] -= m[3]; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(U s) + { + this->value[0] *= s; + this->value[1] *= s; + this->value[2] *= s; + this->value[3] *= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(mat<4, 4, U, Q> const& m) + { + return (*this = *this * m); + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(U s) + { + this->value[0] /= s; + this->value[1] /= s; + this->value[2] /= s; + this->value[3] /= s; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(mat<4, 4, U, Q> const& m) + { + return *this *= inverse(m); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator++() + { + ++this->value[0]; + ++this->value[1]; + ++this->value[2]; + ++this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator--() + { + --this->value[0]; + --this->value[1]; + --this->value[2]; + --this->value[3]; + return *this; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator++(int) + { + mat<4, 4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator--(int) + { + mat<4, 4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m) + { + return m; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + -m[0], + -m[1], + -m[2], + -m[3]); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] + s, + m[1] + s, + m[2] + s, + m[3] + s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] - s, + m[1] - s, + m[2] - s, + m[3] - s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s - m[0], + s - m[1], + s - m[2], + s - m[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return mat<4, 4, T, Q>( + m1[0] - m2[0], + m1[1] - m2[1], + m1[2] - m2[2], + m1[3] - m2[3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const & s) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0] * s, + m[1] * s, + m[2] * s, + m[3] * s); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator* + ( + mat<4, 4, T, Q> const& m, + typename mat<4, 4, T, Q>::row_type const& v + ) + { +/* + __m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0].data, v0); + __m128 m1 = _mm_mul_ps(m[1].data, v1); + __m128 a0 = _mm_add_ps(m0, m1); + + __m128 m2 = _mm_mul_ps(m[2].data, v2); + __m128 m3 = _mm_mul_ps(m[3].data, v3); + __m128 a1 = _mm_add_ps(m2, m3); + + __m128 a2 = _mm_add_ps(a0, a1); + + return typename mat<4, 4, T, Q>::col_type(a2); +*/ + + typename mat<4, 4, T, Q>::col_type const Mov0(v[0]); + typename mat<4, 4, T, Q>::col_type const Mov1(v[1]); + typename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0; + typename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1; + typename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1; + typename mat<4, 4, T, Q>::col_type const Mov2(v[2]); + typename mat<4, 4, T, Q>::col_type const Mov3(v[3]); + typename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2; + typename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3; + typename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3; + typename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1; + return Add2; + +/* + return typename mat<4, 4, T, Q>::col_type( + m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3], + m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3], + m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3], + m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]); +*/ + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator* + ( + typename mat<4, 4, T, Q>::col_type const& v, + mat<4, 4, T, Q> const& m + ) + { + return typename mat<4, 4, T, Q>::row_type( + m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], + m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], + m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], + m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) + { + return mat<2, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) + { + return mat<3, 4, T, Q>( + m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], + m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], + m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], + m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], + m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], + m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], + m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], + m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3], + m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], + m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], + m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], + m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + typename mat<4, 4, T, Q>::col_type const SrcA0 = m1[0]; + typename mat<4, 4, T, Q>::col_type const SrcA1 = m1[1]; + typename mat<4, 4, T, Q>::col_type const SrcA2 = m1[2]; + typename mat<4, 4, T, Q>::col_type const SrcA3 = m1[3]; + + typename mat<4, 4, T, Q>::col_type const SrcB0 = m2[0]; + typename mat<4, 4, T, Q>::col_type const SrcB1 = m2[1]; + typename mat<4, 4, T, Q>::col_type const SrcB2 = m2[2]; + typename mat<4, 4, T, Q>::col_type const SrcB3 = m2[3]; + + mat<4, 4, T, Q> Result; + Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3]; + Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3]; + Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3]; + Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s) + { + return mat<4, 4, T, Q>( + m[0] / s, + m[1] / s, + m[2] / s, + m[3] / s); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + s / m[0], + s / m[1], + s / m[2], + s / m[3]); + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v) + { + return inverse(m) * v; + } + + template + GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m) + { + return v * inverse(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + mat<4, 4, T, Q> m1_copy(m1); + return m1_copy /= m2; + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) + { + return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_mat4x4_simd.inl" +#endif diff --git a/thirdparty/glm/detail/type_mat4x4_simd.inl b/thirdparty/glm/detail/type_mat4x4_simd.inl new file mode 100644 index 0000000..fb3a16f --- /dev/null +++ b/thirdparty/glm/detail/type_mat4x4_simd.inl @@ -0,0 +1,6 @@ +/// @ref core + +namespace glm +{ + +}//namespace glm diff --git a/thirdparty/glm/detail/type_quat.hpp b/thirdparty/glm/detail/type_quat.hpp new file mode 100644 index 0000000..0e60bc3 --- /dev/null +++ b/thirdparty/glm/detail/type_quat.hpp @@ -0,0 +1,186 @@ +/// @ref core +/// @file glm/detail/type_quat.hpp + +#pragma once + +// Dependency: +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" + +namespace glm +{ + template + struct qua + { + // -- Implementation detail -- + + typedef qua type; + typedef T value_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_LANG & GLM_LANG_CXXMS_FLAG + union + { +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + struct { T w, x, y, z; }; +# else + struct { T x, y, z, w; }; +# endif + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + }; +# else +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + T w, x, y, z; +# else + T x, y, z, w; +# endif +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + typedef length_t length_type; + + /// Return the count of components of a quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua(T s, vec<3, T, Q> const& v); + GLM_FUNC_DECL GLM_CONSTEXPR qua(T w, T x, T y, T z); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(qua const& q); + + /// Explicit conversion operators +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + GLM_FUNC_DECL explicit operator mat<3, 3, T, Q>() const; + GLM_FUNC_DECL explicit operator mat<4, 4, T, Q>() const; +# endif + + /// Create a quaternion from two normalized axis + /// + /// @param u A first normalized axis + /// @param v A second normalized axis + /// @see gtc_quaternion + /// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors + GLM_FUNC_DECL qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v); + + /// Build a quaternion from euler angles (pitch, yaw, roll), in radians. + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(vec<3, T, Q> const& eulerAngles); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<3, 3, T, Q> const& q); + GLM_FUNC_DECL GLM_EXPLICIT qua(mat<4, 4, T, Q> const& q); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator=(qua const& q) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator+=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator-=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator*=(qua const& q); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator*=(U s); + template + GLM_FUNC_DECL GLM_CONSTEXPR qua& operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator+(qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator-(qua const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator+(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator-(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(qua const& q, qua const& p); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(qua const& q, T const& s); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator*(T const& s, qua const& q); + + template + GLM_FUNC_DECL GLM_CONSTEXPR qua operator/(qua const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2); +} //namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_quat.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_quat.inl b/thirdparty/glm/detail/type_quat.inl new file mode 100644 index 0000000..67b9310 --- /dev/null +++ b/thirdparty/glm/detail/type_quat.inl @@ -0,0 +1,408 @@ +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "../ext/quaternion_geometric.hpp" +#include + +namespace glm{ +namespace detail +{ + template + struct genTypeTrait > + { + static const genTypeEnum GENTYPE = GENTYPE_QUAT; + }; + + template + struct compute_dot, T, Aligned> + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(qua const& a, qua const& b) + { + vec<4, T, Q> tmp(a.w * b.w, a.x * b.x, a.y * b.y, a.z * b.z); + return (tmp.x + tmp.y) + (tmp.z + tmp.w); + } + }; + + template + struct compute_quat_add + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, qua const& p) + { + return qua(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z); + } + }; + + template + struct compute_quat_sub + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, qua const& p) + { + return qua(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z); + } + }; + + template + struct compute_quat_mul_scalar + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, T s) + { + return qua(q.w * s, q.x * s, q.y * s, q.z * s); + } + }; + + template + struct compute_quat_div_scalar + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua call(qua const& q, T s) + { + return qua(q.w / s, q.x / s, q.y / s, q.z / s); + } + }; + + template + struct compute_quat_mul_vec4 + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(qua const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + }; +}//namespace detail + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & qua::operator[](typename qua::length_type i) + { + assert(i >= 0 && i < this->length()); +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + return (&w)[i]; +# else + return (&x)[i]; +# endif + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& qua::operator[](typename qua::length_type i) const + { + assert(i >= 0 && i < this->length()); +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + return (&w)[i]; +# else + return (&x)[i]; +# endif + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(1), x(0), y(0), z(0) +# else + : x(0), y(0), z(0), w(1) +# endif +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(q.w), x(q.x), y(q.y), z(q.z) +# else + : x(q.x), y(q.y), z(q.z), w(q.w) +# endif + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(q.w), x(q.x), y(q.y), z(q.z) +# else + : x(q.x), y(q.y), z(q.z), w(q.w) +# endif + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T s, vec<3, T, Q> const& v) +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(s), x(v.x), y(v.y), z(v.z) +# else + : x(v.x), y(v.y), z(v.z), w(s) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T _w, T _x, T _y, T _z) +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(_w), x(_x), y(_y), z(_z) +# else + : x(_x), y(_y), z(_z), w(_w) +# endif + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) +# ifdef GLM_FORCE_QUAT_DATA_WXYZ + : w(static_cast(q.w)), x(static_cast(q.x)), y(static_cast(q.y)), z(static_cast(q.z)) +# else + : x(static_cast(q.x)), y(static_cast(q.y)), z(static_cast(q.z)), w(static_cast(q.w)) +# endif + {} + + //template + //GLM_FUNC_QUALIFIER qua::qua + //( + // valType const& pitch, + // valType const& yaw, + // valType const& roll + //) + //{ + // vec<3, valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5)); + // vec<3, valType> c = glm::cos(eulerAngle * valType(0.5)); + // vec<3, valType> s = glm::sin(eulerAngle * valType(0.5)); + // + // this->w = c.x * c.y * c.z + s.x * s.y * s.z; + // this->x = s.x * c.y * c.z - c.x * s.y * s.z; + // this->y = c.x * s.y * c.z + s.x * c.y * s.z; + // this->z = c.x * c.y * s.z - s.x * s.y * c.z; + //} + + template + GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v) + { + T norm_u_norm_v = sqrt(dot(u, u) * dot(v, v)); + T real_part = norm_u_norm_v + dot(u, v); + vec<3, T, Q> t; + + if(real_part < static_cast(1.e-6f) * norm_u_norm_v) + { + // If u and v are exactly opposite, rotate 180 degrees + // around an arbitrary orthogonal axis. Axis normalisation + // can happen later, when we normalise the quaternion. + real_part = static_cast(0); + t = abs(u.x) > abs(u.z) ? vec<3, T, Q>(-u.y, u.x, static_cast(0)) : vec<3, T, Q>(static_cast(0), -u.z, u.y); + } + else + { + // Otherwise, build quaternion the standard way. + t = cross(u, v); + } + + *this = normalize(qua(real_part, t.x, t.y, t.z)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(vec<3, T, Q> const& eulerAngle) + { + vec<3, T, Q> c = glm::cos(eulerAngle * T(0.5)); + vec<3, T, Q> s = glm::sin(eulerAngle * T(0.5)); + + this->w = c.x * c.y * c.z + s.x * s.y * s.z; + this->x = s.x * c.y * c.z - c.x * s.y * s.z; + this->y = c.x * s.y * c.z + s.x * c.y * s.z; + this->z = c.x * c.y * s.z - s.x * s.y * c.z; + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<3, 3, T, Q> const& m) + { + *this = quat_cast(m); + } + + template + GLM_FUNC_QUALIFIER qua::qua(mat<4, 4, T, Q> const& m) + { + *this = quat_cast(m); + } + +# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + template + GLM_FUNC_QUALIFIER qua::operator mat<3, 3, T, Q>() const + { + return mat3_cast(*this); + } + + template + GLM_FUNC_QUALIFIER qua::operator mat<4, 4, T, Q>() const + { + return mat4_cast(*this); + } +# endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator=(qua const& q) + { + this->w = q.w; + this->x = q.x; + this->y = q.y; + this->z = q.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator=(qua const& q) + { + this->w = static_cast(q.w); + this->x = static_cast(q.x); + this->y = static_cast(q.y); + this->z = static_cast(q.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator+=(qua const& q) + { + return (*this = detail::compute_quat_add::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator-=(qua const& q) + { + return (*this = detail::compute_quat_sub::value>::call(*this, qua(q))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator*=(qua const& r) + { + qua const p(*this); + qua const q(r); + + this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z; + this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y; + this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z; + this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator*=(U s) + { + return (*this = detail::compute_quat_mul_scalar::value>::call(*this, static_cast(s))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua & qua::operator/=(U s) + { + return (*this = detail::compute_quat_div_scalar::value>::call(*this, static_cast(s))); + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator+(qua const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator-(qua const& q) + { + return qua(-q.w, -q.x, -q.y, -q.z); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator+(qua const& q, qua const& p) + { + return qua(q) += p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator-(qua const& q, qua const& p) + { + return qua(q) -= p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(qua const& q, qua const& p) + { + return qua(q) *= p; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const QuatVector(q.x, q.y, q.z); + vec<3, T, Q> const uv(glm::cross(QuatVector, v)); + vec<3, T, Q> const uuv(glm::cross(QuatVector, uv)); + + return v + ((uv * q.w) + uuv) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v) + { + return detail::compute_quat_mul_vec4::value>::call(q, v); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(qua const& q, T const& s) + { + return qua( + q.w * s, q.x * s, q.y * s, q.z * s); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator*(T const& s, qua const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua operator/(qua const& q, T const& s) + { + return qua( + q.w / s, q.x / s, q.y / s, q.z / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2) + { + return q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2) + { + return q1.x != q2.x || q1.y != q2.y || q1.z != q2.z || q1.w != q2.w; + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_quat_simd.inl" +#endif + diff --git a/thirdparty/glm/detail/type_quat_simd.inl b/thirdparty/glm/detail/type_quat_simd.inl new file mode 100644 index 0000000..3333e59 --- /dev/null +++ b/thirdparty/glm/detail/type_quat_simd.inl @@ -0,0 +1,188 @@ +/// @ref core + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +/* + template + struct compute_quat_mul + { + static qua call(qua const& q1, qua const& q2) + { + // SSE2 STATS: 11 shuffle, 8 mul, 8 add + // SSE4 STATS: 3 shuffle, 4 mul, 4 dpps + + __m128 const mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3))); + __m128 const mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2))); + __m128 const mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1))); + __m128 const mul3 = _mm_mul_ps(q1.Data, q2.Data); + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + __m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f), 0xff); + __m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f), 0xff); + __m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f), 0xff); + __m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff); +# else + __m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f)); + __m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4)); + __m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1)); + + __m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f)); + __m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5)); + __m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1)); + + __m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f)); + __m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6)); + __m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1)); + + __m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f)); + __m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7)); + __m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1)); + #endif + + // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than + // the final code below. I'll keep this here for reference - maybe somebody else can do something better... + // + //__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0)); + //__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0)); + // + //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0)); + + qua Result; + _mm_store_ss(&Result.x, add4); + _mm_store_ss(&Result.y, add5); + _mm_store_ss(&Result.z, add6); + _mm_store_ss(&Result.w, add7); + return Result; + } + }; +*/ + + template + struct compute_quat_add + { + static qua call(qua const& q, qua const& p) + { + qua Result; + Result.data = _mm_add_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_add + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_sub + { + static qua call(qua const& q, qua const& p) + { + vec<4, float, Q> Result; + Result.data = _mm_sub_ps(q.data, p.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_sub + { + static qua call(qua const& a, qua const& b) + { + qua Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_mul_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_mul_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, float s) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(q.data, _mm_set_ps1(s)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_quat_div_scalar + { + static qua call(qua const& q, double s) + { + qua Result; + Result.data = _mm256_div_pd(q.data, _mm_set_ps1(s)); + return Result; + } + }; +# endif + + template + struct compute_quat_mul_vec4 + { + static vec<4, float, Q> call(qua const& q, vec<4, float, Q> const& v) + { + __m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3)); + __m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2)); + + __m128 uv = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0)); + __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1)); + __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2)); + __m128 uuv = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0)); + + __m128 const two = _mm_set1_ps(2.0f); + uv = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two)); + uuv = _mm_mul_ps(uuv, two); + + vec<4, float, Q> Result; + Result.data = _mm_add_ps(v.Data, _mm_add_ps(uv, uuv)); + return Result; + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/thirdparty/glm/detail/type_vec1.hpp b/thirdparty/glm/detail/type_vec1.hpp new file mode 100644 index 0000000..dd71c32 --- /dev/null +++ b/thirdparty/glm/detail/type_vec1.hpp @@ -0,0 +1,308 @@ +/// @ref core +/// @file glm/detail/type_vec1.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<1, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<1, T, Q> type; + typedef vec<1, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + T x; + T r; + T s; + + typename detail::storage<1, T, detail::is_aligned::value>::type data; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + _GLM_SWIZZLE1_2_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_2_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_3_MEMBERS(T, Q, s) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, x) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, r) + _GLM_SWIZZLE1_4_MEMBERS(T, Q, s) +# endif +*/ + }; +# else + union {T x, r, s;}; +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, Q) +# endif +*/ +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 1;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec() GLM_DEFAULT; + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<1, U, P> const& v); + + // -- Swizzle constructors -- +/* +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<1, T, Q, E0, -1,-2,-3> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +*/ + // -- Unary arithmetic operators -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec<1, T, Q>& operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(vec<1, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(vec<1, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec1.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_vec1.inl b/thirdparty/glm/detail/type_vec1.inl new file mode 100644 index 0000000..c5883ce --- /dev/null +++ b/thirdparty/glm/detail/type_vec1.inl @@ -0,0 +1,551 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, Q> const& v) + : x(v.x) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, P> const& v) + : x(v.x) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(T scalar) + : x(scalar) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) + { + return x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) const + { + return x; + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, T, Q> const& v) + { + this->x = v.x; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, U, Q> const& v) + { + this->x = static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator++() + { + ++this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator--() + { + --this->x; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator++(int) + { + vec<1, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator--(int) + { + vec<1, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= U(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + return *this; + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + -v.x); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar + v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x + v2.x); + } + + //operator- + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar - v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar * v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar / v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x / v2.x); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar % v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar & v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar | v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + v.x ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + scalar ^ v.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + v1.x ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + static_cast(v.x << scalar)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + static_cast(scalar << v.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + static_cast(v1.x << v2.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar) + { + return vec<1, T, Q>( + static_cast(v.x >> scalar)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + static_cast(scalar >> v.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<1, T, Q>( + static_cast(v1.x >> v2.x)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v) + { + return vec<1, T, Q>( + ~v.x); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return detail::compute_equal::is_iec559>::call(v1.x, v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x && v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) + { + return vec<1, bool, Q>(v1.x || v2.x); + } +}//namespace glm diff --git a/thirdparty/glm/detail/type_vec2.hpp b/thirdparty/glm/detail/type_vec2.hpp new file mode 100644 index 0000000..8fc8313 --- /dev/null +++ b/thirdparty/glm/detail/type_vec2.hpp @@ -0,0 +1,399 @@ +/// @ref core +/// @file glm/detail/type_vec2.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<2, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<2, T, Q> type; + typedef vec<2, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + T x, y; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y; }; + struct{ T r, g; }; + struct{ T s, t; }; + + typename detail::storage<2, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t) + GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y) + GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g) + GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t) +# endif + }; +# else + union {T x, r, s;}; + union {T y, g, t;}; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + // GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL GLM_CONSTEXPR T& operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec() GLM_DEFAULT; + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, B y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, vec<1, B, Q> const& y); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, vec<1, B, Q> const& y); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1,-1,-2> const& that) + { + *this = that(); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec<2, T, Q>& operator=(vec const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<2, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<2, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<2, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec2.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_vec2.inl b/thirdparty/glm/detail/type_vec2.inl new file mode 100644 index 0000000..2f4edd0 --- /dev/null +++ b/thirdparty/glm/detail/type_vec2.inl @@ -0,0 +1,913 @@ +/// @ref core + +#include "./compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, Q> const& v) + : x(v.x), y(v.y) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, P> const& v) + : x(v.x), y(v.y) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T scalar) + : x(scalar), y(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T _x, T _y) + : x(_x), y(_y) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, B _y) + : x(static_cast(_x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, B _y) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, vec<1, B, Q> const& _y) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, vec<1, B, Q> const& _y) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) + { + assert(i >= 0 && i < 2); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) const + { + assert(i >= 0 && i < 2); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<2, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<2, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<2, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(U scalar) + { + this->x /= static_cast(scalar); + this->y /= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<2, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator++() + { + ++this->x; + ++this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator--() + { + --this->x; + --this->y; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator++(int) + { + vec<2, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator--(int) + { + vec<2, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(U scalar) + { + this->x %= static_cast(scalar); + this->y %= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<2, U, Q> const& v) + { + this->x %= static_cast(v.x); + this->y %= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(U scalar) + { + this->x &= static_cast(scalar); + this->y &= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<2, U, Q> const& v) + { + this->x &= static_cast(v.x); + this->y &= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(U scalar) + { + this->x |= static_cast(scalar); + this->y |= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<2, U, Q> const& v) + { + this->x |= static_cast(v.x); + this->y |= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(U scalar) + { + this->x ^= static_cast(scalar); + this->y ^= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<2, U, Q> const& v) + { + this->x ^= static_cast(v.x); + this->y ^= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(U scalar) + { + this->x <<= static_cast(scalar); + this->y <<= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<2, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<2, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + -v.x, + -v.y); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x + scalar, + v.y + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar + v.x, + scalar + v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.x + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x + v2.x, + v1.y + v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x - scalar, + v.y - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar - v.x, + scalar - v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.x - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x - v2.x, + v1.y - v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x * scalar, + v.y * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar * v.x, + scalar * v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.x * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x * v2.x, + v1.y * v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x / scalar, + v.y / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar / v.x, + scalar / v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.x / v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x / v2.x, + v1.y / v2.y); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x % scalar, + v.y % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar % v.x, + scalar % v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.x % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x % v2.x, + v1.y % v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x & scalar, + v.y & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar & v.x, + scalar & v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.x & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x & v2.x, + v1.y & v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x | scalar, + v.y | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar | v.x, + scalar | v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.x | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x | v2.x, + v1.y | v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x ^ scalar, + v.y ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar ^ v.x, + scalar ^ v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.x ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x << scalar, + v.y << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar << v.x, + scalar << v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.x << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x << v2.x, + v1.y << v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar) + { + return vec<2, T, Q>( + v.x >> scalar, + v.y >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + scalar >> v.x, + scalar >> v.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.x >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return vec<2, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v) + { + return vec<2, T, Q>( + ~v.x, + ~v.y); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x && v2.x, v1.y && v2.y); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) + { + return vec<2, bool, Q>(v1.x || v2.x, v1.y || v2.y); + } +}//namespace glm diff --git a/thirdparty/glm/detail/type_vec3.hpp b/thirdparty/glm/detail/type_vec3.hpp new file mode 100644 index 0000000..d109fdb --- /dev/null +++ b/thirdparty/glm/detail/type_vec3.hpp @@ -0,0 +1,439 @@ +/// @ref core +/// @file glm/detail/type_vec3.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<3, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<3, T, Q> type; + typedef vec<3, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# pragma warning(disable: 4324) // structure was padded due to alignment specifier +# endif +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + + union { + struct { + T x, y, z; + }; + T c[3]; + }; + +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct{ T x, y, z; }; + struct{ T r, g, b; }; + struct{ T s, t, p; }; + + typename detail::storage<3, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p) + GLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z) + GLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b) + GLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, Q) +# endif//GLM_CONFIG_SWIZZLE +# endif//GLM_LANG + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + /// Return the count of components of the vector + typedef length_t length_type; + // GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 3;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec() GLM_DEFAULT; + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T a, T b, T c); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X x, Y y, Z z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& scalar) + { + *this = vec(v(), scalar); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& scalar, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec(scalar, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec<3, T, Q>& operator=(vec<3, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<3, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<3, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<3, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec3.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_vec3.inl b/thirdparty/glm/detail/type_vec3.inl new file mode 100644 index 0000000..9ec4a16 --- /dev/null +++ b/thirdparty/glm/detail/type_vec3.inl @@ -0,0 +1,1068 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm +{ + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, Q> const& v) + : x(v.x), y(v.y), z(v.z) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, P> const& v) + : x(v.x), y(v.y), z(v.z) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T _x, T _y, T _z) + : x(_x), y(_y), z(_z) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, B _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(A _x, vec<2, B, P> const& _yz) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) + { + assert(i >= 0 && i < 3); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) const + { + assert(i >= 0 && i < 3); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(U scalar) + { + this->x += static_cast(scalar); + this->y += static_cast(scalar); + this->z += static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<1, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.x); + this->z += static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<3, U, Q> const& v) + { + this->x += static_cast(v.x); + this->y += static_cast(v.y); + this->z += static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(U scalar) + { + this->x -= static_cast(scalar); + this->y -= static_cast(scalar); + this->z -= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<1, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.x); + this->z -= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<3, U, Q> const& v) + { + this->x -= static_cast(v.x); + this->y -= static_cast(v.y); + this->z -= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(U scalar) + { + this->x *= static_cast(scalar); + this->y *= static_cast(scalar); + this->z *= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<1, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.x); + this->z *= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<3, U, Q> const& v) + { + this->x *= static_cast(v.x); + this->y *= static_cast(v.y); + this->z *= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(U v) + { + this->x /= static_cast(v); + this->y /= static_cast(v); + this->z /= static_cast(v); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<1, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.x); + this->z /= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<3, U, Q> const& v) + { + this->x /= static_cast(v.x); + this->y /= static_cast(v.y); + this->z /= static_cast(v.z); + return *this; + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator++(int) + { + vec<3, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator--(int) + { + vec<3, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(U scalar) + { + this->x %= scalar; + this->y %= scalar; + this->z %= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<1, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.x; + this->z %= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<3, U, Q> const& v) + { + this->x %= v.x; + this->y %= v.y; + this->z %= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(U scalar) + { + this->x &= scalar; + this->y &= scalar; + this->z &= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<1, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.x; + this->z &= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<3, U, Q> const& v) + { + this->x &= v.x; + this->y &= v.y; + this->z &= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(U scalar) + { + this->x |= scalar; + this->y |= scalar; + this->z |= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<1, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.x; + this->z |= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<3, U, Q> const& v) + { + this->x |= v.x; + this->y |= v.y; + this->z |= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(U scalar) + { + this->x ^= scalar; + this->y ^= scalar; + this->z ^= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<1, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.x; + this->z ^= v.x; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<3, U, Q> const& v) + { + this->x ^= v.x; + this->y ^= v.y; + this->z ^= v.z; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(U scalar) + { + this->x <<= scalar; + this->y <<= scalar; + this->z <<= scalar; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.x); + this->z <<= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<3, U, Q> const& v) + { + this->x <<= static_cast(v.x); + this->y <<= static_cast(v.y); + this->z <<= static_cast(v.z); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(U scalar) + { + this->x >>= static_cast(scalar); + this->y >>= static_cast(scalar); + this->z >>= static_cast(scalar); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.x); + this->z >>= static_cast(v.x); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<3, U, Q> const& v) + { + this->x >>= static_cast(v.x); + this->y >>= static_cast(v.y); + this->z >>= static_cast(v.z); + return *this; + } + + // -- Unary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + -v.x, + -v.y, + -v.z); + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x + scalar, + v.y + scalar, + v.z + scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x + scalar.x, + v.y + scalar.x, + v.z + scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar + v.x, + scalar + v.y, + scalar + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x + v.x, + scalar.x + v.y, + scalar.x + v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x + v2.x, + v1.y + v2.y, + v1.z + v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x - scalar, + v.y - scalar, + v.z - scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x - scalar.x, + v.y - scalar.x, + v.z - scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar - v.x, + scalar - v.y, + scalar - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x - v.x, + scalar.x - v.y, + scalar.x - v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x - v2.x, + v1.y - v2.y, + v1.z - v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x * scalar, + v.y * scalar, + v.z * scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x * scalar.x, + v.y * scalar.x, + v.z * scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar * v.x, + scalar * v.y, + scalar * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x * v.x, + scalar.x * v.y, + scalar.x * v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x * v2.x, + v1.y * v2.y, + v1.z * v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x / scalar, + v.y / scalar, + v.z / scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x / scalar.x, + v.y / scalar.x, + v.z / scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar / v.x, + scalar / v.y, + scalar / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x / v.x, + scalar.x / v.y, + scalar.x / v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x / v2.x, + v1.y / v2.y, + v1.z / v2.z); + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x % scalar, + v.y % scalar, + v.z % scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x % scalar.x, + v.y % scalar.x, + v.z % scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar % v.x, + scalar % v.y, + scalar % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x % v.x, + scalar.x % v.y, + scalar.x % v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x % v2.x, + v1.y % v2.y, + v1.z % v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x & scalar, + v.y & scalar, + v.z & scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x & scalar.x, + v.y & scalar.x, + v.z & scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar & v.x, + scalar & v.y, + scalar & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x & v.x, + scalar.x & v.y, + scalar.x & v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x & v2.x, + v1.y & v2.y, + v1.z & v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x | scalar, + v.y | scalar, + v.z | scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x | scalar.x, + v.y | scalar.x, + v.z | scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar | v.x, + scalar | v.y, + scalar | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x | v.x, + scalar.x | v.y, + scalar.x | v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x | v2.x, + v1.y | v2.y, + v1.z | v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x ^ scalar, + v.y ^ scalar, + v.z ^ scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x ^ scalar.x, + v.y ^ scalar.x, + v.z ^ scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar ^ v.x, + scalar ^ v.y, + scalar ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x ^ v.x, + scalar.x ^ v.y, + scalar.x ^ v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x ^ v2.x, + v1.y ^ v2.y, + v1.z ^ v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x << scalar, + v.y << scalar, + v.z << scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x << scalar.x, + v.y << scalar.x, + v.z << scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar << v.x, + scalar << v.y, + scalar << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x << v.x, + scalar.x << v.y, + scalar.x << v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x << v2.x, + v1.y << v2.y, + v1.z << v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar) + { + return vec<3, T, Q>( + v.x >> scalar, + v.y >> scalar, + v.z >> scalar); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<3, T, Q>( + v.x >> scalar.x, + v.y >> scalar.x, + v.z >> scalar.x); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar >> v.x, + scalar >> v.y, + scalar >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + scalar.x >> v.x, + scalar.x >> v.y, + scalar.x >> v.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return vec<3, T, Q>( + v1.x >> v2.x, + v1.y >> v2.y, + v1.z >> v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v) + { + return vec<3, T, Q>( + ~v.x, + ~v.y, + ~v.z); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) + { + return !(v1 == v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) + { + return vec<3, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z); + } +}//namespace glm diff --git a/thirdparty/glm/detail/type_vec4.hpp b/thirdparty/glm/detail/type_vec4.hpp new file mode 100644 index 0000000..b63a68c --- /dev/null +++ b/thirdparty/glm/detail/type_vec4.hpp @@ -0,0 +1,510 @@ +/// @ref core +/// @file glm/detail/type_vec4.hpp + +#pragma once + +#include "qualifier.hpp" +#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR +# include "_swizzle.hpp" +#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION +# include "_swizzle_func.hpp" +#endif +#include + +namespace glm +{ + template + struct vec<4, T, Q> + { + // -- Implementation detail -- + + typedef T value_type; + typedef vec<4, T, Q> type; + typedef vec<4, bool, Q> bool_type; + + // -- Data -- + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +# elif GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +# pragma clang diagnostic ignored "-Wnested-anon-types" +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union +# endif +# endif + +# if GLM_CONFIG_XYZW_ONLY + union { + struct { + T x, y, z, w; + }; + typename detail::storage<4, T, detail::is_aligned::value>::type data; + }; +# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE + union + { + struct { T x, y, z, w; }; + struct { T r, g, b, a; }; + struct { T s, t, p, q; }; + + typename detail::storage<4, T, detail::is_aligned::value>::type data; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + GLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q) + GLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w) + GLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a) + GLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q) +# endif + }; +# else + union { T x, r, s; }; + union { T y, g, t; }; + union { T z, b, p; }; + union { T w, a, q; }; + +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION + GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, Q) +# endif +# endif + +# if GLM_SILENT_WARNINGS == GLM_ENABLE +# if GLM_COMPILER & GLM_COMPILER_CLANG +# pragma clang diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_GCC +# pragma GCC diagnostic pop +# elif GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif +# endif + + // -- Component accesses -- + + typedef length_t length_type; + + /// Return the count of components of the vector + // GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} + + GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); + GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec() GLM_DEFAULT; + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec(vec<4, T, Q> const& v) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, P> const& v); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); + GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y, T z, T w); + + // -- Conversion scalar constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _Y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); + + // -- Conversion vector constructors -- + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, B _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw); + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw); + + /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); + + // -- Swizzle constructors -- +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<4, T, Q, E0, E1, E2, E3> const& that) + { + *this = that(); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, detail::_swizzle<2, T, Q, F0, F1, -1, -2> const& u) + { + *this = vec<4, T, Q>(v(), u()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, T const& y, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) + { + *this = vec<4, T, Q>(x, y, v()); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& w) + { + *this = vec<4, T, Q>(x, v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& z, T const& w) + { + *this = vec<4, T, Q>(v(), z, w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v, T const& w) + { + *this = vec<4, T, Q>(v(), w); + } + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v) + { + *this = vec<4, T, Q>(x, v()); + } +# endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + // -- Unary arithmetic operators -- + + /* GLM_FUNC_DECL */ GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, T, Q> const& v) GLM_DEFAULT; + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<4, U, Q> const& v); + + // -- Increment and decrement operators -- + + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator++(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator--(); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator++(int); + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator--(int); + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<4, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(U scalar); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<1, U, Q> const& v); + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<4, U, Q> const& v); + }; + + // -- Unary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v); + + // -- Binary operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); + + template + GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); +}//namespace glm + +#ifndef GLM_EXTERNAL_TEMPLATE +#include "type_vec4.inl" +#endif//GLM_EXTERNAL_TEMPLATE diff --git a/thirdparty/glm/detail/type_vec4.inl b/thirdparty/glm/detail/type_vec4.inl new file mode 100644 index 0000000..5ad29cd --- /dev/null +++ b/thirdparty/glm/detail/type_vec4.inl @@ -0,0 +1,1140 @@ +/// @ref core + +#include "compute_vector_relational.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_vec4_add + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + } + }; + + template + struct compute_vec4_sub + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + } + }; + + template + struct compute_vec4_mul + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + } + }; + + template + struct compute_vec4_div + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + } + }; + + template + struct compute_vec4_mod + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w); + } + }; + + template + struct compute_vec4_and + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); + } + }; + + template + struct compute_vec4_or + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); + } + }; + + template + struct compute_vec4_xor + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); + } + }; + + template + struct compute_vec4_shift_left + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w); + } + }; + + template + struct compute_vec4_shift_right + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + return vec<4, T, Q>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w); + } + }; + + template + struct compute_vec4_equal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return + detail::compute_equal::is_iec559>::call(v1.x, v2.x) && + detail::compute_equal::is_iec559>::call(v1.y, v2.y) && + detail::compute_equal::is_iec559>::call(v1.z, v2.z) && + detail::compute_equal::is_iec559>::call(v1.w, v2.w); + } + }; + + template + struct compute_vec4_nequal + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return !compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + }; + + template + struct compute_vec4_bitwise_not + { + GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(~v.x, ~v.y, ~v.z, ~v.w); + } + }; +}//namespace detail + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec() +# if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE + : x(0), y(0), z(0), w(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, Q> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, P> const& v) + : x(v.x), y(v.y), z(v.z), w(v.w) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T scalar) + : x(scalar), y(scalar), z(scalar), w(scalar) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T _x, T _y, T _z, T _w) + : x(_x), y(_y), z(_z), w(_w) + {} + + // -- Conversion scalar constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.x)) + , z(static_cast(v.x)) + , w(static_cast(v.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + // -- Conversion vector constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_z.x)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) + : x(static_cast(_x.x)) + , y(static_cast(_yz.x)) + , z(static_cast(_yz.y)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) + : x(static_cast(_x.x)) + , y(static_cast(_y.x)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, B _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w) + : x(static_cast(_xyz.x)) + , y(static_cast(_xyz.y)) + , z(static_cast(_xyz.z)) + , w(static_cast(_w.x)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw) + : x(static_cast(_x.x)) + , y(static_cast(_yzw.x)) + , z(static_cast(_yzw.y)) + , w(static_cast(_yzw.z)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw) + : x(static_cast(_xy.x)) + , y(static_cast(_xy.y)) + , z(static_cast(_zw.x)) + , w(static_cast(_zw.y)) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, U, P> const& v) + : x(static_cast(v.x)) + , y(static_cast(v.y)) + , z(static_cast(v.z)) + , w(static_cast(v.w)) + {} + + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) + { + assert(i >= 0 && i < 4); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) const + { + assert(i >= 0 && i < 4); + switch(i) + { + default: + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + } + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, T, Q> const& v) + { + this->x = v.x; + this->y = v.y; + this->z = v.z; + this->w = v.w; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, U, Q> const& v) + { + this->x = static_cast(v.x); + this->y = static_cast(v.y); + this->z = static_cast(v.z); + this->w = static_cast(v.w); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(U scalar) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(U scalar) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(U scalar) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(U scalar) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v.x))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Increment and decrement operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator++() + { + ++this->x; + ++this->y; + ++this->z; + ++this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator--() + { + --this->x; + --this->y; + --this->z; + --this->w; + return *this; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator++(int) + { + vec<4, T, Q> Result(*this); + ++*this; + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator--(int) + { + vec<4, T, Q> Result(*this); + --*this; + return Result; + } + + // -- Unary bit operators -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(U scalar) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(U scalar) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(U scalar) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(U scalar) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(U scalar) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(U scalar) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<1, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<4, U, Q> const& v) + { + return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); + } + + // -- Unary constant operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v) + { + return vec<4, T, Q>(0) -= v; + } + + // -- Binary arithmetic operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) += scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) += v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) += v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) -= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) -= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) -= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(v) *= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v2) *= v1; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) *= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar) + { + return vec<4, T, Q>(v) /= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) /= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) /= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) /= v2; + } + + // -- Binary bit operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) %= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar.x) %= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) %= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar) + { + return vec<4, T, Q>(v) &= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) &= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) &= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) |= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) |= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) |= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) ^= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) ^= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) ^= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) <<= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) <<= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) <<= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar) + { + return vec<4, T, Q>(v) >>= scalar; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2.x; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(scalar) >>= v; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1.x) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return vec<4, T, Q>(v1) >>= v2; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v) + { + return detail::compute_vec4_bitwise_not::value, sizeof(T) * 8, detail::is_aligned::value>::call(v); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) + { + return detail::compute_vec4_nequal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) + { + return vec<4, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "type_vec4_simd.inl" +#endif diff --git a/thirdparty/glm/detail/type_vec4_simd.inl b/thirdparty/glm/detail/type_vec4_simd.inl new file mode 100644 index 0000000..29559b5 --- /dev/null +++ b/thirdparty/glm/detail/type_vec4_simd.inl @@ -0,0 +1,775 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ +# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + template + struct _swizzle_base1<4, float, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, float, Q> operator ()() const + { + __m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer); + + vec<4, float, Q> Result; +# if GLM_ARCH & GLM_ARCH_AVX_BIT + Result.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0)); +# else + Result.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0)); +# endif + return Result; + } + }; + + template + struct _swizzle_base1<4, int, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, int, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, int, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; + + template + struct _swizzle_base1<4, uint, Q, E0,E1,E2,E3, true> : public _swizzle_base0 + { + GLM_FUNC_QUALIFIER vec<4, uint, Q> operator ()() const + { + __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); + + vec<4, uint, Q> Result; + Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); + return Result; + } + }; +# endif// GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR + + template + struct compute_vec4_add + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_add_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_add + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_add_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_sub + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_sub_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_sub + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_sub_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_mul + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_mul_ps(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_mul + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_mul_pd(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_div + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = _mm_div_ps(a.data, b.data); + return Result; + } + }; + + # if GLM_ARCH & GLM_ARCH_AVX_BIT + template + struct compute_vec4_div + { + static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) + { + vec<4, double, Q> Result; + Result.data = _mm256_div_pd(a.data, b.data); + return Result; + } + }; +# endif + + template<> + struct compute_vec4_div + { + static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& a, vec<4, float, aligned_lowp> const& b) + { + vec<4, float, aligned_lowp> Result; + Result.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data)); + return Result; + } + }; + + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_and_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_and + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_and_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_or_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_or + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_or_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_xor + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_sll_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_left + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_sll_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm_srl_epi32(a.data, b.data); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_shift_right + { + static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) + { + vec<4, T, Q> Result; + Result.data = _mm256_srl_epi64(a.data, b.data); + return Result; + } + }; +# endif + + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template + struct compute_vec4_bitwise_not + { + static vec<4, T, Q> call(vec<4, T, Q> const& v) + { + vec<4, T, Q> Result; + Result.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1)); + return Result; + } + }; +# endif + + template + struct compute_vec4_equal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpeq_ps(v1.data, v2.data)) != 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_equal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) == 0; + } + }; +# endif + + template + struct compute_vec4_nequal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0; + } + }; + +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + template + struct compute_vec4_nequal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + //return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0; + __m128i neq = _mm_xor_si128(v1.data, v2.data); + return _mm_test_all_zeros(neq, neq) != 0; + } + }; +# endif +}//namespace detail + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : + data(_mm_set1_ps(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_lowp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_mediump>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_highp>::vec(double _s) : + data(_mm256_set1_pd(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : + data(_mm_set1_epi32(_s)) + {} + +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_lowp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_mediump>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_highp>::vec(detail::int64 _s) : + data(_mm256_set1_epi64x(_s)) + {} +# endif + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _x, float _y, float _z, float _w) : + data(_mm_set_ps(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_set_epi32(_w, _z, _y, _x)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) + {} +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + +#if GLM_ARCH & GLM_ARCH_NEON_BIT +namespace glm { +namespace detail { + + template + struct compute_vec4_add + { + static + vec<4, float, Q> + call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vaddq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_add + { + static + vec<4, uint, Q> + call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vaddq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_add + { + static + vec<4, int, Q> + call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vaddq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vsubq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vsubq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_sub + { + static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, int, Q> Result; + Result.data = vsubq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vmulq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) + { + vec<4, uint, Q> Result; + Result.data = vmulq_u32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_mul + { + static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) + { + vec<4, int, Q> Result; + Result.data = vmulq_s32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_div + { + static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) + { + vec<4, float, Q> Result; + Result.data = vdivq_f32(a.data, b.data); + return Result; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + uint32x4_t cmp = vceqq_f32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + uint32x4_t cmp = vceqq_u32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_equal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + uint32x4_t cmp = vceqq_s32(v1.data, v2.data); +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + cmp = vpminq_u32(cmp, cmp); + cmp = vpminq_u32(cmp, cmp); + uint32_t r = cmp[0]; +#else + uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); + cmpx2 = vpmin_u32(cmpx2, cmpx2); + uint32_t r = cmpx2[0]; +#endif + return r == ~0u; + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + + template + struct compute_vec4_nequal + { + static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) + { + return !compute_vec4_equal::call(v1, v2); + } + }; + +}//namespace detail + +#if !GLM_CONFIG_XYZW_ONLY + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : + data(vdupq_n_f32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : + data(vdupq_n_s32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_lowp>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_mediump>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_highp>::vec(uint _s) : + data(vdupq_n_u32(_s)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, float, aligned_highp>& rhs) : + data(rhs.data) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, int, aligned_highp>& rhs) : + data(vcvtq_f32_s32(rhs.data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, uint, aligned_highp>& rhs) : + data(vcvtq_f32_u32(rhs.data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_lowp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_mediump>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : + data(vcvtq_f32_s32(vec<4, int, aligned_highp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_lowp>(_x, _y, _z, _w).data)) + {} + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_mediump>(_x, _y, _z, _w).data)) + {} + + + template<> + template<> + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(uint _x, uint _y, uint _z, uint _w) : + data(vcvtq_f32_u32(vec<4, uint, aligned_highp>(_x, _y, _z, _w).data)) + {} + +#endif +}//namespace glm + +#endif diff --git a/thirdparty/glm/exponential.hpp b/thirdparty/glm/exponential.hpp new file mode 100644 index 0000000..f8fb886 --- /dev/null +++ b/thirdparty/glm/exponential.hpp @@ -0,0 +1,110 @@ +/// @ref core +/// @file glm/exponential.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions +/// +/// @defgroup core_func_exponential Exponential functions +/// @ingroup core +/// +/// Provides GLSL exponential functions +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec1.hpp" +#include "detail/type_vec2.hpp" +#include "detail/type_vec3.hpp" +#include "detail/type_vec4.hpp" +#include + +namespace glm +{ + /// @addtogroup core_func_exponential + /// @{ + + /// Returns 'base' raised to the power 'exponent'. + /// + /// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @param exponent Floating point value representing the 'exponent'. + /// + /// @see GLSL pow man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec pow(vec const& base, vec const& exponent); + + /// Returns the natural exponentiation of x, i.e., e^x. + /// + /// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp(vec const& v); + + /// Returns the natural logarithm of v, i.e., + /// returns the value y which satisfies the equation x = e^y. + /// Results are undefined if v <= 0. + /// + /// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log(vec const& v); + + /// Returns 2 raised to the v power. + /// + /// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL exp2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec exp2(vec const& v); + + /// Returns the base 2 log of x, i.e., returns the value y, + /// which satisfies the equation x = 2 ^ y. + /// + /// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL log2 man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec log2(vec const& v); + + /// Returns the positive square root of v. + /// + /// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL sqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec sqrt(vec const& v); + + /// Returns the reciprocal of the positive square root of v. + /// + /// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL inversesqrt man page + /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions + template + GLM_FUNC_DECL vec inversesqrt(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_exponential.inl" diff --git a/thirdparty/glm/ext.hpp b/thirdparty/glm/ext.hpp new file mode 100644 index 0000000..3249fb9 --- /dev/null +++ b/thirdparty/glm/ext.hpp @@ -0,0 +1,253 @@ +/// @file glm/ext.hpp +/// +/// @ref core (Dependence) + +#include "detail/setup.hpp" + +#pragma once + +#include "glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED) +# define GLM_MESSAGE_EXT_INCLUDED_DISPLAYED +# pragma message("GLM: All extensions included (not recommended)") +#endif//GLM_MESSAGES + +#include "./ext/matrix_clip_space.hpp" +#include "./ext/matrix_common.hpp" + +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" + +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + +#include "./ext/matrix_int2x2.hpp" +#include "./ext/matrix_int2x2_sized.hpp" +#include "./ext/matrix_int2x3.hpp" +#include "./ext/matrix_int2x3_sized.hpp" +#include "./ext/matrix_int2x4.hpp" +#include "./ext/matrix_int2x4_sized.hpp" +#include "./ext/matrix_int3x2.hpp" +#include "./ext/matrix_int3x2_sized.hpp" +#include "./ext/matrix_int3x3.hpp" +#include "./ext/matrix_int3x3_sized.hpp" +#include "./ext/matrix_int3x4.hpp" +#include "./ext/matrix_int3x4_sized.hpp" +#include "./ext/matrix_int4x2.hpp" +#include "./ext/matrix_int4x2_sized.hpp" +#include "./ext/matrix_int4x3.hpp" +#include "./ext/matrix_int4x3_sized.hpp" +#include "./ext/matrix_int4x4.hpp" +#include "./ext/matrix_int4x4_sized.hpp" + +#include "./ext/matrix_uint2x2.hpp" +#include "./ext/matrix_uint2x2_sized.hpp" +#include "./ext/matrix_uint2x3.hpp" +#include "./ext/matrix_uint2x3_sized.hpp" +#include "./ext/matrix_uint2x4.hpp" +#include "./ext/matrix_uint2x4_sized.hpp" +#include "./ext/matrix_uint3x2.hpp" +#include "./ext/matrix_uint3x2_sized.hpp" +#include "./ext/matrix_uint3x3.hpp" +#include "./ext/matrix_uint3x3_sized.hpp" +#include "./ext/matrix_uint3x4.hpp" +#include "./ext/matrix_uint3x4_sized.hpp" +#include "./ext/matrix_uint4x2.hpp" +#include "./ext/matrix_uint4x2_sized.hpp" +#include "./ext/matrix_uint4x3.hpp" +#include "./ext/matrix_uint4x3_sized.hpp" +#include "./ext/matrix_uint4x4.hpp" +#include "./ext/matrix_uint4x4_sized.hpp" + +#include "./ext/matrix_projection.hpp" +#include "./ext/matrix_relational.hpp" +#include "./ext/matrix_transform.hpp" + +#include "./ext/quaternion_common.hpp" +#include "./ext/quaternion_double.hpp" +#include "./ext/quaternion_double_precision.hpp" +#include "./ext/quaternion_float.hpp" +#include "./ext/quaternion_float_precision.hpp" +#include "./ext/quaternion_exponential.hpp" +#include "./ext/quaternion_geometric.hpp" +#include "./ext/quaternion_relational.hpp" +#include "./ext/quaternion_transform.hpp" +#include "./ext/quaternion_trigonometric.hpp" + +#include "./ext/scalar_common.hpp" +#include "./ext/scalar_constants.hpp" +#include "./ext/scalar_integer.hpp" +#include "./ext/scalar_packing.hpp" +#include "./ext/scalar_relational.hpp" +#include "./ext/scalar_ulp.hpp" + +#include "./ext/scalar_int_sized.hpp" +#include "./ext/scalar_uint_sized.hpp" + +#include "./ext/vector_common.hpp" +#include "./ext/vector_integer.hpp" +#include "./ext/vector_packing.hpp" +#include "./ext/vector_relational.hpp" +#include "./ext/vector_ulp.hpp" + +#include "./ext/vector_bool1.hpp" +#include "./ext/vector_bool1_precision.hpp" +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" + +#include "./ext/vector_double1.hpp" +#include "./ext/vector_double1_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" + +#include "./ext/vector_float1.hpp" +#include "./ext/vector_float1_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" + +#include "./ext/vector_int1.hpp" +#include "./ext/vector_int1_sized.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_sized.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_sized.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_sized.hpp" + +#include "./ext/vector_uint1.hpp" +#include "./ext/vector_uint1_sized.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_sized.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_sized.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_sized.hpp" + +#include "./gtc/bitfield.hpp" +#include "./gtc/color_space.hpp" +#include "./gtc/constants.hpp" +#include "./gtc/epsilon.hpp" +#include "./gtc/integer.hpp" +#include "./gtc/matrix_access.hpp" +#include "./gtc/matrix_integer.hpp" +#include "./gtc/matrix_inverse.hpp" +#include "./gtc/matrix_transform.hpp" +#include "./gtc/noise.hpp" +#include "./gtc/packing.hpp" +#include "./gtc/quaternion.hpp" +#include "./gtc/random.hpp" +#include "./gtc/reciprocal.hpp" +#include "./gtc/round.hpp" +#include "./gtc/type_precision.hpp" +#include "./gtc/type_ptr.hpp" +#include "./gtc/ulp.hpp" +#include "./gtc/vec1.hpp" +#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE +# include "./gtc/type_aligned.hpp" +#endif + +#ifdef GLM_ENABLE_EXPERIMENTAL +#include "./gtx/associated_min_max.hpp" +#include "./gtx/bit.hpp" +#include "./gtx/closest_point.hpp" +#include "./gtx/color_encoding.hpp" +#include "./gtx/color_space.hpp" +#include "./gtx/color_space_YCoCg.hpp" +#include "./gtx/compatibility.hpp" +#include "./gtx/component_wise.hpp" +#include "./gtx/dual_quaternion.hpp" +#include "./gtx/euler_angles.hpp" +#include "./gtx/extend.hpp" +#include "./gtx/extended_min_max.hpp" +#include "./gtx/fast_exponential.hpp" +#include "./gtx/fast_square_root.hpp" +#include "./gtx/fast_trigonometry.hpp" +#include "./gtx/functions.hpp" +#include "./gtx/gradient_paint.hpp" +#include "./gtx/handed_coordinate_space.hpp" +#include "./gtx/integer.hpp" +#include "./gtx/intersect.hpp" +#include "./gtx/log_base.hpp" +#include "./gtx/matrix_cross_product.hpp" +#include "./gtx/matrix_interpolation.hpp" +#include "./gtx/matrix_major_storage.hpp" +#include "./gtx/matrix_operation.hpp" +#include "./gtx/matrix_query.hpp" +#include "./gtx/mixed_product.hpp" +#include "./gtx/norm.hpp" +#include "./gtx/normal.hpp" +#include "./gtx/normalize_dot.hpp" +#include "./gtx/number_precision.hpp" +#include "./gtx/optimum_pow.hpp" +#include "./gtx/orthonormalize.hpp" +#include "./gtx/perpendicular.hpp" +#include "./gtx/polar_coordinates.hpp" +#include "./gtx/projection.hpp" +#include "./gtx/quaternion.hpp" +#include "./gtx/raw_data.hpp" +#include "./gtx/rotate_vector.hpp" +#include "./gtx/spline.hpp" +#include "./gtx/std_based_type.hpp" +#if !(GLM_COMPILER & GLM_COMPILER_CUDA) +# include "./gtx/string_cast.hpp" +#endif +#include "./gtx/transform.hpp" +#include "./gtx/transform2.hpp" +#include "./gtx/vec_swizzle.hpp" +#include "./gtx/vector_angle.hpp" +#include "./gtx/vector_query.hpp" +#include "./gtx/wrap.hpp" + +#if GLM_HAS_TEMPLATE_ALIASES +# include "./gtx/scalar_multiplication.hpp" +#endif + +#if GLM_HAS_RANGE_FOR +# include "./gtx/range.hpp" +#endif +#endif//GLM_ENABLE_EXPERIMENTAL diff --git a/thirdparty/glm/ext/matrix_clip_space.hpp b/thirdparty/glm/ext/matrix_clip_space.hpp new file mode 100644 index 0000000..c3874f2 --- /dev/null +++ b/thirdparty/glm/ext/matrix_clip_space.hpp @@ -0,0 +1,522 @@ +/// @ref ext_matrix_clip_space +/// @file glm/ext/matrix_clip_space.hpp +/// +/// @defgroup ext_matrix_clip_space GLM_EXT_matrix_clip_space +/// @ingroup ext +/// +/// Defines functions that generate clip space transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_projection + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_clip_space extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_clip_space + /// @{ + + /// Creates a matrix for projecting two-dimensional coordinates onto the screen. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top, T const& zNear, T const& zFar) + /// @see gluOrtho2D man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_ZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_NO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoZO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoNO( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a matrix for an orthographic parallel viewing volume, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// + /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) + /// @see glOrtho man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( + T left, T right, T bottom, T top, T zNear, T zFar); + + /// Creates a left handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_ZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_NO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumZO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumNO( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a left handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a right handed frustum matrix. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH( + T left, T right, T bottom, T top, T near, T far); + + /// Creates a frustum matrix with default handedness, using the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @tparam T A floating-point scalar type + /// @see glFrustum man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> frustum( + T left, T right, T bottom, T top, T near, T far); + + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_ZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_NO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveZO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveNO( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a right handed, symetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a left handed, symetric perspective-view frustum. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH( + T fovy, T aspect, T near, T far); + + /// Creates a matrix for a symetric perspective-view frustum based on the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fovy Specifies the field of view angle in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + /// @see gluPerspective man page + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspective( + T fovy, T aspect, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_ZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_NO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovZO( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovNO( + T fov, T width, T height, T near, T far); + + /// Builds a right handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH( + T fov, T width, T height, T near, T far); + + /// Builds a left handed perspective projection matrix based on a field of view. + /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH( + T fov, T width, T height, T near, T far); + + /// Builds a perspective projection matrix based on a field of view and the default handedness and default near and far clip planes definition. + /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param fov Expressed in radians. + /// @param width Width of the viewport + /// @param height Height of the viewport + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFov( + T fov, T width, T height, T near, T far); + + /// Creates a matrix for a left handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveLH( + T fovy, T aspect, T near); + + /// Creates a matrix for a right handed, symmetric perspective-view frustum with far plane at infinite. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveRH( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near); + + /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. + /// + /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. + /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). + /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). + /// @param ep Epsilon + /// + /// @tparam T A floating-point scalar type + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( + T fovy, T aspect, T near, T ep); + + /// @} +}//namespace glm + +#include "matrix_clip_space.inl" diff --git a/thirdparty/glm/ext/matrix_clip_space.inl b/thirdparty/glm/ext/matrix_clip_space.inl new file mode 100644 index 0000000..7e4df33 --- /dev/null +++ b/thirdparty/glm/ext/matrix_clip_space.inl @@ -0,0 +1,555 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top) + { + mat<4, 4, T, defaultp> Result(static_cast(1)); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(1) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - zNear / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar) + { + mat<4, 4, T, defaultp> Result(1); + Result[0][0] = static_cast(2) / (right - left); + Result[1][1] = static_cast(2) / (top - bottom); + Result[2][2] = - static_cast(2) / (zFar - zNear); + Result[3][0] = - (right + left) / (right - left); + Result[3][1] = - (top + bottom) / (top - bottom); + Result[3][2] = - (zFar + zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# endif + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# else + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return orthoLH_ZO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return orthoLH_NO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return orthoRH_ZO(left, right, bottom, top, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return orthoRH_NO(left, right, bottom, top, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = farVal / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = farVal / (nearVal - farVal); + Result[2][3] = static_cast(-1); + Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) + { + mat<4, 4, T, defaultp> Result(0); + Result[0][0] = (static_cast(2) * nearVal) / (right - left); + Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); + Result[2][0] = (right + left) / (right - left); + Result[2][1] = (top + bottom) / (top - bottom); + Result[2][2] = - (farVal + nearVal) / (farVal - nearVal); + Result[2][3] = static_cast(-1); + Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# else + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return frustumLH_NO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return frustumRH_NO(left, right, bottom, top, nearVal, farVal); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar) + { + assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); + + T const tanHalfFovy = tan(fovy / static_cast(2)); + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); + Result[1][1] = static_cast(1) / (tanHalfFovy); + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# endif + + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# else + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return perspectiveLH_ZO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return perspectiveLH_NO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return perspectiveRH_ZO(fovy, aspect, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return perspectiveRH_NO(fovy, aspect, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zNear - zFar); + Result[2][3] = - static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = - (zFar + zNear) / (zFar - zNear); + Result[2][3] = - static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = zFar / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = -(zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar) + { + assert(width > static_cast(0)); + assert(height > static_cast(0)); + assert(fov > static_cast(0)); + + T const rad = fov; + T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); + T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = w; + Result[1][1] = h; + Result[2][2] = (zFar + zNear) / (zFar - zNear); + Result[2][3] = static_cast(1); + Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# else + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar) + { +# if GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO + return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO + return perspectiveFovLH_NO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO + return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); +# elif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO + return perspectiveFovRH_NO(fov, width, height, zNear, zFar); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = - static_cast(1); + Result[2][3] = - static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(T(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = static_cast(1); + Result[2][3] = static_cast(1); + Result[3][2] = - static_cast(2) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return infinitePerspectiveLH(fovy, aspect, zNear); +# else + return infinitePerspectiveRH(fovy, aspect, zNear); +# endif + } + + // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep) + { + T const range = tan(fovy / static_cast(2)) * zNear; + T const left = -range * aspect; + T const right = range * aspect; + T const bottom = -range; + T const top = range; + + mat<4, 4, T, defaultp> Result(static_cast(0)); + Result[0][0] = (static_cast(2) * zNear) / (right - left); + Result[1][1] = (static_cast(2) * zNear) / (top - bottom); + Result[2][2] = ep - static_cast(1); + Result[2][3] = static_cast(-1); + Result[3][2] = (ep - static_cast(2)) * zNear; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear) + { + return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon()); + } +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_common.hpp b/thirdparty/glm/ext/matrix_common.hpp new file mode 100644 index 0000000..05c3799 --- /dev/null +++ b/thirdparty/glm/ext/matrix_common.hpp @@ -0,0 +1,36 @@ +/// @ref ext_matrix_common +/// @file glm/ext/matrix_common.hpp +/// +/// @defgroup ext_matrix_common GLM_EXT_matrix_common +/// @ingroup ext +/// +/// Defines functions for common matrix operations. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_common + +#pragma once + +#include "../detail/qualifier.hpp" +#include "../detail/_fixes.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_common + /// @{ + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, mat const& a); + + template + GLM_FUNC_DECL mat mix(mat const& x, mat const& y, U a); + + /// @} +}//namespace glm + +#include "matrix_common.inl" diff --git a/thirdparty/glm/ext/matrix_common.inl b/thirdparty/glm/ext/matrix_common.inl new file mode 100644 index 0000000..9d50848 --- /dev/null +++ b/thirdparty/glm/ext/matrix_common.inl @@ -0,0 +1,16 @@ +#include "../matrix.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, U a) + { + return mat(x) * (static_cast(1) - a) + mat(y) * a; + } + + template + GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, mat const& a) + { + return matrixCompMult(mat(x), static_cast(1) - a) + matrixCompMult(mat(y), a); + } +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x2.hpp b/thirdparty/glm/ext/matrix_double2x2.hpp new file mode 100644 index 0000000..94dca54 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, double, defaultp> dmat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x2_precision.hpp b/thirdparty/glm/ext/matrix_double2x2_precision.hpp new file mode 100644 index 0000000..9e2c174 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + + /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, double, highp> highp_dmat2x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x3.hpp b/thirdparty/glm/ext/matrix_double2x3.hpp new file mode 100644 index 0000000..bfef87a --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, double, defaultp> dmat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x3_precision.hpp b/thirdparty/glm/ext/matrix_double2x3_precision.hpp new file mode 100644 index 0000000..098fb60 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + + /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, double, highp> highp_dmat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x4.hpp b/thirdparty/glm/ext/matrix_double2x4.hpp new file mode 100644 index 0000000..499284b --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, double, defaultp> dmat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double2x4_precision.hpp b/thirdparty/glm/ext/matrix_double2x4_precision.hpp new file mode 100644 index 0000000..9b61ebc --- /dev/null +++ b/thirdparty/glm/ext/matrix_double2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + + /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, double, highp> highp_dmat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x2.hpp b/thirdparty/glm/ext/matrix_double3x2.hpp new file mode 100644 index 0000000..dd23f36 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, double, defaultp> dmat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x2_precision.hpp b/thirdparty/glm/ext/matrix_double3x2_precision.hpp new file mode 100644 index 0000000..068d9e9 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + + /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, double, highp> highp_dmat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x3.hpp b/thirdparty/glm/ext/matrix_double3x3.hpp new file mode 100644 index 0000000..53572b7 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, double, defaultp> dmat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x3_precision.hpp b/thirdparty/glm/ext/matrix_double3x3_precision.hpp new file mode 100644 index 0000000..8691e78 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + + /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, double, highp> highp_dmat3x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x4.hpp b/thirdparty/glm/ext/matrix_double3x4.hpp new file mode 100644 index 0000000..c572d63 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, double, defaultp> dmat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double3x4_precision.hpp b/thirdparty/glm/ext/matrix_double3x4_precision.hpp new file mode 100644 index 0000000..f040217 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + + /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, double, highp> highp_dmat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x2.hpp b/thirdparty/glm/ext/matrix_double4x2.hpp new file mode 100644 index 0000000..9b229f4 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, double, defaultp> dmat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x2_precision.hpp b/thirdparty/glm/ext/matrix_double4x2_precision.hpp new file mode 100644 index 0000000..6ad18ba --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x2_precision.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + + /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, double, highp> highp_dmat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x3.hpp b/thirdparty/glm/ext/matrix_double4x3.hpp new file mode 100644 index 0000000..dca4cf9 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, double, defaultp> dmat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x3_precision.hpp b/thirdparty/glm/ext/matrix_double4x3_precision.hpp new file mode 100644 index 0000000..f7371de --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_double4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + + /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, double, highp> highp_dmat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x4.hpp b/thirdparty/glm/ext/matrix_double4x4.hpp new file mode 100644 index 0000000..81e1bf6 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, double, defaultp> dmat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_double4x4_precision.hpp b/thirdparty/glm/ext/matrix_double4x4_precision.hpp new file mode 100644 index 0000000..4c36a84 --- /dev/null +++ b/thirdparty/glm/ext/matrix_double4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_double4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, double, highp> highp_dmat4x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x2.hpp b/thirdparty/glm/ext/matrix_float2x2.hpp new file mode 100644 index 0000000..53df921 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x2.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 2, float, defaultp> mat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x2_precision.hpp b/thirdparty/glm/ext/matrix_float2x2_precision.hpp new file mode 100644 index 0000000..898b6db --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x2_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, lowp> lowp_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, mediump> mediump_mat2x2; + + /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 2, float, highp> highp_mat2x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x3.hpp b/thirdparty/glm/ext/matrix_float2x3.hpp new file mode 100644 index 0000000..6f68822 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 3, float, defaultp> mat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x3_precision.hpp b/thirdparty/glm/ext/matrix_float2x3_precision.hpp new file mode 100644 index 0000000..50c1032 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x3_precision.hpp + +#pragma once +#include "../detail/type_mat2x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, lowp> lowp_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, mediump> mediump_mat2x3; + + /// 2 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 3, float, highp> highp_mat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x4.hpp b/thirdparty/glm/ext/matrix_float2x4.hpp new file mode 100644 index 0000000..30f30de --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<2, 4, float, defaultp> mat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float2x4_precision.hpp b/thirdparty/glm/ext/matrix_float2x4_precision.hpp new file mode 100644 index 0000000..079d638 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float2x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x4_precision.hpp + +#pragma once +#include "../detail/type_mat2x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, lowp> lowp_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, mediump> mediump_mat2x4; + + /// 2 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<2, 4, float, highp> highp_mat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x2.hpp b/thirdparty/glm/ext/matrix_float3x2.hpp new file mode 100644 index 0000000..d39dd2f --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 2, float, defaultp> mat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x2_precision.hpp b/thirdparty/glm/ext/matrix_float3x2_precision.hpp new file mode 100644 index 0000000..8572c2a --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x2_precision.hpp + +#pragma once +#include "../detail/type_mat3x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, lowp> lowp_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, mediump> mediump_mat3x2; + + /// 3 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 2, float, highp> highp_mat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x3.hpp b/thirdparty/glm/ext/matrix_float3x3.hpp new file mode 100644 index 0000000..177d809 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x3.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 3, float, defaultp> mat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x3_precision.hpp b/thirdparty/glm/ext/matrix_float3x3_precision.hpp new file mode 100644 index 0000000..8a900c1 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x3_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float3x3_precision.hpp + +#pragma once +#include "../detail/type_mat3x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, lowp> lowp_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, mediump> mediump_mat3x3; + + /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 3, float, highp> highp_mat3x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x4.hpp b/thirdparty/glm/ext/matrix_float3x4.hpp new file mode 100644 index 0000000..64b8459 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<3, 4, float, defaultp> mat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float3x4_precision.hpp b/thirdparty/glm/ext/matrix_float3x4_precision.hpp new file mode 100644 index 0000000..bc36bf1 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float3x4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float3x4_precision.hpp + +#pragma once +#include "../detail/type_mat3x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, lowp> lowp_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, mediump> mediump_mat3x4; + + /// 3 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<3, 4, float, highp> highp_mat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x2.hpp b/thirdparty/glm/ext/matrix_float4x2.hpp new file mode 100644 index 0000000..1ed5227 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x2.hpp + +#pragma once +#include "../detail/type_mat4x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 2, float, defaultp> mat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x2_precision.hpp b/thirdparty/glm/ext/matrix_float4x2_precision.hpp new file mode 100644 index 0000000..88fd069 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float2x2_precision.hpp + +#pragma once +#include "../detail/type_mat2x2.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, lowp> lowp_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, mediump> mediump_mat4x2; + + /// 4 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 2, float, highp> highp_mat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x3.hpp b/thirdparty/glm/ext/matrix_float4x3.hpp new file mode 100644 index 0000000..5dbe765 --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 3, float, defaultp> mat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x3_precision.hpp b/thirdparty/glm/ext/matrix_float4x3_precision.hpp new file mode 100644 index 0000000..846ed4f --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/matrix_float4x3_precision.hpp + +#pragma once +#include "../detail/type_mat4x3.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, lowp> lowp_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, mediump> mediump_mat4x3; + + /// 4 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 3, float, highp> highp_mat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x4.hpp b/thirdparty/glm/ext/matrix_float4x4.hpp new file mode 100644 index 0000000..5ba111d --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x4.hpp @@ -0,0 +1,23 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @ingroup core_matrix + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + typedef mat<4, 4, float, defaultp> mat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_float4x4_precision.hpp b/thirdparty/glm/ext/matrix_float4x4_precision.hpp new file mode 100644 index 0000000..597149b --- /dev/null +++ b/thirdparty/glm/ext/matrix_float4x4_precision.hpp @@ -0,0 +1,49 @@ +/// @ref core +/// @file glm/ext/matrix_float4x4_precision.hpp + +#pragma once +#include "../detail/type_mat4x4.hpp" + +namespace glm +{ + /// @addtogroup core_matrix_precision + /// @{ + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, lowp> lowp_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, mediump> mediump_mat4x4; + + /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef mat<4, 4, float, highp> highp_mat4x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x2.hpp b/thirdparty/glm/ext/matrix_int2x2.hpp new file mode 100644 index 0000000..c6aa068 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x2.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int2x2 +/// @file glm/ext/matrix_int2x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x2 GLM_EXT_matrix_int2x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x2 + /// @{ + + /// Signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2 + typedef mat<2, 2, int, defaultp> imat2x2; + + /// Signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2 + typedef mat<2, 2, int, defaultp> imat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x2_sized.hpp b/thirdparty/glm/ext/matrix_int2x2_sized.hpp new file mode 100644 index 0000000..70c0c21 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x2_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int2x2_sized +/// @file glm/ext/matrix_int2x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x2_sized GLM_EXT_matrix_int2x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x2_sized + /// @{ + + /// 8 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int8, defaultp> i8mat2x2; + + /// 16 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int16, defaultp> i16mat2x2; + + /// 32 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int32, defaultp> i32mat2x2; + + /// 64 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int64, defaultp> i64mat2x2; + + + /// 8 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int8, defaultp> i8mat2; + + /// 16 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int16, defaultp> i16mat2; + + /// 32 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int32, defaultp> i32mat2; + + /// 64 bit signed integer 2x2 matrix. + /// + /// @see ext_matrix_int2x2_sized + typedef mat<2, 2, int64, defaultp> i64mat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x3.hpp b/thirdparty/glm/ext/matrix_int2x3.hpp new file mode 100644 index 0000000..aee415c --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int2x3 +/// @file glm/ext/matrix_int2x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x3 GLM_EXT_matrix_int2x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x3 + /// @{ + + /// Signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3 + typedef mat<2, 3, int, defaultp> imat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x3_sized.hpp b/thirdparty/glm/ext/matrix_int2x3_sized.hpp new file mode 100644 index 0000000..b5526fe --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int2x3_sized +/// @file glm/ext/matrix_int2x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x3_sized GLM_EXT_matrix_int2x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x3_sized + /// @{ + + /// 8 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int8, defaultp> i8mat2x3; + + /// 16 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int16, defaultp> i16mat2x3; + + /// 32 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int32, defaultp> i32mat2x3; + + /// 64 bit signed integer 2x3 matrix. + /// + /// @see ext_matrix_int2x3_sized + typedef mat<2, 3, int64, defaultp> i64mat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x4.hpp b/thirdparty/glm/ext/matrix_int2x4.hpp new file mode 100644 index 0000000..4f36331 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int2x4 +/// @file glm/ext/matrix_int2x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x4 GLM_EXT_matrix_int2x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x4 + /// @{ + + /// Signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4 + typedef mat<2, 4, int, defaultp> imat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int2x4_sized.hpp b/thirdparty/glm/ext/matrix_int2x4_sized.hpp new file mode 100644 index 0000000..a66a5e7 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int2x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int2x4_sized +/// @file glm/ext/matrix_int2x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x4_sized GLM_EXT_matrix_int2x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int2x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int2x4_sized + /// @{ + + /// 8 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int8, defaultp> i8mat2x4; + + /// 16 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int16, defaultp> i16mat2x4; + + /// 32 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int32, defaultp> i32mat2x4; + + /// 64 bit signed integer 2x4 matrix. + /// + /// @see ext_matrix_int2x4_sized + typedef mat<2, 4, int64, defaultp> i64mat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x2.hpp b/thirdparty/glm/ext/matrix_int3x2.hpp new file mode 100644 index 0000000..3bd563b --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int3x2 +/// @file glm/ext/matrix_int3x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x2 GLM_EXT_matrix_int3x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x2 + /// @{ + + /// Signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2 + typedef mat<3, 2, int, defaultp> imat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x2_sized.hpp b/thirdparty/glm/ext/matrix_int3x2_sized.hpp new file mode 100644 index 0000000..7e34c52 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int3x2_sized +/// @file glm/ext/matrix_int3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x2_sized GLM_EXT_matrix_int3x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x2_sized + /// @{ + + /// 8 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int8, defaultp> i8mat3x2; + + /// 16 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int16, defaultp> i16mat3x2; + + /// 32 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int32, defaultp> i32mat3x2; + + /// 64 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_int3x2_sized + typedef mat<3, 2, int64, defaultp> i64mat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x3.hpp b/thirdparty/glm/ext/matrix_int3x3.hpp new file mode 100644 index 0000000..287488d --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x3.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int3x3 +/// @file glm/ext/matrix_int3x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x3 GLM_EXT_matrix_int3x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x3 + /// @{ + + /// Signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3 + typedef mat<3, 3, int, defaultp> imat3x3; + + /// Signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3 + typedef mat<3, 3, int, defaultp> imat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x3_sized.hpp b/thirdparty/glm/ext/matrix_int3x3_sized.hpp new file mode 100644 index 0000000..577e305 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x3_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int3x3_sized +/// @file glm/ext/matrix_int3x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x3_sized GLM_EXT_matrix_int3x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x3_sized + /// @{ + + /// 8 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int8, defaultp> i8mat3x3; + + /// 16 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int16, defaultp> i16mat3x3; + + /// 32 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int32, defaultp> i32mat3x3; + + /// 64 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int64, defaultp> i64mat3x3; + + + /// 8 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int8, defaultp> i8mat3; + + /// 16 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int16, defaultp> i16mat3; + + /// 32 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int32, defaultp> i32mat3; + + /// 64 bit signed integer 3x3 matrix. + /// + /// @see ext_matrix_int3x3_sized + typedef mat<3, 3, int64, defaultp> i64mat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x4.hpp b/thirdparty/glm/ext/matrix_int3x4.hpp new file mode 100644 index 0000000..08e534d --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int3x4 +/// @file glm/ext/matrix_int3x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x4 GLM_EXT_matrix_int3x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x4 + /// @{ + + /// Signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4 + typedef mat<3, 4, int, defaultp> imat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int3x4_sized.hpp b/thirdparty/glm/ext/matrix_int3x4_sized.hpp new file mode 100644 index 0000000..692c48c --- /dev/null +++ b/thirdparty/glm/ext/matrix_int3x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int3x4_sized +/// @file glm/ext/matrix_int3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x4_sized GLM_EXT_matrix_int3x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int3x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int3x4_sized + /// @{ + + /// 8 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int8, defaultp> i8mat3x4; + + /// 16 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int16, defaultp> i16mat3x4; + + /// 32 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int32, defaultp> i32mat3x4; + + /// 64 bit signed integer 3x4 matrix. + /// + /// @see ext_matrix_int3x4_sized + typedef mat<3, 4, int64, defaultp> i64mat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x2.hpp b/thirdparty/glm/ext/matrix_int4x2.hpp new file mode 100644 index 0000000..f756ef2 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int4x2 +/// @file glm/ext/matrix_int4x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x2 GLM_EXT_matrix_int4x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x2 + /// @{ + + /// Signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2 + typedef mat<4, 2, int, defaultp> imat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x2_sized.hpp b/thirdparty/glm/ext/matrix_int4x2_sized.hpp new file mode 100644 index 0000000..63a99d6 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int4x2_sized +/// @file glm/ext/matrix_int4x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x2_sized GLM_EXT_matrix_int4x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x2_sized + /// @{ + + /// 8 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int8, defaultp> i8mat4x2; + + /// 16 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int16, defaultp> i16mat4x2; + + /// 32 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int32, defaultp> i32mat4x2; + + /// 64 bit signed integer 4x2 matrix. + /// + /// @see ext_matrix_int4x2_sized + typedef mat<4, 2, int64, defaultp> i64mat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x3.hpp b/thirdparty/glm/ext/matrix_int4x3.hpp new file mode 100644 index 0000000..d5d97a7 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_int4x3 +/// @file glm/ext/matrix_int4x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x3 GLM_EXT_matrix_int4x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x3 + /// @{ + + /// Signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3 + typedef mat<4, 3, int, defaultp> imat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x3_sized.hpp b/thirdparty/glm/ext/matrix_int4x3_sized.hpp new file mode 100644 index 0000000..55078fa --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_int4x3_sized +/// @file glm/ext/matrix_int4x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x3_sized GLM_EXT_matrix_int4x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x3_sized + /// @{ + + /// 8 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int8, defaultp> i8mat4x3; + + /// 16 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int16, defaultp> i16mat4x3; + + /// 32 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int32, defaultp> i32mat4x3; + + /// 64 bit signed integer 4x3 matrix. + /// + /// @see ext_matrix_int4x3_sized + typedef mat<4, 3, int64, defaultp> i64mat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x4.hpp b/thirdparty/glm/ext/matrix_int4x4.hpp new file mode 100644 index 0000000..e17cff1 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x4.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_int4x4 +/// @file glm/ext/matrix_int4x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x4 GLM_EXT_matrix_int4x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x4 + /// @{ + + /// Signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4 + typedef mat<4, 4, int, defaultp> imat4x4; + + /// Signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4 + typedef mat<4, 4, int, defaultp> imat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_int4x4_sized.hpp b/thirdparty/glm/ext/matrix_int4x4_sized.hpp new file mode 100644 index 0000000..4a11203 --- /dev/null +++ b/thirdparty/glm/ext/matrix_int4x4_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_int4x4_sized +/// @file glm/ext/matrix_int4x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int4x4_sized GLM_EXT_matrix_int4x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_int4x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_int4x4_sized + /// @{ + + /// 8 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int8, defaultp> i8mat4x4; + + /// 16 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int16, defaultp> i16mat4x4; + + /// 32 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int32, defaultp> i32mat4x4; + + /// 64 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int64, defaultp> i64mat4x4; + + + /// 8 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int8, defaultp> i8mat4; + + /// 16 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int16, defaultp> i16mat4; + + /// 32 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int32, defaultp> i32mat4; + + /// 64 bit signed integer 4x4 matrix. + /// + /// @see ext_matrix_int4x4_sized + typedef mat<4, 4, int64, defaultp> i64mat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_projection.hpp b/thirdparty/glm/ext/matrix_projection.hpp new file mode 100644 index 0000000..51fd01b --- /dev/null +++ b/thirdparty/glm/ext/matrix_projection.hpp @@ -0,0 +1,149 @@ +/// @ref ext_matrix_projection +/// @file glm/ext/matrix_projection.hpp +/// +/// @defgroup ext_matrix_projection GLM_EXT_matrix_projection +/// @ingroup ext +/// +/// Functions that generate common projection transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_transform +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_projection extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_projection + /// @{ + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectZO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> projectNO( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param obj Specify the object coordinates. + /// @param model Specifies the current modelview matrix + /// @param proj Specifies the current projection matrix + /// @param viewport Specifies the current viewport + /// @return Return the computed window coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluProject man page + template + GLM_FUNC_DECL vec<3, T, Q> project( + vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectZO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. + /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProjectNO( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using default near and far clip planes definition. + /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. + /// + /// @param win Specify the window coordinates to be mapped. + /// @param model Specifies the modelview matrix + /// @param proj Specifies the projection matrix + /// @param viewport Specifies the viewport + /// @return Returns the computed object coordinates. + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluUnProject man page + template + GLM_FUNC_DECL vec<3, T, Q> unProject( + vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); + + /// Define a picking region + /// + /// @param center Specify the center of a picking region in window coordinates. + /// @param delta Specify the width and height, respectively, of the picking region in window coordinates. + /// @param viewport Rendering viewport + /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. + /// @tparam U Currently supported: Floating-point types and integer types. + /// + /// @see gluPickMatrix man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> pickMatrix( + vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport); + + /// @} +}//namespace glm + +#include "matrix_projection.inl" diff --git a/thirdparty/glm/ext/matrix_projection.inl b/thirdparty/glm/ext/matrix_projection.inl new file mode 100644 index 0000000..2f2c196 --- /dev/null +++ b/thirdparty/glm/ext/matrix_projection.inl @@ -0,0 +1,106 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp.x = tmp.x * static_cast(0.5) + static_cast(0.5); + tmp.y = tmp.y * static_cast(0.5) + static_cast(0.5); + + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); + tmp = model * tmp; + tmp = proj * tmp; + + tmp /= tmp.w; + tmp = tmp * static_cast(0.5) + static_cast(0.5); + tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); + tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); + + return vec<3, T, Q>(tmp); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return projectZO(obj, model, proj, viewport); +# else + return projectNO(obj, model, proj, viewport); +# endif + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp.x = tmp.x * static_cast(2) - static_cast(1); + tmp.y = tmp.y * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { + mat<4, 4, T, Q> Inverse = inverse(proj * model); + + vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); + tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); + tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); + tmp = tmp * static_cast(2) - static_cast(1); + + vec<4, T, Q> obj = Inverse * tmp; + obj /= obj.w; + + return vec<3, T, Q>(obj); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT + return unProjectZO(win, model, proj, viewport); +# else + return unProjectNO(win, model, proj, viewport); +# endif + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport) + { + assert(delta.x > static_cast(0) && delta.y > static_cast(0)); + mat<4, 4, T, Q> Result(static_cast(1)); + + if(!(delta.x > static_cast(0) && delta.y > static_cast(0))) + return Result; // Error + + vec<3, T, Q> Temp( + (static_cast(viewport[2]) - static_cast(2) * (center.x - static_cast(viewport[0]))) / delta.x, + (static_cast(viewport[3]) - static_cast(2) * (center.y - static_cast(viewport[1]))) / delta.y, + static_cast(0)); + + // Translate and scale the picked region to the entire window + Result = translate(Result, Temp); + return scale(Result, vec<3, T, Q>(static_cast(viewport[2]) / delta.x, static_cast(viewport[3]) / delta.y, static_cast(1))); + } +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_relational.hpp b/thirdparty/glm/ext/matrix_relational.hpp new file mode 100644 index 0000000..20023ad --- /dev/null +++ b/thirdparty/glm/ext/matrix_relational.hpp @@ -0,0 +1,132 @@ +/// @ref ext_matrix_relational +/// @file glm/ext/matrix_relational.hpp +/// +/// @defgroup ext_matrix_relational GLM_EXT_matrix_relational +/// @ingroup ext +/// +/// Exposes comparison functions for matrix types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_relational +/// @see ext_scalar_relational +/// @see ext_quaternion_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_relational + /// @{ + + /// Perform a component-wise equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y); + + /// Perform a component-wise not-equal-to comparison of two matrices. + /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix + /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "matrix_relational.inl" diff --git a/thirdparty/glm/ext/matrix_relational.inl b/thirdparty/glm/ext/matrix_relational.inl new file mode 100644 index 0000000..b2b8753 --- /dev/null +++ b/thirdparty/glm/ext/matrix_relational.inl @@ -0,0 +1,82 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.inl + +// Dependency: +#include "../ext/vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b) + { + return equal(a, b, static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, T Epsilon) + { + return equal(a, b, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y) + { + return notEqual(x, y, static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T Epsilon) + { + return notEqual(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& Epsilon) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], Epsilon[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, int MaxULPs) + { + return equal(a, b, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = all(equal(a[i], b[i], MaxULPs[i])); + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int MaxULPs) + { + return notEqual(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& MaxULPs) + { + vec Result(true); + for(length_t i = 0; i < C; ++i) + Result[i] = any(notEqual(a[i], b[i], MaxULPs[i])); + return Result; + } + +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_transform.hpp b/thirdparty/glm/ext/matrix_transform.hpp new file mode 100644 index 0000000..cbd187e --- /dev/null +++ b/thirdparty/glm/ext/matrix_transform.hpp @@ -0,0 +1,144 @@ +/// @ref ext_matrix_transform +/// @file glm/ext/matrix_transform.hpp +/// +/// @defgroup ext_matrix_transform GLM_EXT_matrix_transform +/// @ingroup ext +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. +/// +/// Include to use the features of this extension. +/// +/// @see ext_matrix_projection +/// @see ext_matrix_clip_space + +#pragma once + +// Dependencies +#include "../gtc/constants.hpp" +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_transform + /// @{ + + /// Builds an identity matrix. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType identity(); + + /// Builds a translation 4 * 4 matrix created from a vector of 3 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @code + /// #include + /// #include + /// ... + /// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); + /// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f + /// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f + /// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f + /// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f + /// @endcode + /// + /// @see - translate(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - translate(vec<3, T, Q> const& v) + /// @see glTranslate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, recommended to be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + /// @see glRotate man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& axis); + + /// Builds a scale 4 * 4 matrix created from 3 scalars. + /// + /// @param m Input matrix multiplied by this scale matrix. + /// @param v Ratio of scaling for each axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - scale(mat<4, 4, T, Q> const& m, T x, T y, T z) + /// @see - scale(vec<3, T, Q> const& v) + /// @see glScale man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); + + /// Build a right handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtRH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a left handed look at view matrix. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAtLH( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// Build a look at view matrix based on the default handedness. + /// + /// @param eye Position of the camera + /// @param center Position where the camera is looking at + /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) + /// @see gluLookAt man page + template + GLM_FUNC_DECL mat<4, 4, T, Q> lookAt( + vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); + + /// @} +}//namespace glm + +#include "matrix_transform.inl" diff --git a/thirdparty/glm/ext/matrix_transform.inl b/thirdparty/glm/ext/matrix_transform.inl new file mode 100644 index 0000000..a415157 --- /dev/null +++ b/thirdparty/glm/ext/matrix_transform.inl @@ -0,0 +1,152 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType identity() + { + return detail::init_gentype::GENTYPE>::identity(); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(m); + Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> axis(normalize(v)); + vec<3, T, Q> temp((T(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + mat<4, 4, T, Q> Result; + + vec<3, T, Q> axis = normalize(v); + + Result[0][0] = c + (static_cast(1) - c) * axis.x * axis.x; + Result[0][1] = (static_cast(1) - c) * axis.x * axis.y + s * axis.z; + Result[0][2] = (static_cast(1) - c) * axis.x * axis.z - s * axis.y; + Result[0][3] = static_cast(0); + + Result[1][0] = (static_cast(1) - c) * axis.y * axis.x - s * axis.z; + Result[1][1] = c + (static_cast(1) - c) * axis.y * axis.y; + Result[1][2] = (static_cast(1) - c) * axis.y * axis.z + s * axis.x; + Result[1][3] = static_cast(0); + + Result[2][0] = (static_cast(1) - c) * axis.z * axis.x + s * axis.y; + Result[2][1] = (static_cast(1) - c) * axis.z * axis.y - s * axis.x; + Result[2][2] = c + (static_cast(1) - c) * axis.z * axis.z; + Result[2][3] = static_cast(0); + + Result[3] = vec<4, T, Q>(0, 0, 0, 1); + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2] * v[2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) + { + mat<4, 4, T, Q> Result(T(1)); + Result[0][0] = v.x; + Result[1][1] = v.y; + Result[2][2] = v.z; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(f, up))); + vec<3, T, Q> const u(cross(s, f)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] =-f.x; + Result[1][2] =-f.y; + Result[2][2] =-f.z; + Result[3][0] =-dot(s, eye); + Result[3][1] =-dot(u, eye); + Result[3][2] = dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + vec<3, T, Q> const f(normalize(center - eye)); + vec<3, T, Q> const s(normalize(cross(up, f))); + vec<3, T, Q> const u(cross(f, s)); + + mat<4, 4, T, Q> Result(1); + Result[0][0] = s.x; + Result[1][0] = s.y; + Result[2][0] = s.z; + Result[0][1] = u.x; + Result[1][1] = u.y; + Result[2][1] = u.z; + Result[0][2] = f.x; + Result[1][2] = f.y; + Result[2][2] = f.z; + Result[3][0] = -dot(s, eye); + Result[3][1] = -dot(u, eye); + Result[3][2] = -dot(f, eye); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) + { + GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) + return lookAtLH(eye, center, up); + else + return lookAtRH(eye, center, up); + } +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x2.hpp b/thirdparty/glm/ext/matrix_uint2x2.hpp new file mode 100644 index 0000000..034771a --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x2.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint2x2 +/// @file glm/ext/matrix_uint2x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x2 GLM_EXT_matrix_uint2x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x2 + /// @{ + + /// Unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2 + typedef mat<2, 2, uint, defaultp> umat2x2; + + /// Unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2 + typedef mat<2, 2, uint, defaultp> umat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x2_sized.hpp b/thirdparty/glm/ext/matrix_uint2x2_sized.hpp new file mode 100644 index 0000000..4555324 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x2_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint2x2_sized +/// @file glm/ext/matrix_uint2x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x2_sized GLM_EXT_matrix_uint2x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x2_sized + /// @{ + + /// 8 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint8, defaultp> u8mat2x2; + + /// 16 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint16, defaultp> u16mat2x2; + + /// 32 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint32, defaultp> u32mat2x2; + + /// 64 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint64, defaultp> u64mat2x2; + + + /// 8 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint8, defaultp> u8mat2; + + /// 16 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint16, defaultp> u16mat2; + + /// 32 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint32, defaultp> u32mat2; + + /// 64 bit unsigned integer 2x2 matrix. + /// + /// @see ext_matrix_uint2x2_sized + typedef mat<2, 2, uint64, defaultp> u64mat2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x3.hpp b/thirdparty/glm/ext/matrix_uint2x3.hpp new file mode 100644 index 0000000..7de62f6 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint2x3 +/// @file glm/ext/matrix_uint2x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int2x3 GLM_EXT_matrix_uint2x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x3 + /// @{ + + /// Unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3 + typedef mat<2, 3, uint, defaultp> umat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x3_sized.hpp b/thirdparty/glm/ext/matrix_uint2x3_sized.hpp new file mode 100644 index 0000000..db7939c --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint2x3_sized +/// @file glm/ext/matrix_uint2x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x3_sized GLM_EXT_matrix_uint2x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x3_sized + /// @{ + + /// 8 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint8, defaultp> u8mat2x3; + + /// 16 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint16, defaultp> u16mat2x3; + + /// 32 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint32, defaultp> u32mat2x3; + + /// 64 bit unsigned integer 2x3 matrix. + /// + /// @see ext_matrix_uint2x3_sized + typedef mat<2, 3, uint64, defaultp> u64mat2x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x4.hpp b/thirdparty/glm/ext/matrix_uint2x4.hpp new file mode 100644 index 0000000..0f99350 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint2x4 +/// @file glm/ext/matrix_uint2x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x4 GLM_EXT_matrix_int2x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x4 + /// @{ + + /// Unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4 + typedef mat<2, 4, uint, defaultp> umat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint2x4_sized.hpp b/thirdparty/glm/ext/matrix_uint2x4_sized.hpp new file mode 100644 index 0000000..5cb8e54 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint2x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint2x4_sized +/// @file glm/ext/matrixu_uint2x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint2x4_sized GLM_EXT_matrix_uint2x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint2x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint2x4_sized + /// @{ + + /// 8 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint8, defaultp> u8mat2x4; + + /// 16 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint16, defaultp> u16mat2x4; + + /// 32 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint32, defaultp> u32mat2x4; + + /// 64 bit unsigned integer 2x4 matrix. + /// + /// @see ext_matrix_uint2x4_sized + typedef mat<2, 4, uint64, defaultp> u64mat2x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x2.hpp b/thirdparty/glm/ext/matrix_uint3x2.hpp new file mode 100644 index 0000000..47f4873 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint3x2 +/// @file glm/ext/matrix_uint3x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_int3x2 GLM_EXT_matrix_uint3x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x2 + /// @{ + + /// Unsigned integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2 + typedef mat<3, 2, uint, defaultp> umat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x2_sized.hpp b/thirdparty/glm/ext/matrix_uint3x2_sized.hpp new file mode 100644 index 0000000..c81af8f --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint3x2_sized +/// @file glm/ext/matrix_uint3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x2_sized GLM_EXT_matrix_uint3x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x2_sized + /// @{ + + /// 8 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint8, defaultp> u8mat3x2; + + /// 16 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint16, defaultp> u16mat3x2; + + /// 32 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint32, defaultp> u32mat3x2; + + /// 64 bit signed integer 3x2 matrix. + /// + /// @see ext_matrix_uint3x2_sized + typedef mat<3, 2, uint64, defaultp> u64mat3x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x3.hpp b/thirdparty/glm/ext/matrix_uint3x3.hpp new file mode 100644 index 0000000..1004c0d --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x3.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint3x3 +/// @file glm/ext/matrix_uint3x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x3 GLM_EXT_matrix_uint3x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x3 + /// @{ + + /// Unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3 + typedef mat<3, 3, uint, defaultp> umat3x3; + + /// Unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3 + typedef mat<3, 3, uint, defaultp> umat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x3_sized.hpp b/thirdparty/glm/ext/matrix_uint3x3_sized.hpp new file mode 100644 index 0000000..41a8be7 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x3_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint3x3_sized +/// @file glm/ext/matrix_uint3x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x3_sized GLM_EXT_matrix_uint3x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x3_sized + /// @{ + + /// 8 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint8, defaultp> u8mat3x3; + + /// 16 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint16, defaultp> u16mat3x3; + + /// 32 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint32, defaultp> u32mat3x3; + + /// 64 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint64, defaultp> u64mat3x3; + + + /// 8 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint8, defaultp> u8mat3; + + /// 16 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint16, defaultp> u16mat3; + + /// 32 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint32, defaultp> u32mat3; + + /// 64 bit unsigned integer 3x3 matrix. + /// + /// @see ext_matrix_uint3x3_sized + typedef mat<3, 3, uint64, defaultp> u64mat3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x4.hpp b/thirdparty/glm/ext/matrix_uint3x4.hpp new file mode 100644 index 0000000..c6dd78c --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x4.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint3x4 +/// @file glm/ext/matrix_uint3x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x4 GLM_EXT_matrix_uint3x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x4 + /// @{ + + /// Signed integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4 + typedef mat<3, 4, uint, defaultp> umat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint3x4_sized.hpp b/thirdparty/glm/ext/matrix_uint3x4_sized.hpp new file mode 100644 index 0000000..2ce28ad --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint3x4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint3x4_sized +/// @file glm/ext/matrix_uint3x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint3x4_sized GLM_EXT_matrix_uint3x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat3x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint3x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint3x4_sized + /// @{ + + /// 8 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint8, defaultp> u8mat3x4; + + /// 16 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint16, defaultp> u16mat3x4; + + /// 32 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint32, defaultp> u32mat3x4; + + /// 64 bit unsigned integer 3x4 matrix. + /// + /// @see ext_matrix_uint3x4_sized + typedef mat<3, 4, uint64, defaultp> u64mat3x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x2.hpp b/thirdparty/glm/ext/matrix_uint4x2.hpp new file mode 100644 index 0000000..0446f57 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x2.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint4x2 +/// @file glm/ext/matrix_uint4x2.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x2 GLM_EXT_matrix_uint4x2 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x2 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x2 + /// @{ + + /// Unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2 + typedef mat<4, 2, uint, defaultp> umat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x2_sized.hpp b/thirdparty/glm/ext/matrix_uint4x2_sized.hpp new file mode 100644 index 0000000..57a66bf --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint4x2_sized +/// @file glm/ext/matrix_uint4x2_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x2_sized GLM_EXT_matrix_uint4x2_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x2_sized + /// @{ + + /// 8 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint8, defaultp> u8mat4x2; + + /// 16 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint16, defaultp> u16mat4x2; + + /// 32 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint32, defaultp> u32mat4x2; + + /// 64 bit unsigned integer 4x2 matrix. + /// + /// @see ext_matrix_uint4x2_sized + typedef mat<4, 2, uint64, defaultp> u64mat4x2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x3.hpp b/thirdparty/glm/ext/matrix_uint4x3.hpp new file mode 100644 index 0000000..54c24e4 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x3.hpp @@ -0,0 +1,33 @@ +/// @ref ext_matrix_uint4x3 +/// @file glm/ext/matrix_uint4x3.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x3 GLM_EXT_matrix_uint4x3 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x3 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x3 + /// @{ + + /// Unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3 + typedef mat<4, 3, uint, defaultp> umat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x3_sized.hpp b/thirdparty/glm/ext/matrix_uint4x3_sized.hpp new file mode 100644 index 0000000..2e61124 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_matrix_uint4x3_sized +/// @file glm/ext/matrix_uint4x3_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x3_sized GLM_EXT_matrix_uint4x3_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x3_sized + /// @{ + + /// 8 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint8, defaultp> u8mat4x3; + + /// 16 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint16, defaultp> u16mat4x3; + + /// 32 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint32, defaultp> u32mat4x3; + + /// 64 bit unsigned integer 4x3 matrix. + /// + /// @see ext_matrix_uint4x3_sized + typedef mat<4, 3, uint64, defaultp> u64mat4x3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x4.hpp b/thirdparty/glm/ext/matrix_uint4x4.hpp new file mode 100644 index 0000000..5cc8455 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x4.hpp @@ -0,0 +1,38 @@ +/// @ref ext_matrix_uint4x4 +/// @file glm/ext/matrix_uint4x4.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x4 GLM_EXT_matrix_uint4x4 +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x4 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x4 + /// @{ + + /// Unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4 + typedef mat<4, 4, uint, defaultp> umat4x4; + + /// Unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4 + typedef mat<4, 4, uint, defaultp> umat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/matrix_uint4x4_sized.hpp b/thirdparty/glm/ext/matrix_uint4x4_sized.hpp new file mode 100644 index 0000000..bb10bd2 --- /dev/null +++ b/thirdparty/glm/ext/matrix_uint4x4_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_matrix_uint4x4_sized +/// @file glm/ext/matrix_uint4x4_sized.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_matrix_uint4x4_sized GLM_EXT_matrix_uint4x4_sized +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat4x4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_matrix_uint4x4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_matrix_uint4x4_sized + /// @{ + + /// 8 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint8, defaultp> u8mat4x4; + + /// 16 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint16, defaultp> u16mat4x4; + + /// 32 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint32, defaultp> u32mat4x4; + + /// 64 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint64, defaultp> u64mat4x4; + + + /// 8 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint8, defaultp> u8mat4; + + /// 16 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint16, defaultp> u16mat4; + + /// 32 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint32, defaultp> u32mat4; + + /// 64 bit unsigned integer 4x4 matrix. + /// + /// @see ext_matrix_uint4x4_sized + typedef mat<4, 4, uint64, defaultp> u64mat4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/quaternion_common.hpp b/thirdparty/glm/ext/quaternion_common.hpp new file mode 100644 index 0000000..f519d55 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_common.hpp @@ -0,0 +1,135 @@ +/// @ref ext_quaternion_common +/// @file glm/ext/quaternion_common.hpp +/// +/// @defgroup ext_quaternion_common GLM_EXT_quaternion_common +/// @ingroup ext +/// +/// Provides common functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_common +/// @see ext_vector_common +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../ext/scalar_constants.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_common + /// @{ + + /// Spherical linear interpolation of two quaternions. + /// The interpolation is oriented and the rotation is performed at constant speed. + /// For short path spherical linear interpolation, use the slerp function. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + /// + /// @see - slerp(qua const& x, qua const& y, T const& a) + template + GLM_FUNC_DECL qua mix(qua const& x, qua const& y, T a); + + /// Linear interpolation of two quaternions. + /// The interpolation is oriented. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined in the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua lerp(qua const& x, qua const& y, T a); + + /// Spherical linear interpolation of two quaternions. + /// The interpolation always take the short path and the rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a); + + /// Spherical linear interpolation of two quaternions with multiple spins over rotation axis. + /// The interpolation always take the short path when the spin count is positive and long path + /// when count is negative. Rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// @param k Additional spin count. If Value is negative interpolation will be on "long" path. + /// + /// @tparam T A floating-point scalar type + /// @tparam S An integer scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a, S k); + + /// Returns the q conjugate. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua conjugate(qua const& q); + + /// Returns the q inverse. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua inverse(qua const& q); + + /// Returns true if x holds a NaN (not a number) + /// representation in the underlying implementation's set of + /// floating point representations. Returns false otherwise, + /// including for implementations with no NaN + /// representations. + /// + /// /!\ When using compiler fast math, this function may fail. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isnan(qua const& x); + + /// Returns true if x holds a positive infinity or negative + /// infinity representation in the underlying implementation's + /// set of floating point representations. Returns false + /// otherwise, including for implementations with no infinity + /// representations. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> isinf(qua const& x); + + /// @} +} //namespace glm + +#include "quaternion_common.inl" diff --git a/thirdparty/glm/ext/quaternion_common.inl b/thirdparty/glm/ext/quaternion_common.inl new file mode 100644 index 0000000..0e4a3bb --- /dev/null +++ b/thirdparty/glm/ext/quaternion_common.inl @@ -0,0 +1,144 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua mix(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mix' only accept floating-point inputs"); + + T const cosTheta = dot(x, y); + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, y.w, a), + mix(x.x, y.x, a), + mix(x.y, y.y, a), + mix(x.z, y.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua lerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'lerp' only accept floating-point inputs"); + + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + + return x * (static_cast(1) - a) + (y * a); + } + + template + GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + + qua z = y; + + T cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if(cosTheta < static_cast(0)) + { + z = -y; + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a, S k) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'slerp' only accept integer for spin count"); + + qua z = y; + + T cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if (cosTheta < static_cast(0)) + { + z = -y; + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if (cosTheta > static_cast(1) - epsilon()) + { + // Linear interpolation + return qua( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Graphics Gems III, page 96 + T angle = acos(cosTheta); + T phi = angle + k * glm::pi(); + return (sin(angle - a * phi)* x + sin(a * phi) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER qua conjugate(qua const& q) + { + return qua(q.w, -q.x, -q.y, -q.z); + } + + template + GLM_FUNC_QUALIFIER qua inverse(qua const& q) + { + return conjugate(q) / dot(q, q); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isnan(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); + + return vec<4, bool, Q>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isinf(qua const& q) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); + + return vec<4, bool, Q>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w)); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_common_simd.inl" +#endif + diff --git a/thirdparty/glm/ext/quaternion_common_simd.inl b/thirdparty/glm/ext/quaternion_common_simd.inl new file mode 100644 index 0000000..ddfc8a4 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_common_simd.inl @@ -0,0 +1,18 @@ +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +namespace glm{ +namespace detail +{ + template + struct compute_dot, float, true> + { + static GLM_FUNC_QUALIFIER float call(qua const& x, qua const& y) + { + return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); + } + }; +}//namespace detail +}//namespace glm + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/thirdparty/glm/ext/quaternion_double.hpp b/thirdparty/glm/ext/quaternion_double.hpp new file mode 100644 index 0000000..63b24de --- /dev/null +++ b/thirdparty/glm/ext/quaternion_double.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_double +/// @file glm/ext/quaternion_double.hpp +/// +/// @defgroup ext_quaternion_double GLM_EXT_quaternion_double +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double + /// @{ + + /// Quaternion of double-precision floating-point numbers. + typedef qua dquat; + + /// @} +} //namespace glm + diff --git a/thirdparty/glm/ext/quaternion_double_precision.hpp b/thirdparty/glm/ext/quaternion_double_precision.hpp new file mode 100644 index 0000000..8aa24a1 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_double_precision.hpp @@ -0,0 +1,42 @@ +/// @ref ext_quaternion_double_precision +/// @file glm/ext/quaternion_double_precision.hpp +/// +/// @defgroup ext_quaternion_double_precision GLM_EXT_quaternion_double_precision +/// @ingroup ext +/// +/// Exposes double-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_double_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_double_precision + /// @{ + + /// Quaternion of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua lowp_dquat; + + /// Quaternion of medium double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua mediump_dquat; + + /// Quaternion of high double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. + /// + /// @see ext_quaternion_double_precision + typedef qua highp_dquat; + + /// @} +} //namespace glm + diff --git a/thirdparty/glm/ext/quaternion_exponential.hpp b/thirdparty/glm/ext/quaternion_exponential.hpp new file mode 100644 index 0000000..affe297 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_exponential.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_exponential +/// @file glm/ext/quaternion_exponential.hpp +/// +/// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential +/// @ingroup ext +/// +/// Provides exponential functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_exponential +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_exponential extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Returns a exponential of a quaternion. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua exp(qua const& q); + + /// Returns a logarithm of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua log(qua const& q); + + /// Returns a quaternion raised to a power. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua pow(qua const& q, T y); + + /// Returns the square root of a quaternion + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua sqrt(qua const& q); + + /// @} +} //namespace glm + +#include "quaternion_exponential.inl" diff --git a/thirdparty/glm/ext/quaternion_exponential.inl b/thirdparty/glm/ext/quaternion_exponential.inl new file mode 100644 index 0000000..8456c00 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_exponential.inl @@ -0,0 +1,85 @@ +#include "scalar_constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua exp(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T const Angle = glm::length(u); + if (Angle < epsilon()) + return qua(); + + vec<3, T, Q> const v(u / Angle); + return qua(cos(Angle), sin(Angle) * v); + } + + template + GLM_FUNC_QUALIFIER qua log(qua const& q) + { + vec<3, T, Q> u(q.x, q.y, q.z); + T Vec3Len = length(u); + + if (Vec3Len < epsilon()) + { + if(q.w > static_cast(0)) + return qua(log(q.w), static_cast(0), static_cast(0), static_cast(0)); + else if(q.w < static_cast(0)) + return qua(log(-q.w), pi(), static_cast(0), static_cast(0)); + else + return qua(std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); + } + else + { + T t = atan(Vec3Len, T(q.w)) / Vec3Len; + T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w; + return qua(static_cast(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z); + } + } + + template + GLM_FUNC_QUALIFIER qua pow(qua const& x, T y) + { + //Raising to the power of 0 should yield 1 + //Needed to prevent a division by 0 error later on + if(y > -epsilon() && y < epsilon()) + return qua(1,0,0,0); + + //To deal with non-unit quaternions + T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w); + + T Angle; + if(abs(x.w / magnitude) > cos_one_over_two()) + { + //Scalar component is close to 1; using it to recover angle would lose precision + //Instead, we use the non-scalar components since sin() is accurate around 0 + + //Prevent a division by 0 error later on + T VectorMagnitude = x.x * x.x + x.y * x.y + x.z * x.z; + if (glm::abs(VectorMagnitude - static_cast(0)) < glm::epsilon()) { + //Equivalent to raising a real number to a power + return qua(pow(x.w, y), 0, 0, 0); + } + + Angle = asin(sqrt(VectorMagnitude) / magnitude); + } + else + { + //Scalar component is small, shouldn't cause loss of precision + Angle = acos(x.w / magnitude); + } + + T NewAngle = Angle * y; + T Div = sin(NewAngle) / sin(Angle); + T Mag = pow(magnitude, y - static_cast(1)); + return qua(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag); + } + + template + GLM_FUNC_QUALIFIER qua sqrt(qua const& x) + { + return pow(x, static_cast(0.5)); + } +}//namespace glm + + diff --git a/thirdparty/glm/ext/quaternion_float.hpp b/thirdparty/glm/ext/quaternion_float.hpp new file mode 100644 index 0000000..ca42a60 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_float.hpp @@ -0,0 +1,39 @@ +/// @ref ext_quaternion_float +/// @file glm/ext/quaternion_float.hpp +/// +/// @defgroup ext_quaternion_float GLM_EXT_quaternion_float +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_double +/// @see ext_quaternion_float_precision +/// @see ext_quaternion_common +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float + /// @{ + + /// Quaternion of single-precision floating-point numbers. + typedef qua quat; + + /// @} +} //namespace glm + diff --git a/thirdparty/glm/ext/quaternion_float_precision.hpp b/thirdparty/glm/ext/quaternion_float_precision.hpp new file mode 100644 index 0000000..f9e4f5c --- /dev/null +++ b/thirdparty/glm/ext/quaternion_float_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_quaternion_float_precision +/// @file glm/ext/quaternion_float_precision.hpp +/// +/// @defgroup ext_quaternion_float_precision GLM_EXT_quaternion_float_precision +/// @ingroup ext +/// +/// Exposes single-precision floating point quaternion type with various precision in term of ULPs. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependency: +#include "../detail/type_quat.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_float_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_float_precision + /// @{ + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua lowp_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua mediump_quat; + + /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef qua highp_quat; + + /// @} +} //namespace glm + diff --git a/thirdparty/glm/ext/quaternion_geometric.hpp b/thirdparty/glm/ext/quaternion_geometric.hpp new file mode 100644 index 0000000..6d98bbe --- /dev/null +++ b/thirdparty/glm/ext/quaternion_geometric.hpp @@ -0,0 +1,70 @@ +/// @ref ext_quaternion_geometric +/// @file glm/ext/quaternion_geometric.hpp +/// +/// @defgroup ext_quaternion_geometric GLM_EXT_quaternion_geometric +/// @ingroup ext +/// +/// Provides geometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see core_geometric +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../ext/vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_geometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_geometric + /// @{ + + /// Returns the norm of a quaternions + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T length(qua const& q); + + /// Returns the normalized quaternion. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL qua normalize(qua const& q); + + /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ... + /// + /// @tparam T Floating-point scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_DECL T dot(qua const& x, qua const& y); + + /// Compute a cross product. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_geometric + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2); + + /// @} +} //namespace glm + +#include "quaternion_geometric.inl" diff --git a/thirdparty/glm/ext/quaternion_geometric.inl b/thirdparty/glm/ext/quaternion_geometric.inl new file mode 100644 index 0000000..e155ac5 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_geometric.inl @@ -0,0 +1,36 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T dot(qua const& x, qua const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); + return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER T length(qua const& q) + { + return glm::sqrt(dot(q, q)); + } + + template + GLM_FUNC_QUALIFIER qua normalize(qua const& q) + { + T len = length(q); + if(len <= static_cast(0)) // Problem + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + T oneOverLen = static_cast(1) / len; + return qua(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen); + } + + template + GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2) + { + return qua( + q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, + q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, + q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, + q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x); + } +}//namespace glm + diff --git a/thirdparty/glm/ext/quaternion_relational.hpp b/thirdparty/glm/ext/quaternion_relational.hpp new file mode 100644 index 0000000..7aa121d --- /dev/null +++ b/thirdparty/glm/ext/quaternion_relational.hpp @@ -0,0 +1,62 @@ +/// @ref ext_quaternion_relational +/// @file glm/ext/quaternion_relational.hpp +/// +/// @defgroup ext_quaternion_relational GLM_EXT_quaternion_relational +/// @ingroup ext +/// +/// Exposes comparison functions for quaternion types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational +/// @see ext_quaternion_float +/// @see ext_quaternion_double + +#pragma once + +// Dependency: +#include "../vector_relational.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_relational + /// @{ + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon); + + /// @} +} //namespace glm + +#include "quaternion_relational.inl" diff --git a/thirdparty/glm/ext/quaternion_relational.inl b/thirdparty/glm/ext/quaternion_relational.inl new file mode 100644 index 0000000..b1713e9 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_relational.inl @@ -0,0 +1,35 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] == y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] != y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm + diff --git a/thirdparty/glm/ext/quaternion_transform.hpp b/thirdparty/glm/ext/quaternion_transform.hpp new file mode 100644 index 0000000..a9cc5c2 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_transform.hpp @@ -0,0 +1,47 @@ +/// @ref ext_quaternion_transform +/// @file glm/ext/quaternion_transform.hpp +/// +/// @defgroup ext_quaternion_transform GLM_EXT_quaternion_transform +/// @ingroup ext +/// +/// Provides transformation functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_trigonometric + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../trigonometric.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_transform extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_transform + /// @{ + + /// Rotates a quaternion from a vector of 3 components axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Axis of the rotation + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& axis); + /// @} +} //namespace glm + +#include "quaternion_transform.inl" diff --git a/thirdparty/glm/ext/quaternion_transform.inl b/thirdparty/glm/ext/quaternion_transform.inl new file mode 100644 index 0000000..b87ecb6 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_transform.inl @@ -0,0 +1,24 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& v) + { + vec<3, T, Q> Tmp = v; + + // Axis of rotation must be normalised + T len = glm::length(Tmp); + if(abs(len - static_cast(1)) > static_cast(0.001)) + { + T oneOverLen = static_cast(1) / len; + Tmp.x *= oneOverLen; + Tmp.y *= oneOverLen; + Tmp.z *= oneOverLen; + } + + T const AngleRad(angle); + T const Sin = sin(AngleRad * static_cast(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + } +}//namespace glm + diff --git a/thirdparty/glm/ext/quaternion_trigonometric.hpp b/thirdparty/glm/ext/quaternion_trigonometric.hpp new file mode 100644 index 0000000..76cea27 --- /dev/null +++ b/thirdparty/glm/ext/quaternion_trigonometric.hpp @@ -0,0 +1,63 @@ +/// @ref ext_quaternion_trigonometric +/// @file glm/ext/quaternion_trigonometric.hpp +/// +/// @defgroup ext_quaternion_trigonometric GLM_EXT_quaternion_trigonometric +/// @ingroup ext +/// +/// Provides trigonometric functions for quaternion types +/// +/// Include to use the features of this extension. +/// +/// @see ext_quaternion_float +/// @see ext_quaternion_double +/// @see ext_quaternion_exponential +/// @see ext_quaternion_geometric +/// @see ext_quaternion_relational +/// @see ext_quaternion_transform + +#pragma once + +// Dependency: +#include "../trigonometric.hpp" +#include "../exponential.hpp" +#include "scalar_constants.hpp" +#include "vector_relational.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_quaternion_trigonometric extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_quaternion_trigonometric + /// @{ + + /// Returns the quaternion rotation angle. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL T angle(qua const& x); + + /// Returns the q rotation axis. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL vec<3, T, Q> axis(qua const& x); + + /// Build a quaternion from an angle and a normalized axis. + /// + /// @param angle Angle expressed in radians. + /// @param axis Axis of the quaternion, must be normalized. + /// + /// @tparam T A floating-point scalar type + /// @tparam Q A value from qualifier enum + template + GLM_FUNC_DECL qua angleAxis(T const& angle, vec<3, T, Q> const& axis); + + /// @} +} //namespace glm + +#include "quaternion_trigonometric.inl" diff --git a/thirdparty/glm/ext/quaternion_trigonometric.inl b/thirdparty/glm/ext/quaternion_trigonometric.inl new file mode 100644 index 0000000..06b7c4c --- /dev/null +++ b/thirdparty/glm/ext/quaternion_trigonometric.inl @@ -0,0 +1,34 @@ +#include "scalar_constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T angle(qua const& x) + { + if (abs(x.w) > cos_one_over_two()) + { + return asin(sqrt(x.x * x.x + x.y * x.y + x.z * x.z)) * static_cast(2); + } + + return acos(x.w) * static_cast(2); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> axis(qua const& x) + { + T const tmp1 = static_cast(1) - x.w * x.w; + if(tmp1 <= static_cast(0)) + return vec<3, T, Q>(0, 0, 1); + T const tmp2 = static_cast(1) / sqrt(tmp1); + return vec<3, T, Q>(x.x * tmp2, x.y * tmp2, x.z * tmp2); + } + + template + GLM_FUNC_QUALIFIER qua angleAxis(T const& angle, vec<3, T, Q> const& v) + { + T const a(angle); + T const s = glm::sin(a * static_cast(0.5)); + + return qua(glm::cos(a * static_cast(0.5)), v * s); + } +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_common.hpp b/thirdparty/glm/ext/scalar_common.hpp new file mode 100644 index 0000000..aa5a180 --- /dev/null +++ b/thirdparty/glm/ext/scalar_common.hpp @@ -0,0 +1,157 @@ +/// @ref ext_scalar_common +/// @file glm/ext/scalar_common.hpp +/// +/// @defgroup ext_scalar_common GLM_EXT_scalar_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 scalar parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_func_common +/// @see ext_vector_common + +#pragma once + +// Dependency: +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_common + /// @{ + + /// Returns the minimum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T min(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T min(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 3 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T max(T a, T b, T c); + + /// Returns the maximum component-wise values of 4 inputs + /// + /// @tparam T A floating-point scalar type. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL T max(T a, T b, T c, T d); + + /// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b); + + /// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b, T c); + + /// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmin documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmin(T a, T b, T c, T d); + + /// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b); + + /// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b, T C); + + /// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam T A floating-point scalar type. + /// + /// @see std::fmax documentation + /// @see ext_scalar_common + template + GLM_FUNC_DECL T fmax(T a, T b, T C, T D); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common + template + GLM_FUNC_DECL genType fclamp(genType x, genType minVal, genType maxVal); + + /// Simulate GL_CLAMP OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType clamp(genType const& Texcoord); + + /// Simulate GL_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType repeat(genType const& Texcoord); + + /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord); + + /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode + /// + /// @tparam genType Floating-point scalar types. + /// + /// @see ext_scalar_common extension. + template + GLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord); + + /// @} +}//namespace glm + +#include "scalar_common.inl" diff --git a/thirdparty/glm/ext/scalar_common.inl b/thirdparty/glm/ext/scalar_common.inl new file mode 100644 index 0000000..7d9207a --- /dev/null +++ b/thirdparty/glm/ext/scalar_common.inl @@ -0,0 +1,152 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c) + { + return glm::min(glm::min(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T min(T a, T b, T c, T d) + { + return glm::min(glm::min(a, b), glm::min(c, d)); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c) + { + return glm::max(glm::max(a, b), c); + } + + template + GLM_FUNC_QUALIFIER T max(T a, T b, T c, T d) + { + return glm::max(glm::max(a, b), glm::max(c, d)); + } + +# if GLM_HAS_CXX11_STL + using std::fmin; +# else + template + GLM_FUNC_QUALIFIER T fmin(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return b; + return min(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c); + if (isnan(b)) + return fmin(a, c); + if (isnan(c)) + return min(a, b); + return min(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); + + if (isnan(a)) + return fmin(b, c, d); + if (isnan(b)) + return min(a, fmin(c, d)); + if (isnan(c)) + return fmin(min(a, b), d); + if (isnan(d)) + return min(a, b, c); + return min(a, b, c, d); + } + + +# if GLM_HAS_CXX11_STL + using std::fmax; +# else + template + GLM_FUNC_QUALIFIER T fmax(T a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return b; + return max(a, b); + } +# endif + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c); + if (isnan(b)) + return fmax(a, c); + if (isnan(c)) + return max(a, b); + return max(a, b, c); + } + + template + GLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); + + if (isnan(a)) + return fmax(b, c, d); + if (isnan(b)) + return max(a, fmax(c, d)); + if (isnan(c)) + return fmax(max(a, b), d); + if (isnan(d)) + return max(a, b, c); + return max(a, b, c, d); + } + + // fclamp + template + GLM_FUNC_QUALIFIER genType fclamp(genType x, genType minVal, genType maxVal) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fclamp' only accept floating-point or integer inputs"); + return fmin(fmax(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER genType clamp(genType const& Texcoord) + { + return glm::clamp(Texcoord, static_cast(0), static_cast(1)); + } + + template + GLM_FUNC_QUALIFIER genType repeat(genType const& Texcoord) + { + return glm::fract(Texcoord); + } + + template + GLM_FUNC_QUALIFIER genType mirrorClamp(genType const& Texcoord) + { + return glm::fract(glm::abs(Texcoord)); + } + + template + GLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord) + { + genType const Abs = glm::abs(Texcoord); + genType const Clamp = glm::mod(glm::floor(Abs), static_cast(2)); + genType const Floor = glm::floor(Abs); + genType const Rest = Abs - Floor; + genType const Mirror = Clamp + Rest; + return mix(Rest, static_cast(1) - Rest, Mirror >= static_cast(1)); + } +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_constants.hpp b/thirdparty/glm/ext/scalar_constants.hpp new file mode 100644 index 0000000..74e210d --- /dev/null +++ b/thirdparty/glm/ext/scalar_constants.hpp @@ -0,0 +1,40 @@ +/// @ref ext_scalar_constants +/// @file glm/ext/scalar_constants.hpp +/// +/// @defgroup ext_scalar_constants GLM_EXT_scalar_constants +/// @ingroup ext +/// +/// Provides a list of constants and precomputed useful values. +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_constants + /// @{ + + /// Return the epsilon constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType epsilon(); + + /// Return the pi constant for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType pi(); + + /// Return the value of cos(1 / 2) for floating point types. + template + GLM_FUNC_DECL GLM_CONSTEXPR genType cos_one_over_two(); + + /// @} +} //namespace glm + +#include "scalar_constants.inl" diff --git a/thirdparty/glm/ext/scalar_constants.inl b/thirdparty/glm/ext/scalar_constants.inl new file mode 100644 index 0000000..b475adf --- /dev/null +++ b/thirdparty/glm/ext/scalar_constants.inl @@ -0,0 +1,24 @@ +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'epsilon' only accepts floating-point inputs"); + return std::numeric_limits::epsilon(); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi() + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'pi' only accepts floating-point inputs"); + return static_cast(3.14159265358979323846264338327950288); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType cos_one_over_two() + { + return genType(0.877582561890372716130286068203503191); + } +} //namespace glm diff --git a/thirdparty/glm/ext/scalar_int_sized.hpp b/thirdparty/glm/ext/scalar_int_sized.hpp new file mode 100644 index 0000000..8e9c511 --- /dev/null +++ b/thirdparty/glm/ext/scalar_int_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_int_sized +/// @file glm/ext/scalar_int_sized.hpp +/// +/// @defgroup ext_scalar_int_sized GLM_EXT_scalar_int_sized +/// @ingroup ext +/// +/// Exposes sized signed integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_int_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; +# else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; +#endif// + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_int_sized + /// @{ + + /// 8 bit signed integer type. + typedef detail::int8 int8; + + /// 16 bit signed integer type. + typedef detail::int16 int16; + + /// 32 bit signed integer type. + typedef detail::int32 int32; + + /// 64 bit signed integer type. + typedef detail::int64 int64; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_integer.hpp b/thirdparty/glm/ext/scalar_integer.hpp new file mode 100644 index 0000000..a2ca8a2 --- /dev/null +++ b/thirdparty/glm/ext/scalar_integer.hpp @@ -0,0 +1,92 @@ +/// @ref ext_scalar_integer +/// @file glm/ext/scalar_integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_scalar_integer GLM_EXT_scalar_integer +/// @ingroup ext +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../detail/type_float.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_integer + /// @{ + + /// Return true if the value is a power of two number. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL bool isPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType nextPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType prevPowerOfTwo(genIUType v); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam genIUType Integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType nextMultiple(genIUType v, genIUType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genIUType Integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL genIUType prevMultiple(genIUType v, genIUType Multiple); + + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see ext_scalar_integer + template + GLM_FUNC_DECL int findNSB(genIUType x, int significantBitCount); + + /// @} +} //namespace glm + +#include "scalar_integer.inl" diff --git a/thirdparty/glm/ext/scalar_integer.inl b/thirdparty/glm/ext/scalar_integer.inl new file mode 100644 index 0000000..efba960 --- /dev/null +++ b/thirdparty/glm/ext/scalar_integer.inl @@ -0,0 +1,243 @@ +#include "../integer.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T) + { + return v; + } + }; + + template + struct compute_ceilShift + { + GLM_FUNC_QUALIFIER static vec call(vec const& v, T Shift) + { + return v | (v >> Shift); + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec const Sign(sign(x)); + + vec v(abs(x)); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return (v + static_cast(1)) * Sign; + } + }; + + template + struct compute_ceilPowerOfTwo + { + GLM_FUNC_QUALIFIER static vec call(vec const& x) + { + GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); + + vec v(x); + + v = v - static_cast(1); + v = v | (v >> static_cast(1)); + v = v | (v >> static_cast(2)); + v = v | (v >> static_cast(4)); + v = compute_ceilShift= 2>::call(v, 8); + v = compute_ceilShift= 4>::call(v, 16); + v = compute_ceilShift= 8>::call(v, 32); + return v + static_cast(1); + } + }; + + template + struct compute_ceilMultiple{}; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source > genType(0)) + return Source + (Multiple - std::fmod(Source, Multiple)); + else + return Source + std::fmod(-Source, Multiple); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + }; + + template<> + struct compute_ceilMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + assert(Multiple > genType(0)); + if(Source > genType(0)) + { + genType Tmp = Source - genType(1); + return Tmp + (Multiple - (Tmp % Multiple)); + } + else + return Source + (-Source % Multiple); + } + }; + + template + struct compute_floorMultiple{}; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + return Source - std::fmod(Source, Multiple) - Multiple; + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_floorMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if(Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool isPowerOfTwo(genIUType Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); + + genIUType const Result = glm::abs(Value); + return !(Result & (Result - 1)); + } + + template + GLM_FUNC_QUALIFIER genIUType nextPowerOfTwo(genIUType value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); + + return detail::compute_ceilPowerOfTwo<1, genIUType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genIUType, defaultp>(value)).x; + } + + template + GLM_FUNC_QUALIFIER genIUType prevPowerOfTwo(genIUType value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); + + return isPowerOfTwo(value) ? value : static_cast(static_cast(1) << static_cast(findMSB(value))); + } + + template + GLM_FUNC_QUALIFIER bool isMultiple(genIUType Value, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return isMultiple(vec<1, genIUType>(Value), vec<1, genIUType>(Multiple)).x; + } + + template + GLM_FUNC_QUALIFIER genIUType nextMultiple(genIUType Source, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER genIUType prevMultiple(genIUType Source, genIUType Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + if(bitCount(x) < significantBitCount) + return -1; + + genIUType const One = static_cast(1); + int bitPos = 0; + + genIUType key = x; + int nBitCount = significantBitCount; + int Step = sizeof(x) * 8 / 2; + while (key > One) + { + genIUType Mask = static_cast((One << Step) - One); + genIUType currentKey = key & Mask; + int currentBitCount = bitCount(currentKey); + if (nBitCount > currentBitCount) + { + nBitCount -= currentBitCount; + bitPos += Step; + key >>= static_cast(Step); + } + else + { + key = key & Mask; + } + + Step >>= 1; + } + + return static_cast(bitPos); + } +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_packing.hpp b/thirdparty/glm/ext/scalar_packing.hpp new file mode 100644 index 0000000..18b85b7 --- /dev/null +++ b/thirdparty/glm/ext/scalar_packing.hpp @@ -0,0 +1,32 @@ +/// @ref ext_scalar_packing +/// @file glm/ext/scalar_packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_scalar_packing GLM_EXT_scalar_packing +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert scalar values to packed +/// formats. + +#pragma once + +// Dependency: +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_scalar_packing + /// @{ + + + /// @} +}// namespace glm + +#include "scalar_packing.inl" diff --git a/thirdparty/glm/ext/scalar_packing.inl b/thirdparty/glm/ext/scalar_packing.inl new file mode 100644 index 0000000..e69de29 diff --git a/thirdparty/glm/ext/scalar_relational.hpp b/thirdparty/glm/ext/scalar_relational.hpp new file mode 100644 index 0000000..3076a5e --- /dev/null +++ b/thirdparty/glm/ext/scalar_relational.hpp @@ -0,0 +1,65 @@ +/// @ref ext_scalar_relational +/// @file glm/ext/scalar_relational.hpp +/// +/// @defgroup ext_scalar_relational GLM_EXT_scalar_relational +/// @ingroup ext +/// +/// Exposes comparison functions for scalar types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_vector_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_relational extension included") +#endif + +namespace glm +{ + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int ULPs); + + /// Returns the component-wise comparison between two scalars in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @param x First operand. + /// @param y Second operand. + /// @param ULPs Maximum difference in ULPs between the two operators to consider them not equal. + /// + /// @tparam genType Floating-point or integer scalar types + template + GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs); + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/thirdparty/glm/ext/scalar_relational.inl b/thirdparty/glm/ext/scalar_relational.inl new file mode 100644 index 0000000..c85583e --- /dev/null +++ b/thirdparty/glm/ext/scalar_relational.inl @@ -0,0 +1,40 @@ +#include "../common.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon) + { + return abs(x - y) > epsilon; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int MaxULPs) + { + detail::float_t const a(x); + detail::float_t const b(y); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + return false; + + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + return DiffULPs <= MaxULPs; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs) + { + return !equal(x, y, ULPs); + } +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_uint_sized.hpp b/thirdparty/glm/ext/scalar_uint_sized.hpp new file mode 100644 index 0000000..fd5267f --- /dev/null +++ b/thirdparty/glm/ext/scalar_uint_sized.hpp @@ -0,0 +1,70 @@ +/// @ref ext_scalar_uint_sized +/// @file glm/ext/scalar_uint_sized.hpp +/// +/// @defgroup ext_scalar_uint_sized GLM_EXT_scalar_uint_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer scalar types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_uint_sized extension included") +#endif + +namespace glm{ +namespace detail +{ +# if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; +# else + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; +#endif + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; + + template<> + struct is_int + { + enum test {value = ~0}; + }; +}//namespace detail + + + /// @addtogroup ext_scalar_uint_sized + /// @{ + + /// 8 bit unsigned integer type. + typedef detail::uint8 uint8; + + /// 16 bit unsigned integer type. + typedef detail::uint16 uint16; + + /// 32 bit unsigned integer type. + typedef detail::uint32 uint32; + + /// 64 bit unsigned integer type. + typedef detail::uint64 uint64; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/scalar_ulp.hpp b/thirdparty/glm/ext/scalar_ulp.hpp new file mode 100644 index 0000000..941ada3 --- /dev/null +++ b/thirdparty/glm/ext/scalar_ulp.hpp @@ -0,0 +1,74 @@ +/// @ref ext_scalar_ulp +/// @file glm/ext/scalar_ulp.hpp +/// +/// @defgroup ext_scalar_ulp GLM_EXT_scalar_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_ulp +/// @see ext_scalar_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_scalar_ulp extension included") +#endif + +namespace glm +{ + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType nextFloat(genType x); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prevFloat(genType x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType nextFloat(genType x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL genType prevFloat(genType x, int ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int floatDistance(float x, float y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @see ext_scalar_ulp + GLM_FUNC_DECL int64 floatDistance(double x, double y); + + /// @} +}//namespace glm + +#include "scalar_ulp.inl" diff --git a/thirdparty/glm/ext/scalar_ulp.inl b/thirdparty/glm/ext/scalar_ulp.inl new file mode 100644 index 0000000..308df15 --- /dev/null +++ b/thirdparty/glm/ext/scalar_ulp.inl @@ -0,0 +1,284 @@ +/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +/// +/// Developed at SunPro, a Sun Microsystems, Inc. business. +/// Permission to use, copy, modify, and distribute this +/// software is freely granted, provided that this notice +/// is preserved. + +#include "../detail/type_float.hpp" +#include "../ext/scalar_constants.hpp" +#include +#include + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(push) +# pragma warning(disable : 4127) +#endif + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +typedef union +{ + double value; + struct + { + int lsw; + int msw; + } parts; +} ieee_double_shape_type; + +#define GLM_EXTRACT_WORDS(ix0,ix1,d) \ + do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) + +#define GLM_GET_FLOAT_WORD(i,d) \ + do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ + } while (0) + +#define GLM_SET_FLOAT_WORD(d,i) \ + do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ + } while (0) + +#define GLM_INSERT_WORDS(d,ix0,ix1) \ + do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ + } while (0) + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER float nextafterf(float x, float y) + { + volatile float t; + int hx, hy, ix, iy; + + GLM_GET_FLOAT_WORD(hx, x); + GLM_GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if((ix > 0x7f800000) || // x is nan + (iy > 0x7f800000)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if(ix == 0) + { // x == 0 + GLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) + { // x > 0 + if(hx > hy) // x > y, x -= ulp + hx -= 1; + else // x < y, x += ulp + hx += 1; + } + else + { // x < 0 + if(hy >= 0 || hx > hy) // x < y, x -= ulp + hx -= 1; + else // x > y, x += ulp + hx += 1; + } + hy = hx & 0x7f800000; + if(hy >= 0x7f800000) + return x + x; // overflow + if(hy < 0x00800000) // underflow + { + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_SET_FLOAT_WORD(y, hx); + return y; + } + } + GLM_SET_FLOAT_WORD(x, hx); + return x; + } + + GLM_FUNC_QUALIFIER double nextafter(double x, double y) + { + volatile double t; + int hx, hy, ix, iy; + unsigned int lx, ly; + + GLM_EXTRACT_WORDS(hx, lx, x); + GLM_EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; // |x| + iy = hy & 0x7fffffff; // |y| + + if(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || // x is nan + ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) // y is nan + return x + y; + if(abs(y - x) <= epsilon()) + return y; // x=y, return y + if((ix | lx) == 0) + { // x == 0 + GLM_INSERT_WORDS(x, hy & 0x80000000, 1); // return +-minsubnormal + t = x * x; + if(abs(t - x) <= epsilon()) + return t; + else + return x; // raise underflow flag + } + if(hx >= 0) { // x > 0 + if(hx > hy || ((hx == hy) && (lx > ly))) { // x > y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x < y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + else { // x < 0 + if(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp + if(lx == 0) hx -= 1; + lx -= 1; + } + else { // x > y, x += ulp + lx += 1; + if(lx == 0) hx += 1; + } + } + hy = hx & 0x7ff00000; + if(hy >= 0x7ff00000) + return x + x; // overflow + if(hy < 0x00100000) + { // underflow + t = x * x; + if(abs(t - x) > epsilon()) + { // raise underflow flag + GLM_INSERT_WORDS(y, hx, lx); + return y; + } + } + GLM_INSERT_WORDS(x, hx, lx); + return x; + } +}//namespace detail +}//namespace glm + +#if(GLM_COMPILER & GLM_COMPILER_VC) +# pragma warning(pop) +#endif + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER float nextFloat(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MAX); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MAX); +# else + return nextafterf(x, FLT_MAX); +# endif + } + + template<> + GLM_FUNC_QUALIFIER double nextFloat(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafter(x, std::numeric_limits::max()); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MAX); +# else + return nextafter(x, DBL_MAX); +# endif + } + + template + GLM_FUNC_QUALIFIER T nextFloat(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = nextFloat(temp); + return temp; + } + + GLM_FUNC_QUALIFIER float prevFloat(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MIN); +# else + return nextafterf(x, FLT_MIN); +# endif + } + + GLM_FUNC_QUALIFIER double prevFloat(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return _nextafter(x, DBL_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MIN); +# else + return nextafter(x, DBL_MIN); +# endif + } + + template + GLM_FUNC_QUALIFIER T prevFloat(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for(int i = 0; i < ULPs; ++i) + temp = prevFloat(temp); + return temp; + } + + GLM_FUNC_QUALIFIER int floatDistance(float x, float y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + GLM_FUNC_QUALIFIER int64 floatDistance(double x, double y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool1.hpp b/thirdparty/glm/ext/vector_bool1.hpp new file mode 100644 index 0000000..002c320 --- /dev/null +++ b/thirdparty/glm/ext/vector_bool1.hpp @@ -0,0 +1,30 @@ +/// @ref ext_vector_bool1 +/// @file glm/ext/vector_bool1.hpp +/// +/// @defgroup ext_vector_bool1 GLM_EXT_vector_bool1 +/// @ingroup ext +/// +/// Exposes bvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_bool1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1 + /// @{ + + /// 1 components vector of boolean. + typedef vec<1, bool, defaultp> bvec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool1_precision.hpp b/thirdparty/glm/ext/vector_bool1_precision.hpp new file mode 100644 index 0000000..e62d3cf --- /dev/null +++ b/thirdparty/glm/ext/vector_bool1_precision.hpp @@ -0,0 +1,34 @@ +/// @ref ext_vector_bool1_precision +/// @file glm/ext/vector_bool1_precision.hpp +/// +/// @defgroup ext_vector_bool1_precision GLM_EXT_vector_bool1_precision +/// @ingroup ext +/// +/// Exposes highp_bvec1, mediump_bvec1 and lowp_bvec1 types. +/// +/// Include to use the features of this extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_bool1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_bool1_precision + /// @{ + + /// 1 component vector of bool values. + typedef vec<1, bool, highp> highp_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, mediump> mediump_bvec1; + + /// 1 component vector of bool values. + typedef vec<1, bool, lowp> lowp_bvec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool2.hpp b/thirdparty/glm/ext/vector_bool2.hpp new file mode 100644 index 0000000..52288b7 --- /dev/null +++ b/thirdparty/glm/ext/vector_bool2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, bool, defaultp> bvec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool2_precision.hpp b/thirdparty/glm/ext/vector_bool2_precision.hpp new file mode 100644 index 0000000..4370933 --- /dev/null +++ b/thirdparty/glm/ext/vector_bool2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, highp> highp_bvec2; + + /// 2 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, mediump> mediump_bvec2; + + /// 2 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, bool, lowp> lowp_bvec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool3.hpp b/thirdparty/glm/ext/vector_bool3.hpp new file mode 100644 index 0000000..90a0b7e --- /dev/null +++ b/thirdparty/glm/ext/vector_bool3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, bool, defaultp> bvec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool3_precision.hpp b/thirdparty/glm/ext/vector_bool3_precision.hpp new file mode 100644 index 0000000..89cd2d3 --- /dev/null +++ b/thirdparty/glm/ext/vector_bool3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, highp> highp_bvec3; + + /// 3 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, mediump> mediump_bvec3; + + /// 3 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, bool, lowp> lowp_bvec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool4.hpp b/thirdparty/glm/ext/vector_bool4.hpp new file mode 100644 index 0000000..18aa71b --- /dev/null +++ b/thirdparty/glm/ext/vector_bool4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_bool4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of boolean. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, bool, defaultp> bvec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_bool4_precision.hpp b/thirdparty/glm/ext/vector_bool4_precision.hpp new file mode 100644 index 0000000..79786e5 --- /dev/null +++ b/thirdparty/glm/ext/vector_bool4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_bool4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, highp> highp_bvec4; + + /// 4 components vector of medium qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, mediump> mediump_bvec4; + + /// 4 components vector of low qualifier bool numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, bool, lowp> lowp_bvec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_common.hpp b/thirdparty/glm/ext/vector_common.hpp new file mode 100644 index 0000000..521ec01 --- /dev/null +++ b/thirdparty/glm/ext/vector_common.hpp @@ -0,0 +1,204 @@ +/// @ref ext_vector_common +/// @file glm/ext/vector_common.hpp +/// +/// @defgroup ext_vector_common GLM_EXT_vector_common +/// @ingroup ext +/// +/// Exposes min and max functions for 3 to 4 vector parameters. +/// +/// Include to use the features of this extension. +/// +/// @see core_common +/// @see ext_scalar_common + +#pragma once + +// Dependency: +#include "../ext/scalar_common.hpp" +#include "../common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_common extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_common + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c); + + /// Return the minimum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Return the maximum component-wise values of 3 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z); + + /// Return the maximum component-wise values of 4 inputs + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec max( vec const& x, vec const& y, vec const& z, vec const& w); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, T y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& x, vec const& y); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c); + + /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmin documentation + template + GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, T b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c); + + /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see std::fmax documentation + template + GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c, vec const& d); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common + template + GLM_FUNC_DECL vec fclamp(vec const& x, T minVal, T maxVal); + + /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common + template + GLM_FUNC_DECL vec fclamp(vec const& x, vec const& minVal, vec const& maxVal); + + /// Simulate GL_CLAMP OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec clamp(vec const& Texcoord); + + /// Simulate GL_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec repeat(vec const& Texcoord); + + /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec mirrorClamp(vec const& Texcoord); + + /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_common extension. + template + GLM_FUNC_DECL vec mirrorRepeat(vec const& Texcoord); + + /// @} +}//namespace glm + +#include "vector_common.inl" diff --git a/thirdparty/glm/ext/vector_common.inl b/thirdparty/glm/ext/vector_common.inl new file mode 100644 index 0000000..e2747be --- /dev/null +++ b/thirdparty/glm/ext/vector_common.inl @@ -0,0 +1,129 @@ +#include "../detail/_vectorize.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z, vec const& w) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return detail::functor2::call(fmin, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); + return fmin(fmin(a, b), fmin(c, d)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, vec(b)); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return detail::functor2::call(fmax, a, b); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), c); + } + + template + GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c, vec const& d) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); + return fmax(fmax(a, b), fmax(c, d)); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, T minVal, T maxVal) + { + return fmin(fmax(x, vec(minVal)), vec(maxVal)); + } + + template + GLM_FUNC_QUALIFIER vec fclamp(vec const& x, vec const& minVal, vec const& maxVal) + { + return fmin(fmax(x, minVal), maxVal); + } + + template + GLM_FUNC_QUALIFIER vec clamp(vec const& Texcoord) + { + return glm::clamp(Texcoord, vec(0), vec(1)); + } + + template + GLM_FUNC_QUALIFIER vec repeat(vec const& Texcoord) + { + return glm::fract(Texcoord); + } + + template + GLM_FUNC_QUALIFIER vec mirrorClamp(vec const& Texcoord) + { + return glm::fract(glm::abs(Texcoord)); + } + + template + GLM_FUNC_QUALIFIER vec mirrorRepeat(vec const& Texcoord) + { + vec const Abs = glm::abs(Texcoord); + vec const Clamp = glm::mod(glm::floor(Abs), vec(2)); + vec const Floor = glm::floor(Abs); + vec const Rest = Abs - Floor; + vec const Mirror = Clamp + Rest; + return mix(Rest, vec(1) - Rest, glm::greaterThanEqual(Mirror, vec(1))); + } +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double1.hpp b/thirdparty/glm/ext/vector_double1.hpp new file mode 100644 index 0000000..3882667 --- /dev/null +++ b/thirdparty/glm/ext/vector_double1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_double1 +/// @file glm/ext/vector_double1.hpp +/// +/// @defgroup ext_vector_double1 GLM_EXT_vector_double1 +/// @ingroup ext +/// +/// Exposes double-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1_precision extension. +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_double1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1 + /// @{ + + /// 1 components vector of double-precision floating-point numbers. + typedef vec<1, double, defaultp> dvec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double1_precision.hpp b/thirdparty/glm/ext/vector_double1_precision.hpp new file mode 100644 index 0000000..1d47195 --- /dev/null +++ b/thirdparty/glm/ext/vector_double1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_double1_precision +/// @file glm/ext/vector_double1_precision.hpp +/// +/// @defgroup ext_vector_double1_precision GLM_EXT_vector_double1_precision +/// @ingroup ext +/// +/// Exposes highp_dvec1, mediump_dvec1 and lowp_dvec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_double1 + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_double1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_double1_precision + /// @{ + + /// 1 component vector of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, highp> highp_dvec1; + + /// 1 component vector of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, mediump> mediump_dvec1; + + /// 1 component vector of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, lowp> lowp_dvec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double2.hpp b/thirdparty/glm/ext/vector_double2.hpp new file mode 100644 index 0000000..60e3577 --- /dev/null +++ b/thirdparty/glm/ext/vector_double2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, double, defaultp> dvec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double2_precision.hpp b/thirdparty/glm/ext/vector_double2_precision.hpp new file mode 100644 index 0000000..fa53940 --- /dev/null +++ b/thirdparty/glm/ext/vector_double2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_double2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, highp> highp_dvec2; + + /// 2 components vector of medium double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, mediump> mediump_dvec2; + + /// 2 components vector of low double-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, double, lowp> lowp_dvec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double3.hpp b/thirdparty/glm/ext/vector_double3.hpp new file mode 100644 index 0000000..6dfe4c6 --- /dev/null +++ b/thirdparty/glm/ext/vector_double3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, double, defaultp> dvec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double3_precision.hpp b/thirdparty/glm/ext/vector_double3_precision.hpp new file mode 100644 index 0000000..a8cfa37 --- /dev/null +++ b/thirdparty/glm/ext/vector_double3_precision.hpp @@ -0,0 +1,34 @@ +/// @ref core +/// @file glm/ext/vector_double3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, highp> highp_dvec3; + + /// 3 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, mediump> mediump_dvec3; + + /// 3 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, double, lowp> lowp_dvec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double4.hpp b/thirdparty/glm/ext/vector_double4.hpp new file mode 100644 index 0000000..87f225f --- /dev/null +++ b/thirdparty/glm/ext/vector_double4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_double4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of double-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, double, defaultp> dvec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_double4_precision.hpp b/thirdparty/glm/ext/vector_double4_precision.hpp new file mode 100644 index 0000000..09cafa1 --- /dev/null +++ b/thirdparty/glm/ext/vector_double4_precision.hpp @@ -0,0 +1,35 @@ +/// @ref core +/// @file glm/ext/vector_double4_precision.hpp + +#pragma once +#include "../detail/setup.hpp" +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, highp> highp_dvec4; + + /// 4 components vector of medium double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, mediump> mediump_dvec4; + + /// 4 components vector of low double-qualifier floating-point numbers. + /// There is no guarantee on the actual qualifier. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, double, lowp> lowp_dvec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float1.hpp b/thirdparty/glm/ext/vector_float1.hpp new file mode 100644 index 0000000..28acc2c --- /dev/null +++ b/thirdparty/glm/ext/vector_float1.hpp @@ -0,0 +1,31 @@ +/// @ref ext_vector_float1 +/// @file glm/ext/vector_float1.hpp +/// +/// @defgroup ext_vector_float1 GLM_EXT_vector_float1 +/// @ingroup ext +/// +/// Exposes single-precision floating point vector type with one component. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1_precision extension. +/// @see ext_vector_double1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1 + /// @{ + + /// 1 components vector of single-precision floating-point numbers. + typedef vec<1, float, defaultp> vec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float1_precision.hpp b/thirdparty/glm/ext/vector_float1_precision.hpp new file mode 100644 index 0000000..6e8dad8 --- /dev/null +++ b/thirdparty/glm/ext/vector_float1_precision.hpp @@ -0,0 +1,36 @@ +/// @ref ext_vector_float1_precision +/// @file glm/ext/vector_float1_precision.hpp +/// +/// @defgroup ext_vector_float1_precision GLM_EXT_vector_float1_precision +/// @ingroup ext +/// +/// Exposes highp_vec1, mediump_vec1 and lowp_vec1 types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_float1 extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_float1_precision extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_float1_precision + /// @{ + + /// 1 component vector of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, highp> highp_vec1; + + /// 1 component vector of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, mediump> mediump_vec1; + + /// 1 component vector of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, lowp> lowp_vec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float2.hpp b/thirdparty/glm/ext/vector_float2.hpp new file mode 100644 index 0000000..d31545d --- /dev/null +++ b/thirdparty/glm/ext/vector_float2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, float, defaultp> vec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float2_precision.hpp b/thirdparty/glm/ext/vector_float2_precision.hpp new file mode 100644 index 0000000..23c0820 --- /dev/null +++ b/thirdparty/glm/ext/vector_float2_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float2_precision.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 2 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, highp> highp_vec2; + + /// 2 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, mediump> mediump_vec2; + + /// 2 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<2, float, lowp> lowp_vec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float3.hpp b/thirdparty/glm/ext/vector_float3.hpp new file mode 100644 index 0000000..cd79a62 --- /dev/null +++ b/thirdparty/glm/ext/vector_float3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, float, defaultp> vec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float3_precision.hpp b/thirdparty/glm/ext/vector_float3_precision.hpp new file mode 100644 index 0000000..be640b5 --- /dev/null +++ b/thirdparty/glm/ext/vector_float3_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float3_precision.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 3 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, highp> highp_vec3; + + /// 3 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, mediump> mediump_vec3; + + /// 3 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<3, float, lowp> lowp_vec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float4.hpp b/thirdparty/glm/ext/vector_float4.hpp new file mode 100644 index 0000000..d84adcc --- /dev/null +++ b/thirdparty/glm/ext/vector_float4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_float4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of single-precision floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, float, defaultp> vec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_float4_precision.hpp b/thirdparty/glm/ext/vector_float4_precision.hpp new file mode 100644 index 0000000..aede838 --- /dev/null +++ b/thirdparty/glm/ext/vector_float4_precision.hpp @@ -0,0 +1,31 @@ +/// @ref core +/// @file glm/ext/vector_float4_precision.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector_precision + /// @{ + + /// 4 components vector of high single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, highp> highp_vec4; + + /// 4 components vector of medium single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, mediump> mediump_vec4; + + /// 4 components vector of low single-qualifier floating-point numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier + typedef vec<4, float, lowp> lowp_vec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int1.hpp b/thirdparty/glm/ext/vector_int1.hpp new file mode 100644 index 0000000..dc86038 --- /dev/null +++ b/thirdparty/glm/ext/vector_int1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_int1 +/// @file glm/ext/vector_int1.hpp +/// +/// @defgroup ext_vector_int1 GLM_EXT_vector_int1 +/// @ingroup ext +/// +/// Exposes ivec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_uint1 extension. +/// @see ext_vector_int1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1 + /// @{ + + /// 1 component vector of signed integer numbers. + typedef vec<1, int, defaultp> ivec1; + + /// @} +}//namespace glm + diff --git a/thirdparty/glm/ext/vector_int1_sized.hpp b/thirdparty/glm/ext/vector_int1_sized.hpp new file mode 100644 index 0000000..de0d4cf --- /dev/null +++ b/thirdparty/glm/ext/vector_int1_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int1_sized +/// @file glm/ext/vector_int1_sized.hpp +/// +/// @defgroup ext_vector_int1_sized GLM_EXT_vector_int1_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint1_sized + +#pragma once + +#include "../ext/vector_int1.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int1_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int1_sized + /// @{ + + /// 8 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int8, defaultp> i8vec1; + + /// 16 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int16, defaultp> i16vec1; + + /// 32 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int32, defaultp> i32vec1; + + /// 64 bit signed integer vector of 1 component type. + /// + /// @see ext_vector_int1_sized + typedef vec<1, int64, defaultp> i64vec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int2.hpp b/thirdparty/glm/ext/vector_int2.hpp new file mode 100644 index 0000000..aef803e --- /dev/null +++ b/thirdparty/glm/ext/vector_int2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, int, defaultp> ivec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int2_sized.hpp b/thirdparty/glm/ext/vector_int2_sized.hpp new file mode 100644 index 0000000..1fd57ee --- /dev/null +++ b/thirdparty/glm/ext/vector_int2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int2_sized +/// @file glm/ext/vector_int2_sized.hpp +/// +/// @defgroup ext_vector_int2_sized GLM_EXT_vector_int2_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 2 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint2_sized + +#pragma once + +#include "../ext/vector_int2.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int2_sized + /// @{ + + /// 8 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int8, defaultp> i8vec2; + + /// 16 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int16, defaultp> i16vec2; + + /// 32 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int32, defaultp> i32vec2; + + /// 64 bit signed integer vector of 2 components type. + /// + /// @see ext_vector_int2_sized + typedef vec<2, int64, defaultp> i64vec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int3.hpp b/thirdparty/glm/ext/vector_int3.hpp new file mode 100644 index 0000000..4767e61 --- /dev/null +++ b/thirdparty/glm/ext/vector_int3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, int, defaultp> ivec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int3_sized.hpp b/thirdparty/glm/ext/vector_int3_sized.hpp new file mode 100644 index 0000000..085a3fe --- /dev/null +++ b/thirdparty/glm/ext/vector_int3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int3_sized +/// @file glm/ext/vector_int3_sized.hpp +/// +/// @defgroup ext_vector_int3_sized GLM_EXT_vector_int3_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 3 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint3_sized + +#pragma once + +#include "../ext/vector_int3.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int3_sized + /// @{ + + /// 8 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int8, defaultp> i8vec3; + + /// 16 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int16, defaultp> i16vec3; + + /// 32 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int32, defaultp> i32vec3; + + /// 64 bit signed integer vector of 3 components type. + /// + /// @see ext_vector_int3_sized + typedef vec<3, int64, defaultp> i64vec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int4.hpp b/thirdparty/glm/ext/vector_int4.hpp new file mode 100644 index 0000000..bb23adf --- /dev/null +++ b/thirdparty/glm/ext/vector_int4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_int4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of signed integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, int, defaultp> ivec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_int4_sized.hpp b/thirdparty/glm/ext/vector_int4_sized.hpp new file mode 100644 index 0000000..c63d465 --- /dev/null +++ b/thirdparty/glm/ext/vector_int4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_int4_sized +/// @file glm/ext/vector_int4_sized.hpp +/// +/// @defgroup ext_vector_int4_sized GLM_EXT_vector_int4_sized +/// @ingroup ext +/// +/// Exposes sized signed integer vector of 4 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_int_sized +/// @see ext_vector_uint4_sized + +#pragma once + +#include "../ext/vector_int4.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_int4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_int4_sized + /// @{ + + /// 8 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int8, defaultp> i8vec4; + + /// 16 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int16, defaultp> i16vec4; + + /// 32 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int32, defaultp> i32vec4; + + /// 64 bit signed integer vector of 4 components type. + /// + /// @see ext_vector_int4_sized + typedef vec<4, int64, defaultp> i64vec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_integer.hpp b/thirdparty/glm/ext/vector_integer.hpp new file mode 100644 index 0000000..1304dd8 --- /dev/null +++ b/thirdparty/glm/ext/vector_integer.hpp @@ -0,0 +1,149 @@ +/// @ref ext_vector_integer +/// @file glm/ext/vector_integer.hpp +/// +/// @see core (dependence) +/// @see ext_vector_integer (dependence) +/// +/// @defgroup ext_vector_integer GLM_EXT_vector_integer +/// @ingroup ext +/// +/// Include to use the features of this extension. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_integer + /// @{ + + /// Return true if the value is a power of two number. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevPowerOfTwo(vec const& v); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isMultiple(vec const& v, T Multiple); + + /// Return true if the 'Value' is a multiple of 'Multiple'. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec isMultiple(vec const& v, vec const& Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextMultiple(vec const& v, T Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec nextMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevMultiple(vec const& v, T Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed or unsigned integer scalar types. + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec prevMultiple(vec const& v, vec const& Multiple); + + /// Returns the bit number of the Nth significant bit set to + /// 1 in the binary representation of value. + /// If value bitcount is less than the Nth significant bit, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see ext_vector_integer + template + GLM_FUNC_DECL vec findNSB(vec const& Source, vec SignificantBitCount); + + /// @} +} //namespace glm + +#include "vector_integer.inl" diff --git a/thirdparty/glm/ext/vector_integer.inl b/thirdparty/glm/ext/vector_integer.inl new file mode 100644 index 0000000..939ff5e --- /dev/null +++ b/thirdparty/glm/ext/vector_integer.inl @@ -0,0 +1,85 @@ +#include "scalar_integer.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec isPowerOfTwo(vec const& Value) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); + + vec const Result(abs(Value)); + return equal(Result & (Result - vec(1)), vec(0)); + } + + template + GLM_FUNC_QUALIFIER vec nextPowerOfTwo(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); + + return detail::compute_ceilPowerOfTwo::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER vec prevPowerOfTwo(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); + + return detail::functor1::call(prevPowerOfTwo, v); + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return (Value % Multiple) == vec(0); + } + + template + GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); + + return (Value % Multiple) == vec(0); + } + + template + GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::functor2::call(nextMultiple, Source, vec(Multiple)); + } + + template + GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); + + return detail::functor2::call(nextMultiple, Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, T Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::functor2::call(prevMultiple, Source, vec(Multiple)); + } + + template + GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, vec const& Multiple) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); + + return detail::functor2::call(prevMultiple, Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec findNSB(vec const& Source, vec SignificantBitCount) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); + + return detail::functor2_vec_int::call(findNSB, Source, SignificantBitCount); + } +}//namespace glm diff --git a/thirdparty/glm/ext/vector_packing.hpp b/thirdparty/glm/ext/vector_packing.hpp new file mode 100644 index 0000000..76e5d0c --- /dev/null +++ b/thirdparty/glm/ext/vector_packing.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_packing +/// @file glm/ext/vector_packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup ext_vector_packing GLM_EXT_vector_packing +/// @ingroup ext +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert vectors to packed +/// formats. + +#pragma once + +// Dependency: +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_packing + /// @{ + + + /// @} +}// namespace glm + +#include "vector_packing.inl" diff --git a/thirdparty/glm/ext/vector_packing.inl b/thirdparty/glm/ext/vector_packing.inl new file mode 100644 index 0000000..e69de29 diff --git a/thirdparty/glm/ext/vector_relational.hpp b/thirdparty/glm/ext/vector_relational.hpp new file mode 100644 index 0000000..1c2367d --- /dev/null +++ b/thirdparty/glm/ext/vector_relational.hpp @@ -0,0 +1,107 @@ +/// @ref ext_vector_relational +/// @file glm/ext/vector_relational.hpp +/// +/// @see core (dependence) +/// @see ext_scalar_integer (dependence) +/// +/// @defgroup ext_vector_relational GLM_EXT_vector_relational +/// @ingroup ext +/// +/// Exposes comparison functions for vector types that take a user defined epsilon values. +/// +/// Include to use the features of this extension. +/// +/// @see core_vector_relational +/// @see ext_scalar_relational +/// @see ext_matrix_relational + +#pragma once + +// Dependencies +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_relational extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_relational + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& epsilon); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int ULPs); + + /// Returns the component-wise comparison between two vectors in term of ULPs. + /// True if this expression is not satisfied. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& ULPs); + + /// @} +}//namespace glm + +#include "vector_relational.inl" diff --git a/thirdparty/glm/ext/vector_relational.inl b/thirdparty/glm/ext/vector_relational.inl new file mode 100644 index 0000000..7a39ab5 --- /dev/null +++ b/thirdparty/glm/ext/vector_relational.inl @@ -0,0 +1,75 @@ +#include "../vector_relational.hpp" +#include "../common.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_float.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T Epsilon) + { + return equal(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& Epsilon) + { + return lessThanEqual(abs(x - y), Epsilon); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T Epsilon) + { + return notEqual(x, y, vec(Epsilon)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& Epsilon) + { + return greaterThan(abs(x - y), Epsilon); + } + + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int MaxULPs) + { + return equal(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& MaxULPs) + { + vec Result(false); + for(length_t i = 0; i < L; ++i) + { + detail::float_t const a(x[i]); + detail::float_t const b(y[i]); + + // Different signs means they do not match. + if(a.negative() != b.negative()) + { + // Check for equality to make sure +0==-0 + Result[i] = a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); + } + else + { + // Find the difference in ULPs. + typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); + Result[i] = DiffULPs <= MaxULPs[i]; + } + } + return Result; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int MaxULPs) + { + return notEqual(x, y, vec(MaxULPs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& MaxULPs) + { + return not_(equal(x, y, MaxULPs)); + } +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint1.hpp b/thirdparty/glm/ext/vector_uint1.hpp new file mode 100644 index 0000000..eb8a704 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint1.hpp @@ -0,0 +1,32 @@ +/// @ref ext_vector_uint1 +/// @file glm/ext/vector_uint1.hpp +/// +/// @defgroup ext_vector_uint1 GLM_EXT_vector_uint1 +/// @ingroup ext +/// +/// Exposes uvec1 vector type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_vector_int1 extension. +/// @see ext_vector_uint1_precision extension. + +#pragma once + +#include "../detail/type_vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1 extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1 + /// @{ + + /// 1 component vector of unsigned integer numbers. + typedef vec<1, unsigned int, defaultp> uvec1; + + /// @} +}//namespace glm + diff --git a/thirdparty/glm/ext/vector_uint1_sized.hpp b/thirdparty/glm/ext/vector_uint1_sized.hpp new file mode 100644 index 0000000..2a938bb --- /dev/null +++ b/thirdparty/glm/ext/vector_uint1_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint1_sized +/// @file glm/ext/vector_uint1_sized.hpp +/// +/// @defgroup ext_vector_uint1_sized GLM_EXT_vector_uint1_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector types. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int1_sized + +#pragma once + +#include "../ext/vector_uint1.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint1_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint1_sized + /// @{ + + /// 8 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint8, defaultp> u8vec1; + + /// 16 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint16, defaultp> u16vec1; + + /// 32 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint32, defaultp> u32vec1; + + /// 64 bit unsigned integer vector of 1 component type. + /// + /// @see ext_vector_uint1_sized + typedef vec<1, uint64, defaultp> u64vec1; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint2.hpp b/thirdparty/glm/ext/vector_uint2.hpp new file mode 100644 index 0000000..03c00f5 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint2.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint2.hpp + +#pragma once +#include "../detail/type_vec2.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 2 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<2, unsigned int, defaultp> uvec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint2_sized.hpp b/thirdparty/glm/ext/vector_uint2_sized.hpp new file mode 100644 index 0000000..620fdc6 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint2_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint2_sized +/// @file glm/ext/vector_uint2_sized.hpp +/// +/// @defgroup ext_vector_uint2_sized GLM_EXT_vector_uint2_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 2 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int2_sized + +#pragma once + +#include "../ext/vector_uint2.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint2_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint2_sized + /// @{ + + /// 8 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint8, defaultp> u8vec2; + + /// 16 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint16, defaultp> u16vec2; + + /// 32 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint32, defaultp> u32vec2; + + /// 64 bit unsigned integer vector of 2 components type. + /// + /// @see ext_vector_uint2_sized + typedef vec<2, uint64, defaultp> u64vec2; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint3.hpp b/thirdparty/glm/ext/vector_uint3.hpp new file mode 100644 index 0000000..f5b41c4 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint3.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint3.hpp + +#pragma once +#include "../detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 3 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<3, unsigned int, defaultp> uvec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint3_sized.hpp b/thirdparty/glm/ext/vector_uint3_sized.hpp new file mode 100644 index 0000000..6f96b98 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint3_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint3_sized +/// @file glm/ext/vector_uint3_sized.hpp +/// +/// @defgroup ext_vector_uint3_sized GLM_EXT_vector_uint3_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 3 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int3_sized + +#pragma once + +#include "../ext/vector_uint3.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint3_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint3_sized + /// @{ + + /// 8 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint8, defaultp> u8vec3; + + /// 16 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint16, defaultp> u16vec3; + + /// 32 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint32, defaultp> u32vec3; + + /// 64 bit unsigned integer vector of 3 components type. + /// + /// @see ext_vector_uint3_sized + typedef vec<3, uint64, defaultp> u64vec3; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint4.hpp b/thirdparty/glm/ext/vector_uint4.hpp new file mode 100644 index 0000000..32ced58 --- /dev/null +++ b/thirdparty/glm/ext/vector_uint4.hpp @@ -0,0 +1,18 @@ +/// @ref core +/// @file glm/ext/vector_uint4.hpp + +#pragma once +#include "../detail/type_vec4.hpp" + +namespace glm +{ + /// @addtogroup core_vector + /// @{ + + /// 4 components vector of unsigned integer numbers. + /// + /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors + typedef vec<4, unsigned int, defaultp> uvec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_uint4_sized.hpp b/thirdparty/glm/ext/vector_uint4_sized.hpp new file mode 100644 index 0000000..da992ea --- /dev/null +++ b/thirdparty/glm/ext/vector_uint4_sized.hpp @@ -0,0 +1,49 @@ +/// @ref ext_vector_uint4_sized +/// @file glm/ext/vector_uint4_sized.hpp +/// +/// @defgroup ext_vector_uint4_sized GLM_EXT_vector_uint4_sized +/// @ingroup ext +/// +/// Exposes sized unsigned integer vector of 4 components type. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_uint_sized +/// @see ext_vector_int4_sized + +#pragma once + +#include "../ext/vector_uint4.hpp" +#include "../ext/scalar_uint_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_uint4_sized extension included") +#endif + +namespace glm +{ + /// @addtogroup ext_vector_uint4_sized + /// @{ + + /// 8 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint8, defaultp> u8vec4; + + /// 16 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint16, defaultp> u16vec4; + + /// 32 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint32, defaultp> u32vec4; + + /// 64 bit unsigned integer vector of 4 components type. + /// + /// @see ext_vector_uint4_sized + typedef vec<4, uint64, defaultp> u64vec4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/ext/vector_ulp.hpp b/thirdparty/glm/ext/vector_ulp.hpp new file mode 100644 index 0000000..6210396 --- /dev/null +++ b/thirdparty/glm/ext/vector_ulp.hpp @@ -0,0 +1,109 @@ +/// @ref ext_vector_ulp +/// @file glm/ext/vector_ulp.hpp +/// +/// @defgroup ext_vector_ulp GLM_EXT_vector_ulp +/// @ingroup ext +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. +/// +/// Include to use the features of this extension. +/// +/// @see ext_scalar_ulp +/// @see ext_scalar_relational +/// @see ext_vector_relational + +#pragma once + +// Dependencies +#include "../ext/scalar_ulp.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_EXT_vector_ulp extension included") +#endif + +namespace glm +{ + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x, int ULPs); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec nextFloat(vec const& x, vec const& ULPs); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec prevFloat(vec const& x, vec const& ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see ext_scalar_ulp + template + GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "vector_ulp.inl" diff --git a/thirdparty/glm/ext/vector_ulp.inl b/thirdparty/glm/ext/vector_ulp.inl new file mode 100644 index 0000000..91565ce --- /dev/null +++ b/thirdparty/glm/ext/vector_ulp.inl @@ -0,0 +1,74 @@ +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = nextFloat(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, int ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, vec const& ULPs) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prevFloat(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = floatDistance(x[i], y[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = floatDistance(x[i], y[i]); + return Result; + } +}//namespace glm diff --git a/thirdparty/glm/fwd.hpp b/thirdparty/glm/fwd.hpp new file mode 100644 index 0000000..89177f4 --- /dev/null +++ b/thirdparty/glm/fwd.hpp @@ -0,0 +1,1233 @@ +#pragma once + +#include "detail/qualifier.hpp" + +namespace glm +{ +#if GLM_HAS_EXTENDED_INTEGER_TYPE + typedef std::int8_t int8; + typedef std::int16_t int16; + typedef std::int32_t int32; + typedef std::int64_t int64; + + typedef std::uint8_t uint8; + typedef std::uint16_t uint16; + typedef std::uint32_t uint32; + typedef std::uint64_t uint64; +#else + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; + typedef detail::int64 int64; + + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef detail::uint64 uint64; +#endif + + // Scalar int + + typedef int8 lowp_i8; + typedef int8 mediump_i8; + typedef int8 highp_i8; + typedef int8 i8; + + typedef int8 lowp_int8; + typedef int8 mediump_int8; + typedef int8 highp_int8; + + typedef int8 lowp_int8_t; + typedef int8 mediump_int8_t; + typedef int8 highp_int8_t; + typedef int8 int8_t; + + typedef int16 lowp_i16; + typedef int16 mediump_i16; + typedef int16 highp_i16; + typedef int16 i16; + + typedef int16 lowp_int16; + typedef int16 mediump_int16; + typedef int16 highp_int16; + + typedef int16 lowp_int16_t; + typedef int16 mediump_int16_t; + typedef int16 highp_int16_t; + typedef int16 int16_t; + + typedef int32 lowp_i32; + typedef int32 mediump_i32; + typedef int32 highp_i32; + typedef int32 i32; + + typedef int32 lowp_int32; + typedef int32 mediump_int32; + typedef int32 highp_int32; + + typedef int32 lowp_int32_t; + typedef int32 mediump_int32_t; + typedef int32 highp_int32_t; + typedef int32 int32_t; + + typedef int64 lowp_i64; + typedef int64 mediump_i64; + typedef int64 highp_i64; + typedef int64 i64; + + typedef int64 lowp_int64; + typedef int64 mediump_int64; + typedef int64 highp_int64; + + typedef int64 lowp_int64_t; + typedef int64 mediump_int64_t; + typedef int64 highp_int64_t; + typedef int64 int64_t; + + // Scalar uint + + typedef unsigned int uint; + + typedef uint8 lowp_u8; + typedef uint8 mediump_u8; + typedef uint8 highp_u8; + typedef uint8 u8; + + typedef uint8 lowp_uint8; + typedef uint8 mediump_uint8; + typedef uint8 highp_uint8; + + typedef uint8 lowp_uint8_t; + typedef uint8 mediump_uint8_t; + typedef uint8 highp_uint8_t; + typedef uint8 uint8_t; + + typedef uint16 lowp_u16; + typedef uint16 mediump_u16; + typedef uint16 highp_u16; + typedef uint16 u16; + + typedef uint16 lowp_uint16; + typedef uint16 mediump_uint16; + typedef uint16 highp_uint16; + + typedef uint16 lowp_uint16_t; + typedef uint16 mediump_uint16_t; + typedef uint16 highp_uint16_t; + typedef uint16 uint16_t; + + typedef uint32 lowp_u32; + typedef uint32 mediump_u32; + typedef uint32 highp_u32; + typedef uint32 u32; + + typedef uint32 lowp_uint32; + typedef uint32 mediump_uint32; + typedef uint32 highp_uint32; + + typedef uint32 lowp_uint32_t; + typedef uint32 mediump_uint32_t; + typedef uint32 highp_uint32_t; + typedef uint32 uint32_t; + + typedef uint64 lowp_u64; + typedef uint64 mediump_u64; + typedef uint64 highp_u64; + typedef uint64 u64; + + typedef uint64 lowp_uint64; + typedef uint64 mediump_uint64; + typedef uint64 highp_uint64; + + typedef uint64 lowp_uint64_t; + typedef uint64 mediump_uint64_t; + typedef uint64 highp_uint64_t; + typedef uint64 uint64_t; + + // Scalar float + + typedef float lowp_f32; + typedef float mediump_f32; + typedef float highp_f32; + typedef float f32; + + typedef float lowp_float32; + typedef float mediump_float32; + typedef float highp_float32; + typedef float float32; + + typedef float lowp_float32_t; + typedef float mediump_float32_t; + typedef float highp_float32_t; + typedef float float32_t; + + + typedef double lowp_f64; + typedef double mediump_f64; + typedef double highp_f64; + typedef double f64; + + typedef double lowp_float64; + typedef double mediump_float64; + typedef double highp_float64; + typedef double float64; + + typedef double lowp_float64_t; + typedef double mediump_float64_t; + typedef double highp_float64_t; + typedef double float64_t; + + // Vector bool + + typedef vec<1, bool, lowp> lowp_bvec1; + typedef vec<2, bool, lowp> lowp_bvec2; + typedef vec<3, bool, lowp> lowp_bvec3; + typedef vec<4, bool, lowp> lowp_bvec4; + + typedef vec<1, bool, mediump> mediump_bvec1; + typedef vec<2, bool, mediump> mediump_bvec2; + typedef vec<3, bool, mediump> mediump_bvec3; + typedef vec<4, bool, mediump> mediump_bvec4; + + typedef vec<1, bool, highp> highp_bvec1; + typedef vec<2, bool, highp> highp_bvec2; + typedef vec<3, bool, highp> highp_bvec3; + typedef vec<4, bool, highp> highp_bvec4; + + typedef vec<1, bool, defaultp> bvec1; + typedef vec<2, bool, defaultp> bvec2; + typedef vec<3, bool, defaultp> bvec3; + typedef vec<4, bool, defaultp> bvec4; + + // Vector int + + typedef vec<1, int, lowp> lowp_ivec1; + typedef vec<2, int, lowp> lowp_ivec2; + typedef vec<3, int, lowp> lowp_ivec3; + typedef vec<4, int, lowp> lowp_ivec4; + + typedef vec<1, int, mediump> mediump_ivec1; + typedef vec<2, int, mediump> mediump_ivec2; + typedef vec<3, int, mediump> mediump_ivec3; + typedef vec<4, int, mediump> mediump_ivec4; + + typedef vec<1, int, highp> highp_ivec1; + typedef vec<2, int, highp> highp_ivec2; + typedef vec<3, int, highp> highp_ivec3; + typedef vec<4, int, highp> highp_ivec4; + + typedef vec<1, int, defaultp> ivec1; + typedef vec<2, int, defaultp> ivec2; + typedef vec<3, int, defaultp> ivec3; + typedef vec<4, int, defaultp> ivec4; + + typedef vec<1, i8, lowp> lowp_i8vec1; + typedef vec<2, i8, lowp> lowp_i8vec2; + typedef vec<3, i8, lowp> lowp_i8vec3; + typedef vec<4, i8, lowp> lowp_i8vec4; + + typedef vec<1, i8, mediump> mediump_i8vec1; + typedef vec<2, i8, mediump> mediump_i8vec2; + typedef vec<3, i8, mediump> mediump_i8vec3; + typedef vec<4, i8, mediump> mediump_i8vec4; + + typedef vec<1, i8, highp> highp_i8vec1; + typedef vec<2, i8, highp> highp_i8vec2; + typedef vec<3, i8, highp> highp_i8vec3; + typedef vec<4, i8, highp> highp_i8vec4; + + typedef vec<1, i8, defaultp> i8vec1; + typedef vec<2, i8, defaultp> i8vec2; + typedef vec<3, i8, defaultp> i8vec3; + typedef vec<4, i8, defaultp> i8vec4; + + typedef vec<1, i16, lowp> lowp_i16vec1; + typedef vec<2, i16, lowp> lowp_i16vec2; + typedef vec<3, i16, lowp> lowp_i16vec3; + typedef vec<4, i16, lowp> lowp_i16vec4; + + typedef vec<1, i16, mediump> mediump_i16vec1; + typedef vec<2, i16, mediump> mediump_i16vec2; + typedef vec<3, i16, mediump> mediump_i16vec3; + typedef vec<4, i16, mediump> mediump_i16vec4; + + typedef vec<1, i16, highp> highp_i16vec1; + typedef vec<2, i16, highp> highp_i16vec2; + typedef vec<3, i16, highp> highp_i16vec3; + typedef vec<4, i16, highp> highp_i16vec4; + + typedef vec<1, i16, defaultp> i16vec1; + typedef vec<2, i16, defaultp> i16vec2; + typedef vec<3, i16, defaultp> i16vec3; + typedef vec<4, i16, defaultp> i16vec4; + + typedef vec<1, i32, lowp> lowp_i32vec1; + typedef vec<2, i32, lowp> lowp_i32vec2; + typedef vec<3, i32, lowp> lowp_i32vec3; + typedef vec<4, i32, lowp> lowp_i32vec4; + + typedef vec<1, i32, mediump> mediump_i32vec1; + typedef vec<2, i32, mediump> mediump_i32vec2; + typedef vec<3, i32, mediump> mediump_i32vec3; + typedef vec<4, i32, mediump> mediump_i32vec4; + + typedef vec<1, i32, highp> highp_i32vec1; + typedef vec<2, i32, highp> highp_i32vec2; + typedef vec<3, i32, highp> highp_i32vec3; + typedef vec<4, i32, highp> highp_i32vec4; + + typedef vec<1, i32, defaultp> i32vec1; + typedef vec<2, i32, defaultp> i32vec2; + typedef vec<3, i32, defaultp> i32vec3; + typedef vec<4, i32, defaultp> i32vec4; + + typedef vec<1, i64, lowp> lowp_i64vec1; + typedef vec<2, i64, lowp> lowp_i64vec2; + typedef vec<3, i64, lowp> lowp_i64vec3; + typedef vec<4, i64, lowp> lowp_i64vec4; + + typedef vec<1, i64, mediump> mediump_i64vec1; + typedef vec<2, i64, mediump> mediump_i64vec2; + typedef vec<3, i64, mediump> mediump_i64vec3; + typedef vec<4, i64, mediump> mediump_i64vec4; + + typedef vec<1, i64, highp> highp_i64vec1; + typedef vec<2, i64, highp> highp_i64vec2; + typedef vec<3, i64, highp> highp_i64vec3; + typedef vec<4, i64, highp> highp_i64vec4; + + typedef vec<1, i64, defaultp> i64vec1; + typedef vec<2, i64, defaultp> i64vec2; + typedef vec<3, i64, defaultp> i64vec3; + typedef vec<4, i64, defaultp> i64vec4; + + // Vector uint + + typedef vec<1, uint, lowp> lowp_uvec1; + typedef vec<2, uint, lowp> lowp_uvec2; + typedef vec<3, uint, lowp> lowp_uvec3; + typedef vec<4, uint, lowp> lowp_uvec4; + + typedef vec<1, uint, mediump> mediump_uvec1; + typedef vec<2, uint, mediump> mediump_uvec2; + typedef vec<3, uint, mediump> mediump_uvec3; + typedef vec<4, uint, mediump> mediump_uvec4; + + typedef vec<1, uint, highp> highp_uvec1; + typedef vec<2, uint, highp> highp_uvec2; + typedef vec<3, uint, highp> highp_uvec3; + typedef vec<4, uint, highp> highp_uvec4; + + typedef vec<1, uint, defaultp> uvec1; + typedef vec<2, uint, defaultp> uvec2; + typedef vec<3, uint, defaultp> uvec3; + typedef vec<4, uint, defaultp> uvec4; + + typedef vec<1, u8, lowp> lowp_u8vec1; + typedef vec<2, u8, lowp> lowp_u8vec2; + typedef vec<3, u8, lowp> lowp_u8vec3; + typedef vec<4, u8, lowp> lowp_u8vec4; + + typedef vec<1, u8, mediump> mediump_u8vec1; + typedef vec<2, u8, mediump> mediump_u8vec2; + typedef vec<3, u8, mediump> mediump_u8vec3; + typedef vec<4, u8, mediump> mediump_u8vec4; + + typedef vec<1, u8, highp> highp_u8vec1; + typedef vec<2, u8, highp> highp_u8vec2; + typedef vec<3, u8, highp> highp_u8vec3; + typedef vec<4, u8, highp> highp_u8vec4; + + typedef vec<1, u8, defaultp> u8vec1; + typedef vec<2, u8, defaultp> u8vec2; + typedef vec<3, u8, defaultp> u8vec3; + typedef vec<4, u8, defaultp> u8vec4; + + typedef vec<1, u16, lowp> lowp_u16vec1; + typedef vec<2, u16, lowp> lowp_u16vec2; + typedef vec<3, u16, lowp> lowp_u16vec3; + typedef vec<4, u16, lowp> lowp_u16vec4; + + typedef vec<1, u16, mediump> mediump_u16vec1; + typedef vec<2, u16, mediump> mediump_u16vec2; + typedef vec<3, u16, mediump> mediump_u16vec3; + typedef vec<4, u16, mediump> mediump_u16vec4; + + typedef vec<1, u16, highp> highp_u16vec1; + typedef vec<2, u16, highp> highp_u16vec2; + typedef vec<3, u16, highp> highp_u16vec3; + typedef vec<4, u16, highp> highp_u16vec4; + + typedef vec<1, u16, defaultp> u16vec1; + typedef vec<2, u16, defaultp> u16vec2; + typedef vec<3, u16, defaultp> u16vec3; + typedef vec<4, u16, defaultp> u16vec4; + + typedef vec<1, u32, lowp> lowp_u32vec1; + typedef vec<2, u32, lowp> lowp_u32vec2; + typedef vec<3, u32, lowp> lowp_u32vec3; + typedef vec<4, u32, lowp> lowp_u32vec4; + + typedef vec<1, u32, mediump> mediump_u32vec1; + typedef vec<2, u32, mediump> mediump_u32vec2; + typedef vec<3, u32, mediump> mediump_u32vec3; + typedef vec<4, u32, mediump> mediump_u32vec4; + + typedef vec<1, u32, highp> highp_u32vec1; + typedef vec<2, u32, highp> highp_u32vec2; + typedef vec<3, u32, highp> highp_u32vec3; + typedef vec<4, u32, highp> highp_u32vec4; + + typedef vec<1, u32, defaultp> u32vec1; + typedef vec<2, u32, defaultp> u32vec2; + typedef vec<3, u32, defaultp> u32vec3; + typedef vec<4, u32, defaultp> u32vec4; + + typedef vec<1, u64, lowp> lowp_u64vec1; + typedef vec<2, u64, lowp> lowp_u64vec2; + typedef vec<3, u64, lowp> lowp_u64vec3; + typedef vec<4, u64, lowp> lowp_u64vec4; + + typedef vec<1, u64, mediump> mediump_u64vec1; + typedef vec<2, u64, mediump> mediump_u64vec2; + typedef vec<3, u64, mediump> mediump_u64vec3; + typedef vec<4, u64, mediump> mediump_u64vec4; + + typedef vec<1, u64, highp> highp_u64vec1; + typedef vec<2, u64, highp> highp_u64vec2; + typedef vec<3, u64, highp> highp_u64vec3; + typedef vec<4, u64, highp> highp_u64vec4; + + typedef vec<1, u64, defaultp> u64vec1; + typedef vec<2, u64, defaultp> u64vec2; + typedef vec<3, u64, defaultp> u64vec3; + typedef vec<4, u64, defaultp> u64vec4; + + // Vector float + + typedef vec<1, float, lowp> lowp_vec1; + typedef vec<2, float, lowp> lowp_vec2; + typedef vec<3, float, lowp> lowp_vec3; + typedef vec<4, float, lowp> lowp_vec4; + + typedef vec<1, float, mediump> mediump_vec1; + typedef vec<2, float, mediump> mediump_vec2; + typedef vec<3, float, mediump> mediump_vec3; + typedef vec<4, float, mediump> mediump_vec4; + + typedef vec<1, float, highp> highp_vec1; + typedef vec<2, float, highp> highp_vec2; + typedef vec<3, float, highp> highp_vec3; + typedef vec<4, float, highp> highp_vec4; + + typedef vec<1, float, defaultp> vec1; + typedef vec<2, float, defaultp> vec2; + typedef vec<3, float, defaultp> vec3; + typedef vec<4, float, defaultp> vec4; + + typedef vec<1, float, lowp> lowp_fvec1; + typedef vec<2, float, lowp> lowp_fvec2; + typedef vec<3, float, lowp> lowp_fvec3; + typedef vec<4, float, lowp> lowp_fvec4; + + typedef vec<1, float, mediump> mediump_fvec1; + typedef vec<2, float, mediump> mediump_fvec2; + typedef vec<3, float, mediump> mediump_fvec3; + typedef vec<4, float, mediump> mediump_fvec4; + + typedef vec<1, float, highp> highp_fvec1; + typedef vec<2, float, highp> highp_fvec2; + typedef vec<3, float, highp> highp_fvec3; + typedef vec<4, float, highp> highp_fvec4; + + typedef vec<1, f32, defaultp> fvec1; + typedef vec<2, f32, defaultp> fvec2; + typedef vec<3, f32, defaultp> fvec3; + typedef vec<4, f32, defaultp> fvec4; + + typedef vec<1, f32, lowp> lowp_f32vec1; + typedef vec<2, f32, lowp> lowp_f32vec2; + typedef vec<3, f32, lowp> lowp_f32vec3; + typedef vec<4, f32, lowp> lowp_f32vec4; + + typedef vec<1, f32, mediump> mediump_f32vec1; + typedef vec<2, f32, mediump> mediump_f32vec2; + typedef vec<3, f32, mediump> mediump_f32vec3; + typedef vec<4, f32, mediump> mediump_f32vec4; + + typedef vec<1, f32, highp> highp_f32vec1; + typedef vec<2, f32, highp> highp_f32vec2; + typedef vec<3, f32, highp> highp_f32vec3; + typedef vec<4, f32, highp> highp_f32vec4; + + typedef vec<1, f32, defaultp> f32vec1; + typedef vec<2, f32, defaultp> f32vec2; + typedef vec<3, f32, defaultp> f32vec3; + typedef vec<4, f32, defaultp> f32vec4; + + typedef vec<1, f64, lowp> lowp_dvec1; + typedef vec<2, f64, lowp> lowp_dvec2; + typedef vec<3, f64, lowp> lowp_dvec3; + typedef vec<4, f64, lowp> lowp_dvec4; + + typedef vec<1, f64, mediump> mediump_dvec1; + typedef vec<2, f64, mediump> mediump_dvec2; + typedef vec<3, f64, mediump> mediump_dvec3; + typedef vec<4, f64, mediump> mediump_dvec4; + + typedef vec<1, f64, highp> highp_dvec1; + typedef vec<2, f64, highp> highp_dvec2; + typedef vec<3, f64, highp> highp_dvec3; + typedef vec<4, f64, highp> highp_dvec4; + + typedef vec<1, f64, defaultp> dvec1; + typedef vec<2, f64, defaultp> dvec2; + typedef vec<3, f64, defaultp> dvec3; + typedef vec<4, f64, defaultp> dvec4; + + typedef vec<1, f64, lowp> lowp_f64vec1; + typedef vec<2, f64, lowp> lowp_f64vec2; + typedef vec<3, f64, lowp> lowp_f64vec3; + typedef vec<4, f64, lowp> lowp_f64vec4; + + typedef vec<1, f64, mediump> mediump_f64vec1; + typedef vec<2, f64, mediump> mediump_f64vec2; + typedef vec<3, f64, mediump> mediump_f64vec3; + typedef vec<4, f64, mediump> mediump_f64vec4; + + typedef vec<1, f64, highp> highp_f64vec1; + typedef vec<2, f64, highp> highp_f64vec2; + typedef vec<3, f64, highp> highp_f64vec3; + typedef vec<4, f64, highp> highp_f64vec4; + + typedef vec<1, f64, defaultp> f64vec1; + typedef vec<2, f64, defaultp> f64vec2; + typedef vec<3, f64, defaultp> f64vec3; + typedef vec<4, f64, defaultp> f64vec4; + + // Matrix NxN + + typedef mat<2, 2, f32, lowp> lowp_mat2; + typedef mat<3, 3, f32, lowp> lowp_mat3; + typedef mat<4, 4, f32, lowp> lowp_mat4; + + typedef mat<2, 2, f32, mediump> mediump_mat2; + typedef mat<3, 3, f32, mediump> mediump_mat3; + typedef mat<4, 4, f32, mediump> mediump_mat4; + + typedef mat<2, 2, f32, highp> highp_mat2; + typedef mat<3, 3, f32, highp> highp_mat3; + typedef mat<4, 4, f32, highp> highp_mat4; + + typedef mat<2, 2, f32, defaultp> mat2; + typedef mat<3, 3, f32, defaultp> mat3; + typedef mat<4, 4, f32, defaultp> mat4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2; + typedef mat<3, 3, f32, lowp> lowp_fmat3; + typedef mat<4, 4, f32, lowp> lowp_fmat4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2; + typedef mat<3, 3, f32, mediump> mediump_fmat3; + typedef mat<4, 4, f32, mediump> mediump_fmat4; + + typedef mat<2, 2, f32, highp> highp_fmat2; + typedef mat<3, 3, f32, highp> highp_fmat3; + typedef mat<4, 4, f32, highp> highp_fmat4; + + typedef mat<2, 2, f32, defaultp> fmat2; + typedef mat<3, 3, f32, defaultp> fmat3; + typedef mat<4, 4, f32, defaultp> fmat4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4; + + typedef mat<2, 2, f32, highp> highp_f32mat2; + typedef mat<3, 3, f32, highp> highp_f32mat3; + typedef mat<4, 4, f32, highp> highp_f32mat4; + + typedef mat<2, 2, f32, defaultp> f32mat2; + typedef mat<3, 3, f32, defaultp> f32mat3; + typedef mat<4, 4, f32, defaultp> f32mat4; + + typedef mat<2, 2, f64, lowp> lowp_dmat2; + typedef mat<3, 3, f64, lowp> lowp_dmat3; + typedef mat<4, 4, f64, lowp> lowp_dmat4; + + typedef mat<2, 2, f64, mediump> mediump_dmat2; + typedef mat<3, 3, f64, mediump> mediump_dmat3; + typedef mat<4, 4, f64, mediump> mediump_dmat4; + + typedef mat<2, 2, f64, highp> highp_dmat2; + typedef mat<3, 3, f64, highp> highp_dmat3; + typedef mat<4, 4, f64, highp> highp_dmat4; + + typedef mat<2, 2, f64, defaultp> dmat2; + typedef mat<3, 3, f64, defaultp> dmat3; + typedef mat<4, 4, f64, defaultp> dmat4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4; + + typedef mat<2, 2, f64, highp> highp_f64mat2; + typedef mat<3, 3, f64, highp> highp_f64mat3; + typedef mat<4, 4, f64, highp> highp_f64mat4; + + typedef mat<2, 2, f64, defaultp> f64mat2; + typedef mat<3, 3, f64, defaultp> f64mat3; + typedef mat<4, 4, f64, defaultp> f64mat4; + + // Matrix MxN + + typedef mat<2, 2, f32, lowp> lowp_mat2x2; + typedef mat<2, 3, f32, lowp> lowp_mat2x3; + typedef mat<2, 4, f32, lowp> lowp_mat2x4; + typedef mat<3, 2, f32, lowp> lowp_mat3x2; + typedef mat<3, 3, f32, lowp> lowp_mat3x3; + typedef mat<3, 4, f32, lowp> lowp_mat3x4; + typedef mat<4, 2, f32, lowp> lowp_mat4x2; + typedef mat<4, 3, f32, lowp> lowp_mat4x3; + typedef mat<4, 4, f32, lowp> lowp_mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_mat2x2; + typedef mat<2, 3, f32, mediump> mediump_mat2x3; + typedef mat<2, 4, f32, mediump> mediump_mat2x4; + typedef mat<3, 2, f32, mediump> mediump_mat3x2; + typedef mat<3, 3, f32, mediump> mediump_mat3x3; + typedef mat<3, 4, f32, mediump> mediump_mat3x4; + typedef mat<4, 2, f32, mediump> mediump_mat4x2; + typedef mat<4, 3, f32, mediump> mediump_mat4x3; + typedef mat<4, 4, f32, mediump> mediump_mat4x4; + + typedef mat<2, 2, f32, highp> highp_mat2x2; + typedef mat<2, 3, f32, highp> highp_mat2x3; + typedef mat<2, 4, f32, highp> highp_mat2x4; + typedef mat<3, 2, f32, highp> highp_mat3x2; + typedef mat<3, 3, f32, highp> highp_mat3x3; + typedef mat<3, 4, f32, highp> highp_mat3x4; + typedef mat<4, 2, f32, highp> highp_mat4x2; + typedef mat<4, 3, f32, highp> highp_mat4x3; + typedef mat<4, 4, f32, highp> highp_mat4x4; + + typedef mat<2, 2, f32, defaultp> mat2x2; + typedef mat<3, 2, f32, defaultp> mat3x2; + typedef mat<4, 2, f32, defaultp> mat4x2; + typedef mat<2, 3, f32, defaultp> mat2x3; + typedef mat<3, 3, f32, defaultp> mat3x3; + typedef mat<4, 3, f32, defaultp> mat4x3; + typedef mat<2, 4, f32, defaultp> mat2x4; + typedef mat<3, 4, f32, defaultp> mat3x4; + typedef mat<4, 4, f32, defaultp> mat4x4; + + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + typedef mat<2, 2, f32, highp> highp_fmat2x2; + typedef mat<2, 3, f32, highp> highp_fmat2x3; + typedef mat<2, 4, f32, highp> highp_fmat2x4; + typedef mat<3, 2, f32, highp> highp_fmat3x2; + typedef mat<3, 3, f32, highp> highp_fmat3x3; + typedef mat<3, 4, f32, highp> highp_fmat3x4; + typedef mat<4, 2, f32, highp> highp_fmat4x2; + typedef mat<4, 3, f32, highp> highp_fmat4x3; + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + typedef mat<2, 2, f32, defaultp> fmat2x2; + typedef mat<3, 2, f32, defaultp> fmat3x2; + typedef mat<4, 2, f32, defaultp> fmat4x2; + typedef mat<2, 3, f32, defaultp> fmat2x3; + typedef mat<3, 3, f32, defaultp> fmat3x3; + typedef mat<4, 3, f32, defaultp> fmat4x3; + typedef mat<2, 4, f32, defaultp> fmat2x4; + typedef mat<3, 4, f32, defaultp> fmat3x4; + typedef mat<4, 4, f32, defaultp> fmat4x4; + + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + typedef mat<2, 2, f32, defaultp> f32mat2x2; + typedef mat<3, 2, f32, defaultp> f32mat3x2; + typedef mat<4, 2, f32, defaultp> f32mat4x2; + typedef mat<2, 3, f32, defaultp> f32mat2x3; + typedef mat<3, 3, f32, defaultp> f32mat3x3; + typedef mat<4, 3, f32, defaultp> f32mat4x3; + typedef mat<2, 4, f32, defaultp> f32mat2x4; + typedef mat<3, 4, f32, defaultp> f32mat3x4; + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + typedef mat<2, 2, double, lowp> lowp_dmat2x2; + typedef mat<2, 3, double, lowp> lowp_dmat2x3; + typedef mat<2, 4, double, lowp> lowp_dmat2x4; + typedef mat<3, 2, double, lowp> lowp_dmat3x2; + typedef mat<3, 3, double, lowp> lowp_dmat3x3; + typedef mat<3, 4, double, lowp> lowp_dmat3x4; + typedef mat<4, 2, double, lowp> lowp_dmat4x2; + typedef mat<4, 3, double, lowp> lowp_dmat4x3; + typedef mat<4, 4, double, lowp> lowp_dmat4x4; + + typedef mat<2, 2, double, mediump> mediump_dmat2x2; + typedef mat<2, 3, double, mediump> mediump_dmat2x3; + typedef mat<2, 4, double, mediump> mediump_dmat2x4; + typedef mat<3, 2, double, mediump> mediump_dmat3x2; + typedef mat<3, 3, double, mediump> mediump_dmat3x3; + typedef mat<3, 4, double, mediump> mediump_dmat3x4; + typedef mat<4, 2, double, mediump> mediump_dmat4x2; + typedef mat<4, 3, double, mediump> mediump_dmat4x3; + typedef mat<4, 4, double, mediump> mediump_dmat4x4; + + typedef mat<2, 2, double, highp> highp_dmat2x2; + typedef mat<2, 3, double, highp> highp_dmat2x3; + typedef mat<2, 4, double, highp> highp_dmat2x4; + typedef mat<3, 2, double, highp> highp_dmat3x2; + typedef mat<3, 3, double, highp> highp_dmat3x3; + typedef mat<3, 4, double, highp> highp_dmat3x4; + typedef mat<4, 2, double, highp> highp_dmat4x2; + typedef mat<4, 3, double, highp> highp_dmat4x3; + typedef mat<4, 4, double, highp> highp_dmat4x4; + + typedef mat<2, 2, double, defaultp> dmat2x2; + typedef mat<3, 2, double, defaultp> dmat3x2; + typedef mat<4, 2, double, defaultp> dmat4x2; + typedef mat<2, 3, double, defaultp> dmat2x3; + typedef mat<3, 3, double, defaultp> dmat3x3; + typedef mat<4, 3, double, defaultp> dmat4x3; + typedef mat<2, 4, double, defaultp> dmat2x4; + typedef mat<3, 4, double, defaultp> dmat3x4; + typedef mat<4, 4, double, defaultp> dmat4x4; + + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + typedef mat<2, 2, f64, defaultp> f64mat2x2; + typedef mat<3, 2, f64, defaultp> f64mat3x2; + typedef mat<4, 2, f64, defaultp> f64mat4x2; + typedef mat<2, 3, f64, defaultp> f64mat2x3; + typedef mat<3, 3, f64, defaultp> f64mat3x3; + typedef mat<4, 3, f64, defaultp> f64mat4x3; + typedef mat<2, 4, f64, defaultp> f64mat2x4; + typedef mat<3, 4, f64, defaultp> f64mat3x4; + typedef mat<4, 4, f64, defaultp> f64mat4x4; + + // Signed integer matrix MxN + + typedef mat<2, 2, int, lowp> lowp_imat2x2; + typedef mat<2, 3, int, lowp> lowp_imat2x3; + typedef mat<2, 4, int, lowp> lowp_imat2x4; + typedef mat<3, 2, int, lowp> lowp_imat3x2; + typedef mat<3, 3, int, lowp> lowp_imat3x3; + typedef mat<3, 4, int, lowp> lowp_imat3x4; + typedef mat<4, 2, int, lowp> lowp_imat4x2; + typedef mat<4, 3, int, lowp> lowp_imat4x3; + typedef mat<4, 4, int, lowp> lowp_imat4x4; + + typedef mat<2, 2, int, mediump> mediump_imat2x2; + typedef mat<2, 3, int, mediump> mediump_imat2x3; + typedef mat<2, 4, int, mediump> mediump_imat2x4; + typedef mat<3, 2, int, mediump> mediump_imat3x2; + typedef mat<3, 3, int, mediump> mediump_imat3x3; + typedef mat<3, 4, int, mediump> mediump_imat3x4; + typedef mat<4, 2, int, mediump> mediump_imat4x2; + typedef mat<4, 3, int, mediump> mediump_imat4x3; + typedef mat<4, 4, int, mediump> mediump_imat4x4; + + typedef mat<2, 2, int, highp> highp_imat2x2; + typedef mat<2, 3, int, highp> highp_imat2x3; + typedef mat<2, 4, int, highp> highp_imat2x4; + typedef mat<3, 2, int, highp> highp_imat3x2; + typedef mat<3, 3, int, highp> highp_imat3x3; + typedef mat<3, 4, int, highp> highp_imat3x4; + typedef mat<4, 2, int, highp> highp_imat4x2; + typedef mat<4, 3, int, highp> highp_imat4x3; + typedef mat<4, 4, int, highp> highp_imat4x4; + + typedef mat<2, 2, int, defaultp> imat2x2; + typedef mat<3, 2, int, defaultp> imat3x2; + typedef mat<4, 2, int, defaultp> imat4x2; + typedef mat<2, 3, int, defaultp> imat2x3; + typedef mat<3, 3, int, defaultp> imat3x3; + typedef mat<4, 3, int, defaultp> imat4x3; + typedef mat<2, 4, int, defaultp> imat2x4; + typedef mat<3, 4, int, defaultp> imat3x4; + typedef mat<4, 4, int, defaultp> imat4x4; + + + typedef mat<2, 2, int8, lowp> lowp_i8mat2x2; + typedef mat<2, 3, int8, lowp> lowp_i8mat2x3; + typedef mat<2, 4, int8, lowp> lowp_i8mat2x4; + typedef mat<3, 2, int8, lowp> lowp_i8mat3x2; + typedef mat<3, 3, int8, lowp> lowp_i8mat3x3; + typedef mat<3, 4, int8, lowp> lowp_i8mat3x4; + typedef mat<4, 2, int8, lowp> lowp_i8mat4x2; + typedef mat<4, 3, int8, lowp> lowp_i8mat4x3; + typedef mat<4, 4, int8, lowp> lowp_i8mat4x4; + + typedef mat<2, 2, int8, mediump> mediump_i8mat2x2; + typedef mat<2, 3, int8, mediump> mediump_i8mat2x3; + typedef mat<2, 4, int8, mediump> mediump_i8mat2x4; + typedef mat<3, 2, int8, mediump> mediump_i8mat3x2; + typedef mat<3, 3, int8, mediump> mediump_i8mat3x3; + typedef mat<3, 4, int8, mediump> mediump_i8mat3x4; + typedef mat<4, 2, int8, mediump> mediump_i8mat4x2; + typedef mat<4, 3, int8, mediump> mediump_i8mat4x3; + typedef mat<4, 4, int8, mediump> mediump_i8mat4x4; + + typedef mat<2, 2, int8, highp> highp_i8mat2x2; + typedef mat<2, 3, int8, highp> highp_i8mat2x3; + typedef mat<2, 4, int8, highp> highp_i8mat2x4; + typedef mat<3, 2, int8, highp> highp_i8mat3x2; + typedef mat<3, 3, int8, highp> highp_i8mat3x3; + typedef mat<3, 4, int8, highp> highp_i8mat3x4; + typedef mat<4, 2, int8, highp> highp_i8mat4x2; + typedef mat<4, 3, int8, highp> highp_i8mat4x3; + typedef mat<4, 4, int8, highp> highp_i8mat4x4; + + typedef mat<2, 2, int8, defaultp> i8mat2x2; + typedef mat<3, 2, int8, defaultp> i8mat3x2; + typedef mat<4, 2, int8, defaultp> i8mat4x2; + typedef mat<2, 3, int8, defaultp> i8mat2x3; + typedef mat<3, 3, int8, defaultp> i8mat3x3; + typedef mat<4, 3, int8, defaultp> i8mat4x3; + typedef mat<2, 4, int8, defaultp> i8mat2x4; + typedef mat<3, 4, int8, defaultp> i8mat3x4; + typedef mat<4, 4, int8, defaultp> i8mat4x4; + + + typedef mat<2, 2, int16, lowp> lowp_i16mat2x2; + typedef mat<2, 3, int16, lowp> lowp_i16mat2x3; + typedef mat<2, 4, int16, lowp> lowp_i16mat2x4; + typedef mat<3, 2, int16, lowp> lowp_i16mat3x2; + typedef mat<3, 3, int16, lowp> lowp_i16mat3x3; + typedef mat<3, 4, int16, lowp> lowp_i16mat3x4; + typedef mat<4, 2, int16, lowp> lowp_i16mat4x2; + typedef mat<4, 3, int16, lowp> lowp_i16mat4x3; + typedef mat<4, 4, int16, lowp> lowp_i16mat4x4; + + typedef mat<2, 2, int16, mediump> mediump_i16mat2x2; + typedef mat<2, 3, int16, mediump> mediump_i16mat2x3; + typedef mat<2, 4, int16, mediump> mediump_i16mat2x4; + typedef mat<3, 2, int16, mediump> mediump_i16mat3x2; + typedef mat<3, 3, int16, mediump> mediump_i16mat3x3; + typedef mat<3, 4, int16, mediump> mediump_i16mat3x4; + typedef mat<4, 2, int16, mediump> mediump_i16mat4x2; + typedef mat<4, 3, int16, mediump> mediump_i16mat4x3; + typedef mat<4, 4, int16, mediump> mediump_i16mat4x4; + + typedef mat<2, 2, int16, highp> highp_i16mat2x2; + typedef mat<2, 3, int16, highp> highp_i16mat2x3; + typedef mat<2, 4, int16, highp> highp_i16mat2x4; + typedef mat<3, 2, int16, highp> highp_i16mat3x2; + typedef mat<3, 3, int16, highp> highp_i16mat3x3; + typedef mat<3, 4, int16, highp> highp_i16mat3x4; + typedef mat<4, 2, int16, highp> highp_i16mat4x2; + typedef mat<4, 3, int16, highp> highp_i16mat4x3; + typedef mat<4, 4, int16, highp> highp_i16mat4x4; + + typedef mat<2, 2, int16, defaultp> i16mat2x2; + typedef mat<3, 2, int16, defaultp> i16mat3x2; + typedef mat<4, 2, int16, defaultp> i16mat4x2; + typedef mat<2, 3, int16, defaultp> i16mat2x3; + typedef mat<3, 3, int16, defaultp> i16mat3x3; + typedef mat<4, 3, int16, defaultp> i16mat4x3; + typedef mat<2, 4, int16, defaultp> i16mat2x4; + typedef mat<3, 4, int16, defaultp> i16mat3x4; + typedef mat<4, 4, int16, defaultp> i16mat4x4; + + + typedef mat<2, 2, int32, lowp> lowp_i32mat2x2; + typedef mat<2, 3, int32, lowp> lowp_i32mat2x3; + typedef mat<2, 4, int32, lowp> lowp_i32mat2x4; + typedef mat<3, 2, int32, lowp> lowp_i32mat3x2; + typedef mat<3, 3, int32, lowp> lowp_i32mat3x3; + typedef mat<3, 4, int32, lowp> lowp_i32mat3x4; + typedef mat<4, 2, int32, lowp> lowp_i32mat4x2; + typedef mat<4, 3, int32, lowp> lowp_i32mat4x3; + typedef mat<4, 4, int32, lowp> lowp_i32mat4x4; + + typedef mat<2, 2, int32, mediump> mediump_i32mat2x2; + typedef mat<2, 3, int32, mediump> mediump_i32mat2x3; + typedef mat<2, 4, int32, mediump> mediump_i32mat2x4; + typedef mat<3, 2, int32, mediump> mediump_i32mat3x2; + typedef mat<3, 3, int32, mediump> mediump_i32mat3x3; + typedef mat<3, 4, int32, mediump> mediump_i32mat3x4; + typedef mat<4, 2, int32, mediump> mediump_i32mat4x2; + typedef mat<4, 3, int32, mediump> mediump_i32mat4x3; + typedef mat<4, 4, int32, mediump> mediump_i32mat4x4; + + typedef mat<2, 2, int32, highp> highp_i32mat2x2; + typedef mat<2, 3, int32, highp> highp_i32mat2x3; + typedef mat<2, 4, int32, highp> highp_i32mat2x4; + typedef mat<3, 2, int32, highp> highp_i32mat3x2; + typedef mat<3, 3, int32, highp> highp_i32mat3x3; + typedef mat<3, 4, int32, highp> highp_i32mat3x4; + typedef mat<4, 2, int32, highp> highp_i32mat4x2; + typedef mat<4, 3, int32, highp> highp_i32mat4x3; + typedef mat<4, 4, int32, highp> highp_i32mat4x4; + + typedef mat<2, 2, int32, defaultp> i32mat2x2; + typedef mat<3, 2, int32, defaultp> i32mat3x2; + typedef mat<4, 2, int32, defaultp> i32mat4x2; + typedef mat<2, 3, int32, defaultp> i32mat2x3; + typedef mat<3, 3, int32, defaultp> i32mat3x3; + typedef mat<4, 3, int32, defaultp> i32mat4x3; + typedef mat<2, 4, int32, defaultp> i32mat2x4; + typedef mat<3, 4, int32, defaultp> i32mat3x4; + typedef mat<4, 4, int32, defaultp> i32mat4x4; + + + typedef mat<2, 2, int64, lowp> lowp_i64mat2x2; + typedef mat<2, 3, int64, lowp> lowp_i64mat2x3; + typedef mat<2, 4, int64, lowp> lowp_i64mat2x4; + typedef mat<3, 2, int64, lowp> lowp_i64mat3x2; + typedef mat<3, 3, int64, lowp> lowp_i64mat3x3; + typedef mat<3, 4, int64, lowp> lowp_i64mat3x4; + typedef mat<4, 2, int64, lowp> lowp_i64mat4x2; + typedef mat<4, 3, int64, lowp> lowp_i64mat4x3; + typedef mat<4, 4, int64, lowp> lowp_i64mat4x4; + + typedef mat<2, 2, int64, mediump> mediump_i64mat2x2; + typedef mat<2, 3, int64, mediump> mediump_i64mat2x3; + typedef mat<2, 4, int64, mediump> mediump_i64mat2x4; + typedef mat<3, 2, int64, mediump> mediump_i64mat3x2; + typedef mat<3, 3, int64, mediump> mediump_i64mat3x3; + typedef mat<3, 4, int64, mediump> mediump_i64mat3x4; + typedef mat<4, 2, int64, mediump> mediump_i64mat4x2; + typedef mat<4, 3, int64, mediump> mediump_i64mat4x3; + typedef mat<4, 4, int64, mediump> mediump_i64mat4x4; + + typedef mat<2, 2, int64, highp> highp_i64mat2x2; + typedef mat<2, 3, int64, highp> highp_i64mat2x3; + typedef mat<2, 4, int64, highp> highp_i64mat2x4; + typedef mat<3, 2, int64, highp> highp_i64mat3x2; + typedef mat<3, 3, int64, highp> highp_i64mat3x3; + typedef mat<3, 4, int64, highp> highp_i64mat3x4; + typedef mat<4, 2, int64, highp> highp_i64mat4x2; + typedef mat<4, 3, int64, highp> highp_i64mat4x3; + typedef mat<4, 4, int64, highp> highp_i64mat4x4; + + typedef mat<2, 2, int64, defaultp> i64mat2x2; + typedef mat<3, 2, int64, defaultp> i64mat3x2; + typedef mat<4, 2, int64, defaultp> i64mat4x2; + typedef mat<2, 3, int64, defaultp> i64mat2x3; + typedef mat<3, 3, int64, defaultp> i64mat3x3; + typedef mat<4, 3, int64, defaultp> i64mat4x3; + typedef mat<2, 4, int64, defaultp> i64mat2x4; + typedef mat<3, 4, int64, defaultp> i64mat3x4; + typedef mat<4, 4, int64, defaultp> i64mat4x4; + + + // Unsigned integer matrix MxN + + typedef mat<2, 2, uint, lowp> lowp_umat2x2; + typedef mat<2, 3, uint, lowp> lowp_umat2x3; + typedef mat<2, 4, uint, lowp> lowp_umat2x4; + typedef mat<3, 2, uint, lowp> lowp_umat3x2; + typedef mat<3, 3, uint, lowp> lowp_umat3x3; + typedef mat<3, 4, uint, lowp> lowp_umat3x4; + typedef mat<4, 2, uint, lowp> lowp_umat4x2; + typedef mat<4, 3, uint, lowp> lowp_umat4x3; + typedef mat<4, 4, uint, lowp> lowp_umat4x4; + + typedef mat<2, 2, uint, mediump> mediump_umat2x2; + typedef mat<2, 3, uint, mediump> mediump_umat2x3; + typedef mat<2, 4, uint, mediump> mediump_umat2x4; + typedef mat<3, 2, uint, mediump> mediump_umat3x2; + typedef mat<3, 3, uint, mediump> mediump_umat3x3; + typedef mat<3, 4, uint, mediump> mediump_umat3x4; + typedef mat<4, 2, uint, mediump> mediump_umat4x2; + typedef mat<4, 3, uint, mediump> mediump_umat4x3; + typedef mat<4, 4, uint, mediump> mediump_umat4x4; + + typedef mat<2, 2, uint, highp> highp_umat2x2; + typedef mat<2, 3, uint, highp> highp_umat2x3; + typedef mat<2, 4, uint, highp> highp_umat2x4; + typedef mat<3, 2, uint, highp> highp_umat3x2; + typedef mat<3, 3, uint, highp> highp_umat3x3; + typedef mat<3, 4, uint, highp> highp_umat3x4; + typedef mat<4, 2, uint, highp> highp_umat4x2; + typedef mat<4, 3, uint, highp> highp_umat4x3; + typedef mat<4, 4, uint, highp> highp_umat4x4; + + typedef mat<2, 2, uint, defaultp> umat2x2; + typedef mat<3, 2, uint, defaultp> umat3x2; + typedef mat<4, 2, uint, defaultp> umat4x2; + typedef mat<2, 3, uint, defaultp> umat2x3; + typedef mat<3, 3, uint, defaultp> umat3x3; + typedef mat<4, 3, uint, defaultp> umat4x3; + typedef mat<2, 4, uint, defaultp> umat2x4; + typedef mat<3, 4, uint, defaultp> umat3x4; + typedef mat<4, 4, uint, defaultp> umat4x4; + + + typedef mat<2, 2, uint8, lowp> lowp_u8mat2x2; + typedef mat<2, 3, uint8, lowp> lowp_u8mat2x3; + typedef mat<2, 4, uint8, lowp> lowp_u8mat2x4; + typedef mat<3, 2, uint8, lowp> lowp_u8mat3x2; + typedef mat<3, 3, uint8, lowp> lowp_u8mat3x3; + typedef mat<3, 4, uint8, lowp> lowp_u8mat3x4; + typedef mat<4, 2, uint8, lowp> lowp_u8mat4x2; + typedef mat<4, 3, uint8, lowp> lowp_u8mat4x3; + typedef mat<4, 4, uint8, lowp> lowp_u8mat4x4; + + typedef mat<2, 2, uint8, mediump> mediump_u8mat2x2; + typedef mat<2, 3, uint8, mediump> mediump_u8mat2x3; + typedef mat<2, 4, uint8, mediump> mediump_u8mat2x4; + typedef mat<3, 2, uint8, mediump> mediump_u8mat3x2; + typedef mat<3, 3, uint8, mediump> mediump_u8mat3x3; + typedef mat<3, 4, uint8, mediump> mediump_u8mat3x4; + typedef mat<4, 2, uint8, mediump> mediump_u8mat4x2; + typedef mat<4, 3, uint8, mediump> mediump_u8mat4x3; + typedef mat<4, 4, uint8, mediump> mediump_u8mat4x4; + + typedef mat<2, 2, uint8, highp> highp_u8mat2x2; + typedef mat<2, 3, uint8, highp> highp_u8mat2x3; + typedef mat<2, 4, uint8, highp> highp_u8mat2x4; + typedef mat<3, 2, uint8, highp> highp_u8mat3x2; + typedef mat<3, 3, uint8, highp> highp_u8mat3x3; + typedef mat<3, 4, uint8, highp> highp_u8mat3x4; + typedef mat<4, 2, uint8, highp> highp_u8mat4x2; + typedef mat<4, 3, uint8, highp> highp_u8mat4x3; + typedef mat<4, 4, uint8, highp> highp_u8mat4x4; + + typedef mat<2, 2, uint8, defaultp> u8mat2x2; + typedef mat<3, 2, uint8, defaultp> u8mat3x2; + typedef mat<4, 2, uint8, defaultp> u8mat4x2; + typedef mat<2, 3, uint8, defaultp> u8mat2x3; + typedef mat<3, 3, uint8, defaultp> u8mat3x3; + typedef mat<4, 3, uint8, defaultp> u8mat4x3; + typedef mat<2, 4, uint8, defaultp> u8mat2x4; + typedef mat<3, 4, uint8, defaultp> u8mat3x4; + typedef mat<4, 4, uint8, defaultp> u8mat4x4; + + + typedef mat<2, 2, uint16, lowp> lowp_u16mat2x2; + typedef mat<2, 3, uint16, lowp> lowp_u16mat2x3; + typedef mat<2, 4, uint16, lowp> lowp_u16mat2x4; + typedef mat<3, 2, uint16, lowp> lowp_u16mat3x2; + typedef mat<3, 3, uint16, lowp> lowp_u16mat3x3; + typedef mat<3, 4, uint16, lowp> lowp_u16mat3x4; + typedef mat<4, 2, uint16, lowp> lowp_u16mat4x2; + typedef mat<4, 3, uint16, lowp> lowp_u16mat4x3; + typedef mat<4, 4, uint16, lowp> lowp_u16mat4x4; + + typedef mat<2, 2, uint16, mediump> mediump_u16mat2x2; + typedef mat<2, 3, uint16, mediump> mediump_u16mat2x3; + typedef mat<2, 4, uint16, mediump> mediump_u16mat2x4; + typedef mat<3, 2, uint16, mediump> mediump_u16mat3x2; + typedef mat<3, 3, uint16, mediump> mediump_u16mat3x3; + typedef mat<3, 4, uint16, mediump> mediump_u16mat3x4; + typedef mat<4, 2, uint16, mediump> mediump_u16mat4x2; + typedef mat<4, 3, uint16, mediump> mediump_u16mat4x3; + typedef mat<4, 4, uint16, mediump> mediump_u16mat4x4; + + typedef mat<2, 2, uint16, highp> highp_u16mat2x2; + typedef mat<2, 3, uint16, highp> highp_u16mat2x3; + typedef mat<2, 4, uint16, highp> highp_u16mat2x4; + typedef mat<3, 2, uint16, highp> highp_u16mat3x2; + typedef mat<3, 3, uint16, highp> highp_u16mat3x3; + typedef mat<3, 4, uint16, highp> highp_u16mat3x4; + typedef mat<4, 2, uint16, highp> highp_u16mat4x2; + typedef mat<4, 3, uint16, highp> highp_u16mat4x3; + typedef mat<4, 4, uint16, highp> highp_u16mat4x4; + + typedef mat<2, 2, uint16, defaultp> u16mat2x2; + typedef mat<3, 2, uint16, defaultp> u16mat3x2; + typedef mat<4, 2, uint16, defaultp> u16mat4x2; + typedef mat<2, 3, uint16, defaultp> u16mat2x3; + typedef mat<3, 3, uint16, defaultp> u16mat3x3; + typedef mat<4, 3, uint16, defaultp> u16mat4x3; + typedef mat<2, 4, uint16, defaultp> u16mat2x4; + typedef mat<3, 4, uint16, defaultp> u16mat3x4; + typedef mat<4, 4, uint16, defaultp> u16mat4x4; + + + typedef mat<2, 2, uint32, lowp> lowp_u32mat2x2; + typedef mat<2, 3, uint32, lowp> lowp_u32mat2x3; + typedef mat<2, 4, uint32, lowp> lowp_u32mat2x4; + typedef mat<3, 2, uint32, lowp> lowp_u32mat3x2; + typedef mat<3, 3, uint32, lowp> lowp_u32mat3x3; + typedef mat<3, 4, uint32, lowp> lowp_u32mat3x4; + typedef mat<4, 2, uint32, lowp> lowp_u32mat4x2; + typedef mat<4, 3, uint32, lowp> lowp_u32mat4x3; + typedef mat<4, 4, uint32, lowp> lowp_u32mat4x4; + + typedef mat<2, 2, uint32, mediump> mediump_u32mat2x2; + typedef mat<2, 3, uint32, mediump> mediump_u32mat2x3; + typedef mat<2, 4, uint32, mediump> mediump_u32mat2x4; + typedef mat<3, 2, uint32, mediump> mediump_u32mat3x2; + typedef mat<3, 3, uint32, mediump> mediump_u32mat3x3; + typedef mat<3, 4, uint32, mediump> mediump_u32mat3x4; + typedef mat<4, 2, uint32, mediump> mediump_u32mat4x2; + typedef mat<4, 3, uint32, mediump> mediump_u32mat4x3; + typedef mat<4, 4, uint32, mediump> mediump_u32mat4x4; + + typedef mat<2, 2, uint32, highp> highp_u32mat2x2; + typedef mat<2, 3, uint32, highp> highp_u32mat2x3; + typedef mat<2, 4, uint32, highp> highp_u32mat2x4; + typedef mat<3, 2, uint32, highp> highp_u32mat3x2; + typedef mat<3, 3, uint32, highp> highp_u32mat3x3; + typedef mat<3, 4, uint32, highp> highp_u32mat3x4; + typedef mat<4, 2, uint32, highp> highp_u32mat4x2; + typedef mat<4, 3, uint32, highp> highp_u32mat4x3; + typedef mat<4, 4, uint32, highp> highp_u32mat4x4; + + typedef mat<2, 2, uint32, defaultp> u32mat2x2; + typedef mat<3, 2, uint32, defaultp> u32mat3x2; + typedef mat<4, 2, uint32, defaultp> u32mat4x2; + typedef mat<2, 3, uint32, defaultp> u32mat2x3; + typedef mat<3, 3, uint32, defaultp> u32mat3x3; + typedef mat<4, 3, uint32, defaultp> u32mat4x3; + typedef mat<2, 4, uint32, defaultp> u32mat2x4; + typedef mat<3, 4, uint32, defaultp> u32mat3x4; + typedef mat<4, 4, uint32, defaultp> u32mat4x4; + + + typedef mat<2, 2, uint64, lowp> lowp_u64mat2x2; + typedef mat<2, 3, uint64, lowp> lowp_u64mat2x3; + typedef mat<2, 4, uint64, lowp> lowp_u64mat2x4; + typedef mat<3, 2, uint64, lowp> lowp_u64mat3x2; + typedef mat<3, 3, uint64, lowp> lowp_u64mat3x3; + typedef mat<3, 4, uint64, lowp> lowp_u64mat3x4; + typedef mat<4, 2, uint64, lowp> lowp_u64mat4x2; + typedef mat<4, 3, uint64, lowp> lowp_u64mat4x3; + typedef mat<4, 4, uint64, lowp> lowp_u64mat4x4; + + typedef mat<2, 2, uint64, mediump> mediump_u64mat2x2; + typedef mat<2, 3, uint64, mediump> mediump_u64mat2x3; + typedef mat<2, 4, uint64, mediump> mediump_u64mat2x4; + typedef mat<3, 2, uint64, mediump> mediump_u64mat3x2; + typedef mat<3, 3, uint64, mediump> mediump_u64mat3x3; + typedef mat<3, 4, uint64, mediump> mediump_u64mat3x4; + typedef mat<4, 2, uint64, mediump> mediump_u64mat4x2; + typedef mat<4, 3, uint64, mediump> mediump_u64mat4x3; + typedef mat<4, 4, uint64, mediump> mediump_u64mat4x4; + + typedef mat<2, 2, uint64, highp> highp_u64mat2x2; + typedef mat<2, 3, uint64, highp> highp_u64mat2x3; + typedef mat<2, 4, uint64, highp> highp_u64mat2x4; + typedef mat<3, 2, uint64, highp> highp_u64mat3x2; + typedef mat<3, 3, uint64, highp> highp_u64mat3x3; + typedef mat<3, 4, uint64, highp> highp_u64mat3x4; + typedef mat<4, 2, uint64, highp> highp_u64mat4x2; + typedef mat<4, 3, uint64, highp> highp_u64mat4x3; + typedef mat<4, 4, uint64, highp> highp_u64mat4x4; + + typedef mat<2, 2, uint64, defaultp> u64mat2x2; + typedef mat<3, 2, uint64, defaultp> u64mat3x2; + typedef mat<4, 2, uint64, defaultp> u64mat4x2; + typedef mat<2, 3, uint64, defaultp> u64mat2x3; + typedef mat<3, 3, uint64, defaultp> u64mat3x3; + typedef mat<4, 3, uint64, defaultp> u64mat4x3; + typedef mat<2, 4, uint64, defaultp> u64mat2x4; + typedef mat<3, 4, uint64, defaultp> u64mat3x4; + typedef mat<4, 4, uint64, defaultp> u64mat4x4; + + // Quaternion + + typedef qua lowp_quat; + typedef qua mediump_quat; + typedef qua highp_quat; + typedef qua quat; + + typedef qua lowp_fquat; + typedef qua mediump_fquat; + typedef qua highp_fquat; + typedef qua fquat; + + typedef qua lowp_f32quat; + typedef qua mediump_f32quat; + typedef qua highp_f32quat; + typedef qua f32quat; + + typedef qua lowp_dquat; + typedef qua mediump_dquat; + typedef qua highp_dquat; + typedef qua dquat; + + typedef qua lowp_f64quat; + typedef qua mediump_f64quat; + typedef qua highp_f64quat; + typedef qua f64quat; +}//namespace glm + + diff --git a/thirdparty/glm/geometric.hpp b/thirdparty/glm/geometric.hpp new file mode 100644 index 0000000..c068a3c --- /dev/null +++ b/thirdparty/glm/geometric.hpp @@ -0,0 +1,116 @@ +/// @ref core +/// @file glm/geometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions +/// +/// @defgroup core_func_geometric Geometric functions +/// @ingroup core +/// +/// These operate on vectors as vectors, not component-wise. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/type_vec3.hpp" + +namespace glm +{ + /// @addtogroup core_func_geometric + /// @{ + + /// Returns the length of x, i.e., sqrt(x * x). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL length man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T length(vec const& x); + + /// Returns the distance betwwen p0 and p1, i.e., length(p0 - p1). + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL distance man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T distance(vec const& p0, vec const& p1); + + /// Returns the dot product of x and y, i.e., result = x * y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL dot man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL T dot(vec const& x, vec const& y); + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL cross man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// Returns a vector in the same direction as x but with length of 1. + /// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL normalize man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec normalize(vec const& x); + + /// If dot(Nref, I) < 0.0, return N, otherwise, return -N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL faceforward man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec faceforward( + vec const& N, + vec const& I, + vec const& Nref); + + /// For the incident vector I and surface orientation N, + /// returns the reflection direction : result = I - 2.0 * dot(N, I) * N. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL reflect man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec reflect( + vec const& I, + vec const& N); + + /// For the incident vector I and surface normal N, + /// and the ratio of indices of refraction eta, + /// return the refraction vector. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Floating-point scalar types. + /// + /// @see GLSL refract man page + /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions + template + GLM_FUNC_DECL vec refract( + vec const& I, + vec const& N, + T eta); + + /// @} +}//namespace glm + +#include "detail/func_geometric.inl" diff --git a/thirdparty/glm/glm.hpp b/thirdparty/glm/glm.hpp new file mode 100644 index 0000000..8b61064 --- /dev/null +++ b/thirdparty/glm/glm.hpp @@ -0,0 +1,136 @@ +/// @ref core +/// @file glm/glm.hpp +/// +/// @defgroup core Core features +/// +/// @brief Features that implement in C++ the GLSL specification as closely as possible. +/// +/// The GLM core consists of C++ types that mirror GLSL types and +/// C++ functions that mirror the GLSL functions. +/// +/// The best documentation for GLM Core is the current GLSL specification, +/// version 4.2 +/// (pdf file). +/// +/// GLM core functionalities require to be included to be used. +/// +/// +/// @defgroup core_vector Vector types +/// +/// Vector types of two to four components with an exhaustive set of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_vector_precision Vector types with precision qualifiers +/// +/// @brief Vector types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix Matrix types +/// +/// Matrix types of with C columns and R rows where C and R are values between 2 to 4 included. +/// These types have exhaustive sets of operators. +/// +/// @ingroup core +/// +/// +/// @defgroup core_matrix_precision Matrix types with precision qualifiers +/// +/// @brief Matrix types with precision qualifiers which may result in various precision in term of ULPs +/// +/// GLSL allows defining qualifiers for particular variables. +/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, +/// with OpenGL ES's GLSL, these qualifiers do have an effect. +/// +/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: +/// a number of typedefs that use a particular qualifier. +/// +/// None of these types make any guarantees about the actual qualifier used. +/// +/// @ingroup core +/// +/// +/// @defgroup ext Stable extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// EXT extensions are fully tested and documented. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtc Recommended extensions +/// +/// @brief Additional features not specified by GLSL specification. +/// +/// GTC extensions aim to be stable with tests and documentation. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions at once by +/// including . Otherwise, each extension needs to be included a specific file. +/// +/// +/// @defgroup gtx Experimental extensions +/// +/// @brief Experimental features not specified by GLSL specification. +/// +/// Experimental extensions are useful functions and types, but the development of +/// their API and functionality is not necessarily stable. They can change +/// substantially between versions. Backwards compatibility is not much of an issue +/// for them. +/// +/// Even if it's highly unrecommended, it's possible to include all the extensions +/// at once by including . Otherwise, each extension needs to be +/// included a specific file. +/// +/// @mainpage OpenGL Mathematics (GLM) +/// - Website: glm.g-truc.net +/// - GLM API documentation +/// - GLM Manual + +#include "detail/_fixes.hpp" + +#include "detail/setup.hpp" + +#pragma once + +#include +#include +#include +#include +#include +#include "fwd.hpp" + +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +#include "trigonometric.hpp" +#include "exponential.hpp" +#include "common.hpp" +#include "packing.hpp" +#include "geometric.hpp" +#include "matrix.hpp" +#include "vector_relational.hpp" +#include "integer.hpp" diff --git a/thirdparty/glm/gtc/bitfield.hpp b/thirdparty/glm/gtc/bitfield.hpp new file mode 100644 index 0000000..084fbe7 --- /dev/null +++ b/thirdparty/glm/gtc/bitfield.hpp @@ -0,0 +1,266 @@ +/// @ref gtc_bitfield +/// @file glm/gtc/bitfield.hpp +/// +/// @see core (dependence) +/// @see gtc_bitfield (dependence) +/// +/// @defgroup gtc_bitfield GLM_GTC_bitfield +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#include "../detail/setup.hpp" + +#pragma once + +// Dependencies +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "type_precision.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_bitfield extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_bitfield + /// @{ + + /// Build a mask of 'count' bits + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType mask(genIUType Bits); + + /// Build a mask of 'count' bits + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec mask(vec const& v); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift); + + /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateRight(vec const& In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift); + + /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldRotateLeft(vec const& In, int Shift); + + /// Set to 1 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount); + + /// Set to 1 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount); + + /// Set to 0 a range of bits. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Signed and unsigned integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_bitfield + template + GLM_FUNC_DECL vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint16 bitfieldInterleave(u8vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u8vec2 bitfieldDeinterleave(glm::uint16 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(u16vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u16vec2 bitfieldDeinterleave(glm::uint32 x); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of x followed by the first bit of y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y); + + /// Interleaves the bits of x and y. + /// The first bit is the first bit of v.x followed by the first bit of v.y. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(u32vec2 const& v); + + /// Deinterleaves the bits of x. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL glm::u32vec2 bitfieldDeinterleave(glm::uint64 x); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z); + + /// Interleaves the bits of x, y and z. + /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w); + + /// Interleaves the bits of x, y, z and w. + /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. + /// The other bits are interleaved following the previous sequence. + /// + /// @see gtc_bitfield + GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w); + + /// @} +} //namespace glm + +#include "bitfield.inl" diff --git a/thirdparty/glm/gtc/bitfield.inl b/thirdparty/glm/gtc/bitfield.inl new file mode 100644 index 0000000..06cf188 --- /dev/null +++ b/thirdparty/glm/gtc/bitfield.inl @@ -0,0 +1,626 @@ +/// @ref gtc_bitfield + +#include "../simd/integer.h" + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z); + + template + GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w); + + template<> + GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y) + { + glm::uint16 REG1(x); + glm::uint16 REG2(y); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555); + + return REG1 | static_cast(REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x55555555); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x55555555); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555555555555555ull); + REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555555555555555ull); + + return REG1 | (REG2 << 1); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0xFF0000FFu); + REG2 = ((REG2 << 16) | REG2) & static_cast(0xFF0000FFu); + REG3 = ((REG3 << 16) | REG3) & static_cast(0xFF0000FFu); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0x0F00F00Fu); + REG2 = ((REG2 << 8) | REG2) & static_cast(0x0F00F00Fu); + REG3 = ((REG3 << 8) | REG3) & static_cast(0x0F00F00Fu); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0xC30C30C3u); + REG2 = ((REG2 << 4) | REG2) & static_cast(0xC30C30C3u); + REG3 = ((REG3 << 4) | REG3) & static_cast(0xC30C30C3u); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x49249249u); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x49249249u); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x49249249u); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + + REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); + REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); + REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); + + REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); + REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); + REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); + + REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); + REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); + REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); + + REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); + REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); + REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); + + REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); + REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); + REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); + + return REG1 | (REG2 << 1) | (REG3 << 2); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w) + { + glm::uint32 REG1(x); + glm::uint32 REG2(y); + glm::uint32 REG3(z); + glm::uint32 REG4(w); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000Fu); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000Fu); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000Fu); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000Fu); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x03030303u); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x03030303u); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x03030303u); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x03030303u); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x11111111u); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x11111111u); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x11111111u); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x11111111u); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } + + template<> + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w) + { + glm::uint64 REG1(x); + glm::uint64 REG2(y); + glm::uint64 REG3(z); + glm::uint64 REG4(w); + + REG1 = ((REG1 << 24) | REG1) & static_cast(0x000000FF000000FFull); + REG2 = ((REG2 << 24) | REG2) & static_cast(0x000000FF000000FFull); + REG3 = ((REG3 << 24) | REG3) & static_cast(0x000000FF000000FFull); + REG4 = ((REG4 << 24) | REG4) & static_cast(0x000000FF000000FFull); + + REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000F000F000Full); + REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000F000F000Full); + REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000F000F000Full); + REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000F000F000Full); + + REG1 = ((REG1 << 6) | REG1) & static_cast(0x0303030303030303ull); + REG2 = ((REG2 << 6) | REG2) & static_cast(0x0303030303030303ull); + REG3 = ((REG3 << 6) | REG3) & static_cast(0x0303030303030303ull); + REG4 = ((REG4 << 6) | REG4) & static_cast(0x0303030303030303ull); + + REG1 = ((REG1 << 3) | REG1) & static_cast(0x1111111111111111ull); + REG2 = ((REG2 << 3) | REG2) & static_cast(0x1111111111111111ull); + REG3 = ((REG3 << 3) | REG3) & static_cast(0x1111111111111111ull); + REG4 = ((REG4 << 3) | REG4) & static_cast(0x1111111111111111ull); + + return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER genIUType mask(genIUType Bits) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return Bits >= sizeof(genIUType) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); + } + + template + GLM_FUNC_QUALIFIER vec mask(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); + + return detail::functor1::call(mask, v); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateRight(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(genIType) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldRotateLeft(vec const& In, int Shift) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); + + int const BitSize = static_cast(sizeof(T) * 8); + return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount) + { + return Value | static_cast(mask(BitCount) << FirstBit); + } + + template + GLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + template + GLM_FUNC_QUALIFIER vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount) + { + return Value & static_cast(~(mask(BitCount) << FirstBit)); + } + + GLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y; + + union sign16 + { + int16 i; + uint16 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(u8vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER u8vec2 bitfieldDeinterleave(glm::uint16 x) + { + uint16 REG1(x); + uint16 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555); + REG2 = REG2 & static_cast(0x5555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0xFFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0xFFFF); + + return glm::u8vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(u16vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave(glm::uint32 x) + { + glm::uint32 REG1(x); + glm::uint32 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x55555555); + REG2 = REG2 & static_cast(0x55555555); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x33333333); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x33333333); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF); + + return glm::u16vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y) + { + union sign32 + { + int32 i; + uint32 u; + } sign_x, sign_y; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + result.u = bitfieldInterleave(sign_x.u, sign_y.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y) + { + return detail::bitfieldInterleave(x, y); + } + + GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(u32vec2 const& v) + { + return detail::bitfieldInterleave(v.x, v.y); + } + + GLM_FUNC_QUALIFIER glm::u32vec2 bitfieldDeinterleave(glm::uint64 x) + { + glm::uint64 REG1(x); + glm::uint64 REG2(x >>= 1); + + REG1 = REG1 & static_cast(0x5555555555555555ull); + REG2 = REG2 & static_cast(0x5555555555555555ull); + + REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333333333333333ull); + REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333333333333333ull); + + REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); + REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); + + REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF00FF00FFull); + REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF00FF00FFull); + + REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF0000FFFFull); + REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF0000FFFFull); + + REG1 = ((REG1 >> 16) | REG1) & static_cast(0x00000000FFFFFFFFull); + REG2 = ((REG2 >> 16) | REG2) & static_cast(0x00000000FFFFFFFFull); + + return glm::u32vec2(REG1, REG2); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z) + { + union sign16 + { + int32 i; + uint32 u; + } sign_x, sign_y, sign_z; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z) + { + return detail::bitfieldInterleave(x, y, z); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u32vec3 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z); + } + + GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w) + { + union sign8 + { + int8 i; + uint8 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign32 + { + int32 i; + uint32 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } + + GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w) + { + union sign16 + { + int16 i; + uint16 u; + } sign_x, sign_y, sign_z, sign_w; + + union sign64 + { + int64 i; + uint64 u; + } result; + + sign_x.i = x; + sign_y.i = y; + sign_z.i = z; + sign_w.i = w; + result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); + + return result.i; + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w) + { + return detail::bitfieldInterleave(x, y, z, w); + } + + GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec4 const& v) + { + return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/color_space.hpp b/thirdparty/glm/gtc/color_space.hpp new file mode 100644 index 0000000..cffd9f0 --- /dev/null +++ b/thirdparty/glm/gtc/color_space.hpp @@ -0,0 +1,56 @@ +/// @ref gtc_color_space +/// @file glm/gtc/color_space.hpp +/// +/// @see core (dependence) +/// @see gtc_color_space (dependence) +/// +/// @defgroup gtc_color_space GLM_GTC_color_space +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../exponential.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_color_space extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_color_space + /// @{ + + /// Convert a linear color to sRGB color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear); + + /// Convert a linear color to sRGB color using a custom gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear, T Gamma); + + /// Convert a sRGB color to linear color using a standard gamma correction. + /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB); + + /// Convert a sRGB color to linear color using a custom gamma correction. + // IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb + template + GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma); + + /// @} +} //namespace glm + +#include "color_space.inl" diff --git a/thirdparty/glm/gtc/color_space.inl b/thirdparty/glm/gtc/color_space.inl new file mode 100644 index 0000000..2a90004 --- /dev/null +++ b/thirdparty/glm/gtc/color_space.inl @@ -0,0 +1,84 @@ +/// @ref gtc_color_space + +namespace glm{ +namespace detail +{ + template + struct compute_rgbToSrgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorRGB, T GammaCorrection) + { + vec const ClampedColor(clamp(ColorRGB, static_cast(0), static_cast(1))); + + return mix( + pow(ClampedColor, vec(GammaCorrection)) * static_cast(1.055) - static_cast(0.055), + ClampedColor * static_cast(12.92), + lessThan(ClampedColor, vec(static_cast(0.0031308)))); + } + }; + + template + struct compute_rgbToSrgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorRGB, T GammaCorrection) + { + return vec<4, T, Q>(compute_rgbToSrgb<3, T, Q>::call(vec<3, T, Q>(ColorRGB), GammaCorrection), ColorRGB.w); + } + }; + + template + struct compute_srgbToRgb + { + GLM_FUNC_QUALIFIER static vec call(vec const& ColorSRGB, T Gamma) + { + return mix( + pow((ColorSRGB + static_cast(0.055)) * static_cast(0.94786729857819905213270142180095), vec(Gamma)), + ColorSRGB * static_cast(0.07739938080495356037151702786378), + lessThanEqual(ColorSRGB, vec(static_cast(0.04045)))); + } + }; + + template + struct compute_srgbToRgb<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorSRGB, T Gamma) + { + return vec<4, T, Q>(compute_srgbToRgb<3, T, Q>::call(vec<3, T, Q>(ColorSRGB), Gamma), ColorSRGB.w); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(0.41666)); + } + + // Based on Ian Taylor http://chilliant.blogspot.fr/2012/08/srgb-approximations-for-hlsl.html + template<> + GLM_FUNC_QUALIFIER vec<3, float, lowp> convertLinearToSRGB(vec<3, float, lowp> const& ColorLinear) + { + vec<3, float, lowp> S1 = sqrt(ColorLinear); + vec<3, float, lowp> S2 = sqrt(S1); + vec<3, float, lowp> S3 = sqrt(S2); + return 0.662002687f * S1 + 0.684122060f * S2 - 0.323583601f * S3 - 0.0225411470f * ColorLinear; + } + + template + GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear, T Gamma) + { + return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(1) / Gamma); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB) + { + return detail::compute_srgbToRgb::call(ColorSRGB, static_cast(2.4)); + } + + template + GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma) + { + return detail::compute_srgbToRgb::call(ColorSRGB, Gamma); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/constants.hpp b/thirdparty/glm/gtc/constants.hpp new file mode 100644 index 0000000..99f2128 --- /dev/null +++ b/thirdparty/glm/gtc/constants.hpp @@ -0,0 +1,165 @@ +/// @ref gtc_constants +/// @file glm/gtc/constants.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_constants GLM_GTC_constants +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Provide a list of constants and precomputed useful values. + +#pragma once + +// Dependencies +#include "../ext/scalar_constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_constants extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_constants + /// @{ + + /// Return 0. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType zero(); + + /// Return 1. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one(); + + /// Return pi * 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_pi(); + + /// Return square root of pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_pi(); + + /// Return pi / 2. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType half_pi(); + + /// Return pi / 2 * 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi(); + + /// Return pi / 4. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi(); + + /// Return 1 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi(); + + /// Return 1 / (pi * 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi(); + + /// Return 2 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi(); + + /// Return 4 / pi. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi(); + + /// Return 2 / sqrt(pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi(); + + /// Return 1 / sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two(); + + /// Return sqrt(pi / 2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi(); + + /// Return sqrt(2 * pi). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi(); + + /// Return sqrt(ln(4)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four(); + + /// Return e constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType e(); + + /// Return Euler's constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType euler(); + + /// Return sqrt(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_two(); + + /// Return sqrt(3). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_three(); + + /// Return sqrt(5). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType root_five(); + + /// Return ln(2). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_two(); + + /// Return ln(10). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten(); + + /// Return ln(ln(2)). + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two(); + + /// Return 1 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType third(); + + /// Return 2 / 3. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds(); + + /// Return the golden ratio constant. + /// @see gtc_constants + template + GLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio(); + + /// @} +} //namespace glm + +#include "constants.inl" diff --git a/thirdparty/glm/gtc/constants.inl b/thirdparty/glm/gtc/constants.inl new file mode 100644 index 0000000..bb98c6b --- /dev/null +++ b/thirdparty/glm/gtc/constants.inl @@ -0,0 +1,167 @@ +/// @ref gtc_constants + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero() + { + return genType(0); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one() + { + return genType(1); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi() + { + return genType(6.28318530717958647692528676655900576); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi() + { + return genType(1.772453850905516027); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi() + { + return genType(1.57079632679489661923132169163975144); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi() + { + return genType(4.71238898038468985769396507491925432); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi() + { + return genType(0.785398163397448309615660845819875721); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi() + { + return genType(0.318309886183790671537767526745028724); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi() + { + return genType(0.159154943091895335768883763372514362); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi() + { + return genType(0.636619772367581343075535053490057448); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi() + { + return genType(1.273239544735162686151070106980114898); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi() + { + return genType(1.12837916709551257389615890312154517); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two() + { + return genType(0.707106781186547524400844362104849039); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi() + { + return genType(1.253314137315500251); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi() + { + return genType(2.506628274631000502); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four() + { + return genType(1.17741002251547469); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e() + { + return genType(2.71828182845904523536); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler() + { + return genType(0.577215664901532860606); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two() + { + return genType(1.41421356237309504880168872420969808); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three() + { + return genType(1.73205080756887729352744634150587236); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five() + { + return genType(2.23606797749978969640917366873127623); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two() + { + return genType(0.693147180559945309417232121458176568); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten() + { + return genType(2.30258509299404568401799145468436421); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two() + { + return genType(-0.3665129205816643); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third() + { + return genType(0.3333333333333333333333333333333333333333); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds() + { + return genType(0.666666666666666666666666666666666666667); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio() + { + return genType(1.61803398874989484820458683436563811); + } + +} //namespace glm diff --git a/thirdparty/glm/gtc/epsilon.hpp b/thirdparty/glm/gtc/epsilon.hpp new file mode 100644 index 0000000..640439b --- /dev/null +++ b/thirdparty/glm/gtc/epsilon.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_epsilon +/// @file glm/gtc/epsilon.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_epsilon GLM_GTC_epsilon +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Comparison functions for a user defined epsilon values. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_epsilon extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_epsilon + /// @{ + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonEqual(genType const& x, genType const& y, genType const& epsilon); + + /// Returns the component-wise comparison of |x - y| < epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon); + + /// Returns the component-wise comparison of |x - y| >= epsilon. + /// True if this expression is not satisfied. + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL bool epsilonNotEqual(genType const& x, genType const& y, genType const& epsilon); + + /// @} +}//namespace glm + +#include "epsilon.inl" diff --git a/thirdparty/glm/gtc/epsilon.inl b/thirdparty/glm/gtc/epsilon.inl new file mode 100644 index 0000000..508b9f8 --- /dev/null +++ b/thirdparty/glm/gtc/epsilon.inl @@ -0,0 +1,80 @@ +/// @ref gtc_epsilon + +// Dependency: +#include "../vector_relational.hpp" +#include "../common.hpp" + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + float const& x, + float const& y, + float const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonEqual + ( + double const& x, + double const& y, + double const& epsilon + ) + { + return abs(x - y) < epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, T const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, vec const& epsilon) + { + return lessThan(abs(x - y), vec(epsilon)); + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(float const& x, float const& y, float const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template<> + GLM_FUNC_QUALIFIER bool epsilonNotEqual(double const& x, double const& y, double const& epsilon) + { + return abs(x - y) >= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, vec const& epsilon) + { + return greaterThanEqual(abs(x - y), vec(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return lessThan(abs(v), vec<4, T, Q>(epsilon)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonNotEqual(qua const& x, qua const& y, T const& epsilon) + { + vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); + return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/integer.hpp b/thirdparty/glm/gtc/integer.hpp new file mode 100644 index 0000000..64ce10b --- /dev/null +++ b/thirdparty/glm/gtc/integer.hpp @@ -0,0 +1,65 @@ +/// @ref gtc_integer +/// @file glm/gtc/integer.hpp +/// +/// @see core (dependence) +/// @see gtc_integer (dependence) +/// +/// @defgroup gtc_integer GLM_GTC_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../common.hpp" +#include "../integer.hpp" +#include "../exponential.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_integer + /// @{ + + /// Returns the log2 of x for integer values. Usefull to compute mipmap count from the texture size. + /// @see gtc_integer + template + GLM_FUNC_DECL genIUType log2(genIUType x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see gtc_integer + template + GLM_FUNC_DECL vec iround(vec const& x); + + /// Returns a value equal to the nearest integer to x. + /// The fraction 0.5 will round in a direction chosen by the + /// implementation, presumably the direction that is fastest. + /// + /// @param x The values of the argument must be greater or equal to zero. + /// @tparam T floating point scalar types. + /// + /// @see GLSL round man page + /// @see gtc_integer + template + GLM_FUNC_DECL vec uround(vec const& x); + + /// @} +} //namespace glm + +#include "integer.inl" diff --git a/thirdparty/glm/gtc/integer.inl b/thirdparty/glm/gtc/integer.inl new file mode 100644 index 0000000..f0a8b4f --- /dev/null +++ b/thirdparty/glm/gtc/integer.inl @@ -0,0 +1,68 @@ +/// @ref gtc_integer + +namespace glm{ +namespace detail +{ + template + struct compute_log2 + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + //Equivalent to return findMSB(vec); but save one function call in ASM with VC + //return findMSB(vec); + return vec(detail::compute_findMSB_vec::call(v)); + } + }; + +# if GLM_HAS_BITSCAN_WINDOWS + template + struct compute_log2<4, int, Q, false, Aligned> + { + GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) + { + vec<4, int, Q> Result; + _BitScanReverse(reinterpret_cast(&Result.x), v.x); + _BitScanReverse(reinterpret_cast(&Result.y), v.y); + _BitScanReverse(reinterpret_cast(&Result.z), v.z); + _BitScanReverse(reinterpret_cast(&Result.w), v.w); + return Result; + } + }; +# endif//GLM_HAS_BITSCAN_WINDOWS +}//namespace detail + template + GLM_FUNC_QUALIFIER int iround(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER vec iround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER uint uround(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(static_cast(0.0) <= x); + + return static_cast(x + static_cast(0.5)); + } + + template + GLM_FUNC_QUALIFIER vec uround(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); + assert(all(lessThanEqual(vec(0), x))); + + return vec(x + static_cast(0.5)); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/matrix_access.hpp b/thirdparty/glm/gtc/matrix_access.hpp new file mode 100644 index 0000000..4935ba7 --- /dev/null +++ b/thirdparty/glm/gtc/matrix_access.hpp @@ -0,0 +1,60 @@ +/// @ref gtc_matrix_access +/// @file glm/gtc/matrix_access.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_access GLM_GTC_matrix_access +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions to access rows or columns of a matrix easily. + +#pragma once + +// Dependency: +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_access extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_access + /// @{ + + /// Get a specific row of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::row_type row( + genType const& m, + length_t index); + + /// Set a specific row to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType row( + genType const& m, + length_t index, + typename genType::row_type const& x); + + /// Get a specific column of a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL typename genType::col_type column( + genType const& m, + length_t index); + + /// Set a specific column to a matrix. + /// @see gtc_matrix_access + template + GLM_FUNC_DECL genType column( + genType const& m, + length_t index, + typename genType::col_type const& x); + + /// @} +}//namespace glm + +#include "matrix_access.inl" diff --git a/thirdparty/glm/gtc/matrix_access.inl b/thirdparty/glm/gtc/matrix_access.inl new file mode 100644 index 0000000..09fcc10 --- /dev/null +++ b/thirdparty/glm/gtc/matrix_access.inl @@ -0,0 +1,62 @@ +/// @ref gtc_matrix_access + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType row + ( + genType const& m, + length_t index, + typename genType::row_type const& x + ) + { + assert(index >= 0 && index < m[0].length()); + + genType Result = m; + for(length_t i = 0; i < m.length(); ++i) + Result[i][index] = x[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::row_type row + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m[0].length()); + + typename genType::row_type Result(0); + for(length_t i = 0; i < m.length(); ++i) + Result[i] = m[i][index]; + return Result; + } + + template + GLM_FUNC_QUALIFIER genType column + ( + genType const& m, + length_t index, + typename genType::col_type const& x + ) + { + assert(index >= 0 && index < m.length()); + + genType Result = m; + Result[index] = x; + return Result; + } + + template + GLM_FUNC_QUALIFIER typename genType::col_type column + ( + genType const& m, + length_t index + ) + { + assert(index >= 0 && index < m.length()); + + return m[index]; + } +}//namespace glm diff --git a/thirdparty/glm/gtc/matrix_integer.hpp b/thirdparty/glm/gtc/matrix_integer.hpp new file mode 100644 index 0000000..d7ebdc7 --- /dev/null +++ b/thirdparty/glm/gtc/matrix_integer.hpp @@ -0,0 +1,433 @@ +/// @ref gtc_matrix_integer +/// @file glm/gtc/matrix_integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a number of matrices with integer types. + +#pragma once + +// Dependency: +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_integer extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_integer + /// @{ + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4; + + /// High-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, highp> highp_imat2x2; + + /// High-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, highp> highp_imat2x3; + + /// High-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, highp> highp_imat2x4; + + /// High-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, highp> highp_imat3x2; + + /// High-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, highp> highp_imat3x3; + + /// High-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, highp> highp_imat3x4; + + /// High-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, highp> highp_imat4x2; + + /// High-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, highp> highp_imat4x3; + + /// High-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, highp> highp_imat4x4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4; + + + /// Medium-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, mediump> mediump_imat2x2; + + /// Medium-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, mediump> mediump_imat2x3; + + /// Medium-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, mediump> mediump_imat2x4; + + /// Medium-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, mediump> mediump_imat3x2; + + /// Medium-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, mediump> mediump_imat3x3; + + /// Medium-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, mediump> mediump_imat3x4; + + /// Medium-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, mediump> mediump_imat4x2; + + /// Medium-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, mediump> mediump_imat4x3; + + /// Medium-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, mediump> mediump_imat4x4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4; + + + /// Low-qualifier signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, lowp> lowp_imat2x2; + + /// Low-qualifier signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, lowp> lowp_imat2x3; + + /// Low-qualifier signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, lowp> lowp_imat2x4; + + /// Low-qualifier signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, lowp> lowp_imat3x2; + + /// Low-qualifier signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, lowp> lowp_imat3x3; + + /// Low-qualifier signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, lowp> lowp_imat3x4; + + /// Low-qualifier signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, lowp> lowp_imat4x2; + + /// Low-qualifier signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, lowp> lowp_imat4x3; + + /// Low-qualifier signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, lowp> lowp_imat4x4; + + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4; + + /// High-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, highp> highp_umat2x2; + + /// High-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, highp> highp_umat2x3; + + /// High-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, highp> highp_umat2x4; + + /// High-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, highp> highp_umat3x2; + + /// High-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, highp> highp_umat3x3; + + /// High-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, highp> highp_umat3x4; + + /// High-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, highp> highp_umat4x2; + + /// High-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, highp> highp_umat4x3; + + /// High-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, highp> highp_umat4x4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4; + + + /// Medium-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, mediump> mediump_umat2x2; + + /// Medium-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, mediump> mediump_umat2x3; + + /// Medium-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, mediump> mediump_umat2x4; + + /// Medium-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, mediump> mediump_umat3x2; + + /// Medium-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, mediump> mediump_umat3x3; + + /// Medium-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, mediump> mediump_umat3x4; + + /// Medium-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, mediump> mediump_umat4x2; + + /// Medium-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, mediump> mediump_umat4x3; + + /// Medium-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, mediump> mediump_umat4x4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4; + + + /// Low-qualifier unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, lowp> lowp_umat2x2; + + /// Low-qualifier unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, lowp> lowp_umat2x3; + + /// Low-qualifier unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, lowp> lowp_umat2x4; + + /// Low-qualifier unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, lowp> lowp_umat3x2; + + /// Low-qualifier unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, lowp> lowp_umat3x3; + + /// Low-qualifier unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, lowp> lowp_umat3x4; + + /// Low-qualifier unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, lowp> lowp_umat4x2; + + /// Low-qualifier unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, lowp> lowp_umat4x3; + + /// Low-qualifier unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, lowp> lowp_umat4x4; + + + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, defaultp> imat2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, defaultp> imat3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, defaultp> imat4; + + /// Signed integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, int, defaultp> imat2x2; + + /// Signed integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, int, defaultp> imat2x3; + + /// Signed integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, int, defaultp> imat2x4; + + /// Signed integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, int, defaultp> imat3x2; + + /// Signed integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, int, defaultp> imat3x3; + + /// Signed integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, int, defaultp> imat3x4; + + /// Signed integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, int, defaultp> imat4x2; + + /// Signed integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, int, defaultp> imat4x3; + + /// Signed integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, int, defaultp> imat4x4; + + + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, defaultp> umat2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, defaultp> umat3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, defaultp> umat4; + + /// Unsigned integer 2x2 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 2, uint, defaultp> umat2x2; + + /// Unsigned integer 2x3 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 3, uint, defaultp> umat2x3; + + /// Unsigned integer 2x4 matrix. + /// @see gtc_matrix_integer + typedef mat<2, 4, uint, defaultp> umat2x4; + + /// Unsigned integer 3x2 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 2, uint, defaultp> umat3x2; + + /// Unsigned integer 3x3 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 3, uint, defaultp> umat3x3; + + /// Unsigned integer 3x4 matrix. + /// @see gtc_matrix_integer + typedef mat<3, 4, uint, defaultp> umat3x4; + + /// Unsigned integer 4x2 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 2, uint, defaultp> umat4x2; + + /// Unsigned integer 4x3 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 3, uint, defaultp> umat4x3; + + /// Unsigned integer 4x4 matrix. + /// @see gtc_matrix_integer + typedef mat<4, 4, uint, defaultp> umat4x4; + + /// @} +}//namespace glm diff --git a/thirdparty/glm/gtc/matrix_inverse.hpp b/thirdparty/glm/gtc/matrix_inverse.hpp new file mode 100644 index 0000000..a1900ad --- /dev/null +++ b/thirdparty/glm/gtc/matrix_inverse.hpp @@ -0,0 +1,50 @@ +/// @ref gtc_matrix_inverse +/// @file glm/gtc/matrix_inverse.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines additional matrix inverting functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../matrix.hpp" +#include "../mat2x2.hpp" +#include "../mat3x3.hpp" +#include "../mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_inverse extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_matrix_inverse + /// @{ + + /// Fast matrix inverse for affine matrix. + /// + /// @param m Input matrix to invert. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType affineInverse(genType const& m); + + /// Compute the inverse transpose of a matrix. + /// + /// @param m Input matrix to invert transpose. + /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. + /// @see gtc_matrix_inverse + template + GLM_FUNC_DECL genType inverseTranspose(genType const& m); + + /// @} +}//namespace glm + +#include "matrix_inverse.inl" diff --git a/thirdparty/glm/gtc/matrix_inverse.inl b/thirdparty/glm/gtc/matrix_inverse.inl new file mode 100644 index 0000000..c004b9e --- /dev/null +++ b/thirdparty/glm/gtc/matrix_inverse.inl @@ -0,0 +1,118 @@ +/// @ref gtc_matrix_inverse + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> affineInverse(mat<3, 3, T, Q> const& m) + { + mat<2, 2, T, Q> const Inv(inverse(mat<2, 2, T, Q>(m))); + + return mat<3, 3, T, Q>( + vec<3, T, Q>(Inv[0], static_cast(0)), + vec<3, T, Q>(Inv[1], static_cast(0)), + vec<3, T, Q>(-Inv * vec<2, T, Q>(m[2]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> affineInverse(mat<4, 4, T, Q> const& m) + { + mat<3, 3, T, Q> const Inv(inverse(mat<3, 3, T, Q>(m))); + + return mat<4, 4, T, Q>( + vec<4, T, Q>(Inv[0], static_cast(0)), + vec<4, T, Q>(Inv[1], static_cast(0)), + vec<4, T, Q>(Inv[2], static_cast(0)), + vec<4, T, Q>(-Inv * vec<3, T, Q>(m[3]), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> inverseTranspose(mat<2, 2, T, Q> const& m) + { + T Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1]; + + mat<2, 2, T, Q> Inverse( + + m[1][1] / Determinant, + - m[0][1] / Determinant, + - m[1][0] / Determinant, + + m[0][0] / Determinant); + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> inverseTranspose(mat<3, 3, T, Q> const& m) + { + T Determinant = + + m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) + - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + + mat<3, 3, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]); + Inverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]); + Inverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]); + Inverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]); + Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]); + Inverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]); + Inverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]); + Inverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]); + Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]); + Inverse /= Determinant; + + return Inverse; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> inverseTranspose(mat<4, 4, T, Q> const& m) + { + T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + T SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + T SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + T SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + T SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + T SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + T SubFactor11 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + T SubFactor12 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + T SubFactor13 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + T SubFactor14 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + T SubFactor15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + T SubFactor16 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + T SubFactor17 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + mat<4, 4, T, Q> Inverse; + Inverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02); + Inverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04); + Inverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05); + Inverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05); + + Inverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02); + Inverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04); + Inverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05); + Inverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05); + + Inverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08); + Inverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10); + Inverse[2][2] = + (m[0][0] * SubFactor07 - m[0][1] * SubFactor09 + m[0][3] * SubFactor11); + Inverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor11); + + Inverse[3][0] = - (m[0][1] * SubFactor12 - m[0][2] * SubFactor13 + m[0][3] * SubFactor14); + Inverse[3][1] = + (m[0][0] * SubFactor12 - m[0][2] * SubFactor15 + m[0][3] * SubFactor16); + Inverse[3][2] = - (m[0][0] * SubFactor13 - m[0][1] * SubFactor15 + m[0][3] * SubFactor17); + Inverse[3][3] = + (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][2] * SubFactor17); + + T Determinant = + + m[0][0] * Inverse[0][0] + + m[0][1] * Inverse[0][1] + + m[0][2] * Inverse[0][2] + + m[0][3] * Inverse[0][3]; + + Inverse /= Determinant; + + return Inverse; + } +}//namespace glm diff --git a/thirdparty/glm/gtc/matrix_transform.hpp b/thirdparty/glm/gtc/matrix_transform.hpp new file mode 100644 index 0000000..612418f --- /dev/null +++ b/thirdparty/glm/gtc/matrix_transform.hpp @@ -0,0 +1,36 @@ +/// @ref gtc_matrix_transform +/// @file glm/gtc/matrix_transform.hpp +/// +/// @see core (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common transformation matrices. +/// +/// The matrices generated by this extension use standard OpenGL fixed-function +/// conventions. For example, the lookAt function generates a transform from world +/// space into the specific eye space that the projective matrix functions +/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility +/// specifications defines the particular layout of this eye space. + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../ext/matrix_projection.hpp" +#include "../ext/matrix_clip_space.hpp" +#include "../ext/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_matrix_transform extension included") +#endif + +#include "matrix_transform.inl" diff --git a/thirdparty/glm/gtc/matrix_transform.inl b/thirdparty/glm/gtc/matrix_transform.inl new file mode 100644 index 0000000..15b46bc --- /dev/null +++ b/thirdparty/glm/gtc/matrix_transform.inl @@ -0,0 +1,3 @@ +#include "../geometric.hpp" +#include "../trigonometric.hpp" +#include "../matrix.hpp" diff --git a/thirdparty/glm/gtc/noise.hpp b/thirdparty/glm/gtc/noise.hpp new file mode 100644 index 0000000..ab1772e --- /dev/null +++ b/thirdparty/glm/gtc/noise.hpp @@ -0,0 +1,61 @@ +/// @ref gtc_noise +/// @file glm/gtc/noise.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_noise GLM_GTC_noise +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines 2D, 3D and 4D procedural noise functions +/// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +/// https://github.com/ashima/webgl-noise +/// Following Stefan Gustavson's paper "Simplex noise demystified": +/// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_noise.hpp" +#include "../geometric.hpp" +#include "../common.hpp" +#include "../vector_relational.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_noise extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_noise + /// @{ + + /// Classic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p); + + /// Periodic perlin noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T perlin( + vec const& p, + vec const& rep); + + /// Simplex noise. + /// @see gtc_noise + template + GLM_FUNC_DECL T simplex( + vec const& p); + + /// @} +}//namespace glm + +#include "noise.inl" diff --git a/thirdparty/glm/gtc/noise.inl b/thirdparty/glm/gtc/noise.inl new file mode 100644 index 0000000..30d0b27 --- /dev/null +++ b/thirdparty/glm/gtc/noise.inl @@ -0,0 +1,807 @@ +/// @ref gtc_noise +/// +// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": +// https://github.com/ashima/webgl-noise +// Following Stefan Gustavson's paper "Simplex noise demystified": +// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf + +namespace glm{ +namespace gtc +{ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> grad4(T const& j, vec<4, T, Q> const& ip) + { + vec<3, T, Q> pXYZ = floor(fract(vec<3, T, Q>(j) * vec<3, T, Q>(ip)) * T(7)) * ip[2] - T(1); + T pW = static_cast(1.5) - dot(abs(pXYZ), vec<3, T, Q>(1)); + vec<4, T, Q> s = vec<4, T, Q>(lessThan(vec<4, T, Q>(pXYZ, pW), vec<4, T, Q>(0.0))); + pXYZ = pXYZ + (vec<3, T, Q>(s) * T(2) - T(1)) * s.w; + return vec<4, T, Q>(pXYZ, pW); + } +}//namespace gtc + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position) + { + vec<4, T, Q> Pi = glm::floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * glm::fract(i / T(41)) - T(1); + vec<4, T, Q> gy = glm::abs(gx) - T(0.5); + vec<4, T, Q> tx = glm::floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position) + { + vec<3, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = detail::mod289(Pi0); + Pi1 = detail::mod289(Pi1); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(vec<2, T, Q>(Pi0.y), vec<2, T, Q>(Pi1.y)); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); + vec<4, T, Q> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 * T(1.0 / 7.0); + vec<4, T, Q> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + /* + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& P) + { + vec<3, T, Q> Pi0 = floor(P); // Integer part for indexing + vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, T(289)); + Pi1 = mod(Pi1, T(289)); + vec<3, T, Q> Pf0 = fract(P); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = permute(permute(ix) + iy); + vec<4, T, Q> ixy0 = permute(ixy + iz0); + vec<4, T, Q> ixy1 = permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); + gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); + gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix( + vec<2, T, Q>(n_z.x, n_z.y), + vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + */ + // Classic Perlin noise + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position) + { + vec<4, T, Q> Pi0 = floor(Position); // Integer part for indexing + vec<4, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 + Pi0 = mod(Pi0, vec<4, T, Q>(289)); + Pi1 = mod(Pi1, vec<4, T, Q>(289)); + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0.0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(0.0)); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position, vec<2, T, Q> const& rep) + { + vec<4, T, Q> Pi = floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + vec<4, T, Q> Pf = fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, vec<4, T, Q>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period + Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation + vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); + vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); + vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); + vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); + + vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); + + vec<4, T, Q> gx = static_cast(2) * fract(i / T(41)) - T(1); + vec<4, T, Q> gy = abs(gx) - T(0.5); + vec<4, T, Q> tx = floor(gx + T(0.5)); + gx = gx - tx; + + vec<2, T, Q> g00(gx.x, gy.x); + vec<2, T, Q> g10(gx.y, gy.y); + vec<2, T, Q> g01(gx.z, gy.z); + vec<2, T, Q> g11(gx.w, gy.w); + + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); + g00 *= norm.x; + g01 *= norm.y; + g10 *= norm.z; + g11 *= norm.w; + + T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); + T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); + T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); + T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); + + vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); + vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); + T n_xy = mix(n_x.x, n_x.y, fade_xy.y); + return T(2.3) * n_xy; + } + + // Classic Perlin noise, periodic variant + template + GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position, vec<3, T, Q> const& rep) + { + vec<3, T, Q> Pi0 = mod(floor(Position), rep); // Integer part, modulo period + vec<3, T, Q> Pi1 = mod(Pi0 + vec<3, T, Q>(T(1)), rep); // Integer part + 1, mod period + Pi0 = mod(Pi0, vec<3, T, Q>(289)); + Pi1 = mod(Pi1, vec<3, T, Q>(289)); + vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<3, T, Q> Pf1 = Pf0 - vec<3, T, Q>(T(1)); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + + vec<4, T, Q> gx0 = ixy0 / T(7); + vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); + gx0 = fract(gx0); + vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); + vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0)); + gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); + gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); + + vec<4, T, Q> gx1 = ixy1 / T(7); + vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); + gx1 = fract(gx1); + vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); + vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(T(0))); + gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); + gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); + + vec<3, T, Q> g000 = vec<3, T, Q>(gx0.x, gy0.x, gz0.x); + vec<3, T, Q> g100 = vec<3, T, Q>(gx0.y, gy0.y, gz0.y); + vec<3, T, Q> g010 = vec<3, T, Q>(gx0.z, gy0.z, gz0.z); + vec<3, T, Q> g110 = vec<3, T, Q>(gx0.w, gy0.w, gz0.w); + vec<3, T, Q> g001 = vec<3, T, Q>(gx1.x, gy1.x, gz1.x); + vec<3, T, Q> g101 = vec<3, T, Q>(gx1.y, gy1.y, gz1.y); + vec<3, T, Q> g011 = vec<3, T, Q>(gx1.z, gy1.z, gz1.z); + vec<3, T, Q> g111 = vec<3, T, Q>(gx1.w, gy1.w, gz1.w); + + vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + T n000 = dot(g000, Pf0); + T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); + T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); + T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); + T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); + T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); + T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); + T n111 = dot(g111, Pf1); + + vec<3, T, Q> fade_xyz = detail::fade(Pf0); + vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); + vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); + T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return T(2.2) * n_xyz; + } + + // Classic Perlin noise, periodic version + template + GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position, vec<4, T, Q> const& rep) + { + vec<4, T, Q> Pi0 = mod(floor(Position), rep); // Integer part modulo rep + vec<4, T, Q> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep + vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation + vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 + vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec<4, T, Q> iz0(Pi0.z); + vec<4, T, Q> iz1(Pi1.z); + vec<4, T, Q> iw0(Pi0.w); + vec<4, T, Q> iw1(Pi1.w); + + vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); + vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); + vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); + vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); + vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); + vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); + vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); + + vec<4, T, Q> gx00 = ixy00 / T(7); + vec<4, T, Q> gy00 = floor(gx00) / T(7); + vec<4, T, Q> gz00 = floor(gy00) / T(6); + gx00 = fract(gx00) - T(0.5); + gy00 = fract(gy00) - T(0.5); + gz00 = fract(gz00) - T(0.5); + vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); + vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0)); + gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); + gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); + + vec<4, T, Q> gx01 = ixy01 / T(7); + vec<4, T, Q> gy01 = floor(gx01) / T(7); + vec<4, T, Q> gz01 = floor(gy01) / T(6); + gx01 = fract(gx01) - T(0.5); + gy01 = fract(gy01) - T(0.5); + gz01 = fract(gz01) - T(0.5); + vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); + vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); + gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); + gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); + + vec<4, T, Q> gx10 = ixy10 / T(7); + vec<4, T, Q> gy10 = floor(gx10) / T(7); + vec<4, T, Q> gz10 = floor(gy10) / T(6); + gx10 = fract(gx10) - T(0.5); + gy10 = fract(gy10) - T(0.5); + gz10 = fract(gz10) - T(0.5); + vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); + vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0.0)); + gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); + gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); + + vec<4, T, Q> gx11 = ixy11 / T(7); + vec<4, T, Q> gy11 = floor(gx11) / T(7); + vec<4, T, Q> gz11 = floor(gy11) / T(6); + gx11 = fract(gx11) - T(0.5); + gy11 = fract(gy11) - T(0.5); + gz11 = fract(gz11) - T(0.5); + vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); + vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(T(0))); + gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); + gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); + + vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); + vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); + vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); + vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); + vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); + vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); + vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); + vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); + vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); + vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); + vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); + vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); + vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); + vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); + vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); + vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); + + vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); + g0000 *= norm00.x; + g0100 *= norm00.y; + g1000 *= norm00.z; + g1100 *= norm00.w; + + vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); + g0001 *= norm01.x; + g0101 *= norm01.y; + g1001 *= norm01.z; + g1101 *= norm01.w; + + vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); + g0010 *= norm10.x; + g0110 *= norm10.y; + g1010 *= norm10.z; + g1110 *= norm10.w; + + vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); + g0011 *= norm11.x; + g0111 *= norm11.y; + g1011 *= norm11.z; + g1111 *= norm11.w; + + T n0000 = dot(g0000, Pf0); + T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); + T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); + T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); + T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); + T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); + T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); + T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); + T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); + T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); + T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); + T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); + T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); + T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); + T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); + T n1111 = dot(g1111, Pf1); + + vec<4, T, Q> fade_xyzw = detail::fade(Pf0); + vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); + vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); + vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); + vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); + T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); + return T(2.2) * n_xyzw; + } + + template + GLM_FUNC_QUALIFIER T simplex(glm::vec<2, T, Q> const& v) + { + vec<4, T, Q> const C = vec<4, T, Q>( + T( 0.211324865405187), // (3.0 - sqrt(3.0)) / 6.0 + T( 0.366025403784439), // 0.5 * (sqrt(3.0) - 1.0) + T(-0.577350269189626), // -1.0 + 2.0 * C.x + T( 0.024390243902439)); // 1.0 / 41.0 + + // First corner + vec<2, T, Q> i = floor(v + dot(v, vec<2, T, Q>(C[1]))); + vec<2, T, Q> x0 = v - i + dot(i, vec<2, T, Q>(C[0])); + + // Other corners + //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 + //i1.y = 1.0 - i1.x; + vec<2, T, Q> i1 = (x0.x > x0.y) ? vec<2, T, Q>(1, 0) : vec<2, T, Q>(0, 1); + // x0 = x0 - 0.0 + 0.0 * C.xx ; + // x1 = x0 - i1 + 1.0 * C.xx ; + // x2 = x0 - 1.0 + 2.0 * C.xx ; + vec<4, T, Q> x12 = vec<4, T, Q>(x0.x, x0.y, x0.x, x0.y) + vec<4, T, Q>(C.x, C.x, C.z, C.z); + x12 = vec<4, T, Q>(vec<2, T, Q>(x12) - i1, x12.z, x12.w); + + // Permutations + i = mod(i, vec<2, T, Q>(289)); // Avoid truncation effects in permutation + vec<3, T, Q> p = detail::permute( + detail::permute(i.y + vec<3, T, Q>(T(0), i1.y, T(1))) + + i.x + vec<3, T, Q>(T(0), i1.x, T(1))); + + vec<3, T, Q> m = max(vec<3, T, Q>(0.5) - vec<3, T, Q>( + dot(x0, x0), + dot(vec<2, T, Q>(x12.x, x12.y), vec<2, T, Q>(x12.x, x12.y)), + dot(vec<2, T, Q>(x12.z, x12.w), vec<2, T, Q>(x12.z, x12.w))), vec<3, T, Q>(0)); + m = m * m ; + m = m * m ; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec<3, T, Q> x = static_cast(2) * fract(p * C.w) - T(1); + vec<3, T, Q> h = abs(x) - T(0.5); + vec<3, T, Q> ox = floor(x + T(0.5)); + vec<3, T, Q> a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h ); + m *= static_cast(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h); + + // Compute final noise value at P + vec<3, T, Q> g; + g.x = a0.x * x0.x + h.x * x0.y; + //g.yz = a0.yz * x12.xz + h.yz * x12.yw; + g.y = a0.y * x12.x + h.y * x12.y; + g.z = a0.z * x12.z + h.z * x12.w; + return T(130) * dot(m, g); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<3, T, Q> const& v) + { + vec<2, T, Q> const C(1.0 / 6.0, 1.0 / 3.0); + vec<4, T, Q> const D(0.0, 0.5, 1.0, 2.0); + + // First corner + vec<3, T, Q> i(floor(v + dot(v, vec<3, T, Q>(C.y)))); + vec<3, T, Q> x0(v - i + dot(i, vec<3, T, Q>(C.x))); + + // Other corners + vec<3, T, Q> g(step(vec<3, T, Q>(x0.y, x0.z, x0.x), x0)); + vec<3, T, Q> l(T(1) - g); + vec<3, T, Q> i1(min(g, vec<3, T, Q>(l.z, l.x, l.y))); + vec<3, T, Q> i2(max(g, vec<3, T, Q>(l.z, l.x, l.y))); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec<3, T, Q> x1(x0 - i1 + C.x); + vec<3, T, Q> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y + vec<3, T, Q> x3(x0 - D.y); // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = detail::mod289(i); + vec<4, T, Q> p(detail::permute(detail::permute(detail::permute( + i.z + vec<4, T, Q>(T(0), i1.z, i2.z, T(1))) + + i.y + vec<4, T, Q>(T(0), i1.y, i2.y, T(1))) + + i.x + vec<4, T, Q>(T(0), i1.x, i2.x, T(1)))); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + T n_ = static_cast(0.142857142857); // 1.0/7.0 + vec<3, T, Q> ns(n_ * vec<3, T, Q>(D.w, D.y, D.z) - vec<3, T, Q>(D.x, D.z, D.x)); + + vec<4, T, Q> j(p - T(49) * floor(p * ns.z * ns.z)); // mod(p,7*7) + + vec<4, T, Q> x_(floor(j * ns.z)); + vec<4, T, Q> y_(floor(j - T(7) * x_)); // mod(j,N) + + vec<4, T, Q> x(x_ * ns.x + ns.y); + vec<4, T, Q> y(y_ * ns.x + ns.y); + vec<4, T, Q> h(T(1) - abs(x) - abs(y)); + + vec<4, T, Q> b0(x.x, x.y, y.x, y.y); + vec<4, T, Q> b1(x.z, x.w, y.z, y.w); + + // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec<4, T, Q> s0(floor(b0) * T(2) + T(1)); + vec<4, T, Q> s1(floor(b1) * T(2) + T(1)); + vec<4, T, Q> sh(-step(h, vec<4, T, Q>(0.0))); + + vec<4, T, Q> a0 = vec<4, T, Q>(b0.x, b0.z, b0.y, b0.w) + vec<4, T, Q>(s0.x, s0.z, s0.y, s0.w) * vec<4, T, Q>(sh.x, sh.x, sh.y, sh.y); + vec<4, T, Q> a1 = vec<4, T, Q>(b1.x, b1.z, b1.y, b1.w) + vec<4, T, Q>(s1.x, s1.z, s1.y, s1.w) * vec<4, T, Q>(sh.z, sh.z, sh.w, sh.w); + + vec<3, T, Q> p0(a0.x, a0.y, h.x); + vec<3, T, Q> p1(a0.z, a0.w, h.y); + vec<3, T, Q> p2(a1.x, a1.y, h.z); + vec<3, T, Q> p3(a1.z, a1.w, h.w); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec<4, T, Q> m = max(T(0.6) - vec<4, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec<4, T, Q>(0)); + m = m * m; + return T(42) * dot(m * m, vec<4, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); + } + + template + GLM_FUNC_QUALIFIER T simplex(vec<4, T, Q> const& v) + { + vec<4, T, Q> const C( + 0.138196601125011, // (5 - sqrt(5))/20 G4 + 0.276393202250021, // 2 * G4 + 0.414589803375032, // 3 * G4 + -0.447213595499958); // -1 + 4 * G4 + + // (sqrt(5) - 1)/4 = F4, used once below + T const F4 = static_cast(0.309016994374947451); + + // First corner + vec<4, T, Q> i = floor(v + dot(v, vec<4, T, Q>(F4))); + vec<4, T, Q> x0 = v - i + dot(i, vec<4, T, Q>(C.x)); + + // Other corners + + // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) + vec<4, T, Q> i0; + vec<3, T, Q> isX = step(vec<3, T, Q>(x0.y, x0.z, x0.w), vec<3, T, Q>(x0.x)); + vec<3, T, Q> isYZ = step(vec<3, T, Q>(x0.z, x0.w, x0.w), vec<3, T, Q>(x0.y, x0.y, x0.z)); + // i0.x = dot(isX, vec3(1.0)); + //i0.x = isX.x + isX.y + isX.z; + //i0.yzw = static_cast(1) - isX; + i0 = vec<4, T, Q>(isX.x + isX.y + isX.z, T(1) - isX); + // i0.y += dot(isYZ.xy, vec2(1.0)); + i0.y += isYZ.x + isYZ.y; + //i0.zw += 1.0 - vec<2, T, Q>(isYZ.x, isYZ.y); + i0.z += static_cast(1) - isYZ.x; + i0.w += static_cast(1) - isYZ.y; + i0.z += isYZ.z; + i0.w += static_cast(1) - isYZ.z; + + // i0 now contains the unique values 0,1,2,3 in each channel + vec<4, T, Q> i3 = clamp(i0, T(0), T(1)); + vec<4, T, Q> i2 = clamp(i0 - T(1), T(0), T(1)); + vec<4, T, Q> i1 = clamp(i0 - T(2), T(0), T(1)); + + // x0 = x0 - 0.0 + 0.0 * C.xxxx + // x1 = x0 - i1 + 0.0 * C.xxxx + // x2 = x0 - i2 + 0.0 * C.xxxx + // x3 = x0 - i3 + 0.0 * C.xxxx + // x4 = x0 - 1.0 + 4.0 * C.xxxx + vec<4, T, Q> x1 = x0 - i1 + C.x; + vec<4, T, Q> x2 = x0 - i2 + C.y; + vec<4, T, Q> x3 = x0 - i3 + C.z; + vec<4, T, Q> x4 = x0 + C.w; + + // Permutations + i = mod(i, vec<4, T, Q>(289)); + T j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x); + vec<4, T, Q> j1 = detail::permute(detail::permute(detail::permute(detail::permute( + i.w + vec<4, T, Q>(i1.w, i2.w, i3.w, T(1))) + + i.z + vec<4, T, Q>(i1.z, i2.z, i3.z, T(1))) + + i.y + vec<4, T, Q>(i1.y, i2.y, i3.y, T(1))) + + i.x + vec<4, T, Q>(i1.x, i2.x, i3.x, T(1))); + + // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope + // 7*7*6 = 294, which is close to the ring size 17*17 = 289. + vec<4, T, Q> ip = vec<4, T, Q>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0)); + + vec<4, T, Q> p0 = gtc::grad4(j0, ip); + vec<4, T, Q> p1 = gtc::grad4(j1.x, ip); + vec<4, T, Q> p2 = gtc::grad4(j1.y, ip); + vec<4, T, Q> p3 = gtc::grad4(j1.z, ip); + vec<4, T, Q> p4 = gtc::grad4(j1.w, ip); + + // Normalise gradients + vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + p4 *= detail::taylorInvSqrt(dot(p4, p4)); + + // Mix contributions from the five corners + vec<3, T, Q> m0 = max(T(0.6) - vec<3, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), vec<3, T, Q>(0)); + vec<2, T, Q> m1 = max(T(0.6) - vec<2, T, Q>(dot(x3, x3), dot(x4, x4) ), vec<2, T, Q>(0)); + m0 = m0 * m0; + m1 = m1 * m1; + return T(49) * + (dot(m0 * m0, vec<3, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + + dot(m1 * m1, vec<2, T, Q>(dot(p3, x3), dot(p4, x4)))); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/packing.hpp b/thirdparty/glm/gtc/packing.hpp new file mode 100644 index 0000000..8e416b3 --- /dev/null +++ b/thirdparty/glm/gtc/packing.hpp @@ -0,0 +1,728 @@ +/// @ref gtc_packing +/// @file glm/gtc/packing.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_packing GLM_GTC_packing +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// This extension provides a set of function to convert vertors to packed +/// formats. + +#pragma once + +// Dependency: +#include "type_precision.hpp" +#include "../ext/vector_packing.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_packing extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_packing + /// @{ + + /// First, converts the normalized floating-point value v into a 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x8: round(clamp(c, 0, +1) * 255.0) + /// + /// @see gtc_packing + /// @see uint16 packUnorm2x8(vec2 const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packUnorm1x8(float v); + + /// Convert a single 8-bit integer to a normalized floating-point value. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x8(uint16 p) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packUnorm1x8(float const& v) + /// @see uint32 packUnorm4x8(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x8(uint8 v) + /// @see vec4 unpackUnorm4x8(uint32 p) + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into 8-bit integer value. + /// Then, the results are packed into the returned 8-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 127.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm2x8(vec2 const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint8 packSnorm1x8(float s); + + /// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x8: clamp(f / 127.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x8(uint16 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x8(uint8 p); + + /// First, converts each component of the normalized floating-point value v into 8-bit integer values. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint8 packSnorm1x8(float const& v) + /// @see uint32 packSnorm4x8(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm2x8(vec2 const& v); + + /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x8(uint8 p) + /// @see vec4 unpackSnorm4x8(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p); + + /// First, converts the normalized floating-point value v into a 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm1x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packUnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers. + /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm1x16: f / 65535.0 + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see vec4 unpackUnorm4x16(uint64 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackUnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x16(float const& v) + /// @see uint32 packUnorm2x16(vec2 const& v) + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packUnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnormx4x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackUnorm1x16(uint16 p) + /// @see vec2 unpackUnorm2x16(uint32 p) + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p); + + /// First, converts the normalized floating-point value v into 16-bit integer value. + /// Then, the results are packed into the returned 16-bit unsigned integer. + /// + /// The conversion to fixed point is done as follows: + /// packSnorm1x8: round(clamp(s, -1, +1) * 32767.0) + /// + /// @see gtc_packing + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see uint64 packSnorm4x16(vec4 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packSnorm1x16(float v); + + /// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned scalar. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm1x16: clamp(f / 32767.0, -1, +1) + /// + /// @see gtc_packing + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see vec4 unpackSnorm4x16(uint64 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackSnorm1x16(uint16 p); + + /// First, converts each component of the normalized floating-point value v into 16-bit integer values. + /// Then, the results are packed into the returned 64-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x8: round(clamp(c, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see gtc_packing + /// @see uint16 packSnorm1x16(float const& v) + /// @see uint32 packSnorm2x16(vec2 const& v) + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packSnorm4x16(vec4 const& v); + + /// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see float unpackSnorm1x16(uint16 p) + /// @see vec2 unpackSnorm2x16(uint32 p) + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a floating-point scalar + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing this 16-bit value into a 16-bit unsigned integer. + /// + /// @see gtc_packing + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see uint64 packHalf4x16(vec4 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint16 packHalf1x16(float v); + + /// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value, + /// interpreted as a 16-bit floating-point number according to the OpenGL Specification, + /// and converting it to 32-bit floating-point values. + /// + /// @see gtc_packing + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see vec4 unpackHalf4x16(uint64 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL float unpackHalf1x16(uint16 v); + + /// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these four 16-bit values into a 64-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see uint16 packHalf1x16(float const& v) + /// @see uint32 packHalf2x16(vec2 const& v) + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint64 packHalf4x16(vec4 const& v); + + /// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see float unpackHalf1x16(uint16 const& v) + /// @see vec2 unpackHalf2x16(uint32 const& v) + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector + /// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(uvec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackI3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p); + + /// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector + /// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification, + /// and then packing these four values into a 32-bit unsigned integer. + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see uint32 packI3x10_1x2(ivec4 const& v) + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see ivec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const& v); + + /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); + /// @see uvec4 unpackI3x10_1x2(uint32 const& p); + GLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm3x10_1x2(xyz): round(clamp(c, -1, +1) * 511.0) + /// packSnorm3x10_1x2(w): round(clamp(c, -1, +1) * 1.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p); + + /// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values. + /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm3x10_1x2(xyz): round(clamp(c, 0, +1) * 1023.0) + /// packUnorm3x10_1x2(w): round(clamp(c, 0, +1) * 3.0) + /// + /// The first vector component specifies the 10 least-significant bits of the result; + /// the forth component specifies the 2 most-significant bits. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p) + /// @see uint32 packUnorm3x10_1x2(vec4 const& v) + /// @see uint32 packU3x10_1x2(uvec4 const& v) + /// @see uint32 packI3x10_1x2(ivec4 const& v) + GLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1) + /// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packSnorm3x10_1x2(vec4 const& v) + /// @see vec4 unpackInorm3x10_1x2(uint32 const& p)) + /// @see uvec4 unpackI3x10_1x2(uint32 const& p) + /// @see uvec4 unpackU3x10_1x2(uint32 const& p) + GLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p); + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// @see gtc_packing + /// @see vec3 unpackF2x11_1x10(uint32 const& p) + GLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see gtc_packing + /// @see uint32 packF2x11_1x10(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p); + + + /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. + /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The first vector component specifies the 11 least-significant bits of the result; + /// the last component specifies the 10 most-significant bits. + /// + /// packF3x9_E1x5 allows encoding into RGBE / RGB9E5 format + /// + /// @see gtc_packing + /// @see vec3 unpackF3x9_E1x5(uint32 const& p) + GLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . + /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// unpackF3x9_E1x5 allows decoding RGBE / RGB9E5 data + /// + /// @see gtc_packing + /// @see uint32 packF3x9_E1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec<4, T, Q> packRGBM(vec<3, float, Q> const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm); + + /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the forth component specifies the 16 most-significant bits. + /// + /// @see gtc_packing + /// @see vec unpackHalf(vec const& p) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec packHalf(vec const& v); + + /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the forth component is obtained from the 16 most-significant bits of v. + /// + /// @see gtc_packing + /// @see vec packHalf(vec const& v) + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + template + GLM_FUNC_DECL vec unpackHalf(vec const& p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec unpackUnorm(vec const& p); + template + GLM_FUNC_DECL vec packUnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packUnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackUnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into signed integer values. + /// + /// @see gtc_packing + /// @see vec unpackSnorm(vec const& p); + template + GLM_FUNC_DECL vec packSnorm(vec const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see vec packSnorm(vec const& v) + template + GLM_FUNC_DECL vec unpackSnorm(vec const& v); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec2 unpackUnorm2x4(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x4(vec2 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x4(vec2 const& v) + GLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm4x4(uint16 p) + GLM_FUNC_DECL uint16 packUnorm4x4(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm4x4(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p) + GLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec4 unpackUnorm3x5_1x1(uint16 p) + GLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint16 packUnorm3x5_1x1(vec4 const& v) + GLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p); + + /// Convert each component of the normalized floating-point vector into unsigned integer values. + /// + /// @see gtc_packing + /// @see vec3 unpackUnorm2x3_1x2(uint8 p) + GLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const& v); + + /// Convert a packed integer to a normalized floating-point vector. + /// + /// @see gtc_packing + /// @see uint8 packUnorm2x3_1x2(vec3 const& v) + GLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p); + + + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i8vec2 unpackInt2x8(int16 p) + GLM_FUNC_DECL int16 packInt2x8(i8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int16 packInt2x8(i8vec2 const& v) + GLM_FUNC_DECL i8vec2 unpackInt2x8(int16 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec2 unpackInt2x8(uint16 p) + GLM_FUNC_DECL uint16 packUint2x8(u8vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint16 packInt2x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec2 unpackUint2x8(uint16 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i8vec4 unpackInt4x8(int32 p) + GLM_FUNC_DECL int32 packInt4x8(i8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int32 packInt2x8(i8vec4 const& v) + GLM_FUNC_DECL i8vec4 unpackInt4x8(int32 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u8vec4 unpackUint4x8(uint32 p) + GLM_FUNC_DECL uint32 packUint4x8(u8vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint32 packUint4x8(u8vec2 const& v) + GLM_FUNC_DECL u8vec4 unpackUint4x8(uint32 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i16vec2 unpackInt2x16(int p) + GLM_FUNC_DECL int packInt2x16(i16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i16vec2 const& v) + GLM_FUNC_DECL i16vec2 unpackInt2x16(int p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i16vec4 unpackInt4x16(int64 p) + GLM_FUNC_DECL int64 packInt4x16(i16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int64 packInt4x16(i16vec4 const& v) + GLM_FUNC_DECL i16vec4 unpackInt4x16(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec2 unpackUint2x16(uint p) + GLM_FUNC_DECL uint packUint2x16(u16vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint packUint2x16(u16vec2 const& v) + GLM_FUNC_DECL u16vec2 unpackUint2x16(uint p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u16vec4 unpackUint4x16(uint64 p) + GLM_FUNC_DECL uint64 packUint4x16(u16vec4 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see uint64 packUint4x16(u16vec4 const& v) + GLM_FUNC_DECL u16vec4 unpackUint4x16(uint64 p); + + /// Convert each component from an integer vector into a packed integer. + /// + /// @see gtc_packing + /// @see i32vec2 unpackInt2x32(int p) + GLM_FUNC_DECL int64 packInt2x32(i32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packInt2x16(i32vec2 const& v) + GLM_FUNC_DECL i32vec2 unpackInt2x32(int64 p); + + /// Convert each component from an integer vector into a packed unsigned integer. + /// + /// @see gtc_packing + /// @see u32vec2 unpackUint2x32(int p) + GLM_FUNC_DECL uint64 packUint2x32(u32vec2 const& v); + + /// Convert a packed integer into an integer vector. + /// + /// @see gtc_packing + /// @see int packUint2x16(u32vec2 const& v) + GLM_FUNC_DECL u32vec2 unpackUint2x32(uint64 p); + + /// @} +}// namespace glm + +#include "packing.inl" diff --git a/thirdparty/glm/gtc/packing.inl b/thirdparty/glm/gtc/packing.inl new file mode 100644 index 0000000..8c906e1 --- /dev/null +++ b/thirdparty/glm/gtc/packing.inl @@ -0,0 +1,938 @@ +/// @ref gtc_packing + +#include "../ext/scalar_relational.hpp" +#include "../ext/vector_relational.hpp" +#include "../common.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../detail/type_half.hpp" +#include +#include + +namespace glm{ +namespace detail +{ + GLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((f >> 16) & 0x8000) | // sign + ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential + ((f >> 13) & 0x03ff); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential + ((f >> 17) & 0x003f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x000007c0 => 00000000 00000000 00000111 11000000 + // 0x00007c00 => 00000000 00000000 01111100 00000000 + // 0x000003ff => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x003f) << 17); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential + ((f >> 18) & 0x001f); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p) + { + // 10 bits => EE EEEFFFFF + // 11 bits => EEE EEFFFFFF + // Half bits => SEEEEEFF FFFFFFFF + // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF + + // 0x0000001F => 00000000 00000000 00000000 00011111 + // 0x0000003F => 00000000 00000000 00000000 00111111 + // 0x000003E0 => 00000000 00000000 00000011 11100000 + // 0x000007C0 => 00000000 00000000 00000111 11000000 + // 0x00007C00 => 00000000 00000000 01111100 00000000 + // 0x000003FF => 00000000 00000000 00000011 11111111 + // 0x38000000 => 00111000 00000000 00000000 00000000 + // 0x7f800000 => 01111111 10000000 00000000 00000000 + // 0x00008000 => 00000000 00000000 10000000 00000000 + return + ((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential + ((p & 0x001f) << 18); // Mantissa + } + + GLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h) + { + return ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + } + + GLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 6u; + + uint Pack = 0u; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed11(Pack); + } + + GLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 11) - 1)) + return ~0;//NaN + else if(x == (0x1f << 6)) + return ~0;//Inf + + uint Result = packed11ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + + GLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x) + { + if(x == 0.0f) + return 0u; + else if(glm::isnan(x)) + return ~0u; + else if(glm::isinf(x)) + return 0x1Fu << 5u; + + uint Pack = 0; + memcpy(&Pack, &x, sizeof(Pack)); + return float2packed10(Pack); + } + + GLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x) + { + if(x == 0) + return 0.0f; + else if(x == ((1 << 10) - 1)) + return ~0;//NaN + else if(x == (0x1f << 5)) + return ~0;//Inf + + uint Result = packed10ToFloat(x); + + float Temp = 0; + memcpy(&Temp, &Result, sizeof(Temp)); + return Temp; + } + +// GLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z) +// { +// return ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) | ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22); +// } + + union u3u3u2 + { + struct + { + uint x : 3; + uint y : 3; + uint z : 2; + } data; + uint8 pack; + }; + + union u4u4 + { + struct + { + uint x : 4; + uint y : 4; + } data; + uint8 pack; + }; + + union u4u4u4u4 + { + struct + { + uint x : 4; + uint y : 4; + uint z : 4; + uint w : 4; + } data; + uint16 pack; + }; + + union u5u6u5 + { + struct + { + uint x : 5; + uint y : 6; + uint z : 5; + } data; + uint16 pack; + }; + + union u5u5u5u1 + { + struct + { + uint x : 5; + uint y : 5; + uint z : 5; + uint w : 1; + } data; + uint16 pack; + }; + + union u10u10u10u2 + { + struct + { + uint x : 10; + uint y : 10; + uint z : 10; + uint w : 2; + } data; + uint32 pack; + }; + + union i10i10i10i2 + { + struct + { + int x : 10; + int y : 10; + int z : 10; + int w : 2; + } data; + uint32 pack; + }; + + union u9u9u9e5 + { + struct + { + uint x : 9; + uint y : 9; + uint z : 9; + uint w : 5; + } data; + uint32 pack; + }; + + template + struct compute_half + {}; + + template + struct compute_half<1, Q> + { + GLM_FUNC_QUALIFIER static vec<1, uint16, Q> pack(vec<1, float, Q> const& v) + { + int16 const Unpack(detail::toFloat16(v.x)); + u16vec1 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<1, float, Q> unpack(vec<1, uint16, Q> const& v) + { + i16vec1 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<1, float, Q>(detail::toFloat32(v.x)); + } + }; + + template + struct compute_half<2, Q> + { + GLM_FUNC_QUALIFIER static vec<2, uint16, Q> pack(vec<2, float, Q> const& v) + { + vec<2, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y)); + u16vec2 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<2, float, Q> unpack(vec<2, uint16, Q> const& v) + { + i16vec2 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<2, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y)); + } + }; + + template + struct compute_half<3, Q> + { + GLM_FUNC_QUALIFIER static vec<3, uint16, Q> pack(vec<3, float, Q> const& v) + { + vec<3, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z)); + u16vec3 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<3, float, Q> unpack(vec<3, uint16, Q> const& v) + { + i16vec3 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<3, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z)); + } + }; + + template + struct compute_half<4, Q> + { + GLM_FUNC_QUALIFIER static vec<4, uint16, Q> pack(vec<4, float, Q> const& v) + { + vec<4, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w)); + u16vec4 Packed; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER static vec<4, float, Q> unpack(vec<4, uint16, Q> const& v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec<4, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w)); + } + }; +}//namespace detail + + GLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v) + { + return static_cast(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p) + { + float const Unpack(p); + return Unpack * static_cast(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const& v) + { + u8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f)); + + uint16 Unpack = 0; + memcpy(&Unpack, &Topack, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255 + } + + GLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v) + { + int8 const Topack(static_cast(round(clamp(v ,-1.0f, 1.0f) * 127.0f))); + uint8 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p) + { + int8 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const& v) + { + i8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s) + { + return static_cast(round(clamp(s, 0.0f, 1.0f) * 65535.0f)); + } + + GLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p) + { + float const Unpack(p); + return Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const& v) + { + u16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 + } + + GLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v) + { + int16 const Topack = static_cast(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p) + { + int16 Unpack = 0; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + static_cast(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const& v) + { + i16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); + uint64 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return clamp( + vec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, + -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint16 packHalf1x16(float v) + { + int16 const Topack(detail::toFloat16(v)); + uint16 Packed = 0; + memcpy(&Packed, &Topack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v) + { + int16 Unpack = 0; + memcpy(&Unpack, &v, sizeof(Unpack)); + return detail::toFloat32(Unpack); + } + + GLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const& v) + { + i16vec4 const Unpack( + detail::toFloat16(v.x), + detail::toFloat16(v.y), + detail::toFloat16(v.z), + detail::toFloat16(v.w)); + uint64 Packed = 0; + memcpy(&Packed, &Unpack, sizeof(Packed)); + return Packed; + } + + GLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v) + { + i16vec4 Unpack; + memcpy(&Unpack, &v, sizeof(Unpack)); + return vec4( + detail::toFloat32(Unpack.x), + detail::toFloat32(Unpack.y), + detail::toFloat32(Unpack.z), + detail::toFloat32(Unpack.w)); + } + + GLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const& v) + { + detail::i10i10i10i2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + return ivec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const& v) + { + detail::u10u10u10u2 Result; + Result.data.x = v.x; + Result.data.y = v.y; + Result.data.z = v.z; + Result.data.w = v.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v) + { + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return uvec4( + Unpack.data.x, + Unpack.data.y, + Unpack.data.z, + Unpack.data.w); + } + + GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const& v) + { + ivec4 const Pack(round(clamp(v,-1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f))); + + detail::i10i10i10i2 Result; + Result.data.x = Pack.x; + Result.data.y = Pack.y; + Result.data.z = Pack.z; + Result.data.w = Pack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v) + { + detail::i10i10i10i2 Unpack; + Unpack.pack = v; + + vec4 const Result(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); + + return clamp(Result * vec4(1.f / 511.f, 1.f / 511.f, 1.f / 511.f, 1.f), -1.0f, 1.0f); + } + + GLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const& v) + { + uvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f))); + + detail::u10u10u10u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v) + { + vec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f); + + detail::u10u10u10u2 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors; + } + + GLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const& v) + { + return + ((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) << 0) | + ((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) | + ((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22); + } + + GLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v) + { + return vec3( + detail::packed11bitToFloat(v >> 0), + detail::packed11bitToFloat(v >> 11), + detail::packed10bitToFloat(v >> 22)); + } + + GLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const& v) + { + float const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f); + vec3 const Color = clamp(v, 0.0f, SharedExpMax); + float const MaxColor = max(Color.x, max(Color.y, Color.z)); + + float const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f; + float const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 15.f - 9.f)) + 0.5f); + float const ExpShared = equal(MaxShared, pow(2.0f, 9.0f), epsilon()) ? ExpSharedP + 1.0f : ExpSharedP; + + uvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f)); + + detail::u9u9u9e5 Unpack; + Unpack.data.x = ColorComp.x; + Unpack.data.y = ColorComp.y; + Unpack.data.z = ColorComp.z; + Unpack.data.w = uint(ExpShared); + return Unpack.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v) + { + detail::u9u9u9e5 Unpack; + Unpack.pack = v; + + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f); + } + + // Based on Brian Karis http://graphicrants.blogspot.fr/2009/04/rgbm-color-encoding.html + template + GLM_FUNC_QUALIFIER vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb) + { + vec<3, T, Q> const Color(rgb * static_cast(1.0 / 6.0)); + T Alpha = clamp(max(max(Color.x, Color.y), max(Color.z, static_cast(1e-6))), static_cast(0), static_cast(1)); + Alpha = ceil(Alpha * static_cast(255.0)) / static_cast(255.0); + return vec<4, T, Q>(Color / Alpha, Alpha); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm) + { + return vec<3, T, Q>(rgbm.x, rgbm.y, rgbm.z) * rgbm.w * static_cast(6); + } + + template + GLM_FUNC_QUALIFIER vec packHalf(vec const& v) + { + return detail::compute_half::pack(v); + } + + template + GLM_FUNC_QUALIFIER vec unpackHalf(vec const& v) + { + return detail::compute_half::unpack(v); + } + + template + GLM_FUNC_QUALIFIER vec packUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v, static_cast(0), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackUnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())); + } + + template + GLM_FUNC_QUALIFIER vec packSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return vec(round(clamp(v , static_cast(-1), static_cast(1)) * static_cast(std::numeric_limits::max()))); + } + + template + GLM_FUNC_QUALIFIER vec unpackSnorm(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); + + return clamp(vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())), static_cast(-1), static_cast(1)); + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const& v) + { + u32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4 Unpack; + Unpack.pack = v; + return vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); + detail::u4u4u4u4 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v) + { + float const ScaleFactor(1.f / 15.f); + detail::u4u4u4u4 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f))); + detail::u5u6u5 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v) + { + vec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f); + detail::u5u6u5 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const& v) + { + u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f))); + detail::u5u5u5u1 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + Result.data.w = Unpack.w; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v) + { + vec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f); + detail::u5u5u5u1 Unpack; + Unpack.pack = v; + return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const& v) + { + u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f))); + detail::u3u3u2 Result; + Result.data.x = Unpack.x; + Result.data.y = Unpack.y; + Result.data.z = Unpack.z; + return Result.pack; + } + + GLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v) + { + vec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f); + detail::u3u3u2 Unpack; + Unpack.pack = v; + return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; + } + + GLM_FUNC_QUALIFIER int16 packInt2x8(i8vec2 const& v) + { + int16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec2 unpackInt2x8(int16 p) + { + i8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint16 packUint2x8(u8vec2 const& v) + { + uint16 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec2 unpackUint2x8(uint16 p) + { + u8vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int32 packInt4x8(i8vec4 const& v) + { + int32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i8vec4 unpackInt4x8(int32 p) + { + i8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint32 packUint4x8(u8vec4 const& v) + { + uint32 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u8vec4 unpackUint4x8(uint32 p) + { + u8vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int packInt2x16(i16vec2 const& v) + { + int Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec2 unpackInt2x16(int p) + { + i16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt4x16(i16vec4 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i16vec4 unpackInt4x16(int64 p) + { + i16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint packUint2x16(u16vec2 const& v) + { + uint Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec2 unpackUint2x16(uint p) + { + u16vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint4x16(u16vec4 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u16vec4 unpackUint4x16(uint64 p) + { + u16vec4 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER int64 packInt2x32(i32vec2 const& v) + { + int64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER i32vec2 unpackInt2x32(int64 p) + { + i32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } + + GLM_FUNC_QUALIFIER uint64 packUint2x32(u32vec2 const& v) + { + uint64 Pack = 0; + memcpy(&Pack, &v, sizeof(Pack)); + return Pack; + } + + GLM_FUNC_QUALIFIER u32vec2 unpackUint2x32(uint64 p) + { + u32vec2 Unpack; + memcpy(&Unpack, &p, sizeof(Unpack)); + return Unpack; + } +}//namespace glm + diff --git a/thirdparty/glm/gtc/quaternion.hpp b/thirdparty/glm/gtc/quaternion.hpp new file mode 100644 index 0000000..359e072 --- /dev/null +++ b/thirdparty/glm/gtc/quaternion.hpp @@ -0,0 +1,173 @@ +/// @ref gtc_quaternion +/// @file glm/gtc/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// +/// @defgroup gtc_quaternion GLM_GTC_quaternion +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines a templated quaternion type and several quaternion operations. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" +#include "../gtc/matrix_transform.hpp" +#include "../ext/vector_relational.hpp" +#include "../ext/quaternion_common.hpp" +#include "../ext/quaternion_float.hpp" +#include "../ext/quaternion_float_precision.hpp" +#include "../ext/quaternion_double.hpp" +#include "../ext/quaternion_double_precision.hpp" +#include "../ext/quaternion_relational.hpp" +#include "../ext/quaternion_geometric.hpp" +#include "../ext/quaternion_trigonometric.hpp" +#include "../ext/quaternion_transform.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat4x4.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_quaternion extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_quaternion + /// @{ + + /// Returns euler angles, pitch as x, yaw as y, roll as z. + /// The result is expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> eulerAngles(qua const& x); + + /// Returns roll value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T roll(qua const& x); + + /// Returns pitch value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T pitch(qua const& x); + + /// Returns yaw value of euler angles expressed in radians. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL T yaw(qua const& x); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<3, 3, T, Q> mat3_cast(qua const& x); + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL mat<4, 4, T, Q> mat4_cast(qua const& x); + + /// Converts a pure rotation 3 * 3 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<3, 3, T, Q> const& x); + + /// Converts a pure rotation 4 * 4 matrix to a quaternion. + /// + /// @tparam T Floating-point scalar types. + /// + /// @see gtc_quaternion + template + GLM_FUNC_DECL qua quat_cast(mat<4, 4, T, Q> const& x); + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThan(qua const& x, qua const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_quaternion_relational + template + GLM_FUNC_DECL vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y); + + /// Build a look at quaternion based on the default handedness. + /// + /// @param direction Desired forward direction. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAt( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a right-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtRH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + + /// Build a left-handed look at quaternion. + /// + /// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized. + /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). + template + GLM_FUNC_DECL qua quatLookAtLH( + vec<3, T, Q> const& direction, + vec<3, T, Q> const& up); + /// @} +} //namespace glm + +#include "quaternion.inl" diff --git a/thirdparty/glm/gtc/quaternion.inl b/thirdparty/glm/gtc/quaternion.inl new file mode 100644 index 0000000..06f9f02 --- /dev/null +++ b/thirdparty/glm/gtc/quaternion.inl @@ -0,0 +1,202 @@ +#include "../trigonometric.hpp" +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "epsilon.hpp" +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> eulerAngles(qua const& x) + { + return vec<3, T, Q>(pitch(x), yaw(x), roll(x)); + } + + template + GLM_FUNC_QUALIFIER T roll(qua const& q) + { + return static_cast(atan(static_cast(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z)); + } + + template + GLM_FUNC_QUALIFIER T pitch(qua const& q) + { + //return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z)); + T const y = static_cast(2) * (q.y * q.z + q.w * q.x); + T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; + + if(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon()))) //avoid atan2(0,0) - handle singularity - Matiis + return static_cast(static_cast(2) * atan(q.x, q.w)); + + return static_cast(atan(y, x)); + } + + template + GLM_FUNC_QUALIFIER T yaw(qua const& q) + { + return asin(clamp(static_cast(-2) * (q.x * q.z - q.w * q.y), static_cast(-1), static_cast(1))); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat3_cast(qua const& q) + { + mat<3, 3, T, Q> Result(T(1)); + T qxx(q.x * q.x); + T qyy(q.y * q.y); + T qzz(q.z * q.z); + T qxz(q.x * q.z); + T qxy(q.x * q.y); + T qyz(q.y * q.z); + T qwx(q.w * q.x); + T qwy(q.w * q.y); + T qwz(q.w * q.z); + + Result[0][0] = T(1) - T(2) * (qyy + qzz); + Result[0][1] = T(2) * (qxy + qwz); + Result[0][2] = T(2) * (qxz - qwy); + + Result[1][0] = T(2) * (qxy - qwz); + Result[1][1] = T(1) - T(2) * (qxx + qzz); + Result[1][2] = T(2) * (qyz + qwx); + + Result[2][0] = T(2) * (qxz + qwy); + Result[2][1] = T(2) * (qyz - qwx); + Result[2][2] = T(1) - T(2) * (qxx + qyy); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat4_cast(qua const& q) + { + return mat<4, 4, T, Q>(mat3_cast(q)); + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<3, 3, T, Q> const& m) + { + T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; + T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; + T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; + T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; + + int biggestIndex = 0; + T fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + T biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast(1)) * static_cast(0.5); + T mult = static_cast(0.25) / biggestVal; + + switch(biggestIndex) + { + case 0: + return qua(biggestVal, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult); + case 1: + return qua((m[1][2] - m[2][1]) * mult, biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult); + case 2: + return qua((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult); + case 3: + return qua((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal); + default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. + assert(false); + return qua(1, 0, 0, 0); + } + } + + template + GLM_FUNC_QUALIFIER qua quat_cast(mat<4, 4, T, Q> const& m4) + { + return quat_cast(mat<3, 3, T, Q>(m4)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] < y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] <= y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThan(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] > y[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y) + { + vec<4, bool, Q> Result; + for(length_t i = 0; i < x.length(); ++i) + Result[i] = x[i] >= y[i]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER qua quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { +# if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT + return quatLookAtLH(direction, up); +# else + return quatLookAtRH(direction, up); +# endif + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = -direction; + vec<3, T, Q> const& Right = cross(up, Result[2]); + Result[0] = Right * inversesqrt(max(static_cast(0.00001), dot(Right, Right))); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } + + template + GLM_FUNC_QUALIFIER qua quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) + { + mat<3, 3, T, Q> Result; + + Result[2] = direction; + vec<3, T, Q> const& Right = cross(up, Result[2]); + Result[0] = Right * inversesqrt(max(static_cast(0.00001), dot(Right, Right))); + Result[1] = cross(Result[2], Result[0]); + + return quat_cast(Result); + } +}//namespace glm + +#if GLM_CONFIG_SIMD == GLM_ENABLE +# include "quaternion_simd.inl" +#endif + diff --git a/thirdparty/glm/gtc/quaternion_simd.inl b/thirdparty/glm/gtc/quaternion_simd.inl new file mode 100644 index 0000000..e69de29 diff --git a/thirdparty/glm/gtc/random.hpp b/thirdparty/glm/gtc/random.hpp new file mode 100644 index 0000000..9a85958 --- /dev/null +++ b/thirdparty/glm/gtc/random.hpp @@ -0,0 +1,82 @@ +/// @ref gtc_random +/// @file glm/gtc/random.hpp +/// +/// @see core (dependence) +/// @see gtx_random (extended) +/// +/// @defgroup gtc_random GLM_GTC_random +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Generate random number from various distribution methods. + +#pragma once + +// Dependency: +#include "../ext/scalar_int_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_random extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_random + /// @{ + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam genType Value type. Currently supported: float or double scalars. + /// @see gtc_random + template + GLM_FUNC_DECL genType linearRand(genType Min, genType Max); + + /// Generate random numbers in the interval [Min, Max], according a linear distribution + /// + /// @param Min Minimum value included in the sampling + /// @param Max Maximum value included in the sampling + /// @tparam T Value type. Currently supported: float or double. + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec linearRand(vec const& Min, vec const& Max); + + /// Generate random numbers in the interval [Min, Max], according a gaussian distribution + /// + /// @see gtc_random + template + GLM_FUNC_DECL genType gaussRand(genType Mean, genType Deviation); + + /// Generate a random 2D vector which coordinates are regulary distributed on a circle of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> circularRand(T Radius); + + /// Generate a random 3D vector which coordinates are regulary distributed on a sphere of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> sphericalRand(T Radius); + + /// Generate a random 2D vector which coordinates are regulary distributed within the area of a disk of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<2, T, defaultp> diskRand(T Radius); + + /// Generate a random 3D vector which coordinates are regulary distributed within the volume of a ball of a given radius + /// + /// @see gtc_random + template + GLM_FUNC_DECL vec<3, T, defaultp> ballRand(T Radius); + + /// @} +}//namespace glm + +#include "random.inl" diff --git a/thirdparty/glm/gtc/random.inl b/thirdparty/glm/gtc/random.inl new file mode 100644 index 0000000..7048509 --- /dev/null +++ b/thirdparty/glm/gtc/random.inl @@ -0,0 +1,303 @@ +#include "../geometric.hpp" +#include "../exponential.hpp" +#include "../trigonometric.hpp" +#include "../detail/type_vec1.hpp" +#include +#include +#include +#include + +namespace glm{ +namespace detail +{ + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call(); + }; + + template + struct compute_rand<1, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<1, uint8, P> call() + { + return vec<1, uint8, P>( + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<2, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<2, uint8, P> call() + { + return vec<2, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<3, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<3, uint8, P> call() + { + return vec<3, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand<4, uint8, P> + { + GLM_FUNC_QUALIFIER static vec<4, uint8, P> call() + { + return vec<4, uint8, P>( + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max(), + std::rand() % std::numeric_limits::max()); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(8)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(16)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_rand + { + GLM_FUNC_QUALIFIER static vec call() + { + return + (vec(compute_rand::call()) << static_cast(32)) | + (vec(compute_rand::call()) << static_cast(0)); + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max); + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; + + template + struct compute_linearRand + { + GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) + { + return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max) + { + return detail::compute_linearRand<1, genType, highp>::call( + vec<1, genType, highp>(Min), + vec<1, genType, highp>(Max)).x; + } + + template + GLM_FUNC_QUALIFIER vec linearRand(vec const& Min, vec const& Max) + { + return detail::compute_linearRand::call(Min, Max); + } + + template + GLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation) + { + genType w, x1, x2; + + do + { + x1 = linearRand(genType(-1), genType(1)); + x2 = linearRand(genType(-1), genType(1)); + + w = x1 * x1 + x2 * x2; + } while(w > genType(1)); + + return static_cast(x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean); + } + + template + GLM_FUNC_QUALIFIER vec gaussRand(vec const& Mean, vec const& Deviation) + { + return detail::functor2::call(gaussRand, Mean, Deviation); + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> diskRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<2, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<2, T, defaultp>(-Radius), + vec<2, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> ballRand(T Radius) + { + assert(Radius > static_cast(0)); + + vec<3, T, defaultp> Result(T(0)); + T LenRadius(T(0)); + + do + { + Result = linearRand( + vec<3, T, defaultp>(-Radius), + vec<3, T, defaultp>(Radius)); + LenRadius = length(Result); + } + while(LenRadius > Radius); + + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> circularRand(T Radius) + { + assert(Radius > static_cast(0)); + + T a = linearRand(T(0), static_cast(6.283185307179586476925286766559)); + return vec<2, T, defaultp>(glm::cos(a), glm::sin(a)) * Radius; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> sphericalRand(T Radius) + { + assert(Radius > static_cast(0)); + + T theta = linearRand(T(0), T(6.283185307179586476925286766559f)); + T phi = std::acos(linearRand(T(-1.0f), T(1.0f))); + + T x = std::sin(phi) * std::cos(theta); + T y = std::sin(phi) * std::sin(theta); + T z = std::cos(phi); + + return vec<3, T, defaultp>(x, y, z) * Radius; + } +}//namespace glm diff --git a/thirdparty/glm/gtc/reciprocal.hpp b/thirdparty/glm/gtc/reciprocal.hpp new file mode 100644 index 0000000..c7d1330 --- /dev/null +++ b/thirdparty/glm/gtc/reciprocal.hpp @@ -0,0 +1,135 @@ +/// @ref gtc_reciprocal +/// @file glm/gtc/reciprocal.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_reciprocal GLM_GTC_reciprocal +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Define secant, cosecant and cotangent functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_reciprocal extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_reciprocal + /// @{ + + /// Secant function. + /// hypotenuse / adjacent or 1 / cos(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType sec(genType angle); + + /// Cosecant function. + /// hypotenuse / opposite or 1 / sin(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType csc(genType angle); + + /// Cotangent function. + /// adjacent / opposite or 1 / tan(x) + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType cot(genType angle); + + /// Inverse secant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType asec(genType x); + + /// Inverse cosecant function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acsc(genType x); + + /// Inverse cotangent function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acot(genType x); + + /// Secant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType sech(genType angle); + + /// Cosecant hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType csch(genType angle); + + /// Cotangent hyperbolic function. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType coth(genType angle); + + /// Inverse secant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType asech(genType x); + + /// Inverse cosecant hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acsch(genType x); + + /// Inverse cotangent hyperbolic function. + /// + /// @return Return an angle expressed in radians. + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see gtc_reciprocal + template + GLM_FUNC_DECL genType acoth(genType x); + + /// @} +}//namespace glm + +#include "reciprocal.inl" diff --git a/thirdparty/glm/gtc/reciprocal.inl b/thirdparty/glm/gtc/reciprocal.inl new file mode 100644 index 0000000..d88729e --- /dev/null +++ b/thirdparty/glm/gtc/reciprocal.inl @@ -0,0 +1,191 @@ +/// @ref gtc_reciprocal + +#include "../trigonometric.hpp" +#include + +namespace glm +{ + // sec + template + GLM_FUNC_QUALIFIER genType sec(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point values"); + return genType(1) / glm::cos(angle); + } + + template + GLM_FUNC_QUALIFIER vec sec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point inputs"); + return detail::functor1::call(sec, x); + } + + // csc + template + GLM_FUNC_QUALIFIER genType csc(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point values"); + return genType(1) / glm::sin(angle); + } + + template + GLM_FUNC_QUALIFIER vec csc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point inputs"); + return detail::functor1::call(csc, x); + } + + // cot + template + GLM_FUNC_QUALIFIER genType cot(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return glm::tan(pi_over_2 - angle); + } + + template + GLM_FUNC_QUALIFIER vec cot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point inputs"); + return detail::functor1::call(cot, x); + } + + // asec + template + GLM_FUNC_QUALIFIER genType asec(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point values"); + return acos(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec asec(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point inputs"); + return detail::functor1::call(asec, x); + } + + // acsc + template + GLM_FUNC_QUALIFIER genType acsc(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point values"); + return asin(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acsc(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point inputs"); + return detail::functor1::call(acsc, x); + } + + // acot + template + GLM_FUNC_QUALIFIER genType acot(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point values"); + + genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); + return pi_over_2 - atan(x); + } + + template + GLM_FUNC_QUALIFIER vec acot(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point inputs"); + return detail::functor1::call(acot, x); + } + + // sech + template + GLM_FUNC_QUALIFIER genType sech(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point values"); + return genType(1) / glm::cosh(angle); + } + + template + GLM_FUNC_QUALIFIER vec sech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point inputs"); + return detail::functor1::call(sech, x); + } + + // csch + template + GLM_FUNC_QUALIFIER genType csch(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point values"); + return genType(1) / glm::sinh(angle); + } + + template + GLM_FUNC_QUALIFIER vec csch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point inputs"); + return detail::functor1::call(csch, x); + } + + // coth + template + GLM_FUNC_QUALIFIER genType coth(genType angle) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point values"); + return glm::cosh(angle) / glm::sinh(angle); + } + + template + GLM_FUNC_QUALIFIER vec coth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point inputs"); + return detail::functor1::call(coth, x); + } + + // asech + template + GLM_FUNC_QUALIFIER genType asech(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point values"); + return acosh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec asech(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point inputs"); + return detail::functor1::call(asech, x); + } + + // acsch + template + GLM_FUNC_QUALIFIER genType acsch(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point values"); + return asinh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acsch(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point inputs"); + return detail::functor1::call(acsch, x); + } + + // acoth + template + GLM_FUNC_QUALIFIER genType acoth(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point values"); + return atanh(genType(1) / x); + } + + template + GLM_FUNC_QUALIFIER vec acoth(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point inputs"); + return detail::functor1::call(acoth, x); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/round.hpp b/thirdparty/glm/gtc/round.hpp new file mode 100644 index 0000000..56edbbc --- /dev/null +++ b/thirdparty/glm/gtc/round.hpp @@ -0,0 +1,160 @@ +/// @ref gtc_round +/// @file glm/gtc/round.hpp +/// +/// @see core (dependence) +/// @see gtc_round (dependence) +/// +/// @defgroup gtc_round GLM_GTC_round +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Rounding value to specific boundings + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../vector_relational.hpp" +#include "../common.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_round extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_round + /// @{ + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just higher the input value, + /// round up to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilPowerOfTwo(vec const& v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType v); + + /// Return the power of two number which value is just lower the input value, + /// round down to a power of two. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorPowerOfTwo(vec const& v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @see gtc_round + template + GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType v); + + /// Return the power of two number which value is the closet to the input value. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundPowerOfTwo(vec const& v); + + /// Higher multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType ceilMultiple(genType v, genType Multiple); + + /// Higher multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec ceilMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType floorMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec floorMultiple(vec const& v, vec const& Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam genType Floating-point or integer scalar or vector types. + /// + /// @param v Source value to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL genType roundMultiple(genType v, genType Multiple); + + /// Lower multiple number of Source. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @param v Source values to which is applied the function + /// @param Multiple Must be a null or positive value + /// + /// @see gtc_round + template + GLM_FUNC_DECL vec roundMultiple(vec const& v, vec const& Multiple); + + /// @} +} //namespace glm + +#include "round.inl" diff --git a/thirdparty/glm/gtc/round.inl b/thirdparty/glm/gtc/round.inl new file mode 100644 index 0000000..48411e4 --- /dev/null +++ b/thirdparty/glm/gtc/round.inl @@ -0,0 +1,155 @@ +/// @ref gtc_round + +#include "../integer.hpp" +#include "../ext/vector_integer.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_roundMultiple {}; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - std::fmod(Source, Multiple); + else + { + genType Tmp = Source + genType(1); + return Tmp - std::fmod(Tmp, Multiple) - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; + + template<> + struct compute_roundMultiple + { + template + GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) + { + if (Source >= genType(0)) + return Source - Source % Multiple; + else + { + genType Tmp = Source + genType(1); + return Tmp - Tmp % Multiple - Multiple; + } + } + }; +}//namespace detail + + ////////////////// + // ceilPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) + { + return detail::compute_ceilPowerOfTwo<1, genType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genType, defaultp>(value)).x; + } + + template + GLM_FUNC_QUALIFIER vec ceilPowerOfTwo(vec const& v) + { + return detail::compute_ceilPowerOfTwo::is_signed>::call(v); + } + + /////////////////// + // floorPowerOfTwo + + template + GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) + { + return isPowerOfTwo(value) ? value : static_cast(1) << findMSB(value); + } + + template + GLM_FUNC_QUALIFIER vec floorPowerOfTwo(vec const& v) + { + return detail::functor1::call(floorPowerOfTwo, v); + } + + /////////////////// + // roundPowerOfTwo + + template + GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) + { + if(isPowerOfTwo(value)) + return value; + + genIUType const prev = static_cast(1) << findMSB(value); + genIUType const next = prev << static_cast(1); + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec roundPowerOfTwo(vec const& v) + { + return detail::functor1::call(roundPowerOfTwo, v); + } + + ////////////////////// + // ceilMultiple + + template + GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple) + { + return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec ceilMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(ceilMultiple, Source, Multiple); + } + + ////////////////////// + // floorMultiple + + template + GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple) + { + return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec floorMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(floorMultiple, Source, Multiple); + } + + ////////////////////// + // roundMultiple + + template + GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple) + { + return detail::compute_roundMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); + } + + template + GLM_FUNC_QUALIFIER vec roundMultiple(vec const& Source, vec const& Multiple) + { + return detail::functor2::call(roundMultiple, Source, Multiple); + } +}//namespace glm diff --git a/thirdparty/glm/gtc/type_aligned.hpp b/thirdparty/glm/gtc/type_aligned.hpp new file mode 100644 index 0000000..5403abf --- /dev/null +++ b/thirdparty/glm/gtc/type_aligned.hpp @@ -0,0 +1,1315 @@ +/// @ref gtc_type_aligned +/// @file glm/gtc/type_aligned.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_type_aligned GLM_GTC_type_aligned +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Aligned types allowing SIMD optimizations of vectors and matrices types + +#pragma once + +#if (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) +# error "GLM: Aligned gentypes require to enable C++ language extensions. Define GLM_FORCE_ALIGNED_GENTYPES before including GLM headers to use aligned types." +#endif + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_aligned extension included") +#endif + +#include "../mat4x4.hpp" +#include "../mat4x3.hpp" +#include "../mat4x2.hpp" +#include "../mat3x4.hpp" +#include "../mat3x3.hpp" +#include "../mat3x2.hpp" +#include "../mat2x4.hpp" +#include "../mat2x3.hpp" +#include "../mat2x2.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" + +namespace glm +{ + /// @addtogroup gtc_type_aligned + /// @{ + + // -- *vec1 -- + + /// 1 component vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_highp> aligned_highp_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_mediump> aligned_mediump_vec1; + + /// 1 component vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, aligned_lowp> aligned_lowp_vec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_highp> aligned_highp_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_mediump> aligned_mediump_dvec1; + + /// 1 component vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, aligned_lowp> aligned_lowp_dvec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_highp> aligned_highp_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_mediump> aligned_mediump_ivec1; + + /// 1 component vector aligned in memory of signed integer numbers. + typedef vec<1, int, aligned_lowp> aligned_lowp_ivec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_highp> aligned_highp_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_mediump> aligned_mediump_uvec1; + + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef vec<1, uint, aligned_lowp> aligned_lowp_uvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_highp> aligned_highp_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_mediump> aligned_mediump_bvec1; + + /// 1 component vector aligned in memory of bool values. + typedef vec<1, bool, aligned_lowp> aligned_lowp_bvec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, float, packed_highp> packed_highp_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, float, packed_mediump> packed_mediump_vec1; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, float, packed_lowp> packed_lowp_vec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<1, double, packed_highp> packed_highp_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<1, double, packed_mediump> packed_mediump_dvec1; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<1, double, packed_lowp> packed_lowp_dvec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_highp> packed_highp_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_mediump> packed_mediump_ivec1; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef vec<1, int, packed_lowp> packed_lowp_ivec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_highp> packed_highp_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_mediump> packed_mediump_uvec1; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef vec<1, uint, packed_lowp> packed_lowp_uvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_highp> packed_highp_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_mediump> packed_mediump_bvec1; + + /// 1 component vector tightly packed in memory of bool values. + typedef vec<1, bool, packed_lowp> packed_lowp_bvec1; + + // -- *vec2 -- + + /// 2 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_highp> aligned_highp_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_mediump> aligned_mediump_vec2; + + /// 2 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, aligned_lowp> aligned_lowp_vec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_highp> aligned_highp_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_mediump> aligned_mediump_dvec2; + + /// 2 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, aligned_lowp> aligned_lowp_dvec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_highp> aligned_highp_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_mediump> aligned_mediump_ivec2; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef vec<2, int, aligned_lowp> aligned_lowp_ivec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_highp> aligned_highp_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_mediump> aligned_mediump_uvec2; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef vec<2, uint, aligned_lowp> aligned_lowp_uvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_highp> aligned_highp_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_mediump> aligned_mediump_bvec2; + + /// 2 components vector aligned in memory of bool values. + typedef vec<2, bool, aligned_lowp> aligned_lowp_bvec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, float, packed_highp> packed_highp_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, float, packed_mediump> packed_mediump_vec2; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, float, packed_lowp> packed_lowp_vec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<2, double, packed_highp> packed_highp_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<2, double, packed_mediump> packed_mediump_dvec2; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<2, double, packed_lowp> packed_lowp_dvec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_highp> packed_highp_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_mediump> packed_mediump_ivec2; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef vec<2, int, packed_lowp> packed_lowp_ivec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_highp> packed_highp_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_mediump> packed_mediump_uvec2; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<2, uint, packed_lowp> packed_lowp_uvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_highp> packed_highp_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_mediump> packed_mediump_bvec2; + + /// 2 components vector tightly packed in memory of bool values. + typedef vec<2, bool, packed_lowp> packed_lowp_bvec2; + + // -- *vec3 -- + + /// 3 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_highp> aligned_highp_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_mediump> aligned_mediump_vec3; + + /// 3 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, aligned_lowp> aligned_lowp_vec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_highp> aligned_highp_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_mediump> aligned_mediump_dvec3; + + /// 3 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, aligned_lowp> aligned_lowp_dvec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_highp> aligned_highp_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_mediump> aligned_mediump_ivec3; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef vec<3, int, aligned_lowp> aligned_lowp_ivec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_highp> aligned_highp_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_mediump> aligned_mediump_uvec3; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef vec<3, uint, aligned_lowp> aligned_lowp_uvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_highp> aligned_highp_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_mediump> aligned_mediump_bvec3; + + /// 3 components vector aligned in memory of bool values. + typedef vec<3, bool, aligned_lowp> aligned_lowp_bvec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, float, packed_highp> packed_highp_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, float, packed_mediump> packed_mediump_vec3; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, float, packed_lowp> packed_lowp_vec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<3, double, packed_highp> packed_highp_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<3, double, packed_mediump> packed_mediump_dvec3; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<3, double, packed_lowp> packed_lowp_dvec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_highp> packed_highp_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_mediump> packed_mediump_ivec3; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef vec<3, int, packed_lowp> packed_lowp_ivec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_highp> packed_highp_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_mediump> packed_mediump_uvec3; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<3, uint, packed_lowp> packed_lowp_uvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_highp> packed_highp_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_mediump> packed_mediump_bvec3; + + /// 3 components vector tightly packed in memory of bool values. + typedef vec<3, bool, packed_lowp> packed_lowp_bvec3; + + // -- *vec4 -- + + /// 4 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_highp> aligned_highp_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_mediump> aligned_mediump_vec4; + + /// 4 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, aligned_lowp> aligned_lowp_vec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_highp> aligned_highp_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_mediump> aligned_mediump_dvec4; + + /// 4 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, aligned_lowp> aligned_lowp_dvec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_highp> aligned_highp_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_mediump> aligned_mediump_ivec4; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef vec<4, int, aligned_lowp> aligned_lowp_ivec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_highp> aligned_highp_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_mediump> aligned_mediump_uvec4; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef vec<4, uint, aligned_lowp> aligned_lowp_uvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_highp> aligned_highp_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_mediump> aligned_mediump_bvec4; + + /// 4 components vector aligned in memory of bool values. + typedef vec<4, bool, aligned_lowp> aligned_lowp_bvec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, float, packed_highp> packed_highp_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, float, packed_mediump> packed_mediump_vec4; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, float, packed_lowp> packed_lowp_vec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef vec<4, double, packed_highp> packed_highp_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef vec<4, double, packed_mediump> packed_mediump_dvec4; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef vec<4, double, packed_lowp> packed_lowp_dvec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_highp> packed_highp_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_mediump> packed_mediump_ivec4; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef vec<4, int, packed_lowp> packed_lowp_ivec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_highp> packed_highp_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_mediump> packed_mediump_uvec4; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef vec<4, uint, packed_lowp> packed_lowp_uvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_highp> packed_highp_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_mediump> packed_mediump_bvec4; + + /// 4 components vector tightly packed in memory of bool values. + typedef vec<4, bool, packed_lowp> packed_lowp_bvec4; + + // -- *mat2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2; + + // -- *mat3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3; + + // -- *mat4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4; + + // -- *mat2x2 -- + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2x2; + + /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2x2; + + /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_highp> packed_highp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_highp> packed_highp_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2x2; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2x2; + + // -- *mat2x3 -- + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_highp> aligned_highp_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_mediump> aligned_mediump_mat2x3; + + /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, aligned_lowp> aligned_lowp_mat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_highp> aligned_highp_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_mediump> aligned_mediump_dmat2x3; + + /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, aligned_lowp> aligned_lowp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_highp> packed_highp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_mediump> packed_mediump_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, float, packed_lowp> packed_lowp_mat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_highp> packed_highp_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_mediump> packed_mediump_dmat2x3; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 3, double, packed_lowp> packed_lowp_dmat2x3; + + // -- *mat2x4 -- + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_highp> aligned_highp_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_mediump> aligned_mediump_mat2x4; + + /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, aligned_lowp> aligned_lowp_mat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_highp> aligned_highp_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_mediump> aligned_mediump_dmat2x4; + + /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, aligned_lowp> aligned_lowp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_highp> packed_highp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_mediump> packed_mediump_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, float, packed_lowp> packed_lowp_mat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_highp> packed_highp_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_mediump> packed_mediump_dmat2x4; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<2, 4, double, packed_lowp> packed_lowp_dmat2x4; + + // -- *mat3x2 -- + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_highp> aligned_highp_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_mediump> aligned_mediump_mat3x2; + + /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, aligned_lowp> aligned_lowp_mat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_highp> aligned_highp_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_mediump> aligned_mediump_dmat3x2; + + /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, aligned_lowp> aligned_lowp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_highp> packed_highp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_mediump> packed_mediump_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, float, packed_lowp> packed_lowp_mat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_highp> packed_highp_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_mediump> packed_mediump_dmat3x2; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 2, double, packed_lowp> packed_lowp_dmat3x2; + + // -- *mat3x3 -- + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3x3; + + /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3x3; + + /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_highp> packed_highp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_highp> packed_highp_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3x3; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3x3; + + // -- *mat3x4 -- + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_highp> aligned_highp_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_mediump> aligned_mediump_mat3x4; + + /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, aligned_lowp> aligned_lowp_mat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_highp> aligned_highp_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_mediump> aligned_mediump_dmat3x4; + + /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, aligned_lowp> aligned_lowp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_highp> packed_highp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_mediump> packed_mediump_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, float, packed_lowp> packed_lowp_mat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_highp> packed_highp_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_mediump> packed_mediump_dmat3x4; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<3, 4, double, packed_lowp> packed_lowp_dmat3x4; + + // -- *mat4x2 -- + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_highp> aligned_highp_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_mediump> aligned_mediump_mat4x2; + + /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, aligned_lowp> aligned_lowp_mat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_highp> aligned_highp_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_mediump> aligned_mediump_dmat4x2; + + /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, aligned_lowp> aligned_lowp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_highp> packed_highp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_mediump> packed_mediump_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, float, packed_lowp> packed_lowp_mat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_highp> packed_highp_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_mediump> packed_mediump_dmat4x2; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 2, double, packed_lowp> packed_lowp_dmat4x2; + + // -- *mat4x3 -- + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_highp> aligned_highp_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_mediump> aligned_mediump_mat4x3; + + /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, aligned_lowp> aligned_lowp_mat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_highp> aligned_highp_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_mediump> aligned_mediump_dmat4x3; + + /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, aligned_lowp> aligned_lowp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_highp> packed_highp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_mediump> packed_mediump_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, float, packed_lowp> packed_lowp_mat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_highp> packed_highp_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_mediump> packed_mediump_dmat4x3; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 3, double, packed_lowp> packed_lowp_dmat4x3; + + // -- *mat4x4 -- + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4x4; + + /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4x4; + + /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_highp> packed_highp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_highp> packed_highp_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4x4; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. + typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4x4; + + // -- default -- + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + typedef aligned_lowp_vec1 aligned_vec1; + typedef aligned_lowp_vec2 aligned_vec2; + typedef aligned_lowp_vec3 aligned_vec3; + typedef aligned_lowp_vec4 aligned_vec4; + typedef packed_lowp_vec1 packed_vec1; + typedef packed_lowp_vec2 packed_vec2; + typedef packed_lowp_vec3 packed_vec3; + typedef packed_lowp_vec4 packed_vec4; + + typedef aligned_lowp_mat2 aligned_mat2; + typedef aligned_lowp_mat3 aligned_mat3; + typedef aligned_lowp_mat4 aligned_mat4; + typedef packed_lowp_mat2 packed_mat2; + typedef packed_lowp_mat3 packed_mat3; + typedef packed_lowp_mat4 packed_mat4; + + typedef aligned_lowp_mat2x2 aligned_mat2x2; + typedef aligned_lowp_mat2x3 aligned_mat2x3; + typedef aligned_lowp_mat2x4 aligned_mat2x4; + typedef aligned_lowp_mat3x2 aligned_mat3x2; + typedef aligned_lowp_mat3x3 aligned_mat3x3; + typedef aligned_lowp_mat3x4 aligned_mat3x4; + typedef aligned_lowp_mat4x2 aligned_mat4x2; + typedef aligned_lowp_mat4x3 aligned_mat4x3; + typedef aligned_lowp_mat4x4 aligned_mat4x4; + typedef packed_lowp_mat2x2 packed_mat2x2; + typedef packed_lowp_mat2x3 packed_mat2x3; + typedef packed_lowp_mat2x4 packed_mat2x4; + typedef packed_lowp_mat3x2 packed_mat3x2; + typedef packed_lowp_mat3x3 packed_mat3x3; + typedef packed_lowp_mat3x4 packed_mat3x4; + typedef packed_lowp_mat4x2 packed_mat4x2; + typedef packed_lowp_mat4x3 packed_mat4x3; + typedef packed_lowp_mat4x4 packed_mat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + typedef aligned_mediump_vec1 aligned_vec1; + typedef aligned_mediump_vec2 aligned_vec2; + typedef aligned_mediump_vec3 aligned_vec3; + typedef aligned_mediump_vec4 aligned_vec4; + typedef packed_mediump_vec1 packed_vec1; + typedef packed_mediump_vec2 packed_vec2; + typedef packed_mediump_vec3 packed_vec3; + typedef packed_mediump_vec4 packed_vec4; + + typedef aligned_mediump_mat2 aligned_mat2; + typedef aligned_mediump_mat3 aligned_mat3; + typedef aligned_mediump_mat4 aligned_mat4; + typedef packed_mediump_mat2 packed_mat2; + typedef packed_mediump_mat3 packed_mat3; + typedef packed_mediump_mat4 packed_mat4; + + typedef aligned_mediump_mat2x2 aligned_mat2x2; + typedef aligned_mediump_mat2x3 aligned_mat2x3; + typedef aligned_mediump_mat2x4 aligned_mat2x4; + typedef aligned_mediump_mat3x2 aligned_mat3x2; + typedef aligned_mediump_mat3x3 aligned_mat3x3; + typedef aligned_mediump_mat3x4 aligned_mat3x4; + typedef aligned_mediump_mat4x2 aligned_mat4x2; + typedef aligned_mediump_mat4x3 aligned_mat4x3; + typedef aligned_mediump_mat4x4 aligned_mat4x4; + typedef packed_mediump_mat2x2 packed_mat2x2; + typedef packed_mediump_mat2x3 packed_mat2x3; + typedef packed_mediump_mat2x4 packed_mat2x4; + typedef packed_mediump_mat3x2 packed_mat3x2; + typedef packed_mediump_mat3x3 packed_mat3x3; + typedef packed_mediump_mat3x4 packed_mat3x4; + typedef packed_mediump_mat4x2 packed_mat4x2; + typedef packed_mediump_mat4x3 packed_mat4x3; + typedef packed_mediump_mat4x4 packed_mat4x4; +#else //defined(GLM_PRECISION_HIGHP_FLOAT) + /// 1 component vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec1 aligned_vec1; + + /// 2 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec2 aligned_vec2; + + /// 3 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec3 aligned_vec3; + + /// 4 components vector aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_vec4 aligned_vec4; + + /// 1 component vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec1 packed_vec1; + + /// 2 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec2 packed_vec2; + + /// 3 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec3 packed_vec3; + + /// 4 components vector tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_vec4 packed_vec4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2 aligned_mat2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3 aligned_mat3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4 aligned_mat4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2 packed_mat2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3 packed_mat3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4 packed_mat4; + + /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x2 aligned_mat2x2; + + /// 2 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x3 aligned_mat2x3; + + /// 2 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat2x4 aligned_mat2x4; + + /// 3 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x2 aligned_mat3x2; + + /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x3 aligned_mat3x3; + + /// 3 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat3x4 aligned_mat3x4; + + /// 4 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x2 aligned_mat4x2; + + /// 4 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x3 aligned_mat4x3; + + /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. + typedef aligned_highp_mat4x4 aligned_mat4x4; + + /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x2 packed_mat2x2; + + /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x3 packed_mat2x3; + + /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat2x4 packed_mat2x4; + + /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x2 packed_mat3x2; + + /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x3 packed_mat3x3; + + /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat3x4 packed_mat3x4; + + /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x2 packed_mat4x2; + + /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x3 packed_mat4x3; + + /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. + typedef packed_highp_mat4x4 packed_mat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef aligned_lowp_dvec1 aligned_dvec1; + typedef aligned_lowp_dvec2 aligned_dvec2; + typedef aligned_lowp_dvec3 aligned_dvec3; + typedef aligned_lowp_dvec4 aligned_dvec4; + typedef packed_lowp_dvec1 packed_dvec1; + typedef packed_lowp_dvec2 packed_dvec2; + typedef packed_lowp_dvec3 packed_dvec3; + typedef packed_lowp_dvec4 packed_dvec4; + + typedef aligned_lowp_dmat2 aligned_dmat2; + typedef aligned_lowp_dmat3 aligned_dmat3; + typedef aligned_lowp_dmat4 aligned_dmat4; + typedef packed_lowp_dmat2 packed_dmat2; + typedef packed_lowp_dmat3 packed_dmat3; + typedef packed_lowp_dmat4 packed_dmat4; + + typedef aligned_lowp_dmat2x2 aligned_dmat2x2; + typedef aligned_lowp_dmat2x3 aligned_dmat2x3; + typedef aligned_lowp_dmat2x4 aligned_dmat2x4; + typedef aligned_lowp_dmat3x2 aligned_dmat3x2; + typedef aligned_lowp_dmat3x3 aligned_dmat3x3; + typedef aligned_lowp_dmat3x4 aligned_dmat3x4; + typedef aligned_lowp_dmat4x2 aligned_dmat4x2; + typedef aligned_lowp_dmat4x3 aligned_dmat4x3; + typedef aligned_lowp_dmat4x4 aligned_dmat4x4; + typedef packed_lowp_dmat2x2 packed_dmat2x2; + typedef packed_lowp_dmat2x3 packed_dmat2x3; + typedef packed_lowp_dmat2x4 packed_dmat2x4; + typedef packed_lowp_dmat3x2 packed_dmat3x2; + typedef packed_lowp_dmat3x3 packed_dmat3x3; + typedef packed_lowp_dmat3x4 packed_dmat3x4; + typedef packed_lowp_dmat4x2 packed_dmat4x2; + typedef packed_lowp_dmat4x3 packed_dmat4x3; + typedef packed_lowp_dmat4x4 packed_dmat4x4; +#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE)) + typedef aligned_mediump_dvec1 aligned_dvec1; + typedef aligned_mediump_dvec2 aligned_dvec2; + typedef aligned_mediump_dvec3 aligned_dvec3; + typedef aligned_mediump_dvec4 aligned_dvec4; + typedef packed_mediump_dvec1 packed_dvec1; + typedef packed_mediump_dvec2 packed_dvec2; + typedef packed_mediump_dvec3 packed_dvec3; + typedef packed_mediump_dvec4 packed_dvec4; + + typedef aligned_mediump_dmat2 aligned_dmat2; + typedef aligned_mediump_dmat3 aligned_dmat3; + typedef aligned_mediump_dmat4 aligned_dmat4; + typedef packed_mediump_dmat2 packed_dmat2; + typedef packed_mediump_dmat3 packed_dmat3; + typedef packed_mediump_dmat4 packed_dmat4; + + typedef aligned_mediump_dmat2x2 aligned_dmat2x2; + typedef aligned_mediump_dmat2x3 aligned_dmat2x3; + typedef aligned_mediump_dmat2x4 aligned_dmat2x4; + typedef aligned_mediump_dmat3x2 aligned_dmat3x2; + typedef aligned_mediump_dmat3x3 aligned_dmat3x3; + typedef aligned_mediump_dmat3x4 aligned_dmat3x4; + typedef aligned_mediump_dmat4x2 aligned_dmat4x2; + typedef aligned_mediump_dmat4x3 aligned_dmat4x3; + typedef aligned_mediump_dmat4x4 aligned_dmat4x4; + typedef packed_mediump_dmat2x2 packed_dmat2x2; + typedef packed_mediump_dmat2x3 packed_dmat2x3; + typedef packed_mediump_dmat2x4 packed_dmat2x4; + typedef packed_mediump_dmat3x2 packed_dmat3x2; + typedef packed_mediump_dmat3x3 packed_dmat3x3; + typedef packed_mediump_dmat3x4 packed_dmat3x4; + typedef packed_mediump_dmat4x2 packed_dmat4x2; + typedef packed_mediump_dmat4x3 packed_dmat4x3; + typedef packed_mediump_dmat4x4 packed_dmat4x4; +#else //defined(GLM_PRECISION_HIGHP_DOUBLE) + /// 1 component vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec1 aligned_dvec1; + + /// 2 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec2 aligned_dvec2; + + /// 3 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec3 aligned_dvec3; + + /// 4 components vector aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dvec4 aligned_dvec4; + + /// 1 component vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec1 packed_dvec1; + + /// 2 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec2 packed_dvec2; + + /// 3 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec3 packed_dvec3; + + /// 4 components vector tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dvec4 packed_dvec4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2 aligned_dmat2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3 aligned_dmat3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4 aligned_dmat4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2 packed_dmat2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3 packed_dmat3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4 packed_dmat4; + + /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x2 aligned_dmat2x2; + + /// 2 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x3 aligned_dmat2x3; + + /// 2 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat2x4 aligned_dmat2x4; + + /// 3 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x2 aligned_dmat3x2; + + /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x3 aligned_dmat3x3; + + /// 3 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat3x4 aligned_dmat3x4; + + /// 4 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x2 aligned_dmat4x2; + + /// 4 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x3 aligned_dmat4x3; + + /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. + typedef aligned_highp_dmat4x4 aligned_dmat4x4; + + /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x2 packed_dmat2x2; + + /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x3 packed_dmat2x3; + + /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat2x4 packed_dmat2x4; + + /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x2 packed_dmat3x2; + + /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x3 packed_dmat3x3; + + /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat3x4 packed_dmat3x4; + + /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x2 packed_dmat4x2; + + /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x3 packed_dmat4x3; + + /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. + typedef packed_highp_dmat4x4 packed_dmat4x4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_INT)) + typedef aligned_lowp_ivec1 aligned_ivec1; + typedef aligned_lowp_ivec2 aligned_ivec2; + typedef aligned_lowp_ivec3 aligned_ivec3; + typedef aligned_lowp_ivec4 aligned_ivec4; +#elif(defined(GLM_PRECISION_MEDIUMP_INT)) + typedef aligned_mediump_ivec1 aligned_ivec1; + typedef aligned_mediump_ivec2 aligned_ivec2; + typedef aligned_mediump_ivec3 aligned_ivec3; + typedef aligned_mediump_ivec4 aligned_ivec4; +#else //defined(GLM_PRECISION_HIGHP_INT) + /// 1 component vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec1 aligned_ivec1; + + /// 2 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec2 aligned_ivec2; + + /// 3 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec3 aligned_ivec3; + + /// 4 components vector aligned in memory of signed integer numbers. + typedef aligned_highp_ivec4 aligned_ivec4; + + /// 1 component vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec1 packed_ivec1; + + /// 2 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec2 packed_ivec2; + + /// 3 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec3 packed_ivec3; + + /// 4 components vector tightly packed in memory of signed integer numbers. + typedef packed_highp_ivec4 packed_ivec4; +#endif//GLM_PRECISION + + // -- Unsigned integer definition -- + +#if(defined(GLM_PRECISION_LOWP_UINT)) + typedef aligned_lowp_uvec1 aligned_uvec1; + typedef aligned_lowp_uvec2 aligned_uvec2; + typedef aligned_lowp_uvec3 aligned_uvec3; + typedef aligned_lowp_uvec4 aligned_uvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_UINT)) + typedef aligned_mediump_uvec1 aligned_uvec1; + typedef aligned_mediump_uvec2 aligned_uvec2; + typedef aligned_mediump_uvec3 aligned_uvec3; + typedef aligned_mediump_uvec4 aligned_uvec4; +#else //defined(GLM_PRECISION_HIGHP_UINT) + /// 1 component vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec1 aligned_uvec1; + + /// 2 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec2 aligned_uvec2; + + /// 3 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec3 aligned_uvec3; + + /// 4 components vector aligned in memory of unsigned integer numbers. + typedef aligned_highp_uvec4 aligned_uvec4; + + /// 1 component vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec1 packed_uvec1; + + /// 2 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec2 packed_uvec2; + + /// 3 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec3 packed_uvec3; + + /// 4 components vector tightly packed in memory of unsigned integer numbers. + typedef packed_highp_uvec4 packed_uvec4; +#endif//GLM_PRECISION + +#if(defined(GLM_PRECISION_LOWP_BOOL)) + typedef aligned_lowp_bvec1 aligned_bvec1; + typedef aligned_lowp_bvec2 aligned_bvec2; + typedef aligned_lowp_bvec3 aligned_bvec3; + typedef aligned_lowp_bvec4 aligned_bvec4; +#elif(defined(GLM_PRECISION_MEDIUMP_BOOL)) + typedef aligned_mediump_bvec1 aligned_bvec1; + typedef aligned_mediump_bvec2 aligned_bvec2; + typedef aligned_mediump_bvec3 aligned_bvec3; + typedef aligned_mediump_bvec4 aligned_bvec4; +#else //defined(GLM_PRECISION_HIGHP_BOOL) + /// 1 component vector aligned in memory of bool values. + typedef aligned_highp_bvec1 aligned_bvec1; + + /// 2 components vector aligned in memory of bool values. + typedef aligned_highp_bvec2 aligned_bvec2; + + /// 3 components vector aligned in memory of bool values. + typedef aligned_highp_bvec3 aligned_bvec3; + + /// 4 components vector aligned in memory of bool values. + typedef aligned_highp_bvec4 aligned_bvec4; + + /// 1 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec1 packed_bvec1; + + /// 2 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec2 packed_bvec2; + + /// 3 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec3 packed_bvec3; + + /// 4 components vector tightly packed in memory of bool values. + typedef packed_highp_bvec4 packed_bvec4; +#endif//GLM_PRECISION + + /// @} +}//namespace glm diff --git a/thirdparty/glm/gtc/type_precision.hpp b/thirdparty/glm/gtc/type_precision.hpp new file mode 100644 index 0000000..775e2f4 --- /dev/null +++ b/thirdparty/glm/gtc/type_precision.hpp @@ -0,0 +1,2094 @@ +/// @ref gtc_type_precision +/// @file glm/gtc/type_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_precision GLM_GTC_type_precision +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Defines specific C++-based qualifier types. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../ext/vector_int1_sized.hpp" +#include "../ext/vector_int2_sized.hpp" +#include "../ext/vector_int3_sized.hpp" +#include "../ext/vector_int4_sized.hpp" +#include "../ext/scalar_int_sized.hpp" +#include "../ext/vector_uint1_sized.hpp" +#include "../ext/vector_uint2_sized.hpp" +#include "../ext/vector_uint3_sized.hpp" +#include "../ext/vector_uint4_sized.hpp" +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/type_vec2.hpp" +#include "../detail/type_vec3.hpp" +#include "../detail/type_vec4.hpp" +#include "../detail/type_mat2x2.hpp" +#include "../detail/type_mat2x3.hpp" +#include "../detail/type_mat2x4.hpp" +#include "../detail/type_mat3x2.hpp" +#include "../detail/type_mat3x3.hpp" +#include "../detail/type_mat3x4.hpp" +#include "../detail/type_mat4x2.hpp" +#include "../detail/type_mat4x3.hpp" +#include "../detail/type_mat4x4.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_precision extension included") +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtc_type_precision + /// @{ + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_int8_t; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_int16_t; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_int32_t; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_int64_t; + + /// Low qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 lowp_i8; + + /// Low qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 lowp_i16; + + /// Low qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 lowp_i32; + + /// Low qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 lowp_i64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_int8_t; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_int16_t; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_int32_t; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_int64_t; + + /// Medium qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 mediump_i8; + + /// Medium qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 mediump_i16; + + /// Medium qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 mediump_i32; + + /// Medium qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 mediump_i64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_int8_t; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_int32_t; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_int64_t; + + /// High qualifier 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 highp_i8; + + /// High qualifier 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 highp_i16; + + /// High qualifier 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 highp_i32; + + /// High qualifier 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 highp_i64; + + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::int8_t; + using std::int16_t; + using std::int32_t; + using std::int64_t; +#else + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 int8_t; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 int16_t; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 int32_t; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 int64_t; +#endif + + /// 8 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int8 i8; + + /// 16 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int16 i16; + + /// 32 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int32 i32; + + /// 64 bit signed integer type. + /// @see gtc_type_precision + typedef detail::int64 i64; + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_uint8_t; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_uint16_t; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_uint32_t; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_uint64_t; + + /// Low qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 lowp_u8; + + /// Low qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 lowp_u16; + + /// Low qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 lowp_u32; + + /// Low qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 lowp_u64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_uint8_t; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_uint16_t; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_uint32_t; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_uint64_t; + + /// Medium qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 mediump_u8; + + /// Medium qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 mediump_u16; + + /// Medium qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 mediump_u32; + + /// Medium qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 mediump_u64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_uint8_t; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_uint16_t; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_uint32_t; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_uint64_t; + + /// High qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 highp_u8; + + /// High qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 highp_u16; + + /// High qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 highp_u32; + + /// High qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 highp_u64; + +#if GLM_HAS_EXTENDED_INTEGER_TYPE + using std::uint8_t; + using std::uint16_t; + using std::uint32_t; + using std::uint64_t; +#else + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 uint8_t; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 uint16_t; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 uint32_t; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 uint64_t; +#endif + + /// Default qualifier 8 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint8 u8; + + /// Default qualifier 16 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint16 u16; + + /// Default qualifier 32 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint32 u32; + + /// Default qualifier 64 bit unsigned integer type. + /// @see gtc_type_precision + typedef detail::uint64 u64; + + + + + + ////////////////////// + // Float vector types + + /// Single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float float32; + + /// Double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef double float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_float32_t; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_float64_t; + + /// Low 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 lowp_f32; + + /// Low 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 lowp_f64; + + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_float32_t; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_float64_t; + + /// Medium 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 mediump_f32; + + /// Medium 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 mediump_f64; + + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_float32_t; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_float64_t; + + /// High 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 highp_f32; + + /// High 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 highp_f64; + + +#if(defined(GLM_PRECISION_LOWP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef lowp_f64 f64; + +#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float32 f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef mediump_float64 f64; + +#else//(defined(GLM_PRECISION_HIGHP_FLOAT)) + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t float32_t; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t float64_t; + + /// Default 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float32_t f32; + + /// Default 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef highp_float64_t f64; +#endif + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, lowp> lowp_fvec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, lowp> lowp_fvec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, lowp> lowp_fvec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, lowp> lowp_fvec4; + + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, mediump> mediump_fvec1; + + /// Medium Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, mediump> mediump_fvec2; + + /// Medium Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, mediump> mediump_fvec3; + + /// Medium Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, mediump> mediump_fvec4; + + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, highp> highp_fvec1; + + /// High Single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, float, highp> highp_fvec2; + + /// High Single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, float, highp> highp_fvec3; + + /// High Single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, float, highp> highp_fvec4; + + + /// Low single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, lowp> lowp_f32vec1; + + /// Low single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, lowp> lowp_f32vec2; + + /// Low single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, lowp> lowp_f32vec3; + + /// Low single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, lowp> lowp_f32vec4; + + /// Medium single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, mediump> mediump_f32vec1; + + /// Medium single-qualifier floating-point vector of 2 components. + /// @see core_precision + typedef vec<2, f32, mediump> mediump_f32vec2; + + /// Medium single-qualifier floating-point vector of 3 components. + /// @see core_precision + typedef vec<3, f32, mediump> mediump_f32vec3; + + /// Medium single-qualifier floating-point vector of 4 components. + /// @see core_precision + typedef vec<4, f32, mediump> mediump_f32vec4; + + /// High single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, highp> highp_f32vec1; + + /// High single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, highp> highp_f32vec2; + + /// High single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, highp> highp_f32vec3; + + /// High single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, highp> highp_f32vec4; + + + /// Low double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, lowp> lowp_f64vec1; + + /// Low double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, lowp> lowp_f64vec2; + + /// Low double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, lowp> lowp_f64vec3; + + /// Low double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, lowp> lowp_f64vec4; + + /// Medium double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, mediump> mediump_f64vec1; + + /// Medium double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, mediump> mediump_f64vec2; + + /// Medium double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, mediump> mediump_f64vec3; + + /// Medium double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, mediump> mediump_f64vec4; + + /// High double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, highp> highp_f64vec1; + + /// High double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, highp> highp_f64vec2; + + /// High double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, highp> highp_f64vec3; + + /// High double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, highp> highp_f64vec4; + + + + ////////////////////// + // Float matrix types + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f32 lowp_fmat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_fmat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_fmat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_fmat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_fmat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_fmat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_fmat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_fmat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_fmat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_fmat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_fmat1x1 lowp_fmat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_fmat2x2 lowp_fmat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_fmat3x3 lowp_fmat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_fmat4x4 lowp_fmat4; + + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f32 mediump_fmat1x1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_fmat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_fmat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_fmat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_fmat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_fmat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_fmat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_fmat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_fmat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_fmat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_fmat1x1 mediump_fmat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_fmat2x2 mediump_fmat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_fmat3x3 mediump_fmat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_fmat4x4 mediump_fmat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f32 highp_fmat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_fmat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_fmat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_fmat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_fmat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_fmat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_fmat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_fmat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_fmat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_fmat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_fmat1x1 highp_fmat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_fmat2x2 highp_fmat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_fmat3x3 highp_fmat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_fmat4x4 highp_fmat4; + + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 lowp_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; + + /// Low single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; + + /// Low single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; + + /// Low single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; + + /// Low single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; + + /// Low single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; + + /// Low single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; + + /// Low single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 lowp_f32mat1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat2x2 lowp_f32mat2; + + /// Low single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat3x3 lowp_f32mat3; + + /// Low single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f32mat4x4 lowp_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 mediump_f32mat1x1; + + /// Low single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; + + /// Medium single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; + + /// Medium single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; + + /// Medium single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; + + /// Medium single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; + + /// Medium single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; + + /// Medium single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; + + /// Medium single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Medium single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat2x2 mediump_f32mat2; + + /// Medium single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat3x3 mediump_f32mat3; + + /// Medium single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f32mat4x4 mediump_f32mat4; + + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 highp_f32mat1x1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, highp> highp_f32mat2x2; + + /// High single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, highp> highp_f32mat2x3; + + /// High single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, highp> highp_f32mat2x4; + + /// High single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, highp> highp_f32mat3x2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, highp> highp_f32mat3x3; + + /// High single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, highp> highp_f32mat3x4; + + /// High single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, highp> highp_f32mat4x2; + + /// High single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, highp> highp_f32mat4x3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, highp> highp_f32mat4x4; + + /// High single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// High single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f32mat2x2 highp_f32mat2; + + /// High single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f32mat3x3 highp_f32mat3; + + /// High single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f32mat4x4 highp_f32mat4; + + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 lowp_f64mat1x1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; + + /// Low double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; + + /// Low double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; + + /// Low double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; + + /// Low double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; + + /// Low double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; + + /// Low double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; + + /// Low double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef lowp_f64mat1x1 lowp_f64mat1; + + /// Low double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat2x2 lowp_f64mat2; + + /// Low double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat3x3 lowp_f64mat3; + + /// Low double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef lowp_f64mat4x4 lowp_f64mat4; + + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 Highp_f64mat1x1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; + + /// Medium double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; + + /// Medium double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; + + /// Medium double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; + + /// Medium double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; + + /// Medium double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; + + /// Medium double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; + + /// Medium double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef mediump_f64mat1x1 mediump_f64mat1; + + /// Medium double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat2x2 mediump_f64mat2; + + /// Medium double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat3x3 mediump_f64mat3; + + /// Medium double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mediump_f64mat4x4 mediump_f64mat4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 highp_f64mat1x1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, highp> highp_f64mat2x2; + + /// High double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, highp> highp_f64mat2x3; + + /// High double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, highp> highp_f64mat2x4; + + /// High double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, highp> highp_f64mat3x2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, highp> highp_f64mat3x3; + + /// High double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, highp> highp_f64mat3x4; + + /// High double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, highp> highp_f64mat4x2; + + /// High double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, highp> highp_f64mat4x3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, highp> highp_f64mat4x4; + + /// High double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef highp_f64mat1x1 highp_f64mat1; + + /// High double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef highp_f64mat2x2 highp_f64mat2; + + /// High double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef highp_f64mat3x3 highp_f64mat3; + + /// High double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef highp_f64mat4x4 highp_f64mat4; + + + ///////////////////////////// + // Signed int vector types + + /// Low qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, lowp> lowp_ivec1; + + /// Low qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, lowp> lowp_ivec2; + + /// Low qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, lowp> lowp_ivec3; + + /// Low qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, lowp> lowp_ivec4; + + + /// Medium qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, mediump> mediump_ivec1; + + /// Medium qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, mediump> mediump_ivec2; + + /// Medium qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, mediump> mediump_ivec3; + + /// Medium qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, mediump> mediump_ivec4; + + + /// High qualifier signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, int, highp> highp_ivec1; + + /// High qualifier signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, int, highp> highp_ivec2; + + /// High qualifier signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, int, highp> highp_ivec3; + + /// High qualifier signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, int, highp> highp_ivec4; + + + /// Low qualifier 8 bit signed integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, i8, lowp> lowp_i8vec1; + + /// Low qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, lowp> lowp_i8vec2; + + /// Low qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, lowp> lowp_i8vec3; + + /// Low qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, lowp> lowp_i8vec4; + + + /// Medium qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, mediump> mediump_i8vec1; + + /// Medium qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, mediump> mediump_i8vec2; + + /// Medium qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, mediump> mediump_i8vec3; + + /// Medium qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, mediump> mediump_i8vec4; + + + /// High qualifier 8 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i8, highp> highp_i8vec1; + + /// High qualifier 8 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i8, highp> highp_i8vec2; + + /// High qualifier 8 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i8, highp> highp_i8vec3; + + /// High qualifier 8 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i8, highp> highp_i8vec4; + + + /// Low qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, lowp> lowp_i16vec1; + + /// Low qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, lowp> lowp_i16vec2; + + /// Low qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, lowp> lowp_i16vec3; + + /// Low qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, lowp> lowp_i16vec4; + + + /// Medium qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, mediump> mediump_i16vec1; + + /// Medium qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, mediump> mediump_i16vec2; + + /// Medium qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, mediump> mediump_i16vec3; + + /// Medium qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, mediump> mediump_i16vec4; + + + /// High qualifier 16 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i16, highp> highp_i16vec1; + + /// High qualifier 16 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i16, highp> highp_i16vec2; + + /// High qualifier 16 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i16, highp> highp_i16vec3; + + /// High qualifier 16 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i16, highp> highp_i16vec4; + + + /// Low qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, lowp> lowp_i32vec1; + + /// Low qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, lowp> lowp_i32vec2; + + /// Low qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, lowp> lowp_i32vec3; + + /// Low qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, lowp> lowp_i32vec4; + + + /// Medium qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, mediump> mediump_i32vec1; + + /// Medium qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, mediump> mediump_i32vec2; + + /// Medium qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, mediump> mediump_i32vec3; + + /// Medium qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, mediump> mediump_i32vec4; + + + /// High qualifier 32 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i32, highp> highp_i32vec1; + + /// High qualifier 32 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i32, highp> highp_i32vec2; + + /// High qualifier 32 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i32, highp> highp_i32vec3; + + /// High qualifier 32 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i32, highp> highp_i32vec4; + + + /// Low qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, lowp> lowp_i64vec1; + + /// Low qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, lowp> lowp_i64vec2; + + /// Low qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, lowp> lowp_i64vec3; + + /// Low qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, lowp> lowp_i64vec4; + + + /// Medium qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, mediump> mediump_i64vec1; + + /// Medium qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, mediump> mediump_i64vec2; + + /// Medium qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, mediump> mediump_i64vec3; + + /// Medium qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, mediump> mediump_i64vec4; + + + /// High qualifier 64 bit signed integer scalar type. + /// @see gtc_type_precision + typedef vec<1, i64, highp> highp_i64vec1; + + /// High qualifier 64 bit signed integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, i64, highp> highp_i64vec2; + + /// High qualifier 64 bit signed integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, i64, highp> highp_i64vec3; + + /// High qualifier 64 bit signed integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, i64, highp> highp_i64vec4; + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, lowp> lowp_uvec1; + + /// Low qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, lowp> lowp_uvec2; + + /// Low qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, lowp> lowp_uvec3; + + /// Low qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, lowp> lowp_uvec4; + + + /// Medium qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, mediump> mediump_uvec1; + + /// Medium qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, mediump> mediump_uvec2; + + /// Medium qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, mediump> mediump_uvec3; + + /// Medium qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, mediump> mediump_uvec4; + + + /// High qualifier unsigned integer vector of 1 component type. + /// @see gtc_type_precision + typedef vec<1, uint, highp> highp_uvec1; + + /// High qualifier unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, uint, highp> highp_uvec2; + + /// High qualifier unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, uint, highp> highp_uvec3; + + /// High qualifier unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, uint, highp> highp_uvec4; + + + /// Low qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, lowp> lowp_u8vec1; + + /// Low qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, lowp> lowp_u8vec2; + + /// Low qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, lowp> lowp_u8vec3; + + /// Low qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, lowp> lowp_u8vec4; + + + /// Medium qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, mediump> mediump_u8vec1; + + /// Medium qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, mediump> mediump_u8vec2; + + /// Medium qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, mediump> mediump_u8vec3; + + /// Medium qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, mediump> mediump_u8vec4; + + + /// High qualifier 8 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u8, highp> highp_u8vec1; + + /// High qualifier 8 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u8, highp> highp_u8vec2; + + /// High qualifier 8 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u8, highp> highp_u8vec3; + + /// High qualifier 8 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u8, highp> highp_u8vec4; + + + /// Low qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, lowp> lowp_u16vec1; + + /// Low qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, lowp> lowp_u16vec2; + + /// Low qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, lowp> lowp_u16vec3; + + /// Low qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, lowp> lowp_u16vec4; + + + /// Medium qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, mediump> mediump_u16vec1; + + /// Medium qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, mediump> mediump_u16vec2; + + /// Medium qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, mediump> mediump_u16vec3; + + /// Medium qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, mediump> mediump_u16vec4; + + + /// High qualifier 16 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u16, highp> highp_u16vec1; + + /// High qualifier 16 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u16, highp> highp_u16vec2; + + /// High qualifier 16 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u16, highp> highp_u16vec3; + + /// High qualifier 16 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u16, highp> highp_u16vec4; + + + /// Low qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, lowp> lowp_u32vec1; + + /// Low qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, lowp> lowp_u32vec2; + + /// Low qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, lowp> lowp_u32vec3; + + /// Low qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, lowp> lowp_u32vec4; + + + /// Medium qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, mediump> mediump_u32vec1; + + /// Medium qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, mediump> mediump_u32vec2; + + /// Medium qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, mediump> mediump_u32vec3; + + /// Medium qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, mediump> mediump_u32vec4; + + + /// High qualifier 32 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u32, highp> highp_u32vec1; + + /// High qualifier 32 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u32, highp> highp_u32vec2; + + /// High qualifier 32 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u32, highp> highp_u32vec3; + + /// High qualifier 32 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u32, highp> highp_u32vec4; + + + /// Low qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, lowp> lowp_u64vec1; + + /// Low qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, lowp> lowp_u64vec2; + + /// Low qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, lowp> lowp_u64vec3; + + /// Low qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, lowp> lowp_u64vec4; + + + /// Medium qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, mediump> mediump_u64vec1; + + /// Medium qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, mediump> mediump_u64vec2; + + /// Medium qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, mediump> mediump_u64vec3; + + /// Medium qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, mediump> mediump_u64vec4; + + + /// High qualifier 64 bit unsigned integer scalar type. + /// @see gtc_type_precision + typedef vec<1, u64, highp> highp_u64vec1; + + /// High qualifier 64 bit unsigned integer vector of 2 components type. + /// @see gtc_type_precision + typedef vec<2, u64, highp> highp_u64vec2; + + /// High qualifier 64 bit unsigned integer vector of 3 components type. + /// @see gtc_type_precision + typedef vec<3, u64, highp> highp_u64vec3; + + /// High qualifier 64 bit unsigned integer vector of 4 components type. + /// @see gtc_type_precision + typedef vec<4, u64, highp> highp_u64vec4; + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 float32_t; + + /// 32 bit single-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float32 f32; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 float64_t; + + /// 64 bit double-qualifier floating-point scalar. + /// @see gtc_type_precision + typedef float64 f64; +# endif//GLM_FORCE_SINGLE_ONLY + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, float, defaultp> fvec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, float, defaultp> fvec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, float, defaultp> fvec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, float, defaultp> fvec4; + + + /// Single-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f32, defaultp> f32vec1; + + /// Single-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f32, defaultp> f32vec2; + + /// Single-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f32, defaultp> f32vec3; + + /// Single-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f32, defaultp> f32vec4; + +# ifndef GLM_FORCE_SINGLE_ONLY + /// Double-qualifier floating-point vector of 1 component. + /// @see gtc_type_precision + typedef vec<1, f64, defaultp> f64vec1; + + /// Double-qualifier floating-point vector of 2 components. + /// @see gtc_type_precision + typedef vec<2, f64, defaultp> f64vec2; + + /// Double-qualifier floating-point vector of 3 components. + /// @see gtc_type_precision + typedef vec<3, f64, defaultp> f64vec3; + + /// Double-qualifier floating-point vector of 4 components. + /// @see gtc_type_precision + typedef vec<4, f64, defaultp> f64vec4; +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> fmat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> fmat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> fmat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> fmat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> fmat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> fmat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> fmat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> fmat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> fmat4x4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4; + + + /// Single-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f32, defaultp> f32mat2x2; + + /// Single-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f32, defaultp> f32mat2x3; + + /// Single-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f32, defaultp> f32mat2x4; + + /// Single-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f32, defaultp> f32mat3x2; + + /// Single-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f32, defaultp> f32mat3x3; + + /// Single-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f32, defaultp> f32mat3x4; + + /// Single-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f32, defaultp> f32mat4x2; + + /// Single-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f32, defaultp> f32mat4x3; + + /// Single-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f32, defaultp> f32mat4x4; + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4; + + + /// Double-qualifier floating-point 1x1 matrix. + /// @see gtc_type_precision + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point 2x2 matrix. + /// @see gtc_type_precision + typedef mat<2, 2, f64, defaultp> f64mat2x2; + + /// Double-qualifier floating-point 2x3 matrix. + /// @see gtc_type_precision + typedef mat<2, 3, f64, defaultp> f64mat2x3; + + /// Double-qualifier floating-point 2x4 matrix. + /// @see gtc_type_precision + typedef mat<2, 4, f64, defaultp> f64mat2x4; + + /// Double-qualifier floating-point 3x2 matrix. + /// @see gtc_type_precision + typedef mat<3, 2, f64, defaultp> f64mat3x2; + + /// Double-qualifier floating-point 3x3 matrix. + /// @see gtc_type_precision + typedef mat<3, 3, f64, defaultp> f64mat3x3; + + /// Double-qualifier floating-point 3x4 matrix. + /// @see gtc_type_precision + typedef mat<3, 4, f64, defaultp> f64mat3x4; + + /// Double-qualifier floating-point 4x2 matrix. + /// @see gtc_type_precision + typedef mat<4, 2, f64, defaultp> f64mat4x2; + + /// Double-qualifier floating-point 4x3 matrix. + /// @see gtc_type_precision + typedef mat<4, 3, f64, defaultp> f64mat4x3; + + /// Double-qualifier floating-point 4x4 matrix. + /// @see gtc_type_precision + typedef mat<4, 4, f64, defaultp> f64mat4x4; + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f32quat; + + /// Low single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f32quat; + + /// Low double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua lowp_f64quat; + + /// Medium single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f32quat; + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Medium double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua mediump_f64quat; + + /// High single-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f32quat; + + /// High double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua highp_f64quat; + + /// Double-qualifier floating-point quaternion. + /// @see gtc_type_precision + typedef qua f64quat; + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_precision.inl" diff --git a/thirdparty/glm/gtc/type_precision.inl b/thirdparty/glm/gtc/type_precision.inl new file mode 100644 index 0000000..ae80912 --- /dev/null +++ b/thirdparty/glm/gtc/type_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtc_precision + +namespace glm +{ + +} diff --git a/thirdparty/glm/gtc/type_ptr.hpp b/thirdparty/glm/gtc/type_ptr.hpp new file mode 100644 index 0000000..d7e625a --- /dev/null +++ b/thirdparty/glm/gtc/type_ptr.hpp @@ -0,0 +1,230 @@ +/// @ref gtc_type_ptr +/// @file glm/gtc/type_ptr.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtc_type_ptr GLM_GTC_type_ptr +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Handles the interaction between pointers and vector, matrix types. +/// +/// This extension defines an overloaded function, glm::value_ptr. It returns +/// a pointer to the memory layout of the object. Matrix types store their values +/// in column-major order. +/// +/// This is useful for uploading data to matrices or copying data to buffer objects. +/// +/// Example: +/// @code +/// #include +/// #include +/// +/// glm::vec3 aVector(3); +/// glm::mat4 someMatrix(1.0); +/// +/// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector)); +/// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix)); +/// @endcode +/// +/// need to be included to use the features of this extension. + +#pragma once + +// Dependency: +#include "../gtc/quaternion.hpp" +#include "../gtc/vec1.hpp" +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_type_ptr extension included") +#endif + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + /// Return the constant address to the data of the input parameter. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<2, T, defaultp> make_vec2(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<3, T, defaultp> make_vec3(T const * const ptr); + + /// Build a vector from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL vec<4, T, defaultp> make_vec4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 3, T, defaultp> make_mat2x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 4, T, defaultp> make_mat2x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 2, T, defaultp> make_mat3x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 4, T, defaultp> make_mat3x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 2, T, defaultp> make_mat4x2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 3, T, defaultp> make_mat4x3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4x4(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3(T const * const ptr); + + /// Build a matrix from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4(T const * const ptr); + + /// Build a quaternion from a pointer. + /// @see gtc_type_ptr + template + GLM_FUNC_DECL qua make_quat(T const * const ptr); + + /// @} +}//namespace glm + +#include "type_ptr.inl" diff --git a/thirdparty/glm/gtc/type_ptr.inl b/thirdparty/glm/gtc/type_ptr.inl new file mode 100644 index 0000000..71df4d3 --- /dev/null +++ b/thirdparty/glm/gtc/type_ptr.inl @@ -0,0 +1,386 @@ +/// @ref gtc_type_ptr + +#include + +namespace glm +{ + /// @addtogroup gtc_type_ptr + /// @{ + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<2, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<2, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(vec<3, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<3, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(vec<4, T, Q> const& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(vec<4, T, Q>& v) + { + return &(v.x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 2, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 2, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 4, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 4, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 3, T, Q> const& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T * value_ptr(mat<4, 3, T, Q>& m) + { + return &(m[0].x); + } + + template + GLM_FUNC_QUALIFIER T const * value_ptr(qua const& q) + { + return &(q[0]); + } + + template + GLM_FUNC_QUALIFIER T* value_ptr(qua& q) + { + return &(q[0]); + } + + template + inline vec<1, T, Q> make_vec1(vec<1, T, Q> const& v) + { + return v; + } + + template + inline vec<1, T, Q> make_vec1(vec<2, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<1, T, Q> make_vec1(vec<3, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<1, T, Q> make_vec1(vec<4, T, Q> const& v) + { + return vec<1, T, Q>(v); + } + + template + inline vec<2, T, Q> make_vec2(vec<1, T, Q> const& v) + { + return vec<2, T, Q>(v.x, static_cast(0)); + } + + template + inline vec<2, T, Q> make_vec2(vec<2, T, Q> const& v) + { + return v; + } + + template + inline vec<2, T, Q> make_vec2(vec<3, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + inline vec<2, T, Q> make_vec2(vec<4, T, Q> const& v) + { + return vec<2, T, Q>(v); + } + + template + inline vec<3, T, Q> make_vec3(vec<1, T, Q> const& v) + { + return vec<3, T, Q>(v.x, static_cast(0), static_cast(0)); + } + + template + inline vec<3, T, Q> make_vec3(vec<2, T, Q> const& v) + { + return vec<3, T, Q>(v.x, v.y, static_cast(0)); + } + + template + inline vec<3, T, Q> make_vec3(vec<3, T, Q> const& v) + { + return v; + } + + template + inline vec<3, T, Q> make_vec3(vec<4, T, Q> const& v) + { + return vec<3, T, Q>(v); + } + + template + inline vec<4, T, Q> make_vec4(vec<1, T, Q> const& v) + { + return vec<4, T, Q>(v.x, static_cast(0), static_cast(0), static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<2, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, static_cast(0), static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<3, T, Q> const& v) + { + return vec<4, T, Q>(v.x, v.y, v.z, static_cast(1)); + } + + template + inline vec<4, T, Q> make_vec4(vec<4, T, Q> const& v) + { + return v; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, defaultp> make_vec2(T const *const ptr) + { + vec<2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, defaultp> make_vec3(T const *const ptr) + { + vec<3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, defaultp> make_vec4(T const *const ptr) + { + vec<4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(vec<4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2x2(T const *const ptr) + { + mat<2, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, defaultp> make_mat2x3(T const *const ptr) + { + mat<2, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, defaultp> make_mat2x4(T const *const ptr) + { + mat<2, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<2, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, defaultp> make_mat3x2(T const *const ptr) + { + mat<3, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3x3(T const *const ptr) + { + mat<3, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, defaultp> make_mat3x4(T const *const ptr) + { + mat<3, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<3, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, defaultp> make_mat4x2(T const *const ptr) + { + mat<4, 2, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 2, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, defaultp> make_mat4x3(T const *const ptr) + { + mat<4, 3, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 3, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4x4(T const *const ptr) + { + mat<4, 4, T, defaultp> Result; + memcpy(value_ptr(Result), ptr, sizeof(mat<4, 4, T, defaultp>)); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2(T const *const ptr) + { + return make_mat2x2(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3(T const *const ptr) + { + return make_mat3x3(ptr); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4(T const *const ptr) + { + return make_mat4x4(ptr); + } + + template + GLM_FUNC_QUALIFIER qua make_quat(T const *const ptr) + { + qua Result; + memcpy(value_ptr(Result), ptr, sizeof(qua)); + return Result; + } + + /// @} +}//namespace glm + diff --git a/thirdparty/glm/gtc/ulp.hpp b/thirdparty/glm/gtc/ulp.hpp new file mode 100644 index 0000000..0d80a75 --- /dev/null +++ b/thirdparty/glm/gtc/ulp.hpp @@ -0,0 +1,152 @@ +/// @ref gtc_ulp +/// @file glm/gtc/ulp.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_ulp GLM_GTC_ulp +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Allow the measurement of the accuracy of a function against a reference +/// implementation. This extension works on floating-point data and provide results +/// in ULP. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/_vectorize.hpp" +#include "../ext/scalar_int_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_ulp extension included") +#endif + +namespace glm +{ + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType next_float(genType x); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType prev_float(genType x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType next_float(genType x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam genType A floating-point scalar type. + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL genType prev_float(genType x, int ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @see gtc_ulp + GLM_FUNC_DECL int float_distance(float x, float y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @see gtc_ulp + GLM_FUNC_DECL int64 float_distance(double x, double y); + + /// Return the next ULP value(s) after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance after the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec next_float(vec const& x, vec const& ULPs); + + /// Return the previous ULP value(s) before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, int ULPs); + + /// Return the value(s) ULP distance before the input value(s). + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec prev_float(vec const& x, vec const& ULPs); + + /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam Q Value from qualifier enum + /// + /// @see gtc_ulp + template + GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "ulp.inl" diff --git a/thirdparty/glm/gtc/ulp.inl b/thirdparty/glm/gtc/ulp.inl new file mode 100644 index 0000000..4ecbd3f --- /dev/null +++ b/thirdparty/glm/gtc/ulp.inl @@ -0,0 +1,173 @@ +/// @ref gtc_ulp + +#include "../ext/scalar_ulp.hpp" + +namespace glm +{ + template<> + GLM_FUNC_QUALIFIER float next_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MAX); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MAX); +# else + return nextafterf(x, FLT_MAX); +# endif + } + + template<> + GLM_FUNC_QUALIFIER double next_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::max()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafter(x, std::numeric_limits::max()); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MAX); +# else + return nextafter(x, DBL_MAX); +# endif + } + + template + GLM_FUNC_QUALIFIER T next_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for (int i = 0; i < ULPs; ++i) + temp = next_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER float prev_float(float x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return detail::nextafterf(x, FLT_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafterf(x, FLT_MIN); +# else + return nextafterf(x, FLT_MIN); +# endif + } + + GLM_FUNC_QUALIFIER double prev_float(double x) + { +# if GLM_HAS_CXX11_STL + return std::nextafter(x, std::numeric_limits::min()); +# elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) + return _nextafter(x, DBL_MIN); +# elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) + return __builtin_nextafter(x, DBL_MIN); +# else + return nextafter(x, DBL_MIN); +# endif + } + + template + GLM_FUNC_QUALIFIER T prev_float(T x, int ULPs) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); + assert(ULPs >= 0); + + T temp = x; + for (int i = 0; i < ULPs; ++i) + temp = prev_float(temp); + return temp; + } + + GLM_FUNC_QUALIFIER int float_distance(float x, float y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + GLM_FUNC_QUALIFIER int64 float_distance(double x, double y) + { + detail::float_t const a(x); + detail::float_t const b(y); + + return abs(a.i - b.i); + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, int ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec next_float(vec const& x, vec const& ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = next_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, int ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec prev_float(vec const& x, vec const& ULPs) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = prev_float(x[i], ULPs[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) + { + vec Result; + for (length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = float_distance(x[i], y[i]); + return Result; + } +}//namespace glm + diff --git a/thirdparty/glm/gtc/vec1.hpp b/thirdparty/glm/gtc/vec1.hpp new file mode 100644 index 0000000..63697a2 --- /dev/null +++ b/thirdparty/glm/gtc/vec1.hpp @@ -0,0 +1,30 @@ +/// @ref gtc_vec1 +/// @file glm/gtc/vec1.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtc_vec1 GLM_GTC_vec1 +/// @ingroup gtc +/// +/// Include to use the features of this extension. +/// +/// Add vec1, ivec1, uvec1 and bvec1 types. + +#pragma once + +// Dependency: +#include "../ext/vector_bool1.hpp" +#include "../ext/vector_bool1_precision.hpp" +#include "../ext/vector_float1.hpp" +#include "../ext/vector_float1_precision.hpp" +#include "../ext/vector_double1.hpp" +#include "../ext/vector_double1_precision.hpp" +#include "../ext/vector_int1.hpp" +#include "../ext/vector_int1_sized.hpp" +#include "../ext/vector_uint1.hpp" +#include "../ext/vector_uint1_sized.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# pragma message("GLM: GLM_GTC_vec1 extension included") +#endif + diff --git a/thirdparty/glm/gtx/associated_min_max.hpp b/thirdparty/glm/gtx/associated_min_max.hpp new file mode 100644 index 0000000..d1a41c0 --- /dev/null +++ b/thirdparty/glm/gtx/associated_min_max.hpp @@ -0,0 +1,207 @@ +/// @ref gtx_associated_min_max +/// @file glm/gtx/associated_min_max.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Min and max functions that return associated values not the compared onces. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_associated_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_associated_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_associated_min_max + /// @{ + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin(T x, U a, T y, U b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec<2, U, Q> associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, const vec& a, + T y, const vec& b); + + /// Minimum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c); + + /// Minimum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMin( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Minimum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMin( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax(T x, U a, T y, U b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec<2, U, Q> associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b); + + /// Maximum comparison between 2 variables and returns 2 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c); + + /// Maximum comparison between 3 variables and returns 3 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL U associatedMax( + T x, U a, + T y, U b, + T z, U c, + T w, U d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d); + + /// Maximum comparison between 4 variables and returns 4 associated variable values + /// @see gtx_associated_min_max + template + GLM_FUNC_DECL vec associatedMax( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d); + + /// @} +} //namespace glm + +#include "associated_min_max.inl" diff --git a/thirdparty/glm/gtx/associated_min_max.inl b/thirdparty/glm/gtx/associated_min_max.inl new file mode 100644 index 0000000..5186c47 --- /dev/null +++ b/thirdparty/glm/gtx/associated_min_max.inl @@ -0,0 +1,354 @@ +/// @ref gtx_associated_min_max + +namespace glm{ + +// Min comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b) +{ + return x < y ? a : b; +} + +template +GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, const vec& a, + T y, const vec& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x < y ? a[i] : b[i]; + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? a : b; + return Result; +} + +// Min comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x < y ? (x < z ? a : c) : (y < z ? b : c); + return Result; +} + +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]); + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMin +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + U Result1 = x < y ? a : b; + U Result2 = z < w ? c : d; + U Result = Test1 < Test2 ? Result1 : Result2; + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a[i] : b[i]; + U Result2 = z[i] < w[i] ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = min(x, y); + T Test2 = min(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x < y ? a[i] : b[i]; + U Result2 = z < w ? c[i] : d[i]; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Min comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMin +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = min(x[i], y[i]); + T Test2 = min(z[i], w[i]); + U Result1 = x[i] < y[i] ? a : b; + U Result2 = z[i] < w[i] ? c : d; + Result[i] = Test1 < Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b) +{ + return x > y ? a : b; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? a[i] : b[i]; + return Result; +} + +// Max comparison between 2 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? a : b; + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c +) +{ + U Result = x > y ? (x > z ? a : c) : (y > z ? b : c); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]); + return Result; +} + +// Max comparison between 3 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c); + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER U associatedMax +( + T x, U a, + T y, U b, + T z, U c, + T w, U d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + U Result1 = x > y ? a : b; + U Result2 = z > w ? c : d; + U Result = Test1 > Test2 ? Result1 : Result2; + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, vec const& a, + vec const& y, vec const& b, + vec const& z, vec const& c, + vec const& w, vec const& d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a[i] : b[i]; + U Result2 = z[i] > w[i] ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + T x, vec const& a, + T y, vec const& b, + T z, vec const& c, + T w, vec const& d +) +{ + T Test1 = max(x, y); + T Test2 = max(z, w); + + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + U Result1 = x > y ? a[i] : b[i]; + U Result2 = z > w ? c[i] : d[i]; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} + +// Max comparison between 4 variables +template +GLM_FUNC_QUALIFIER vec associatedMax +( + vec const& x, U a, + vec const& y, U b, + vec const& z, U c, + vec const& w, U d +) +{ + vec Result; + for(length_t i = 0, n = Result.length(); i < n; ++i) + { + T Test1 = max(x[i], y[i]); + T Test2 = max(z[i], w[i]); + U Result1 = x[i] > y[i] ? a : b; + U Result2 = z[i] > w[i] ? c : d; + Result[i] = Test1 > Test2 ? Result1 : Result2; + } + return Result; +} +}//namespace glm diff --git a/thirdparty/glm/gtx/bit.hpp b/thirdparty/glm/gtx/bit.hpp new file mode 100644 index 0000000..60a7aef --- /dev/null +++ b/thirdparty/glm/gtx/bit.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_bit +/// @file glm/gtx/bit.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_bit GLM_GTX_bit +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../gtc/bitfield.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_bit is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_bit extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_bit + /// @{ + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType highestBitValue(genIUType Value); + + /// @see gtx_bit + template + GLM_FUNC_DECL genIUType lowestBitValue(genIUType Value); + + /// Find the highest bit set to 1 in a integer variable and return its value. + /// + /// @see gtx_bit + template + GLM_FUNC_DECL vec highestBitValue(vec const& value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value); + + /// Return the power of two number which value is just higher the input value. + /// Deprecated, use ceilPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoAbove(vec const& value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value); + + /// Return the power of two number which value is just lower the input value. + /// Deprecated, use floorPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoBelow(vec const& value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value); + + /// Return the power of two number which value is the closet to the input value. + /// Deprecated, use roundPowerOfTwo from GTC_round instead + /// + /// @see gtc_round + /// @see gtx_bit + template + GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoNearest(vec const& value); + + /// @} +} //namespace glm + + +#include "bit.inl" + diff --git a/thirdparty/glm/gtx/bit.inl b/thirdparty/glm/gtx/bit.inl new file mode 100644 index 0000000..621b626 --- /dev/null +++ b/thirdparty/glm/gtx/bit.inl @@ -0,0 +1,92 @@ +/// @ref gtx_bit + +namespace glm +{ + /////////////////// + // highestBitValue + + template + GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) + { + genIUType tmp = Value; + genIUType result = genIUType(0); + while(tmp) + { + result = (tmp & (~tmp + 1)); // grab lowest bit + tmp &= ~result; // clear lowest bit + } + return result; + } + + template + GLM_FUNC_QUALIFIER vec highestBitValue(vec const& v) + { + return detail::functor1::call(highestBitValue, v); + } + + /////////////////// + // lowestBitValue + + template + GLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value) + { + return (Value & (~Value + 1)); + } + + template + GLM_FUNC_QUALIFIER vec lowestBitValue(vec const& v) + { + return detail::functor1::call(lowestBitValue, v); + } + + /////////////////// + // powerOfTwoAbove + + template + GLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value) << 1; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoAbove(vec const& v) + { + return detail::functor1::call(powerOfTwoAbove, v); + } + + /////////////////// + // powerOfTwoBelow + + template + GLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value) + { + return isPowerOfTwo(value) ? value : highestBitValue(value); + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoBelow(vec const& v) + { + return detail::functor1::call(powerOfTwoBelow, v); + } + + ///////////////////// + // powerOfTwoNearest + + template + GLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value) + { + if(isPowerOfTwo(value)) + return value; + + genType const prev = highestBitValue(value); + genType const next = prev << 1; + return (next - value) < (value - prev) ? next : prev; + } + + template + GLM_FUNC_QUALIFIER vec powerOfTwoNearest(vec const& v) + { + return detail::functor1::call(powerOfTwoNearest, v); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/closest_point.hpp b/thirdparty/glm/gtx/closest_point.hpp new file mode 100644 index 0000000..de6dbbf --- /dev/null +++ b/thirdparty/glm/gtx/closest_point.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_closest_point +/// @file glm/gtx/closest_point.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_closest_point GLM_GTX_closest_point +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Find the point on a straight line which is the closet of a point. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_closest_point + /// @{ + + /// Find the point on a straight line which is the closet of a point. + /// @see gtx_closest_point + template + GLM_FUNC_DECL vec<3, T, Q> closestPointOnLine( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b); + + /// 2d lines work as well + template + GLM_FUNC_DECL vec<2, T, Q> closestPointOnLine( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b); + + /// @} +}// namespace glm + +#include "closest_point.inl" diff --git a/thirdparty/glm/gtx/closest_point.inl b/thirdparty/glm/gtx/closest_point.inl new file mode 100644 index 0000000..0a39b04 --- /dev/null +++ b/thirdparty/glm/gtx/closest_point.inl @@ -0,0 +1,45 @@ +/// @ref gtx_closest_point + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> closestPointOnLine + ( + vec<3, T, Q> const& point, + vec<3, T, Q> const& a, + vec<3, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<3, T, Q> Vector = point - a; + vec<3, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> closestPointOnLine + ( + vec<2, T, Q> const& point, + vec<2, T, Q> const& a, + vec<2, T, Q> const& b + ) + { + T LineLength = distance(a, b); + vec<2, T, Q> Vector = point - a; + vec<2, T, Q> LineDirection = (b - a) / LineLength; + + // Project Vector to LineDirection to get the distance of point from a + T Distance = dot(Vector, LineDirection); + + if(Distance <= T(0)) return a; + if(Distance >= LineLength) return b; + return a + LineDirection * Distance; + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/color_encoding.hpp b/thirdparty/glm/gtx/color_encoding.hpp new file mode 100644 index 0000000..96ded2a --- /dev/null +++ b/thirdparty/glm/gtx/color_encoding.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_color_encoding +/// @file glm/gtx/color_encoding.hpp +/// +/// @see core (dependence) +/// @see gtx_color_encoding (dependence) +/// +/// @defgroup gtx_color_encoding GLM_GTX_color_encoding +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../vec3.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTC_color_encoding is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTC_color_encoding extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_encoding + /// @{ + + /// Convert a linear sRGB color to D65 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a linear sRGB color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB); + + /// Convert a D65 YUV color to linear sRGB. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ); + + /// Convert a D65 YUV color to D50 YUV. + template + GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ); + + /// @} +} //namespace glm + +#include "color_encoding.inl" diff --git a/thirdparty/glm/gtx/color_encoding.inl b/thirdparty/glm/gtx/color_encoding.inl new file mode 100644 index 0000000..e50fa3e --- /dev/null +++ b/thirdparty/glm/gtx/color_encoding.inl @@ -0,0 +1,45 @@ +/// @ref gtx_color_encoding + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.490f, 0.17697f, 0.2f); + vec<3, T, Q> const N(0.31f, 0.8124f, 0.01063f); + vec<3, T, Q> const O(0.490f, 0.01f, 0.99f); + + return (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast(5.650675255693055f); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB) + { + vec<3, T, Q> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f); + vec<3, T, Q> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f); + vec<3, T, Q> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f); + + return M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(0.41847f, -0.091169f, 0.0009209f); + vec<3, T, Q> const N(-0.15866f, 0.25243f, 0.015708f); + vec<3, T, Q> const O(0.0009209f, -0.0025498f, 0.1786f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ) + { + vec<3, T, Q> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f); + vec<3, T, Q> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f); + vec<3, T, Q> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f); + + return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/color_space.hpp b/thirdparty/glm/gtx/color_space.hpp new file mode 100644 index 0000000..a634392 --- /dev/null +++ b/thirdparty/glm/gtx/color_space.hpp @@ -0,0 +1,72 @@ +/// @ref gtx_color_space +/// @file glm/gtx/color_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space GLM_GTX_color_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Related to RGB to HSV conversions and operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space + /// @{ + + /// Converts a color from HSV color space to its color in RGB color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> rgbColor( + vec<3, T, Q> const& hsvValue); + + /// Converts a color from RGB color space to its color in HSV color space. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> hsvColor( + vec<3, T, Q> const& rgbValue); + + /// Build a saturation matrix. + /// @see gtx_color_space + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> saturation( + T const s); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<3, T, Q> saturation( + T const s, + vec<3, T, Q> const& color); + + /// Modify the saturation of a color. + /// @see gtx_color_space + template + GLM_FUNC_DECL vec<4, T, Q> saturation( + T const s, + vec<4, T, Q> const& color); + + /// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals. + /// @see gtx_color_space + template + GLM_FUNC_DECL T luminosity( + vec<3, T, Q> const& color); + + /// @} +}//namespace glm + +#include "color_space.inl" diff --git a/thirdparty/glm/gtx/color_space.inl b/thirdparty/glm/gtx/color_space.inl new file mode 100644 index 0000000..f698afe --- /dev/null +++ b/thirdparty/glm/gtx/color_space.inl @@ -0,0 +1,141 @@ +/// @ref gtx_color_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgbColor(const vec<3, T, Q>& hsvColor) + { + vec<3, T, Q> hsv = hsvColor; + vec<3, T, Q> rgbColor; + + if(hsv.y == static_cast(0)) + // achromatic (grey) + rgbColor = vec<3, T, Q>(hsv.z); + else + { + T sector = floor(hsv.x * (T(1) / T(60))); + T frac = (hsv.x * (T(1) / T(60))) - sector; + // factorial part of h + T o = hsv.z * (T(1) - hsv.y); + T p = hsv.z * (T(1) - hsv.y * frac); + T q = hsv.z * (T(1) - hsv.y * (T(1) - frac)); + + switch(int(sector)) + { + default: + case 0: + rgbColor.r = hsv.z; + rgbColor.g = q; + rgbColor.b = o; + break; + case 1: + rgbColor.r = p; + rgbColor.g = hsv.z; + rgbColor.b = o; + break; + case 2: + rgbColor.r = o; + rgbColor.g = hsv.z; + rgbColor.b = q; + break; + case 3: + rgbColor.r = o; + rgbColor.g = p; + rgbColor.b = hsv.z; + break; + case 4: + rgbColor.r = q; + rgbColor.g = o; + rgbColor.b = hsv.z; + break; + case 5: + rgbColor.r = hsv.z; + rgbColor.g = o; + rgbColor.b = p; + break; + } + } + + return rgbColor; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> hsvColor(const vec<3, T, Q>& rgbColor) + { + vec<3, T, Q> hsv = rgbColor; + float Min = min(min(rgbColor.r, rgbColor.g), rgbColor.b); + float Max = max(max(rgbColor.r, rgbColor.g), rgbColor.b); + float Delta = Max - Min; + + hsv.z = Max; + + if(Max != static_cast(0)) + { + hsv.y = Delta / hsv.z; + T h = static_cast(0); + + if(rgbColor.r == Max) + // between yellow & magenta + h = static_cast(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta; + else if(rgbColor.g == Max) + // between cyan & yellow + h = static_cast(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta; + else + // between magenta & cyan + h = static_cast(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta; + + if(h < T(0)) + hsv.x = h + T(360); + else + hsv.x = h; + } + else + { + // If r = g = b = 0 then s = 0, h is undefined + hsv.y = static_cast(0); + hsv.x = static_cast(0); + } + + return hsv; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> saturation(T const s) + { + vec<3, T, defaultp> rgbw = vec<3, T, defaultp>(T(0.2126), T(0.7152), T(0.0722)); + + vec<3, T, defaultp> const col((T(1) - s) * rgbw); + + mat<4, 4, T, defaultp> result(T(1)); + result[0][0] = col.x + s; + result[0][1] = col.x; + result[0][2] = col.x; + result[1][0] = col.y; + result[1][1] = col.y + s; + result[1][2] = col.y; + result[2][0] = col.z; + result[2][1] = col.z; + result[2][2] = col.z + s; + + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> saturation(const T s, const vec<3, T, Q>& color) + { + return vec<3, T, Q>(saturation(s) * vec<4, T, Q>(color, T(0))); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> saturation(const T s, const vec<4, T, Q>& color) + { + return saturation(s) * color; + } + + template + GLM_FUNC_QUALIFIER T luminosity(const vec<3, T, Q>& color) + { + const vec<3, T, Q> tmp = vec<3, T, Q>(0.33, 0.59, 0.11); + return dot(color, tmp); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/color_space_YCoCg.hpp b/thirdparty/glm/gtx/color_space_YCoCg.hpp new file mode 100644 index 0000000..dd2b771 --- /dev/null +++ b/thirdparty/glm/gtx/color_space_YCoCg.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_color_space_YCoCg +/// @file glm/gtx/color_space_YCoCg.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// RGB to YCoCg conversions and operations + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_color_space_YCoCg is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_color_space_YCoCg extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_color_space_YCoCg + /// @{ + + /// Convert a color from RGB color space to YCoCg color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCg( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCg color space to RGB color space. + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCg2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// Convert a color from RGB color space to YCoCgR color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCgR( + vec<3, T, Q> const& rgbColor); + + /// Convert a color from YCoCgR color space to RGB color space. + /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" + /// @see gtx_color_space_YCoCg + template + GLM_FUNC_DECL vec<3, T, Q> YCoCgR2rgb( + vec<3, T, Q> const& YCoCgColor); + + /// @} +}//namespace glm + +#include "color_space_YCoCg.inl" diff --git a/thirdparty/glm/gtx/color_space_YCoCg.inl b/thirdparty/glm/gtx/color_space_YCoCg.inl new file mode 100644 index 0000000..83ba857 --- /dev/null +++ b/thirdparty/glm/gtx/color_space_YCoCg.inl @@ -0,0 +1,107 @@ +/// @ref gtx_color_space_YCoCg + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCg + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4); + result.y/*Co*/ = rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2); + result.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4); + return result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCg2rgb + ( + vec<3, T, Q> const& YCoCgColor + ) + { + vec<3, T, Q> result; + result.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z; + result.g = YCoCgColor.x + YCoCgColor.z; + result.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z; + return result; + } + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.x/*Y */ = rgbColor.g * static_cast(0.5) + (rgbColor.r + rgbColor.b) * static_cast(0.25); + result.y/*Co*/ = rgbColor.r - rgbColor.b; + result.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) * static_cast(0.5); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z * static_cast(0.5)); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y * static_cast(0.5)); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + class compute_YCoCgR { + public: + static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + vec<3, T, Q> result; + result.y/*Co*/ = rgbColor.r - rgbColor.b; + T tmp = rgbColor.b + (result.y >> 1); + result.z/*Cg*/ = rgbColor.g - tmp; + result.x/*Y */ = tmp + (result.z >> 1); + return result; + } + + static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + vec<3, T, Q> result; + T tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1); + result.g = YCoCgRColor.z + tmp; + result.b = tmp - (YCoCgRColor.y >> 1); + result.r = result.b + YCoCgRColor.y; + return result; + } + }; + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR + ( + vec<3, T, Q> const& rgbColor + ) + { + return compute_YCoCgR::is_integer>::rgb2YCoCgR(rgbColor); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb + ( + vec<3, T, Q> const& YCoCgRColor + ) + { + return compute_YCoCgR::is_integer>::YCoCgR2rgb(YCoCgRColor); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/common.hpp b/thirdparty/glm/gtx/common.hpp new file mode 100644 index 0000000..254ada2 --- /dev/null +++ b/thirdparty/glm/gtx/common.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_common +/// @file glm/gtx/common.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_common GLM_GTX_common +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependencies: +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_common is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_common extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_common + /// @{ + + /// Returns true if x is a denormalized number + /// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format. + /// This format is less precise but can represent values closer to zero. + /// + /// @tparam genType Floating-point scalar or vector types. + /// + /// @see GLSL isnan man page + /// @see GLSL 4.20.8 specification, section 8.3 Common Functions + template + GLM_FUNC_DECL typename genType::bool_type isdenormal(genType const& x); + + /// Similar to 'mod' but with a different rounding and integer support. + /// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)' + /// + /// @see GLSL mod vs HLSL fmod + /// @see GLSL mod man page + template + GLM_FUNC_DECL vec fmod(vec const& v); + + /// Returns whether vector components values are within an interval. A open interval excludes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec openBounded(vec const& Value, vec const& Min, vec const& Max); + + /// Returns whether vector components values are within an interval. A closed interval includes its endpoints, and is denoted with square brackets. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see ext_vector_relational + template + GLM_FUNC_DECL vec closeBounded(vec const& Value, vec const& Min, vec const& Max); + + /// @} +}//namespace glm + +#include "common.inl" diff --git a/thirdparty/glm/gtx/common.inl b/thirdparty/glm/gtx/common.inl new file mode 100644 index 0000000..4ad2126 --- /dev/null +++ b/thirdparty/glm/gtx/common.inl @@ -0,0 +1,125 @@ +/// @ref gtx_common + +#include +#include "../gtc/epsilon.hpp" +#include "../gtc/constants.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return detail::functor2::call(std::fmod, a, b); + } + }; + + template + struct compute_fmod + { + GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) + { + return a % b; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool isdenormal(T const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + +# if GLM_HAS_CXX11_STL + return std::fpclassify(x) == FP_SUBNORMAL; +# else + return epsilonNotEqual(x, static_cast(0), epsilon()) && std::fabs(x) < std::numeric_limits::min(); +# endif + } + + template + GLM_FUNC_QUALIFIER typename vec<1, T, Q>::bool_type isdenormal + ( + vec<1, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<1, T, Q>::bool_type( + isdenormal(x.x)); + } + + template + GLM_FUNC_QUALIFIER typename vec<2, T, Q>::bool_type isdenormal + ( + vec<2, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<2, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y)); + } + + template + GLM_FUNC_QUALIFIER typename vec<3, T, Q>::bool_type isdenormal + ( + vec<3, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<3, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z)); + } + + template + GLM_FUNC_QUALIFIER typename vec<4, T, Q>::bool_type isdenormal + ( + vec<4, T, Q> const& x + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); + + return typename vec<4, T, Q>::bool_type( + isdenormal(x.x), + isdenormal(x.y), + isdenormal(x.z), + isdenormal(x.w)); + } + + // fmod + template + GLM_FUNC_QUALIFIER genType fmod(genType x, genType y) + { + return fmod(vec<1, genType>(x), y).x; + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, T y) + { + return detail::compute_fmod::is_iec559>::call(x, vec(y)); + } + + template + GLM_FUNC_QUALIFIER vec fmod(vec const& x, vec const& y) + { + return detail::compute_fmod::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER vec openBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThan(Value, Min) && lessThan(Value, Max); + } + + template + GLM_FUNC_QUALIFIER vec closeBounded(vec const& Value, vec const& Min, vec const& Max) + { + return greaterThanEqual(Value, Min) && lessThanEqual(Value, Max); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/compatibility.hpp b/thirdparty/glm/gtx/compatibility.hpp new file mode 100644 index 0000000..f1b00a6 --- /dev/null +++ b/thirdparty/glm/gtx/compatibility.hpp @@ -0,0 +1,133 @@ +/// @ref gtx_compatibility +/// @file glm/gtx/compatibility.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_compatibility GLM_GTX_compatibility +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Provide functions to increase the compatibility with Cg and HLSL languages + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_compatibility is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_compatibility extension included") +# endif +#endif + +#if GLM_COMPILER & GLM_COMPILER_VC +# include +#elif GLM_COMPILER & GLM_COMPILER_GCC +# include +# if(GLM_PLATFORM & GLM_PLATFORM_ANDROID) +# undef isfinite +# endif +#endif//GLM_COMPILER + +namespace glm +{ + /// @addtogroup gtx_compatibility + /// @{ + + template GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, const vec<2, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, const vec<3, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, const vec<4, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> saturate(const vec<2, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> saturate(const vec<3, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> saturate(const vec<4, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) + + template GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<2, T, Q> atan2(const vec<2, T, Q>& x, const vec<2, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<3, T, Q> atan2(const vec<3, T, Q>& x, const vec<3, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + template GLM_FUNC_QUALIFIER vec<4, T, Q> atan2(const vec<4, T, Q>& x, const vec<4, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) + + template GLM_FUNC_DECL bool isfinite(genType const& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<1, bool, Q> isfinite(const vec<1, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<2, bool, Q> isfinite(const vec<2, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<3, bool, Q> isfinite(const vec<3, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + template GLM_FUNC_DECL vec<4, bool, Q> isfinite(const vec<4, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) + + typedef bool bool1; //!< \brief boolean type with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, bool, highp> bool2; //!< \brief boolean type with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, bool, highp> bool3; //!< \brief boolean type with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, bool, highp> bool4; //!< \brief boolean type with 4 components. (From GLM_GTX_compatibility extension) + + typedef bool bool1x1; //!< \brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, bool, highp> bool2x2; //!< \brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, bool, highp> bool2x3; //!< \brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, bool, highp> bool2x4; //!< \brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, bool, highp> bool3x2; //!< \brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, bool, highp> bool3x3; //!< \brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, bool, highp> bool3x4; //!< \brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, bool, highp> bool4x2; //!< \brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, bool, highp> bool4x3; //!< \brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, bool, highp> bool4x4; //!< \brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1; //!< \brief integer vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, int, highp> int2; //!< \brief integer vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, int, highp> int3; //!< \brief integer vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, int, highp> int4; //!< \brief integer vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef int int1x1; //!< \brief integer matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, int, highp> int2x2; //!< \brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, int, highp> int2x3; //!< \brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, int, highp> int2x4; //!< \brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, int, highp> int3x2; //!< \brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, int, highp> int3x3; //!< \brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, int, highp> int3x4; //!< \brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, int, highp> int4x2; //!< \brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, int, highp> int4x3; //!< \brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, int, highp> int4x4; //!< \brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1; //!< \brief single-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, float, highp> float2; //!< \brief single-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, float, highp> float3; //!< \brief single-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, float, highp> float4; //!< \brief single-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef float float1x1; //!< \brief single-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, float, highp> float2x2; //!< \brief single-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, float, highp> float2x3; //!< \brief single-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, float, highp> float2x4; //!< \brief single-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, float, highp> float3x2; //!< \brief single-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, float, highp> float3x3; //!< \brief single-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, float, highp> float3x4; //!< \brief single-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, float, highp> float4x2; //!< \brief single-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, float, highp> float4x3; //!< \brief single-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, float, highp> float4x4; //!< \brief single-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1; //!< \brief double-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) + typedef vec<2, double, highp> double2; //!< \brief double-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) + typedef vec<3, double, highp> double3; //!< \brief double-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) + typedef vec<4, double, highp> double4; //!< \brief double-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) + + typedef double double1x1; //!< \brief double-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) + typedef mat<2, 2, double, highp> double2x2; //!< \brief double-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 3, double, highp> double2x3; //!< \brief double-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<2, 4, double, highp> double2x4; //!< \brief double-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 2, double, highp> double3x2; //!< \brief double-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 3, double, highp> double3x3; //!< \brief double-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<3, 4, double, highp> double3x4; //!< \brief double-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 2, double, highp> double4x2; //!< \brief double-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 3, double, highp> double4x3; //!< \brief double-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) + typedef mat<4, 4, double, highp> double4x4; //!< \brief double-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) + + /// @} +}//namespace glm + +#include "compatibility.inl" diff --git a/thirdparty/glm/gtx/compatibility.inl b/thirdparty/glm/gtx/compatibility.inl new file mode 100644 index 0000000..1d49496 --- /dev/null +++ b/thirdparty/glm/gtx/compatibility.inl @@ -0,0 +1,62 @@ +#include + +namespace glm +{ + // isfinite + template + GLM_FUNC_QUALIFIER bool isfinite( + genType const& x) + { +# if GLM_HAS_CXX11_STL + return std::isfinite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_VC + return _finite(x) != 0; +# elif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID + return _isfinite(x) != 0; +# else + if (std::numeric_limits::is_integer || std::denorm_absent == std::numeric_limits::has_denorm) + return std::numeric_limits::min() <= x && std::numeric_limits::max() >= x; + else + return -std::numeric_limits::max() <= x && std::numeric_limits::max() >= x; +# endif + } + + template + GLM_FUNC_QUALIFIER vec<1, bool, Q> isfinite( + vec<1, T, Q> const& x) + { + return vec<1, bool, Q>( + isfinite(x.x)); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isfinite( + vec<2, T, Q> const& x) + { + return vec<2, bool, Q>( + isfinite(x.x), + isfinite(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isfinite( + vec<3, T, Q> const& x) + { + return vec<3, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isfinite( + vec<4, T, Q> const& x) + { + return vec<4, bool, Q>( + isfinite(x.x), + isfinite(x.y), + isfinite(x.z), + isfinite(x.w)); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/component_wise.hpp b/thirdparty/glm/gtx/component_wise.hpp new file mode 100644 index 0000000..34a2b0a --- /dev/null +++ b/thirdparty/glm/gtx/component_wise.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_component_wise +/// @file glm/gtx/component_wise.hpp +/// @date 2007-05-21 / 2011-06-07 +/// @author Christophe Riccio +/// +/// @see core (dependence) +/// +/// @defgroup gtx_component_wise GLM_GTX_component_wise +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Operations between components of a type + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_component_wise is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_component_wise extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_component_wise + /// @{ + + /// Convert an integer vector to a normalized float vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compNormalize(vec const& v); + + /// Convert a normalized float vector to an integer vector. + /// If the parameter value type is already a floating qualifier type, the value is passed through. + /// @see gtx_component_wise + template + GLM_FUNC_DECL vec compScale(vec const& v); + + /// Add all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compAdd(genType const& v); + + /// Multiply all vector components together. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMul(genType const& v); + + /// Find the minimum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMin(genType const& v); + + /// Find the maximum value between single vector components. + /// @see gtx_component_wise + template + GLM_FUNC_DECL typename genType::value_type compMax(genType const& v); + + /// @} +}//namespace glm + +#include "component_wise.inl" diff --git a/thirdparty/glm/gtx/component_wise.inl b/thirdparty/glm/gtx/component_wise.inl new file mode 100644 index 0000000..cbbc7d4 --- /dev/null +++ b/thirdparty/glm/gtx/component_wise.inl @@ -0,0 +1,127 @@ +/// @ref gtx_component_wise + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_compNormalize + {}; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Min = static_cast(std::numeric_limits::min()); + floatType const Max = static_cast(std::numeric_limits::max()); + return (vec(v) - Min) / (Max - Min) * static_cast(2) - static_cast(1); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + }; + + template + struct compute_compNormalize + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; + + template + struct compute_compScale + {}; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + floatType const Max = static_cast(std::numeric_limits::max()) + static_cast(0.5); + vec const Scaled(v * Max); + vec const Result(Scaled - static_cast(0.5)); + return Result; + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return vec(vec(v) * static_cast(std::numeric_limits::max())); + } + }; + + template + struct compute_compScale + { + GLM_FUNC_QUALIFIER static vec call(vec const& v) + { + return v; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER vec compNormalize(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compNormalize' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compNormalize::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER vec compScale(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compScale' accepts only floating-point types for 'floatType' template parameter"); + + return detail::compute_compScale::is_integer, std::numeric_limits::is_signed>::call(v); + } + + template + GLM_FUNC_QUALIFIER T compAdd(vec const& v) + { + T Result(0); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result += v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMul(vec const& v) + { + T Result(1); + for(length_t i = 0, n = v.length(); i < n; ++i) + Result *= v[i]; + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMin(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = min(Result, v[i]); + return Result; + } + + template + GLM_FUNC_QUALIFIER T compMax(vec const& v) + { + T Result(v[0]); + for(length_t i = 1, n = v.length(); i < n; ++i) + Result = max(Result, v[i]); + return Result; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/dual_quaternion.hpp b/thirdparty/glm/gtx/dual_quaternion.hpp new file mode 100644 index 0000000..6a51ab7 --- /dev/null +++ b/thirdparty/glm/gtx/dual_quaternion.hpp @@ -0,0 +1,274 @@ +/// @ref gtx_dual_quaternion +/// @file glm/gtx/dual_quaternion.hpp +/// @author Maksim Vorobiev (msomeone@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_constants (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines a templated dual-quaternion type and several dual-quaternion operations. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_dual_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_dual_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_dual_quaternion + /// @{ + + template + struct tdualquat + { + // -- Implementation detail -- + + typedef T value_type; + typedef qua part_type; + + // -- Data -- + + qua real, dual; + + // -- Component accesses -- + + typedef length_t length_type; + /// Return the count of components of a dual quaternion + GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} + + GLM_FUNC_DECL part_type & operator[](length_type i); + GLM_FUNC_DECL part_type const& operator[](length_type i) const; + + // -- Implicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT; + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d) GLM_DEFAULT; + template + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d); + + // -- Explicit basic constructors -- + + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& orientation, vec<3, T, Q> const& translation); + GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real, qua const& dual); + + // -- Conversion constructors -- + + template + GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat const& q); + + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<2, 4, T, Q> const& holder_mat); + GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<3, 4, T, Q> const& aug_mat); + + // -- Unary arithmetic operators -- + + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m) GLM_DEFAULT; + + template + GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m); + template + GLM_FUNC_DECL tdualquat & operator*=(U s); + template + GLM_FUNC_DECL tdualquat & operator/=(U s); + }; + + // -- Unary bit operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator-(tdualquat const& q); + + // -- Binary operators -- + + template + GLM_FUNC_DECL tdualquat operator+(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, tdualquat const& p); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v); + + template + GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v); + + template + GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, T const& s); + + template + GLM_FUNC_DECL tdualquat operator*(T const& s, tdualquat const& q); + + template + GLM_FUNC_DECL tdualquat operator/(tdualquat const& q, T const& s); + + // -- Boolean operators -- + + template + GLM_FUNC_DECL bool operator==(tdualquat const& q1, tdualquat const& q2); + + template + GLM_FUNC_DECL bool operator!=(tdualquat const& q1, tdualquat const& q2); + + /// Creates an identity dual quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dual_quat_identity(); + + /// Returns the normalized quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat normalize(tdualquat const& q); + + /// Returns the linear interpolation of two dual quaternion. + /// + /// @see gtc_dual_quaternion + template + GLM_FUNC_DECL tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a); + + /// Returns the q inverse. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat inverse(tdualquat const& q); + + /// Converts a quaternion to a 2 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x); + + /// Converts a quaternion to a 3 * 4 matrix. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x); + + /// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<2, 4, T, Q> const& x); + + /// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion. + /// + /// @see gtx_dual_quaternion + template + GLM_FUNC_DECL tdualquat dualquat_cast(mat<3, 4, T, Q> const& x); + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_dualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_dualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_dualquat; + + + /// Dual-quaternion of low single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_fdualquat; + + /// Dual-quaternion of medium single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_fdualquat; + + /// Dual-quaternion of high single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_fdualquat; + + + /// Dual-quaternion of low double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat lowp_ddualquat; + + /// Dual-quaternion of medium double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat mediump_ddualquat; + + /// Dual-quaternion of high double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef tdualquat highp_ddualquat; + + +#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + /// Dual-quaternion of floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat dualquat; + + /// Dual-quaternion of single-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_fdualquat fdualquat; +#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef highp_fdualquat dualquat; + typedef highp_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) + typedef mediump_fdualquat dualquat; + typedef mediump_fdualquat fdualquat; +#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT)) + typedef lowp_fdualquat dualquat; + typedef lowp_fdualquat fdualquat; +#else +# error "GLM error: multiple default precision requested for single-precision floating-point types" +#endif + + +#if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + /// Dual-quaternion of default double-qualifier floating-point numbers. + /// + /// @see gtx_dual_quaternion + typedef highp_ddualquat ddualquat; +#elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef highp_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef mediump_ddualquat ddualquat; +#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE)) + typedef lowp_ddualquat ddualquat; +#else +# error "GLM error: Multiple default precision requested for double-precision floating-point types" +#endif + + /// @} +} //namespace glm + +#include "dual_quaternion.inl" diff --git a/thirdparty/glm/gtx/dual_quaternion.inl b/thirdparty/glm/gtx/dual_quaternion.inl new file mode 100644 index 0000000..fad07ea --- /dev/null +++ b/thirdparty/glm/gtx/dual_quaternion.inl @@ -0,0 +1,352 @@ +/// @ref gtx_dual_quaternion + +#include "../geometric.hpp" +#include + +namespace glm +{ + // -- Component accesses -- + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type & tdualquat::operator[](typename tdualquat::length_type i) + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + template + GLM_FUNC_QUALIFIER typename tdualquat::part_type const& tdualquat::operator[](typename tdualquat::length_type i) const + { + assert(i >= 0 && i < this->length()); + return (&real)[i]; + } + + // -- Implicit basic constructors -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat() +# if GLM_CONFIG_DEFAULTED_FUNCTIONS != GLM_DISABLE + : real(qua()) + , dual(qua(0, 0, 0, 0)) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} +# endif + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) + : real(d.real) + , dual(d.dual) + {} + + // -- Explicit basic constructors -- + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r) + : real(r), dual(qua(0, 0, 0, 0)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& q, vec<3, T, Q> const& p) + : real(q), dual( + T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z), + T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y), + T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x), + T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w)) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r, qua const& d) + : real(r), dual(d) + {} + + // -- Conversion constructors -- + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& q) + : real(q.real) + , dual(q.dual) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<2, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<3, 4, T, Q> const& m) + { + *this = dualquat_cast(m); + } + + // -- Unary arithmetic operators -- + +# if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } +# endif + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) + { + this->real = q.real; + this->dual = q.dual; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator*=(U s) + { + this->real *= static_cast(s); + this->dual *= static_cast(s); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator/=(U s) + { + this->real /= static_cast(s); + this->dual /= static_cast(s); + return *this; + } + + // -- Unary bit operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q) + { + return q; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator-(tdualquat const& q) + { + return tdualquat(-q.real, -q.dual); + } + + // -- Binary operators -- + + template + GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q, tdualquat const& p) + { + return tdualquat(q.real + p.real,q.dual + p.dual); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& p, tdualquat const& o) + { + return tdualquat(p.real * o.real,p.real * o.dual + p.dual * o.real); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v) + { + vec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z); + vec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z); + return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v) + { + return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q) + { + return glm::inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& q, T const& s) + { + return tdualquat(q.real * s, q.dual * s); + } + + template + GLM_FUNC_QUALIFIER tdualquat operator*(T const& s, tdualquat const& q) + { + return q * s; + } + + template + GLM_FUNC_QUALIFIER tdualquat operator/(tdualquat const& q, T const& s) + { + return tdualquat(q.real / s, q.dual / s); + } + + // -- Boolean operators -- + + template + GLM_FUNC_QUALIFIER bool operator==(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real == q2.real) && (q1.dual == q2.dual); + } + + template + GLM_FUNC_QUALIFIER bool operator!=(tdualquat const& q1, tdualquat const& q2) + { + return (q1.real != q2.real) || (q1.dual != q2.dual); + } + + // -- Operations -- + + template + GLM_FUNC_QUALIFIER tdualquat dual_quat_identity() + { + return tdualquat( + qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)), + qua(static_cast(0), static_cast(0), static_cast(0), static_cast(0))); + } + + template + GLM_FUNC_QUALIFIER tdualquat normalize(tdualquat const& q) + { + return q / length(q.real); + } + + template + GLM_FUNC_QUALIFIER tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a) + { + // Dual Quaternion Linear blend aka DLB: + // Lerp is only defined in [0, 1] + assert(a >= static_cast(0)); + assert(a <= static_cast(1)); + T const k = dot(x.real,y.real) < static_cast(0) ? -a : a; + T const one(1); + return tdualquat(x * (one - a) + y * k); + } + + template + GLM_FUNC_QUALIFIER tdualquat inverse(tdualquat const& q) + { + const glm::qua real = conjugate(q.real); + const glm::qua dual = conjugate(q.dual); + return tdualquat(real, dual + (real * (-2.0f * dot(real,dual)))); + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x) + { + return mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w ); + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x) + { + qua r = x.real / length2(x.real); + + qua const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z); + r *= static_cast(2); + + T const xy = r.x * x.real.y; + T const xz = r.x * x.real.z; + T const yz = r.y * x.real.z; + T const wx = r.w * x.real.x; + T const wy = r.w * x.real.y; + T const wz = r.w * x.real.z; + + vec<4, T, Q> const a( + rr.w + rr.x - rr.y - rr.z, + xy - wz, + xz + wy, + -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y)); + + vec<4, T, Q> const b( + xy + wz, + rr.w + rr.y - rr.x - rr.z, + yz - wx, + -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x)); + + vec<4, T, Q> const c( + xz - wy, + yz + wx, + rr.w + rr.z - rr.x - rr.y, + -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w)); + + return mat<3, 4, T, Q>(a, b, c); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<2, 4, T, Q> const& x) + { + return tdualquat( + qua( x[0].w, x[0].x, x[0].y, x[0].z ), + qua( x[1].w, x[1].x, x[1].y, x[1].z )); + } + + template + GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<3, 4, T, Q> const& x) + { + qua real; + + T const trace = x[0].x + x[1].y + x[2].z; + if(trace > static_cast(0)) + { + T const r = sqrt(T(1) + trace); + T const invr = static_cast(0.5) / r; + real.w = static_cast(0.5) * r; + real.x = (x[2].y - x[1].z) * invr; + real.y = (x[0].z - x[2].x) * invr; + real.z = (x[1].x - x[0].y) * invr; + } + else if(x[0].x > x[1].y && x[0].x > x[2].z) + { + T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = static_cast(0.5)*r; + real.y = (x[1].x + x[0].y) * invr; + real.z = (x[0].z + x[2].x) * invr; + real.w = (x[2].y - x[1].z) * invr; + } + else if(x[1].y > x[2].z) + { + T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z); + T const invr = static_cast(0.5) / r; + real.x = (x[1].x + x[0].y) * invr; + real.y = static_cast(0.5) * r; + real.z = (x[2].y + x[1].z) * invr; + real.w = (x[0].z - x[2].x) * invr; + } + else + { + T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y); + T const invr = static_cast(0.5) / r; + real.x = (x[0].z + x[2].x) * invr; + real.y = (x[2].y + x[1].z) * invr; + real.z = static_cast(0.5) * r; + real.w = (x[1].x - x[0].y) * invr; + } + + qua dual; + dual.x = static_cast(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y); + dual.y = static_cast(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x); + dual.z = static_cast(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w); + dual.w = -static_cast(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z); + return tdualquat(real, dual); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/easing.hpp b/thirdparty/glm/gtx/easing.hpp new file mode 100644 index 0000000..57f3d61 --- /dev/null +++ b/thirdparty/glm/gtx/easing.hpp @@ -0,0 +1,219 @@ +/// @ref gtx_easing +/// @file glm/gtx/easing.hpp +/// @author Robert Chisholm +/// +/// @see core (dependence) +/// +/// @defgroup gtx_easing GLM_GTX_easing +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Easing functions for animations and transitons +/// All functions take a parameter x in the range [0.0,1.0] +/// +/// Based on the AHEasing project of Warren Moore (https://github.com/warrenm/AHEasing) + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_easing is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_easing extension included") +# endif +#endif + +namespace glm{ + /// @addtogroup gtx_easing + /// @{ + + /// Modelled after the line y = x + /// @see gtx_easing + template + GLM_FUNC_DECL genType linearInterpolation(genType const & a); + + /// Modelled after the parabola y = x^2 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseIn(genType const & a); + + /// Modelled after the parabola y = -x^2 + 2x + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseOut(genType const & a); + + /// Modelled after the piecewise quadratic + /// y = (1/2)((2x)^2) ; [0, 0.5) + /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quadraticEaseInOut(genType const & a); + + /// Modelled after the cubic y = x^3 + template + GLM_FUNC_DECL genType cubicEaseIn(genType const & a); + + /// Modelled after the cubic y = (x - 1)^3 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseOut(genType const & a); + + /// Modelled after the piecewise cubic + /// y = (1/2)((2x)^3) ; [0, 0.5) + /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType cubicEaseInOut(genType const & a); + + /// Modelled after the quartic x^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseIn(genType const & a); + + /// Modelled after the quartic y = 1 - (x - 1)^4 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseOut(genType const & a); + + /// Modelled after the piecewise quartic + /// y = (1/2)((2x)^4) ; [0, 0.5) + /// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quarticEaseInOut(genType const & a); + + /// Modelled after the quintic y = x^5 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseIn(genType const & a); + + /// Modelled after the quintic y = (x - 1)^5 + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseOut(genType const & a); + + /// Modelled after the piecewise quintic + /// y = (1/2)((2x)^5) ; [0, 0.5) + /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType quinticEaseInOut(genType const & a); + + /// Modelled after quarter-cycle of sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseIn(genType const & a); + + /// Modelled after quarter-cycle of sine wave (different phase) + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseOut(genType const & a); + + /// Modelled after half sine wave + /// @see gtx_easing + template + GLM_FUNC_DECL genType sineEaseInOut(genType const & a); + + /// Modelled after shifted quadrant IV of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseIn(genType const & a); + + /// Modelled after shifted quadrant II of unit circle + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseOut(genType const & a); + + /// Modelled after the piecewise circular function + /// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) + /// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType circularEaseInOut(genType const & a); + + /// Modelled after the exponential function y = 2^(10(x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseIn(genType const & a); + + /// Modelled after the exponential function y = -2^(-10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseOut(genType const & a); + + /// Modelled after the piecewise exponential + /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) + /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType exponentialEaseInOut(genType const & a); + + /// Modelled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseIn(genType const & a); + + /// Modelled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseOut(genType const & a); + + /// Modelled after the piecewise exponentially-damped sine wave: + /// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) + /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] + /// @see gtx_easing + template + GLM_FUNC_DECL genType elasticEaseInOut(genType const & a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseIn(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseOut(genType const& a, genType const& o); + + /// @param a parameter + /// @param o Optional overshoot modifier + /// @see gtx_easing + template + GLM_FUNC_DECL genType backEaseInOut(genType const& a, genType const& o); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseIn(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseOut(genType const& a); + + /// @see gtx_easing + template + GLM_FUNC_DECL genType bounceEaseInOut(genType const& a); + + /// @} +}//namespace glm + +#include "easing.inl" diff --git a/thirdparty/glm/gtx/easing.inl b/thirdparty/glm/gtx/easing.inl new file mode 100644 index 0000000..4b7d05b --- /dev/null +++ b/thirdparty/glm/gtx/easing.inl @@ -0,0 +1,436 @@ +/// @ref gtx_easing + +#include + +namespace glm{ + + template + GLM_FUNC_QUALIFIER genType linearInterpolation(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a; + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return -(a * (a - static_cast(2))); + } + + template + GLM_FUNC_QUALIFIER genType quadraticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(2) * a * a; + } + else + { + return (-static_cast(2) * a * a) + (4 * a) - one(); + } + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = a - one(); + return f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType cubicEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if (a < static_cast(0.5)) + { + return static_cast(4) * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * (one() - a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType quarticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(8) * a * a * a * a; + } + else + { + genType const f = (a - one()); + return -static_cast(8) * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return a * a * a * a * a; + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType const f = (a - one()); + return f * f * f * f * f + one(); + } + + template + GLM_FUNC_QUALIFIER genType quinticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(16) * a * a * a * a * a; + } + else + { + genType const f = ((static_cast(2) * a) - static_cast(2)); + return static_cast(0.5) * f * f * f * f * f + one(); + } + } + + template + GLM_FUNC_QUALIFIER genType sineEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin((a - one()) * half_pi()) + one(); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sin(a * half_pi()); + } + + template + GLM_FUNC_QUALIFIER genType sineEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return static_cast(0.5) * (one() - cos(a * pi())); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - sqrt(one() - (a * a)); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return sqrt((static_cast(2) - a) * a); + } + + template + GLM_FUNC_QUALIFIER genType circularEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - std::sqrt(one() - static_cast(4) * (a * a))); + } + else + { + return static_cast(0.5) * (std::sqrt(-((static_cast(2) * a) - static_cast(3)) * ((static_cast(2) * a) - one())) + one()); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a <= zero()) + return a; + else + { + genType const Complementary = a - one(); + genType const Two = static_cast(2); + + return glm::pow(Two, Complementary * static_cast(10)); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a >= one()) + return a; + else + { + return one() - glm::pow(static_cast(2), -static_cast(10) * a); + } + } + + template + GLM_FUNC_QUALIFIER genType exponentialEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * glm::pow(static_cast(2), (static_cast(20) * a) - static_cast(10)); + else + return -static_cast(0.5) * glm::pow(static_cast(2), (-static_cast(20) * a) + static_cast(10)) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(static_cast(13) * half_pi() * a) * glm::pow(static_cast(2), static_cast(10) * (a - one())); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return std::sin(-static_cast(13) * half_pi() * (a + one())) * glm::pow(static_cast(2), -static_cast(10) * a) + one(); + } + + template + GLM_FUNC_QUALIFIER genType elasticEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + return static_cast(0.5) * std::sin(static_cast(13) * half_pi() * (static_cast(2) * a)) * glm::pow(static_cast(2), static_cast(10) * ((static_cast(2) * a) - one())); + else + return static_cast(0.5) * (std::sin(-static_cast(13) * half_pi() * ((static_cast(2) * a - one()) + one())) * glm::pow(static_cast(2), -static_cast(10) * (static_cast(2) * a - one())) + static_cast(2)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType z = ((o + one()) * a) - o; + return (a * a * z); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType n = a - one(); + genType z = ((o + one()) * n) + o; + return (n * n * z) + one(); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a, genType const& o) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + genType s = o * static_cast(1.525); + genType x = static_cast(0.5); + genType n = a / static_cast(0.5); + + if (n < static_cast(1)) + { + genType z = ((s + static_cast(1)) * n) - s; + genType m = n * n * z; + return x * m; + } + else + { + n -= static_cast(2); + genType z = ((s + static_cast(1)) * n) + s; + genType m = (n*n*z) + static_cast(2); + return x * m; + } + } + + template + GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a) + { + return backEaseIn(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a) + { + return backEaseOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a) + { + return backEaseInOut(a, static_cast(1.70158)); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(4.0 / 11.0)) + { + return (static_cast(121) * a * a) / static_cast(16); + } + else if(a < static_cast(8.0 / 11.0)) + { + return (static_cast(363.0 / 40.0) * a * a) - (static_cast(99.0 / 10.0) * a) + static_cast(17.0 / 5.0); + } + else if(a < static_cast(9.0 / 10.0)) + { + return (static_cast(4356.0 / 361.0) * a * a) - (static_cast(35442.0 / 1805.0) * a) + static_cast(16061.0 / 1805.0); + } + else + { + return (static_cast(54.0 / 5.0) * a * a) - (static_cast(513.0 / 25.0) * a) + static_cast(268.0 / 25.0); + } + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseIn(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + return one() - bounceEaseOut(one() - a); + } + + template + GLM_FUNC_QUALIFIER genType bounceEaseInOut(genType const& a) + { + // Only defined in [0, 1] + assert(a >= zero()); + assert(a <= one()); + + if(a < static_cast(0.5)) + { + return static_cast(0.5) * (one() - bounceEaseOut(a * static_cast(2))); + } + else + { + return static_cast(0.5) * bounceEaseOut(a * static_cast(2) - one()) + static_cast(0.5); + } + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/euler_angles.hpp b/thirdparty/glm/gtx/euler_angles.hpp new file mode 100644 index 0000000..2723697 --- /dev/null +++ b/thirdparty/glm/gtx/euler_angles.hpp @@ -0,0 +1,335 @@ +/// @ref gtx_euler_angles +/// @file glm/gtx/euler_angles.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_euler_angles GLM_GTX_euler_angles +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices from Euler angles. +/// +/// Extraction of Euler angles from rotation matrix. +/// Based on the original paper 2014 Mike Day - Extracting Euler Angles from a Rotation Matrix. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_euler_angles is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_euler_angles extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_euler_angles + /// @{ + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleX( + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleY( + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZ( + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about X-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleX( + T const & angleX, T const & angularVelocityX); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Y-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleY( + T const & angleY, T const & angularVelocityY); + + /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Z-axis. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleZ( + T const & angleZ, T const & angularVelocityZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXY( + T const& angleX, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYX( + T const& angleY, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZ( + T const& angleX, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZX( + T const& angle, + T const& angleX); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZ( + T const& angleY, + T const& angleZ); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZY( + T const& angleZ, + T const& angleY); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYZ( + T const& t1, + T const& t2, + T const& t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXZ( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXZ( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * X). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYX( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Y). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXY( + T const & t1, + T const & t2, + T const & t3); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, defaultp> yawPitchRoll( + T const& yaw, + T const& pitch, + T const& roll); + + /// Creates a 2D 2 * 2 rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<2, 2, T, defaultp> orientate2(T const& angle); + + /// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle. + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, defaultp> orientate3(T const& angle); + + /// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<3, 3, T, Q> orientate3(vec<3, T, Q> const& angles); + + /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). + /// @see gtx_euler_angles + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientate4(vec<3, T, Q> const& angles); + + /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Z) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (X * Z * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Y * Z * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * Y * X) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// Extracts the (Z * X * Y) Euler angles from the rotation matrix M + /// @see gtx_euler_angles + template + GLM_FUNC_DECL void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3); + + /// @} +}//namespace glm + +#include "euler_angles.inl" diff --git a/thirdparty/glm/gtx/euler_angles.inl b/thirdparty/glm/gtx/euler_angles.inl new file mode 100644 index 0000000..68c5012 --- /dev/null +++ b/thirdparty/glm/gtx/euler_angles.inl @@ -0,0 +1,899 @@ +/// @ref gtx_euler_angles + +#include "compatibility.hpp" // glm::atan2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleX + ( + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + + return mat<4, 4, T, defaultp>( + T(1), T(0), T(0), T(0), + T(0), cosX, sinX, T(0), + T(0),-sinX, cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleY + ( + T const& angleY + ) + { + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, T(0), -sinY, T(0), + T(0), T(1), T(0), T(0), + sinY, T(0), cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZ + ( + T const& angleZ + ) + { + T cosZ = glm::cos(angleZ); + T sinZ = glm::sin(angleZ); + + return mat<4, 4, T, defaultp>( + cosZ, sinZ, T(0), T(0), + -sinZ, cosZ, T(0), T(0), + T(0), T(0), T(1), T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleX + ( + T const & angleX, + T const & angularVelocityX + ) + { + T cosX = glm::cos(angleX) * angularVelocityX; + T sinX = glm::sin(angleX) * angularVelocityX; + + return mat<4, 4, T, defaultp>( + T(0), T(0), T(0), T(0), + T(0),-sinX, cosX, T(0), + T(0),-cosX,-sinX, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleY + ( + T const & angleY, + T const & angularVelocityY + ) + { + T cosY = glm::cos(angleY) * angularVelocityY; + T sinY = glm::sin(angleY) * angularVelocityY; + + return mat<4, 4, T, defaultp>( + -sinY, T(0), -cosY, T(0), + T(0), T(0), T(0), T(0), + cosY, T(0), -sinY, T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleZ + ( + T const & angleZ, + T const & angularVelocityZ + ) + { + T cosZ = glm::cos(angleZ) * angularVelocityZ; + T sinZ = glm::sin(angleZ) * angularVelocityZ; + + return mat<4, 4, T, defaultp>( + -sinZ, cosZ, T(0), T(0), + -cosZ, -sinZ, T(0), T(0), + T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXY + ( + T const& angleX, + T const& angleY + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, -sinX * -sinY, cosX * -sinY, T(0), + T(0), cosX, sinX, T(0), + sinY, -sinX * cosY, cosX * cosY, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYX + ( + T const& angleY, + T const& angleX + ) + { + T cosX = glm::cos(angleX); + T sinX = glm::sin(angleX); + T cosY = glm::cos(angleY); + T sinY = glm::sin(angleY); + + return mat<4, 4, T, defaultp>( + cosY, 0, -sinY, T(0), + sinY * sinX, cosX, cosY * sinX, T(0), + sinY * cosX, -sinX, cosY * cosX, T(0), + T(0), T(0), T(0), T(1)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZ + ( + T const& angleX, + T const& angleZ + ) + { + return eulerAngleX(angleX) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZX + ( + T const& angleZ, + T const& angleX + ) + { + return eulerAngleZ(angleZ) * eulerAngleX(angleX); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZ + ( + T const& angleY, + T const& angleZ + ) + { + return eulerAngleY(angleY) * eulerAngleZ(angleZ); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZY + ( + T const& angleZ, + T const& angleY + ) + { + return eulerAngleZ(angleZ) * eulerAngleY(angleY); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYZ + ( + T const& t1, + T const& t2, + T const& t3 + ) + { + T c1 = glm::cos(-t1); + T c2 = glm::cos(-t2); + T c3 = glm::cos(-t3); + T s1 = glm::sin(-t1); + T s2 = glm::sin(-t2); + T s3 = glm::sin(-t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] =-c1 * s3 + s1 * s2 * c3; + Result[0][2] = s1 * s3 + c1 * s2 * c3; + Result[0][3] = static_cast(0); + Result[1][0] = c2 * s3; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] =-s1 * c3 + c1 * s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] =-s2; + Result[2][1] = s1 * c2; + Result[2][2] = c1 * c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXZ + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = c1 * s2; + Result[0][2] = s1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s2; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c1 * s3 + c2 * c3 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = s2 * s3; + Result[2][1] =-c3 * s1 - c1 * c2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2; + Result[0][1] = s1 * s2; + Result[0][2] =-c1 * s2; + Result[0][3] = static_cast(0); + Result[1][0] = s2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = c3 * s1 + c1 * c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s2; + Result[2][1] =-c1 * s3 - c2 * c3 * s1; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = s2* s3; + Result[0][2] =-c3 * s1 - c1 * c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s2; + Result[1][1] = c2; + Result[1][2] = c1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c2 * c3 * s1; + Result[2][1] =-c3 * s2; + Result[2][2] = c1 * c2 * c3 - s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c3 * s2; + Result[0][2] =-c1 * s3 - c2 * c3 * s1; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s2; + Result[1][1] = c2; + Result[1][2] = s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * c2 * s3; + Result[2][1] = s2 * s3; + Result[2][2] = c1 * c3 - c2 * s1 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2 * c3 - s1 * s3; + Result[0][1] = c1 * s3 + c2 * c3 * s1; + Result[0][2] =-c3 * s2; + Result[0][3] = static_cast(0); + Result[1][0] =-c3 * s1 - c1 * c2 * s3; + Result[1][1] = c1 * c3 - c2 * s1 * s3; + Result[1][2] = s2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s2; + Result[2][1] = s1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXZ + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - c2 * s1 * s3; + Result[0][1] = c3 * s1 + c1 * c2 * s3; + Result[0][2] = s2 *s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c1 * s3 - c2 * c3 * s1; + Result[1][1] = c1 * c2 * c3 - s1 * s3; + Result[1][2] = c3 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s2; + Result[2][1] =-c1 * s2; + Result[2][2] = c2; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c2 * c3; + Result[0][1] = s1 * s3 + c1 * c3 * s2; + Result[0][2] = c3 * s1 * s2 - c1 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-s2; + Result[1][1] = c1 * c2; + Result[1][2] = c2 * s1; + Result[1][3] = static_cast(0); + Result[2][0] = c2 * s3; + Result[2][1] = c1 * s2 * s3 - c3 * s1; + Result[2][2] = c1 * c3 + s1 * s2 *s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = s2; + Result[0][2] =-c2 * s1; + Result[0][3] = static_cast(0); + Result[1][0] = s1 * s3 - c1 * c3 * s2; + Result[1][1] = c2 * c3; + Result[1][2] = c1 * s3 + c3 * s1 * s2; + Result[1][3] = static_cast(0); + Result[2][0] = c3 * s1 + c1 * s2 * s3; + Result[2][1] =-c2 * s3; + Result[2][2] = c1 * c3 - s1 * s2 * s3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYX + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c2; + Result[0][1] = c2 * s1; + Result[0][2] =-s2; + Result[0][3] = static_cast(0); + Result[1][0] = c1 * s2 * s3 - c3 * s1; + Result[1][1] = c1 * c3 + s1 * s2 * s3; + Result[1][2] = c2 * s3; + Result[1][3] = static_cast(0); + Result[2][0] = s1 * s3 + c1 * c3 * s2; + Result[2][1] = c3 * s1 * s2 - c1 * s3; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXY + ( + T const & t1, + T const & t2, + T const & t3 + ) + { + T c1 = glm::cos(t1); + T s1 = glm::sin(t1); + T c2 = glm::cos(t2); + T s2 = glm::sin(t2); + T c3 = glm::cos(t3); + T s3 = glm::sin(t3); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = c1 * c3 - s1 * s2 * s3; + Result[0][1] = c3 * s1 + c1 * s2 * s3; + Result[0][2] =-c2 * s3; + Result[0][3] = static_cast(0); + Result[1][0] =-c2 * s1; + Result[1][1] = c1 * c2; + Result[1][2] = s2; + Result[1][3] = static_cast(0); + Result[2][0] = c1 * s3 + c3 * s1 * s2; + Result[2][1] = s1 * s3 - c1 * c3 * s2; + Result[2][2] = c2 * c3; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> yawPitchRoll + ( + T const& yaw, + T const& pitch, + T const& roll + ) + { + T tmp_ch = glm::cos(yaw); + T tmp_sh = glm::sin(yaw); + T tmp_cp = glm::cos(pitch); + T tmp_sp = glm::sin(pitch); + T tmp_cb = glm::cos(roll); + T tmp_sb = glm::sin(roll); + + mat<4, 4, T, defaultp> Result; + Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; + Result[0][1] = tmp_sb * tmp_cp; + Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; + Result[0][3] = static_cast(0); + Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; + Result[1][1] = tmp_cb * tmp_cp; + Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; + Result[1][3] = static_cast(0); + Result[2][0] = tmp_sh * tmp_cp; + Result[2][1] = -tmp_sp; + Result[2][2] = tmp_ch * tmp_cp; + Result[2][3] = static_cast(0); + Result[3][0] = static_cast(0); + Result[3][1] = static_cast(0); + Result[3][2] = static_cast(0); + Result[3][3] = static_cast(1); + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> orientate2 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<2, 2, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[1][0] = -s; + Result[1][1] = c; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> orientate3 + ( + T const& angle + ) + { + T c = glm::cos(angle); + T s = glm::sin(angle); + + mat<3, 3, T, defaultp> Result; + Result[0][0] = c; + Result[0][1] = s; + Result[0][2] = 0.0f; + Result[1][0] = -s; + Result[1][1] = c; + Result[1][2] = 0.0f; + Result[2][0] = 0.0f; + Result[2][1] = 0.0f; + Result[2][2] = 1.0f; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orientate3 + ( + vec<3, T, Q> const& angles + ) + { + return mat<3, 3, T, Q>(yawPitchRoll(angles.z, angles.x, angles.y)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientate4 + ( + vec<3, T, Q> const& angles + ) + { + return yawPitchRoll(angles.z, angles.x, angles.y); + } + + template + GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][2]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]); + T T2 = glm::atan2(-M[2][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2 ]); + t1 = -T1; + t2 = -T2; + t3 = -T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], M[2][2]); + T C2 = glm::sqrt(M[0][1]*M[0][1] + M[1][1]*M[1][1]); + T T2 = glm::atan2(-M[2][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][2] - C1*M[1][0], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][2], M[0][1]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[1][2] - S1*M[1][1], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], -M[0][2]); + T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(S2, M[0][0]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[2][1] - S1*M[2][2], C1*M[1][1] + S1*M[1][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][0], M[1][2]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] - S1*M[2][2], C1*M[0][0] - S1*M[0][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], -M[1][0]); + T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(S2, M[1][1]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-S1*M[0][0] - C1*M[0][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][1], M[2][0]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[0][1] - S1*M[0][0], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[2][0], -M[2][1]); + T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); + T T2 = glm::atan2(S2, M[2][2]); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(-C1*M[1][0] - S1*M[1][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[1][2], M[1][1]); + T C2 = glm::sqrt(M[0][0]*M[0][0] + M[2][0]*M[2][0]); + T T2 = glm::atan2(-M[1][0], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[0][1] - C1*M[0][2], C1*M[2][2] - S1*M[2][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[0][2], M[0][0]); + T C2 = glm::sqrt(M[1][1]*M[1][1] + M[2][1]*M[2][1]); + T T2 = glm::atan2(M[0][1], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[1][0] + C1*M[1][2], S1*M[2][0] + C1*M[2][2]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(M[0][1], M[0][0]); + T C2 = glm::sqrt(M[1][2]*M[1][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(-M[0][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(S1*M[2][0] - C1*M[2][1], C1*M[1][1] - S1*M[1][0]); + t1 = T1; + t2 = T2; + t3 = T3; + } + + template + GLM_FUNC_QUALIFIER void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, + T & t1, + T & t2, + T & t3) + { + T T1 = glm::atan2(-M[1][0], M[1][1]); + T C2 = glm::sqrt(M[0][2]*M[0][2] + M[2][2]*M[2][2]); + T T2 = glm::atan2(M[1][2], C2); + T S1 = glm::sin(T1); + T C1 = glm::cos(T1); + T T3 = glm::atan2(C1*M[2][0] + S1*M[2][1], C1*M[0][0] + S1*M[0][1]); + t1 = T1; + t2 = T2; + t3 = T3; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/extend.hpp b/thirdparty/glm/gtx/extend.hpp new file mode 100644 index 0000000..28b7c5c --- /dev/null +++ b/thirdparty/glm/gtx/extend.hpp @@ -0,0 +1,42 @@ +/// @ref gtx_extend +/// @file glm/gtx/extend.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extend GLM_GTX_extend +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extend + /// @{ + + /// Extends of Length the Origin position using the (Source - Origin) direction. + /// @see gtx_extend + template + GLM_FUNC_DECL genType extend( + genType const& Origin, + genType const& Source, + typename genType::value_type const Length); + + /// @} +}//namespace glm + +#include "extend.inl" diff --git a/thirdparty/glm/gtx/extend.inl b/thirdparty/glm/gtx/extend.inl new file mode 100644 index 0000000..32128eb --- /dev/null +++ b/thirdparty/glm/gtx/extend.inl @@ -0,0 +1,48 @@ +/// @ref gtx_extend + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType extend + ( + genType const& Origin, + genType const& Source, + genType const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> extend + ( + vec<2, T, Q> const& Origin, + vec<2, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> extend + ( + vec<3, T, Q> const& Origin, + vec<3, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> extend + ( + vec<4, T, Q> const& Origin, + vec<4, T, Q> const& Source, + T const& Distance + ) + { + return Origin + (Source - Origin) * Distance; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/extended_min_max.hpp b/thirdparty/glm/gtx/extended_min_max.hpp new file mode 100644 index 0000000..025eda2 --- /dev/null +++ b/thirdparty/glm/gtx/extended_min_max.hpp @@ -0,0 +1,137 @@ +/// @ref gtx_extended_min_max +/// @file glm/gtx/extended_min_max.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_extended_min_max GLM_GTX_extented_min_max +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Min and max functions for 3 to 4 parameters. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../ext/vector_common.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extented_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extented_min_max extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_extended_min_max + /// @{ + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the minimum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T min( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the minimum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C min( + C const& x, + C const& y, + C const& z, + C const& w); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z); + + /// Return the maximum component-wise values of 3 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template + GLM_FUNC_DECL T max( + T const& x, + T const& y, + T const& z, + T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w); + + /// Return the maximum component-wise values of 4 inputs + /// @see gtx_extented_min_max + template class C> + GLM_FUNC_DECL C max( + C const& x, + C const& y, + C const& z, + C const& w); + + /// @} +}//namespace glm + +#include "extended_min_max.inl" diff --git a/thirdparty/glm/gtx/extended_min_max.inl b/thirdparty/glm/gtx/extended_min_max.inl new file mode 100644 index 0000000..de5998f --- /dev/null +++ b/thirdparty/glm/gtx/extended_min_max.inl @@ -0,0 +1,138 @@ +/// @ref gtx_extended_min_max + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T min( + T const& x, + T const& y, + T const& z) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::min(glm::min(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T min + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C min + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::min(glm::min(x, y), glm::min(z, w)); + } + + template + GLM_FUNC_QUALIFIER T max( + T const& x, + T const& y, + T const& z) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z + ) + { + return glm::max(glm::max(x, y), z); + } + + template + GLM_FUNC_QUALIFIER T max + ( + T const& x, + T const& y, + T const& z, + T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + typename C::T const& y, + typename C::T const& z, + typename C::T const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } + + template class C> + GLM_FUNC_QUALIFIER C max + ( + C const& x, + C const& y, + C const& z, + C const& w + ) + { + return glm::max(glm::max(x, y), glm::max(z, w)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/exterior_product.hpp b/thirdparty/glm/gtx/exterior_product.hpp new file mode 100644 index 0000000..5522df7 --- /dev/null +++ b/thirdparty/glm/gtx/exterior_product.hpp @@ -0,0 +1,45 @@ +/// @ref gtx_exterior_product +/// @file glm/gtx/exterior_product.hpp +/// +/// @see core (dependence) +/// @see gtx_exterior_product (dependence) +/// +/// @defgroup gtx_exterior_product GLM_GTX_exterior_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// @brief Allow to perform bit operations on integer values + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_exterior_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_exterior_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_exterior_product + /// @{ + + /// Returns the cross product of x and y. + /// + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see Exterior product + template + GLM_FUNC_DECL T cross(vec<2, T, Q> const& v, vec<2, T, Q> const& u); + + /// @} +} //namespace glm + +#include "exterior_product.inl" diff --git a/thirdparty/glm/gtx/exterior_product.inl b/thirdparty/glm/gtx/exterior_product.inl new file mode 100644 index 0000000..93661fd --- /dev/null +++ b/thirdparty/glm/gtx/exterior_product.inl @@ -0,0 +1,26 @@ +/// @ref gtx_exterior_product + +#include + +namespace glm { +namespace detail +{ + template + struct compute_cross_vec2 + { + GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& v, vec<2, T, Q> const& u) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); + + return v.x * u.y - u.x * v.y; + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER T cross(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + return detail::compute_cross_vec2::value>::call(x, y); + } +}//namespace glm + diff --git a/thirdparty/glm/gtx/fast_exponential.hpp b/thirdparty/glm/gtx/fast_exponential.hpp new file mode 100644 index 0000000..6fb7286 --- /dev/null +++ b/thirdparty/glm/gtx/fast_exponential.hpp @@ -0,0 +1,95 @@ +/// @ref gtx_fast_exponential +/// @file glm/gtx/fast_exponential.hpp +/// +/// @see core (dependence) +/// @see gtx_half_float (dependence) +/// +/// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of exponential based functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_exponential is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_exponential extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_exponential + /// @{ + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genType fastPow(genType x, genType y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x, vec const& y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y); + + /// Faster than the common pow function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastPow(vec const& x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp(T x); + + /// Faster than the common exp function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp(vec const& x); + + /// Faster than the common log function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog(vec const& x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastExp2(T x); + + /// Faster than the common exp2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastExp2(vec const& x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL T fastLog2(T x); + + /// Faster than the common log2 function but less accurate. + /// @see gtx_fast_exponential + template + GLM_FUNC_DECL vec fastLog2(vec const& x); + + /// @} +}//namespace glm + +#include "fast_exponential.inl" diff --git a/thirdparty/glm/gtx/fast_exponential.inl b/thirdparty/glm/gtx/fast_exponential.inl new file mode 100644 index 0000000..f139e50 --- /dev/null +++ b/thirdparty/glm/gtx/fast_exponential.inl @@ -0,0 +1,136 @@ +/// @ref gtx_fast_exponential + +namespace glm +{ + // fastPow: + template + GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + return exp(y * log(x)); + } + + template + GLM_FUNC_QUALIFIER T fastPow(T x, int y) + { + T f = static_cast(1); + for(int i = 0; i < y; ++i) + f *= x; + return f; + } + + template + GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) + { + vec Result; + for(length_t i = 0, n = x.length(); i < n; ++i) + Result[i] = fastPow(x[i], y[i]); + return Result; + } + + // fastExp + // Note: This function provides accurate results only for value between -1 and 1, else avoid it. + template + GLM_FUNC_QUALIFIER T fastExp(T x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + T x2 = x * x; + T x3 = x2 * x; + T x4 = x3 * x; + T x5 = x4 * x; + return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333)); + } + /* // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance + GLM_FUNC_QUALIFIER float fastExp(float x) + { + const float e = 2.718281828f; + const float IntegerPart = floor(x); + const float FloatPart = x - IntegerPart; + float z = 1.f; + + for(int i = 0; i < int(IntegerPart); ++i) + z *= e; + + const float x2 = FloatPart * FloatPart; + const float x3 = x2 * FloatPart; + const float x4 = x3 * FloatPart; + const float x5 = x4 * FloatPart; + return z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)); + } + + // Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers + GLM_FUNC_QUALIFIER float fastExp(float x) + { + // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. + // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); + float x2 = x * x; + float x3 = x2 * x; + float x4 = x3 * x; + float x5 = x4 * x; + float x6 = x5 * x; + float x7 = x6 * x; + float x8 = x7 * x; + return 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);; + } + */ + + template + GLM_FUNC_QUALIFIER vec fastExp(vec const& x) + { + return detail::functor1::call(fastExp, x); + } + + // fastLog + template + GLM_FUNC_QUALIFIER genType fastLog(genType x) + { + return std::log(x); + } + + /* Slower than the VC7.1 function... + GLM_FUNC_QUALIFIER float fastLog(float x) + { + float y1 = (x - 1.0f) / (x + 1.0f); + float y2 = y1 * y1; + return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f))); + } + */ + + template + GLM_FUNC_QUALIFIER vec fastLog(vec const& x) + { + return detail::functor1::call(fastLog, x); + } + + //fastExp2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastExp2(genType x) + { + return fastExp(0.69314718055994530941723212145818f * x); + } + + template + GLM_FUNC_QUALIFIER vec fastExp2(vec const& x) + { + return detail::functor1::call(fastExp2, x); + } + + // fastLog2, ln2 = 0.69314718055994530941723212145818f + template + GLM_FUNC_QUALIFIER genType fastLog2(genType x) + { + return fastLog(x) / 0.69314718055994530941723212145818f; + } + + template + GLM_FUNC_QUALIFIER vec fastLog2(vec const& x) + { + return detail::functor1::call(fastLog2, x); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/fast_square_root.hpp b/thirdparty/glm/gtx/fast_square_root.hpp new file mode 100644 index 0000000..9fb3f2f --- /dev/null +++ b/thirdparty/glm/gtx/fast_square_root.hpp @@ -0,0 +1,92 @@ +/// @ref gtx_fast_square_root +/// @file glm/gtx/fast_square_root.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of square root based functions. +/// - Sqrt optimisation based on Newton's method, +/// www.gamedev.net/community/forums/topic.asp?topic id=139956 + +#pragma once + +// Dependency: +#include "../common.hpp" +#include "../exponential.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_square_root is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_square_root extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_square_root + /// @{ + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastSqrt(genType x); + + /// Faster than the common sqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastSqrt(vec const& x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastInverseSqrt(genType x); + + /// Faster than the common inversesqrt function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL vec fastInverseSqrt(vec const& x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastLength(genType x); + + /// Faster than the common length function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastLength(vec const& x); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastDistance(genType x, genType y); + + /// Faster than the common distance function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL T fastDistance(vec const& x, vec const& y); + + /// Faster than the common normalize function but less accurate. + /// + /// @see gtx_fast_square_root extension. + template + GLM_FUNC_DECL genType fastNormalize(genType const& x); + + /// @} +}// namespace glm + +#include "fast_square_root.inl" diff --git a/thirdparty/glm/gtx/fast_square_root.inl b/thirdparty/glm/gtx/fast_square_root.inl new file mode 100644 index 0000000..4e6c6de --- /dev/null +++ b/thirdparty/glm/gtx/fast_square_root.inl @@ -0,0 +1,75 @@ +/// @ref gtx_fast_square_root + +namespace glm +{ + // fastSqrt + template + GLM_FUNC_QUALIFIER genType fastSqrt(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastSqrt' only accept floating-point input"); + + return genType(1) / fastInverseSqrt(x); + } + + template + GLM_FUNC_QUALIFIER vec fastSqrt(vec const& x) + { + return detail::functor1::call(fastSqrt, x); + } + + // fastInversesqrt + template + GLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x) + { + return detail::compute_inversesqrt<1, genType, lowp, detail::is_aligned::value>::call(vec<1, genType, lowp>(x)).x; + } + + template + GLM_FUNC_QUALIFIER vec fastInverseSqrt(vec const& x) + { + return detail::compute_inversesqrt::value>::call(x); + } + + // fastLength + template + GLM_FUNC_QUALIFIER genType fastLength(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return abs(x); + } + + template + GLM_FUNC_QUALIFIER T fastLength(vec const& x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); + + return fastSqrt(dot(x, x)); + } + + // fastDistance + template + GLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y) + { + return fastLength(y - x); + } + + template + GLM_FUNC_QUALIFIER T fastDistance(vec const& x, vec const& y) + { + return fastLength(y - x); + } + + // fastNormalize + template + GLM_FUNC_QUALIFIER genType fastNormalize(genType x) + { + return x > genType(0) ? genType(1) : -genType(1); + } + + template + GLM_FUNC_QUALIFIER vec fastNormalize(vec const& x) + { + return x * fastInverseSqrt(dot(x, x)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/fast_trigonometry.hpp b/thirdparty/glm/gtx/fast_trigonometry.hpp new file mode 100644 index 0000000..2650d6e --- /dev/null +++ b/thirdparty/glm/gtx/fast_trigonometry.hpp @@ -0,0 +1,79 @@ +/// @ref gtx_fast_trigonometry +/// @file glm/gtx/fast_trigonometry.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Fast but less accurate implementations of trigonometric functions. + +#pragma once + +// Dependency: +#include "../gtc/constants.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_fast_trigonometry is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_fast_trigonometry extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_fast_trigonometry + /// @{ + + /// Wrap an angle to [0 2pi[ + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T wrapAngle(T angle); + + /// Faster than the common sin function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastSin(T angle); + + /// Faster than the common cos function but less accurate. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastCos(T angle); + + /// Faster than the common tan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastTan(T angle); + + /// Faster than the common asin function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAsin(T angle); + + /// Faster than the common acos function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAcos(T angle); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T y, T x); + + /// Faster than the common atan function but less accurate. + /// Defined between -2pi and 2pi. + /// From GLM_GTX_fast_trigonometry extension. + template + GLM_FUNC_DECL T fastAtan(T angle); + + /// @} +}//namespace glm + +#include "fast_trigonometry.inl" diff --git a/thirdparty/glm/gtx/fast_trigonometry.inl b/thirdparty/glm/gtx/fast_trigonometry.inl new file mode 100644 index 0000000..1a710cb --- /dev/null +++ b/thirdparty/glm/gtx/fast_trigonometry.inl @@ -0,0 +1,142 @@ +/// @ref gtx_fast_trigonometry + +namespace glm{ +namespace detail +{ + template + GLM_FUNC_QUALIFIER vec taylorCos(vec const& x) + { + return static_cast(1) + - (x * x) * (1.f / 2.f) + + ((x * x) * (x * x)) * (1.f / 24.f) + - (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f) + + (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f); + } + + template + GLM_FUNC_QUALIFIER T cos_52s(T x) + { + T const xx(x * x); + return (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095)))); + } + + template + GLM_FUNC_QUALIFIER vec cos_52s(vec const& x) + { + return detail::functor1::call(cos_52s, x); + } +}//namespace detail + + // wrapAngle + template + GLM_FUNC_QUALIFIER T wrapAngle(T angle) + { + return abs(mod(angle, two_pi())); + } + + template + GLM_FUNC_QUALIFIER vec wrapAngle(vec const& x) + { + return detail::functor1::call(wrapAngle, x); + } + + // cos + template + GLM_FUNC_QUALIFIER T fastCos(T x) + { + T const angle(wrapAngle(x)); + + if(angle < half_pi()) + return detail::cos_52s(angle); + if(angle < pi()) + return -detail::cos_52s(pi() - angle); + if(angle < (T(3) * half_pi())) + return -detail::cos_52s(angle - pi()); + + return detail::cos_52s(two_pi() - angle); + } + + template + GLM_FUNC_QUALIFIER vec fastCos(vec const& x) + { + return detail::functor1::call(fastCos, x); + } + + // sin + template + GLM_FUNC_QUALIFIER T fastSin(T x) + { + return fastCos(half_pi() - x); + } + + template + GLM_FUNC_QUALIFIER vec fastSin(vec const& x) + { + return detail::functor1::call(fastSin, x); + } + + // tan + template + GLM_FUNC_QUALIFIER T fastTan(T x) + { + return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539)); + } + + template + GLM_FUNC_QUALIFIER vec fastTan(vec const& x) + { + return detail::functor1::call(fastTan, x); + } + + // asin + template + GLM_FUNC_QUALIFIER T fastAsin(T x) + { + return x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159)); + } + + template + GLM_FUNC_QUALIFIER vec fastAsin(vec const& x) + { + return detail::functor1::call(fastAsin, x); + } + + // acos + template + GLM_FUNC_QUALIFIER T fastAcos(T x) + { + return T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2) + } + + template + GLM_FUNC_QUALIFIER vec fastAcos(vec const& x) + { + return detail::functor1::call(fastAcos, x); + } + + // atan + template + GLM_FUNC_QUALIFIER T fastAtan(T y, T x) + { + T sgn = sign(y) * sign(x); + return abs(fastAtan(y / x)) * sgn; + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& y, vec const& x) + { + return detail::functor2::call(fastAtan, y, x); + } + + template + GLM_FUNC_QUALIFIER T fastAtan(T x) + { + return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909)); + } + + template + GLM_FUNC_QUALIFIER vec fastAtan(vec const& x) + { + return detail::functor1::call(fastAtan, x); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/float_notmalize.inl b/thirdparty/glm/gtx/float_notmalize.inl new file mode 100644 index 0000000..8cdbc5a --- /dev/null +++ b/thirdparty/glm/gtx/float_notmalize.inl @@ -0,0 +1,13 @@ +/// @ref gtx_float_normalize + +#include + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec floatNormalize(vec const& v) + { + return vec(v) / static_cast(std::numeric_limits::max()); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/functions.hpp b/thirdparty/glm/gtx/functions.hpp new file mode 100644 index 0000000..9f4166c --- /dev/null +++ b/thirdparty/glm/gtx/functions.hpp @@ -0,0 +1,56 @@ +/// @ref gtx_functions +/// @file glm/gtx/functions.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_functions GLM_GTX_functions +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// List of useful common functions. + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" +#include "../detail/qualifier.hpp" +#include "../detail/type_vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_functions is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_functions extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_functions + /// @{ + + /// 1D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + T x, + T ExpectedValue, + T StandardDeviation); + + /// 2D gauss function + /// + /// @see gtc_epsilon + template + GLM_FUNC_DECL T gauss( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation); + + /// @} +}//namespace glm + +#include "functions.inl" + diff --git a/thirdparty/glm/gtx/functions.inl b/thirdparty/glm/gtx/functions.inl new file mode 100644 index 0000000..29cbb20 --- /dev/null +++ b/thirdparty/glm/gtx/functions.inl @@ -0,0 +1,30 @@ +/// @ref gtx_functions + +#include "../exponential.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T gauss + ( + T x, + T ExpectedValue, + T StandardDeviation + ) + { + return exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast(6.28318530717958647692528676655900576))); + } + + template + GLM_FUNC_QUALIFIER T gauss + ( + vec<2, T, Q> const& Coord, + vec<2, T, Q> const& ExpectedValue, + vec<2, T, Q> const& StandardDeviation + ) + { + vec<2, T, Q> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation); + return exp(-(Squared.x + Squared.y)); + } +}//namespace glm + diff --git a/thirdparty/glm/gtx/gradient_paint.hpp b/thirdparty/glm/gtx/gradient_paint.hpp new file mode 100644 index 0000000..6f85bf4 --- /dev/null +++ b/thirdparty/glm/gtx/gradient_paint.hpp @@ -0,0 +1,53 @@ +/// @ref gtx_gradient_paint +/// @file glm/gtx/gradient_paint.hpp +/// +/// @see core (dependence) +/// @see gtx_optimum_pow (dependence) +/// +/// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions that return the color of procedural gradient for specific coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_gradient_paint is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_gradient_paint extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_gradient_paint + /// @{ + + /// Return a color from a radial gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T radialGradient( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position); + + /// Return a color from a linear gradient. + /// @see - gtx_gradient_paint + template + GLM_FUNC_DECL T linearGradient( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position); + + /// @} +}// namespace glm + +#include "gradient_paint.inl" diff --git a/thirdparty/glm/gtx/gradient_paint.inl b/thirdparty/glm/gtx/gradient_paint.inl new file mode 100644 index 0000000..4c495e6 --- /dev/null +++ b/thirdparty/glm/gtx/gradient_paint.inl @@ -0,0 +1,36 @@ +/// @ref gtx_gradient_paint + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T radialGradient + ( + vec<2, T, Q> const& Center, + T const& Radius, + vec<2, T, Q> const& Focal, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> F = Focal - Center; + vec<2, T, Q> D = Position - Focal; + T Radius2 = pow2(Radius); + T Fx2 = pow2(F.x); + T Fy2 = pow2(F.y); + + T Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x)); + T Denominator = Radius2 - (Fx2 + Fy2); + return Numerator / Denominator; + } + + template + GLM_FUNC_QUALIFIER T linearGradient + ( + vec<2, T, Q> const& Point0, + vec<2, T, Q> const& Point1, + vec<2, T, Q> const& Position + ) + { + vec<2, T, Q> Dist = Point1 - Point0; + return (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/handed_coordinate_space.hpp b/thirdparty/glm/gtx/handed_coordinate_space.hpp new file mode 100644 index 0000000..3c85968 --- /dev/null +++ b/thirdparty/glm/gtx/handed_coordinate_space.hpp @@ -0,0 +1,50 @@ +/// @ref gtx_handed_coordinate_space +/// @file glm/gtx/handed_coordinate_space.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// To know if a set of three basis vectors defines a right or left-handed coordinate system. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_handed_coordinate_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_handed_coordinate_space extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_handed_coordinate_space + /// @{ + + //! Return if a trihedron right handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool rightHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + //! Return if a trihedron left handed or not. + //! From GLM_GTX_handed_coordinate_space extension. + template + GLM_FUNC_DECL bool leftHanded( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal); + + /// @} +}// namespace glm + +#include "handed_coordinate_space.inl" diff --git a/thirdparty/glm/gtx/handed_coordinate_space.inl b/thirdparty/glm/gtx/handed_coordinate_space.inl new file mode 100644 index 0000000..e43c17b --- /dev/null +++ b/thirdparty/glm/gtx/handed_coordinate_space.inl @@ -0,0 +1,26 @@ +/// @ref gtx_handed_coordinate_space + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool rightHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) > T(0); + } + + template + GLM_FUNC_QUALIFIER bool leftHanded + ( + vec<3, T, Q> const& tangent, + vec<3, T, Q> const& binormal, + vec<3, T, Q> const& normal + ) + { + return dot(cross(normal, tangent), binormal) < T(0); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/hash.hpp b/thirdparty/glm/gtx/hash.hpp new file mode 100644 index 0000000..05dae9f --- /dev/null +++ b/thirdparty/glm/gtx/hash.hpp @@ -0,0 +1,142 @@ +/// @ref gtx_hash +/// @file glm/gtx/hash.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_hash GLM_GTX_hash +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add std::hash support for glm types + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_hash is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_hash extension included") +# endif +#endif + +#include + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../gtc/vec1.hpp" + +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +#include "../mat2x2.hpp" +#include "../mat2x3.hpp" +#include "../mat2x4.hpp" + +#include "../mat3x2.hpp" +#include "../mat3x3.hpp" +#include "../mat3x4.hpp" + +#include "../mat4x2.hpp" +#include "../mat4x3.hpp" +#include "../mat4x4.hpp" + +#if !GLM_HAS_CXX11_STL +# error "GLM_GTX_hash requires C++11 standard library support" +#endif + +namespace std +{ + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<1, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<2, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<3, T, Q> const& v) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::vec<4, T, Q> const& v) const; + }; + + template + struct hash> + { + GLM_FUNC_DECL size_t operator()(glm::qua const& q) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::tdualquat const& q) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<2, 4, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<3, 4, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 2, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 3, T,Q> const& m) const; + }; + + template + struct hash > + { + GLM_FUNC_DECL size_t operator()(glm::mat<4, 4, T,Q> const& m) const; + }; +} // namespace std + +#include "hash.inl" diff --git a/thirdparty/glm/gtx/hash.inl b/thirdparty/glm/gtx/hash.inl new file mode 100644 index 0000000..ff71ca9 --- /dev/null +++ b/thirdparty/glm/gtx/hash.inl @@ -0,0 +1,184 @@ +/// @ref gtx_hash +/// +/// @see core (dependence) +/// +/// @defgroup gtx_hash GLM_GTX_hash +/// @ingroup gtx +/// +/// @brief Add std::hash support for glm types +/// +/// need to be included to use the features of this extension. + +namespace glm { +namespace detail +{ + GLM_INLINE void hash_combine(size_t &seed, size_t hash) + { + hash += 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= hash; + } +}} + +namespace std +{ + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<1, T, Q> const& v) const + { + hash hasher; + return hasher(v.x); + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<2, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<3, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<4, T, Q> const& v) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(v.x)); + glm::detail::hash_combine(seed, hasher(v.y)); + glm::detail::hash_combine(seed, hasher(v.z)); + glm::detail::hash_combine(seed, hasher(v.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::qua const& q) const + { + size_t seed = 0; + hash hasher; + glm::detail::hash_combine(seed, hasher(q.x)); + glm::detail::hash_combine(seed, hasher(q.y)); + glm::detail::hash_combine(seed, hasher(q.z)); + glm::detail::hash_combine(seed, hasher(q.w)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::tdualquat const& q) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(q.real)); + glm::detail::hash_combine(seed, hasher(q.dual)); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 2, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 3, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 2, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 3, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 2, T,Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 3, T,Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } + + template + GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 4, T, Q> const& m) const + { + size_t seed = 0; + hash> hasher; + glm::detail::hash_combine(seed, hasher(m[0])); + glm::detail::hash_combine(seed, hasher(m[1])); + glm::detail::hash_combine(seed, hasher(m[2])); + glm::detail::hash_combine(seed, hasher(m[3])); + return seed; + } +} diff --git a/thirdparty/glm/gtx/integer.hpp b/thirdparty/glm/gtx/integer.hpp new file mode 100644 index 0000000..d0b4c61 --- /dev/null +++ b/thirdparty/glm/gtx/integer.hpp @@ -0,0 +1,76 @@ +/// @ref gtx_integer +/// @file glm/gtx/integer.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_integer GLM_GTX_integer +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add support for integer for core functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_integer is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_integer extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_integer + /// @{ + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int pow(int x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int sqrt(int x); + + //! Returns the floor log2 of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL unsigned int floor_log2(unsigned int x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL int mod(int x, int y); + + //! Return the factorial value of a number (!12 max, integer only) + //! From GLM_GTX_integer extension. + template + GLM_FUNC_DECL genType factorial(genType const& x); + + //! 32bit signed integer. + //! From GLM_GTX_integer extension. + typedef signed int sint; + + //! Returns x raised to the y power. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint pow(uint x, uint y); + + //! Returns the positive square root of x. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint sqrt(uint x); + + //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint mod(uint x, uint y); + + //! Returns the number of leading zeros. + //! From GLM_GTX_integer extension. + GLM_FUNC_DECL uint nlz(uint x); + + /// @} +}//namespace glm + +#include "integer.inl" diff --git a/thirdparty/glm/gtx/integer.inl b/thirdparty/glm/gtx/integer.inl new file mode 100644 index 0000000..956366b --- /dev/null +++ b/thirdparty/glm/gtx/integer.inl @@ -0,0 +1,185 @@ +/// @ref gtx_integer + +namespace glm +{ + // pow + GLM_FUNC_QUALIFIER int pow(int x, uint y) + { + if(y == 0) + return x >= 0 ? 1 : -1; + + int result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + // sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387 + GLM_FUNC_QUALIFIER int sqrt(int x) + { + if(x <= 1) return x; + + int NextTrial = x >> 1; + int CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + +// Henry Gordon Dietz: http://aggregate.org/MAGIC/ +namespace detail +{ + GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x) + { + /* 32-bit recursive reduction using SWAR... + but first step is mapping 2-bit values + into sum of 2 1-bit values in sneaky way + */ + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + return(x & 0x0000003f); + } +}//namespace detail + + // Henry Gordon Dietz: http://aggregate.org/MAGIC/ +/* + GLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + + return _detail::ones32(x) >> 1; + } +*/ + // mod + GLM_FUNC_QUALIFIER int mod(int x, int y) + { + return ((x % y) + y) % y; + } + + // factorial (!12 max, integer only) + template + GLM_FUNC_QUALIFIER genType factorial(genType const& x) + { + genType Temp = x; + genType Result; + for(Result = 1; Temp > 1; --Temp) + Result *= Temp; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> factorial( + vec<2, T, Q> const& x) + { + return vec<2, T, Q>( + factorial(x.x), + factorial(x.y)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> factorial( + vec<3, T, Q> const& x) + { + return vec<3, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z)); + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> factorial( + vec<4, T, Q> const& x) + { + return vec<4, T, Q>( + factorial(x.x), + factorial(x.y), + factorial(x.z), + factorial(x.w)); + } + + GLM_FUNC_QUALIFIER uint pow(uint x, uint y) + { + if (y == 0) + return 1u; + + uint result = x; + for(uint i = 1; i < y; ++i) + result *= x; + return result; + } + + GLM_FUNC_QUALIFIER uint sqrt(uint x) + { + if(x <= 1) return x; + + uint NextTrial = x >> 1; + uint CurrentAnswer; + + do + { + CurrentAnswer = NextTrial; + NextTrial = (NextTrial + x / NextTrial) >> 1; + } while(NextTrial < CurrentAnswer); + + return CurrentAnswer; + } + + GLM_FUNC_QUALIFIER uint mod(uint x, uint y) + { + return x - y * (x / y); + } + +#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) + + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + return 31u - findMSB(x); + } + +#else + + // Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt + GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) + { + int y, m, n; + + y = -int(x >> 16); // If left half of x is 0, + m = (y >> 16) & 16; // set n = 16. If left half + n = 16 - m; // is nonzero, set n = 0 and + x = x >> m; // shift x right 16. + // Now x is of the form 0000xxxx. + y = x - 0x100; // If positions 8-15 are 0, + m = (y >> 16) & 8; // add 8 to n and shift x left 8. + n = n + m; + x = x << m; + + y = x - 0x1000; // If positions 12-15 are 0, + m = (y >> 16) & 4; // add 4 to n and shift x left 4. + n = n + m; + x = x << m; + + y = x - 0x4000; // If positions 14-15 are 0, + m = (y >> 16) & 2; // add 2 to n and shift x left 2. + n = n + m; + x = x << m; + + y = x >> 14; // Set y = 0, 1, 2, or 3. + m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. + return unsigned(n + 2 - m); + } + +#endif//(GLM_COMPILER) + +}//namespace glm diff --git a/thirdparty/glm/gtx/intersect.hpp b/thirdparty/glm/gtx/intersect.hpp new file mode 100644 index 0000000..3c78f2b --- /dev/null +++ b/thirdparty/glm/gtx/intersect.hpp @@ -0,0 +1,92 @@ +/// @ref gtx_intersect +/// @file glm/gtx/intersect.hpp +/// +/// @see core (dependence) +/// @see gtx_closest_point (dependence) +/// +/// @defgroup gtx_intersect GLM_GTX_intersect +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add intersection functions + +#pragma once + +// Dependency: +#include +#include +#include "../glm.hpp" +#include "../geometric.hpp" +#include "../gtx/closest_point.hpp" +#include "../gtx/vector_query.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_closest_point extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_intersect + /// @{ + + //! Compute the intersection of a ray and a plane. + //! Ray direction and plane normal must be unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayPlane( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a triangle. + /// Based om Tomas Möller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/ + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRayTriangle( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, + vec<2, T, Q>& baryPosition, T& distance); + + //! Compute the intersection of a line and a triangle. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectLineTriangle( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position); + + //! Compute the intersection distance of a ray and a sphere. + //! The ray direction vector is unit length. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, typename genType::value_type const sphereRadiusSquered, + typename genType::value_type & intersectionDistance); + + //! Compute the intersection of a ray and a sphere. + //! From GLM_GTX_intersect extension. + template + GLM_FUNC_DECL bool intersectRaySphere( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal); + + //! Compute the intersection of a line and a sphere. + //! From GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool intersectLineSphere( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPosition1, genType & intersectionNormal1, + genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType()); + + /// @} +}//namespace glm + +#include "intersect.inl" diff --git a/thirdparty/glm/gtx/intersect.inl b/thirdparty/glm/gtx/intersect.inl new file mode 100644 index 0000000..54ecb4d --- /dev/null +++ b/thirdparty/glm/gtx/intersect.inl @@ -0,0 +1,200 @@ +/// @ref gtx_intersect + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool intersectRayPlane + ( + genType const& orig, genType const& dir, + genType const& planeOrig, genType const& planeNormal, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type d = glm::dot(dir, planeNormal); + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + if(glm::abs(d) > Epsilon) // if dir and planeNormal are not perpendicular + { + typename genType::value_type const tmp_intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d; + if (tmp_intersectionDistance > static_cast(0)) { // allow only intersections + intersectionDistance = tmp_intersectionDistance; + return true; + } + } + + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectRayTriangle + ( + vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, + vec<3, T, Q> const& vert0, vec<3, T, Q> const& vert1, vec<3, T, Q> const& vert2, + vec<2, T, Q>& baryPosition, T& distance + ) + { + // find vectors for two edges sharing vert0 + vec<3, T, Q> const edge1 = vert1 - vert0; + vec<3, T, Q> const edge2 = vert2 - vert0; + + // begin calculating determinant - also used to calculate U parameter + vec<3, T, Q> const p = glm::cross(dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + T const det = glm::dot(edge1, p); + + vec<3, T, Q> Perpendicular(0); + + if(det > std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if(baryPosition.x < static_cast(0) || baryPosition.x > det) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y < static_cast(0)) || ((baryPosition.x + baryPosition.y) > det)) + return false; + } + else if(det < -std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + vec<3, T, Q> const dist = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(dist, p); + if((baryPosition.x > static_cast(0)) || (baryPosition.x < det)) + return false; + + // prepare to test V parameter + Perpendicular = glm::cross(dist, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, Perpendicular); + if((baryPosition.y > static_cast(0)) || (baryPosition.x + baryPosition.y < det)) + return false; + } + else + return false; // ray is parallel to the plane of the triangle + + T inv_det = static_cast(1) / det; + + // calculate distance, ray intersects triangle + distance = glm::dot(edge2, Perpendicular) * inv_det; + baryPosition *= inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineTriangle + ( + genType const& orig, genType const& dir, + genType const& vert0, genType const& vert1, genType const& vert2, + genType & position + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + + genType edge1 = vert1 - vert0; + genType edge2 = vert2 - vert0; + + genType Perpendicular = cross(dir, edge2); + + float det = dot(edge1, Perpendicular); + + if (det > -Epsilon && det < Epsilon) + return false; + typename genType::value_type inv_det = typename genType::value_type(1) / det; + + genType Tengant = orig - vert0; + + position.y = dot(Tengant, Perpendicular) * inv_det; + if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1)) + return false; + + genType Cotengant = cross(Tengant, edge1); + + position.z = dot(dir, Cotengant) * inv_det; + if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1)) + return false; + + position.x = dot(edge2, Cotengant) * inv_det; + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadiusSquered, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType diff = sphereCenter - rayStarting; + typename genType::value_type t0 = dot(diff, rayNormalizedDirection); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadiusSquered ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared ); + intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1; + return intersectionDistance > Epsilon; + } + + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const& rayStarting, genType const& rayNormalizedDirection, + genType const& sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal + ) + { + typename genType::value_type distance; + if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) ) + { + intersectionPosition = rayStarting + rayNormalizedDirection * distance; + intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius; + return true; + } + return false; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineSphere + ( + genType const& point0, genType const& point1, + genType const& sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPoint1, genType & intersectionNormal1, + genType & intersectionPoint2, genType & intersectionNormal2 + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType dir = normalize(point1 - point0); + genType diff = sphereCenter - point0; + typename genType::value_type t0 = dot(diff, dir); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadius * sphereRadius ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared ); + if( t0 < t1 + Epsilon ) + t1 = -t1; + intersectionPoint1 = point0 + dir * (t0 - t1); + intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius; + intersectionPoint2 = point0 + dir * (t0 + t1); + intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius; + return true; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/io.hpp b/thirdparty/glm/gtx/io.hpp new file mode 100644 index 0000000..8d974f0 --- /dev/null +++ b/thirdparty/glm/gtx/io.hpp @@ -0,0 +1,201 @@ +/// @ref gtx_io +/// @file glm/gtx/io.hpp +/// @author Jan P Springer (regnirpsj@gmail.com) +/// +/// @see core (dependence) +/// @see gtc_matrix_access (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_io GLM_GTX_io +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// std::[w]ostream support for glm types +/// +/// std::[w]ostream support for glm types + qualifier/width/etc. manipulators +/// based on howard hinnant's std::chrono io proposal +/// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html] + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_io is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_io extension included") +# endif +#endif + +#include // std::basic_ostream<> (fwd) +#include // std::locale, std::locale::facet, std::locale::id +#include // std::pair<> + +namespace glm +{ + /// @addtogroup gtx_io + /// @{ + + namespace io + { + enum order_type { column_major, row_major}; + + template + class format_punct : public std::locale::facet + { + typedef CTy char_type; + + public: + + static std::locale::id id; + + bool formatted; + unsigned precision; + unsigned width; + char_type separator; + char_type delim_left; + char_type delim_right; + char_type space; + char_type newline; + order_type order; + + GLM_FUNC_DECL explicit format_punct(size_t a = 0); + GLM_FUNC_DECL explicit format_punct(format_punct const&); + }; + + template > + class basic_state_saver { + + public: + + GLM_FUNC_DECL explicit basic_state_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_state_saver(); + + private: + + typedef ::std::basic_ios state_type; + typedef typename state_type::char_type char_type; + typedef ::std::ios_base::fmtflags flags_type; + typedef ::std::streamsize streamsize_type; + typedef ::std::locale const locale_type; + + state_type& state_; + flags_type flags_; + streamsize_type precision_; + streamsize_type width_; + char_type fill_; + locale_type locale_; + + GLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&); + }; + + typedef basic_state_saver state_saver; + typedef basic_state_saver wstate_saver; + + template > + class basic_format_saver + { + public: + + GLM_FUNC_DECL explicit basic_format_saver(std::basic_ios&); + GLM_FUNC_DECL ~basic_format_saver(); + + private: + + basic_state_saver const bss_; + + GLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&); + }; + + typedef basic_format_saver format_saver; + typedef basic_format_saver wformat_saver; + + struct precision + { + unsigned value; + + GLM_FUNC_DECL explicit precision(unsigned); + }; + + struct width + { + unsigned value; + + GLM_FUNC_DECL explicit width(unsigned); + }; + + template + struct delimeter + { + CTy value[3]; + + GLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ','); + }; + + struct order + { + order_type value; + + GLM_FUNC_DECL explicit order(order_type); + }; + + // functions, inlined (inline) + + template + FTy const& get_facet(std::basic_ios&); + template + std::basic_ios& formatted(std::basic_ios&); + template + std::basic_ios& unformattet(std::basic_ios&); + + template + std::basic_ostream& operator<<(std::basic_ostream&, precision const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, width const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, delimeter const&); + template + std::basic_ostream& operator<<(std::basic_ostream&, order const&); + }//namespace io + + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, qua const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<1, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 4, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 2, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 3, T, Q> const&); + template + GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 4, T, Q> const&); + + template + GLM_FUNC_DECL std::basic_ostream & operator<<(std::basic_ostream &, + std::pair const, mat<4, 4, T, Q> const> const&); + + /// @} +}//namespace glm + +#include "io.inl" diff --git a/thirdparty/glm/gtx/io.inl b/thirdparty/glm/gtx/io.inl new file mode 100644 index 0000000..a3a1bb6 --- /dev/null +++ b/thirdparty/glm/gtx/io.inl @@ -0,0 +1,440 @@ +/// @ref gtx_io +/// @author Jan P Springer (regnirpsj@gmail.com) + +#include // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw +#include // std::basic_ostream<> +#include "../gtc/matrix_access.hpp" // glm::col, glm::row +#include "../gtx/type_trait.hpp" // glm::type<> + +namespace glm{ +namespace io +{ + template + GLM_FUNC_QUALIFIER format_punct::format_punct(size_t a) + : std::locale::facet(a) + , formatted(true) + , precision(3) + , width(1 + 4 + 1 + precision) + , separator(',') + , delim_left('[') + , delim_right(']') + , space(' ') + , newline('\n') + , order(column_major) + {} + + template + GLM_FUNC_QUALIFIER format_punct::format_punct(format_punct const& a) + : std::locale::facet(0) + , formatted(a.formatted) + , precision(a.precision) + , width(a.width) + , separator(a.separator) + , delim_left(a.delim_left) + , delim_right(a.delim_right) + , space(a.space) + , newline(a.newline) + , order(a.order) + {} + + template std::locale::id format_punct::id; + + template + GLM_FUNC_QUALIFIER basic_state_saver::basic_state_saver(std::basic_ios& a) + : state_(a) + , flags_(a.flags()) + , precision_(a.precision()) + , width_(a.width()) + , fill_(a.fill()) + , locale_(a.getloc()) + {} + + template + GLM_FUNC_QUALIFIER basic_state_saver::~basic_state_saver() + { + state_.imbue(locale_); + state_.fill(fill_); + state_.width(width_); + state_.precision(precision_); + state_.flags(flags_); + } + + template + GLM_FUNC_QUALIFIER basic_format_saver::basic_format_saver(std::basic_ios& a) + : bss_(a) + { + a.imbue(std::locale(a.getloc(), new format_punct(get_facet >(a)))); + } + + template + GLM_FUNC_QUALIFIER + basic_format_saver::~basic_format_saver() + {} + + GLM_FUNC_QUALIFIER precision::precision(unsigned a) + : value(a) + {} + + GLM_FUNC_QUALIFIER width::width(unsigned a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER delimeter::delimeter(CTy a, CTy b, CTy c) + : value() + { + value[0] = a; + value[1] = b; + value[2] = c; + } + + GLM_FUNC_QUALIFIER order::order(order_type a) + : value(a) + {} + + template + GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios& ios) + { + if(!std::has_facet(ios.getloc())) + ios.imbue(std::locale(ios.getloc(), new FTy)); + + return std::use_facet(ios.getloc()); + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& formatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = true; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ios& unformatted(std::basic_ios& ios) + { + const_cast&>(get_facet >(ios)).formatted = false; + return ios; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, precision const& a) + { + const_cast&>(get_facet >(os)).precision = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, width const& a) + { + const_cast&>(get_facet >(os)).width = a.value; + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, delimeter const& a) + { + format_punct & fmt(const_cast&>(get_facet >(os))); + + fmt.delim_left = a.value[0]; + fmt.delim_right = a.value[1]; + fmt.separator = a.value[2]; + + return os; + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, order const& a) + { + const_cast&>(get_facet >(os)).order = a.value; + return os; + } +} // namespace io + +namespace detail +{ + template + GLM_FUNC_QUALIFIER std::basic_ostream& + print_vector_on(std::basic_ostream& os, V const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& components(type::components); + + if(fmt.formatted) + { + io::basic_state_saver const bss(os); + + os << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left; + + for(length_t i(0); i < components; ++i) + { + os << std::setw(fmt.width) << a[i]; + if(components-1 != i) + os << fmt.separator; + } + + os << fmt.delim_right; + } + else + { + for(length_t i(0); i < components; ++i) + { + os << a[i]; + + if(components-1 != i) + os << fmt.space; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, qua const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<1, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<2, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<3, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<4, T, Q> const& a) + { + return detail::print_vector_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_on(std::basic_ostream& os, M const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if (0 != i) + os << fmt.space; + + os << row(a, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(a, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + switch (fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < cols; ++i) + { + os << column(a, i); + + if(cols - 1 != i) + os << fmt.space; + } + } + break; + + case io::row_major: + { + for (length_t i(0); i < rows; ++i) + { + os << row(a, i); + + if (rows-1 != i) + os << fmt.space; + } + } + break; + } + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<3, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 2, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 3, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + + template + GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 4, T, Q> const& a) + { + return detail::print_matrix_on(os, a); + } + +namespace detail +{ + template class M, length_t C, length_t R, typename T, qualifier Q> + GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_pair_on(std::basic_ostream& os, std::pair const, M const> const& a) + { + typename std::basic_ostream::sentry const cerberus(os); + + if(cerberus) + { + io::format_punct const& fmt(io::get_facet >(os)); + M const& ml(a.first); + M const& mr(a.second); + length_t const& cols(type >::cols); + length_t const& rows(type >::rows); + + if(fmt.formatted) + { + os << fmt.newline << fmt.delim_left; + + switch(fmt.order) + { + case io::column_major: + { + for(length_t i(0); i < rows; ++i) + { + if(0 != i) + os << fmt.space; + + os << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i); + + if(rows-1 != i) + os << fmt.newline; + } + } + break; + case io::row_major: + { + for(length_t i(0); i < cols; ++i) + { + if(0 != i) + os << fmt.space; + + os << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i); + + if(cols-1 != i) + os << fmt.newline; + } + } + break; + } + + os << fmt.delim_right; + } + else + { + os << ml << fmt.space << mr; + } + } + + return os; + } +}//namespace detail + + template + GLM_FUNC_QUALIFIER std::basic_ostream& operator<<( + std::basic_ostream & os, + std::pair const, + mat<4, 4, T, Q> const> const& a) + { + return detail::print_matrix_pair_on(os, a); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/log_base.hpp b/thirdparty/glm/gtx/log_base.hpp new file mode 100644 index 0000000..ba28c9d --- /dev/null +++ b/thirdparty/glm/gtx/log_base.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_log_base +/// @file glm/gtx/log_base.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_log_base GLM_GTX_log_base +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Logarithm for any base. base can be a vector or a scalar. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_log_base is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_log_base extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_log_base + /// @{ + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL genType log( + genType const& x, + genType const& base); + + /// Logarithm for any base. + /// From GLM_GTX_log_base. + template + GLM_FUNC_DECL vec sign( + vec const& x, + vec const& base); + + /// @} +}//namespace glm + +#include "log_base.inl" diff --git a/thirdparty/glm/gtx/log_base.inl b/thirdparty/glm/gtx/log_base.inl new file mode 100644 index 0000000..4bbb8e8 --- /dev/null +++ b/thirdparty/glm/gtx/log_base.inl @@ -0,0 +1,16 @@ +/// @ref gtx_log_base + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType log(genType const& x, genType const& base) + { + return glm::log(x) / glm::log(base); + } + + template + GLM_FUNC_QUALIFIER vec log(vec const& x, vec const& base) + { + return glm::log(x) / glm::log(base); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_cross_product.hpp b/thirdparty/glm/gtx/matrix_cross_product.hpp new file mode 100644 index 0000000..1e585f9 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_cross_product.hpp @@ -0,0 +1,47 @@ +/// @ref gtx_matrix_cross_product +/// @file glm/gtx/matrix_cross_product.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build cross product matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_cross_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_cross_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_cross_product + /// @{ + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> matrixCross3( + vec<3, T, Q> const& x); + + //! Build a cross product matrix. + //! From GLM_GTX_matrix_cross_product extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> matrixCross4( + vec<3, T, Q> const& x); + + /// @} +}//namespace glm + +#include "matrix_cross_product.inl" diff --git a/thirdparty/glm/gtx/matrix_cross_product.inl b/thirdparty/glm/gtx/matrix_cross_product.inl new file mode 100644 index 0000000..3a15397 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_cross_product.inl @@ -0,0 +1,37 @@ +/// @ref gtx_matrix_cross_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> matrixCross3 + ( + vec<3, T, Q> const& x + ) + { + mat<3, 3, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> matrixCross4 + ( + vec<3, T, Q> const& x + ) + { + mat<4, 4, T, Q> Result(T(0)); + Result[0][1] = x.z; + Result[1][0] = -x.z; + Result[0][2] = -x.y; + Result[2][0] = x.y; + Result[1][2] = x.x; + Result[2][1] = -x.x; + return Result; + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_decompose.hpp b/thirdparty/glm/gtx/matrix_decompose.hpp new file mode 100644 index 0000000..acd7a7f --- /dev/null +++ b/thirdparty/glm/gtx/matrix_decompose.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_matrix_decompose +/// @file glm/gtx/matrix_decompose.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Decomposes a model matrix to translations, rotation and scale components + +#pragma once + +// Dependencies +#include "../mat4x4.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../geometric.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_decompose is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_decompose extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_decompose + /// @{ + + /// Decomposes a model matrix to translations, rotation and scale components + /// @see gtx_matrix_decompose + template + GLM_FUNC_DECL bool decompose( + mat<4, 4, T, Q> const& modelMatrix, + vec<3, T, Q> & scale, qua & orientation, vec<3, T, Q> & translation, vec<3, T, Q> & skew, vec<4, T, Q> & perspective); + + /// @} +}//namespace glm + +#include "matrix_decompose.inl" diff --git a/thirdparty/glm/gtx/matrix_decompose.inl b/thirdparty/glm/gtx/matrix_decompose.inl new file mode 100644 index 0000000..694f5ec --- /dev/null +++ b/thirdparty/glm/gtx/matrix_decompose.inl @@ -0,0 +1,186 @@ +/// @ref gtx_matrix_decompose + +#include "../gtc/constants.hpp" +#include "../gtc/epsilon.hpp" + +namespace glm{ +namespace detail +{ + /// Make a linear combination of two vectors and return the result. + // result = (a * ascl) + (b * bscl) + template + GLM_FUNC_QUALIFIER vec<3, T, Q> combine( + vec<3, T, Q> const& a, + vec<3, T, Q> const& b, + T ascl, T bscl) + { + return (a * ascl) + (b * bscl); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength) + { + return v * desiredLength / length(v); + } +}//namespace detail + + // Matrix decompose + // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp + // Decomposes the mode matrix to translations,rotation scale components + + template + GLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective) + { + mat<4, 4, T, Q> LocalMatrix(ModelMatrix); + + // Normalize the matrix. + if(epsilonEqual(LocalMatrix[3][3], static_cast(0), epsilon())) + return false; + + for(length_t i = 0; i < 4; ++i) + for(length_t j = 0; j < 4; ++j) + LocalMatrix[i][j] /= LocalMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix); + + for(length_t i = 0; i < 3; i++) + PerspectiveMatrix[i][3] = static_cast(0); + PerspectiveMatrix[3][3] = static_cast(1); + + /// TODO: Fixme! + if(epsilonEqual(determinant(PerspectiveMatrix), static_cast(0), epsilon())) + return false; + + // First, isolate perspective. This is the messiest. + if( + epsilonNotEqual(LocalMatrix[0][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[1][3], static_cast(0), epsilon()) || + epsilonNotEqual(LocalMatrix[2][3], static_cast(0), epsilon())) + { + // rightHandSide is the right hand side of the equation. + vec<4, T, Q> RightHandSide; + RightHandSide[0] = LocalMatrix[0][3]; + RightHandSide[1] = LocalMatrix[1][3]; + RightHandSide[2] = LocalMatrix[2][3]; + RightHandSide[3] = LocalMatrix[3][3]; + + // Solve the equation by inverting PerspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + mat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix); + mat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Perspective = TransposedInversePerspectiveMatrix * RightHandSide; + // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + // Clear the perspective partition + LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast(0); + LocalMatrix[3][3] = static_cast(1); + } + else + { + // No perspective. + Perspective = vec<4, T, Q>(0, 0, 0, 1); + } + + // Next take care of translation (easy). + Translation = vec<3, T, Q>(LocalMatrix[3]); + LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w); + + vec<3, T, Q> Row[3], Pdum3; + + // Now get scale and shear. + for(length_t i = 0; i < 3; ++i) + for(length_t j = 0; j < 3; ++j) + Row[i][j] = LocalMatrix[i][j]; + + // Compute X scale factor and normalize first row. + Scale.x = length(Row[0]);// v3Length(Row[0]); + + Row[0] = detail::scale(Row[0], static_cast(1)); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + Skew.z = dot(Row[0], Row[1]); + Row[1] = detail::combine(Row[1], Row[0], static_cast(1), -Skew.z); + + // Now, compute Y scale and normalize 2nd row. + Scale.y = length(Row[1]); + Row[1] = detail::scale(Row[1], static_cast(1)); + Skew.z /= Scale.y; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + Skew.y = glm::dot(Row[0], Row[2]); + Row[2] = detail::combine(Row[2], Row[0], static_cast(1), -Skew.y); + Skew.x = glm::dot(Row[1], Row[2]); + Row[2] = detail::combine(Row[2], Row[1], static_cast(1), -Skew.x); + + // Next, get Z scale and normalize 3rd row. + Scale.z = length(Row[2]); + Row[2] = detail::scale(Row[2], static_cast(1)); + Skew.y /= Scale.z; + Skew.x /= Scale.z; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3); + if(dot(Row[0], Pdum3) < 0) + { + for(length_t i = 0; i < 3; i++) + { + Scale[i] *= static_cast(-1); + Row[i] *= static_cast(-1); + } + } + + // Now, get the rotations out, as described in the gem. + + // FIXME - Add the ability to return either quaternions (which are + // easier to recompose with) or Euler angles (rx, ry, rz), which + // are easier for authors to deal with. The latter will only be useful + // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I + // will leave the Euler angle code here for now. + + // ret.rotateY = asin(-Row[0][2]); + // if (cos(ret.rotateY) != 0) { + // ret.rotateX = atan2(Row[1][2], Row[2][2]); + // ret.rotateZ = atan2(Row[0][1], Row[0][0]); + // } else { + // ret.rotateX = atan2(-Row[2][0], Row[1][1]); + // ret.rotateZ = 0; + // } + + int i, j, k = 0; + T root, trace = Row[0].x + Row[1].y + Row[2].z; + if(trace > static_cast(0)) + { + root = sqrt(trace + static_cast(1.0)); + Orientation.w = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation.x = root * (Row[1].z - Row[2].y); + Orientation.y = root * (Row[2].x - Row[0].z); + Orientation.z = root * (Row[0].y - Row[1].x); + } // End if > 0 + else + { + static int Next[3] = {1, 2, 0}; + i = 0; + if(Row[1].y > Row[0].x) i = 1; + if(Row[2].z > Row[i][i]) i = 2; + j = Next[i]; + k = Next[j]; + + root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast(1.0)); + + Orientation[i] = static_cast(0.5) * root; + root = static_cast(0.5) / root; + Orientation[j] = root * (Row[i][j] + Row[j][i]); + Orientation[k] = root * (Row[i][k] + Row[k][i]); + Orientation.w = root * (Row[j][k] - Row[k][j]); + } // End if <= 0 + + return true; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_factorisation.hpp b/thirdparty/glm/gtx/matrix_factorisation.hpp new file mode 100644 index 0000000..5a975d6 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_factorisation.hpp @@ -0,0 +1,69 @@ +/// @ref gtx_matrix_factorisation +/// @file glm/gtx/matrix_factorisation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_factorisation GLM_GTX_matrix_factorisation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to factor matrices in various forms + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_factorisation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_factorisation extension included") +# endif +#endif + +/* +Suggestions: + - Move helper functions flipud and fliplr to another file: They may be helpful in more general circumstances. + - Implement other types of matrix factorisation, such as: QL and LQ, L(D)U, eigendecompositions, etc... +*/ + +namespace glm +{ + /// @addtogroup gtx_matrix_factorisation + /// @{ + + /// Flips the matrix rows up and down. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat flipud(mat const& in); + + /// Flips the matrix columns right and left. + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL mat fliplr(mat const& in); + + /// Performs QR factorisation of a matrix. + /// Returns 2 matrices, q and r, such that the columns of q are orthonormal and span the same subspace than those of the input matrix, r is an upper triangular matrix, and q*r=in. + /// Given an n-by-m input matrix, q has dimensions min(n,m)-by-m, and r has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r); + + /// Performs RQ factorisation of a matrix. + /// Returns 2 matrices, r and q, such that r is an upper triangular matrix, the rows of q are orthonormal and span the same subspace than those of the input matrix, and r*q=in. + /// Note that in the context of RQ factorisation, the diagonal is seen as starting in the lower-right corner of the matrix, instead of the usual upper-left. + /// Given an n-by-m input matrix, r has dimensions min(n,m)-by-m, and q has dimensions n-by-min(n,m). + /// + /// From GLM_GTX_matrix_factorisation extension. + template + GLM_FUNC_DECL void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q); + + /// @} +} + +#include "matrix_factorisation.inl" diff --git a/thirdparty/glm/gtx/matrix_factorisation.inl b/thirdparty/glm/gtx/matrix_factorisation.inl new file mode 100644 index 0000000..c479b8a --- /dev/null +++ b/thirdparty/glm/gtx/matrix_factorisation.inl @@ -0,0 +1,84 @@ +/// @ref gtx_matrix_factorisation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat flipud(mat const& in) + { + mat tin = transpose(in); + tin = fliplr(tin); + mat out = transpose(tin); + + return out; + } + + template + GLM_FUNC_QUALIFIER mat fliplr(mat const& in) + { + mat out; + for (length_t i = 0; i < C; i++) + { + out[i] = in[(C - i) - 1]; + } + + return out; + } + + template + GLM_FUNC_QUALIFIER void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r) + { + // Uses modified Gram-Schmidt method + // Source: https://en.wikipedia.org/wiki/Gram–Schmidt_process + // And https://en.wikipedia.org/wiki/QR_decomposition + + //For all the linearly independs columns of the input... + // (there can be no more linearly independents columns than there are rows.) + for (length_t i = 0; i < (C < R ? C : R); i++) + { + //Copy in Q the input's i-th column. + q[i] = in[i]; + + //j = [0,i[ + // Make that column orthogonal to all the previous ones by substracting to it the non-orthogonal projection of all the previous columns. + // Also: Fill the zero elements of R + for (length_t j = 0; j < i; j++) + { + q[i] -= dot(q[i], q[j])*q[j]; + r[j][i] = 0; + } + + //Now, Q i-th column is orthogonal to all the previous columns. Normalize it. + q[i] = normalize(q[i]); + + //j = [i,C[ + //Finally, compute the corresponding coefficients of R by computing the projection of the resulting column on the other columns of the input. + for (length_t j = i; j < C; j++) + { + r[j][i] = dot(in[j], q[i]); + } + } + } + + template + GLM_FUNC_QUALIFIER void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q) + { + // From https://en.wikipedia.org/wiki/QR_decomposition: + // The RQ decomposition transforms a matrix A into the product of an upper triangular matrix R (also known as right-triangular) and an orthogonal matrix Q. The only difference from QR decomposition is the order of these matrices. + // QR decomposition is Gram–Schmidt orthogonalization of columns of A, started from the first column. + // RQ decomposition is Gram–Schmidt orthogonalization of rows of A, started from the last row. + + mat tin = transpose(in); + tin = fliplr(tin); + + mat tr; + mat<(C < R ? C : R), C, T, Q> tq; + qr_decompose(tin, tq, tr); + + tr = fliplr(tr); + r = transpose(tr); + r = fliplr(r); + + tq = fliplr(tq); + q = transpose(tq); + } +} //namespace glm diff --git a/thirdparty/glm/gtx/matrix_interpolation.hpp b/thirdparty/glm/gtx/matrix_interpolation.hpp new file mode 100644 index 0000000..7d5ad4c --- /dev/null +++ b/thirdparty/glm/gtx/matrix_interpolation.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_matrix_interpolation +/// @file glm/gtx/matrix_interpolation.hpp +/// @author Ghenadii Ursachi (the.asteroth@gmail.com) +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Allows to directly interpolate two matrices. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_interpolation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_interpolation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_interpolation + /// @{ + + /// Get the axis and angle of the rotation from a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL void axisAngle( + mat<4, 4, T, Q> const& Mat, vec<3, T, Q> & Axis, T & Angle); + + /// Build a matrix from axis and angle. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> axisAngleMatrix( + vec<3, T, Q> const& Axis, T const Angle); + + /// Extracts the rotation part of a matrix. + /// From GLM_GTX_matrix_interpolation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> extractMatrixRotation( + mat<4, 4, T, Q> const& Mat); + + /// Build a interpolation of 4 * 4 matrixes. + /// From GLM_GTX_matrix_interpolation extension. + /// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results. + template + GLM_FUNC_DECL mat<4, 4, T, Q> interpolate( + mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const Delta); + + /// @} +}//namespace glm + +#include "matrix_interpolation.inl" diff --git a/thirdparty/glm/gtx/matrix_interpolation.inl b/thirdparty/glm/gtx/matrix_interpolation.inl new file mode 100644 index 0000000..de40b7d --- /dev/null +++ b/thirdparty/glm/gtx/matrix_interpolation.inl @@ -0,0 +1,129 @@ +/// @ref gtx_matrix_interpolation + +#include "../gtc/constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER void axisAngle(mat<4, 4, T, Q> const& m, vec<3, T, Q> & axis, T& angle) + { + T epsilon = static_cast(0.01); + T epsilon2 = static_cast(0.1); + + if((abs(m[1][0] - m[0][1]) < epsilon) && (abs(m[2][0] - m[0][2]) < epsilon) && (abs(m[2][1] - m[1][2]) < epsilon)) + { + if ((abs(m[1][0] + m[0][1]) < epsilon2) && (abs(m[2][0] + m[0][2]) < epsilon2) && (abs(m[2][1] + m[1][2]) < epsilon2) && (abs(m[0][0] + m[1][1] + m[2][2] - static_cast(3.0)) < epsilon2)) + { + angle = static_cast(0.0); + axis.x = static_cast(1.0); + axis.y = static_cast(0.0); + axis.z = static_cast(0.0); + return; + } + angle = static_cast(3.1415926535897932384626433832795); + T xx = (m[0][0] + static_cast(1.0)) * static_cast(0.5); + T yy = (m[1][1] + static_cast(1.0)) * static_cast(0.5); + T zz = (m[2][2] + static_cast(1.0)) * static_cast(0.5); + T xy = (m[1][0] + m[0][1]) * static_cast(0.25); + T xz = (m[2][0] + m[0][2]) * static_cast(0.25); + T yz = (m[2][1] + m[1][2]) * static_cast(0.25); + if((xx > yy) && (xx > zz)) + { + if(xx < epsilon) + { + axis.x = static_cast(0.0); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.7071); + } + else + { + axis.x = sqrt(xx); + axis.y = xy / axis.x; + axis.z = xz / axis.x; + } + } + else if (yy > zz) + { + if(yy < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.0); + axis.z = static_cast(0.7071); + } + else + { + axis.y = sqrt(yy); + axis.x = xy / axis.y; + axis.z = yz / axis.y; + } + } + else + { + if (zz < epsilon) + { + axis.x = static_cast(0.7071); + axis.y = static_cast(0.7071); + axis.z = static_cast(0.0); + } + else + { + axis.z = sqrt(zz); + axis.x = xz / axis.z; + axis.y = yz / axis.z; + } + } + return; + } + T s = sqrt((m[2][1] - m[1][2]) * (m[2][1] - m[1][2]) + (m[2][0] - m[0][2]) * (m[2][0] - m[0][2]) + (m[1][0] - m[0][1]) * (m[1][0] - m[0][1])); + if (glm::abs(s) < T(0.001)) + s = static_cast(1); + T const angleCos = (m[0][0] + m[1][1] + m[2][2] - static_cast(1)) * static_cast(0.5); + if(angleCos - static_cast(1) < epsilon) + angle = pi() * static_cast(0.25); + else + angle = acos(angleCos); + axis.x = (m[1][2] - m[2][1]) / s; + axis.y = (m[2][0] - m[0][2]) / s; + axis.z = (m[0][1] - m[1][0]) / s; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> axisAngleMatrix(vec<3, T, Q> const& axis, T const angle) + { + T c = cos(angle); + T s = sin(angle); + T t = static_cast(1) - c; + vec<3, T, Q> n = normalize(axis); + + return mat<4, 4, T, Q>( + t * n.x * n.x + c, t * n.x * n.y + n.z * s, t * n.x * n.z - n.y * s, static_cast(0.0), + t * n.x * n.y - n.z * s, t * n.y * n.y + c, t * n.y * n.z + n.x * s, static_cast(0.0), + t * n.x * n.z + n.y * s, t * n.y * n.z - n.x * s, t * n.z * n.z + c, static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> extractMatrixRotation(mat<4, 4, T, Q> const& m) + { + return mat<4, 4, T, Q>( + m[0][0], m[0][1], m[0][2], static_cast(0.0), + m[1][0], m[1][1], m[1][2], static_cast(0.0), + m[2][0], m[2][1], m[2][2], static_cast(0.0), + static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> interpolate(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const delta) + { + mat<4, 4, T, Q> m1rot = extractMatrixRotation(m1); + mat<4, 4, T, Q> dltRotation = m2 * transpose(m1rot); + vec<3, T, Q> dltAxis; + T dltAngle; + axisAngle(dltRotation, dltAxis, dltAngle); + mat<4, 4, T, Q> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot; + out[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]); + out[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]); + out[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]); + return out; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_major_storage.hpp b/thirdparty/glm/gtx/matrix_major_storage.hpp new file mode 100644 index 0000000..8c6bc22 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_major_storage.hpp @@ -0,0 +1,119 @@ +/// @ref gtx_matrix_major_storage +/// @file glm/gtx/matrix_major_storage.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build matrices with specific matrix order, row or column + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_major_storage is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_major_storage extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_major_storage + /// @{ + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a row major matrix from row vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a row major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( + mat<4, 4, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( + mat<2, 2, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( + mat<3, 3, T, Q> const& m); + + //! Build a column major matrix from column vectors. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + vec<4, T, Q> const& v1, + vec<4, T, Q> const& v2, + vec<4, T, Q> const& v3, + vec<4, T, Q> const& v4); + + //! Build a column major matrix from other matrix. + //! From GLM_GTX_matrix_major_storage extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( + mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_major_storage.inl" diff --git a/thirdparty/glm/gtx/matrix_major_storage.inl b/thirdparty/glm/gtx/matrix_major_storage.inl new file mode 100644 index 0000000..279dd34 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_major_storage.inl @@ -0,0 +1,166 @@ +/// @ref gtx_matrix_major_storage + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2 + ( + vec<2, T, Q> const& v1, + vec<2, T, Q> const& v2 + ) + { + mat<2, 2, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2( + const mat<2, 2, T, Q>& m) + { + mat<2, 2, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + mat<3, 3, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( + const mat<3, 3, T, Q>& m) + { + mat<3, 3, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + mat<4, 4, T, Q> Result; + Result[0][0] = v1.x; + Result[1][0] = v1.y; + Result[2][0] = v1.z; + Result[3][0] = v1.w; + Result[0][1] = v2.x; + Result[1][1] = v2.y; + Result[2][1] = v2.z; + Result[3][1] = v2.w; + Result[0][2] = v3.x; + Result[1][2] = v3.y; + Result[2][2] = v3.z; + Result[3][2] = v3.w; + Result[0][3] = v4.x; + Result[1][3] = v4.y; + Result[2][3] = v4.z; + Result[3][3] = v4.w; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( + const mat<4, 4, T, Q>& m) + { + mat<4, 4, T, Q> Result; + Result[0][0] = m[0][0]; + Result[0][1] = m[1][0]; + Result[0][2] = m[2][0]; + Result[0][3] = m[3][0]; + Result[1][0] = m[0][1]; + Result[1][1] = m[1][1]; + Result[1][2] = m[2][1]; + Result[1][3] = m[3][1]; + Result[2][0] = m[0][2]; + Result[2][1] = m[1][2]; + Result[2][2] = m[2][2]; + Result[2][3] = m[3][2]; + Result[3][0] = m[0][3]; + Result[3][1] = m[1][3]; + Result[3][2] = m[2][3]; + Result[3][3] = m[3][3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const vec<2, T, Q>& v1, + const vec<2, T, Q>& v2) + { + return mat<2, 2, T, Q>(v1, v2); + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( + const mat<2, 2, T, Q>& m) + { + return mat<2, 2, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const vec<3, T, Q>& v1, + const vec<3, T, Q>& v2, + const vec<3, T, Q>& v3) + { + return mat<3, 3, T, Q>(v1, v2, v3); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( + const mat<3, 3, T, Q>& m) + { + return mat<3, 3, T, Q>(m); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const vec<4, T, Q>& v1, + const vec<4, T, Q>& v2, + const vec<4, T, Q>& v3, + const vec<4, T, Q>& v4) + { + return mat<4, 4, T, Q>(v1, v2, v3, v4); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( + const mat<4, 4, T, Q>& m) + { + return mat<4, 4, T, Q>(m); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_operation.hpp b/thirdparty/glm/gtx/matrix_operation.hpp new file mode 100644 index 0000000..de6ff1f --- /dev/null +++ b/thirdparty/glm/gtx/matrix_operation.hpp @@ -0,0 +1,103 @@ +/// @ref gtx_matrix_operation +/// @file glm/gtx/matrix_operation.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Build diagonal matrices from vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_operation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_operation extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_operation + /// @{ + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> diagonal2x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 3, T, Q> diagonal2x3( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 4, T, Q> diagonal2x4( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 2, T, Q> diagonal3x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> diagonal3x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 4, T, Q> diagonal3x4( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 2, T, Q> diagonal4x2( + vec<2, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 3, T, Q> diagonal4x3( + vec<3, T, Q> const& v); + + //! Build a diagonal matrix. + //! From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> diagonal4x4( + vec<4, T, Q> const& v); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m); + + /// Build an adjugate matrix. + /// From GLM_GTX_matrix_operation extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m); + + /// @} +}//namespace glm + +#include "matrix_operation.inl" diff --git a/thirdparty/glm/gtx/matrix_operation.inl b/thirdparty/glm/gtx/matrix_operation.inl new file mode 100644 index 0000000..9de83f8 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_operation.inl @@ -0,0 +1,176 @@ +/// @ref gtx_matrix_operation + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> diagonal2x2 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 3, T, Q> diagonal2x3 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 4, T, Q> diagonal2x4 + ( + vec<2, T, Q> const& v + ) + { + mat<2, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 2, T, Q> diagonal3x2 + ( + vec<2, T, Q> const& v + ) + { + mat<3, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> diagonal3x3 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 4, T, Q> diagonal3x4 + ( + vec<3, T, Q> const& v + ) + { + mat<3, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> diagonal4x4 + ( + vec<4, T, Q> const& v + ) + { + mat<4, 4, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + Result[3][3] = v[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 3, T, Q> diagonal4x3 + ( + vec<3, T, Q> const& v + ) + { + mat<4, 3, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + Result[2][2] = v[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 2, T, Q> diagonal4x2 + ( + vec<2, T, Q> const& v + ) + { + mat<4, 2, T, Q> Result(static_cast(1)); + Result[0][0] = v[0]; + Result[1][1] = v[1]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m) + { + return mat<2, 2, T, Q>( + +m[1][1], -m[1][0], + -m[0][1], +m[0][0]); + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m) + { + T const m00 = determinant(mat<2, 2, T, Q>(m[1][1], m[2][1], m[1][2], m[2][2])); + T const m01 = determinant(mat<2, 2, T, Q>(m[0][1], m[2][1], m[0][2], m[2][2])); + T const m02 = determinant(mat<2, 2, T, Q>(m[0][1], m[1][1], m[0][2], m[1][2])); + + T const m10 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][2], m[2][2])); + T const m11 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][2], m[2][2])); + T const m12 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][2], m[1][2])); + + T const m20 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][1], m[2][1])); + T const m21 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][1], m[2][1])); + T const m22 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][1], m[1][1])); + + return mat<3, 3, T, Q>( + +m00, -m01, +m02, + -m10, +m11, -m12, + +m20, -m21, +m22); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m) + { + T const m00 = determinant(mat<3, 3, T, Q>(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m01 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m02 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m03 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m10 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); + T const m11 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); + T const m12 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3])); + T const m13 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); + + T const m20 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], m[3][3])); + T const m21 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], m[3][3])); + T const m22 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], m[3][3])); + T const m23 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], m[3][2])); + + T const m30 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3])); + T const m31 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3])); + T const m32 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3])); + T const m33 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2])); + + return mat<4, 4, T, Q>( + +m00, -m01, +m02, -m03, + -m10, +m11, -m12, +m13, + +m20, -m21, +m22, -m23, + -m30, +m31, -m32, +m33); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_query.hpp b/thirdparty/glm/gtx/matrix_query.hpp new file mode 100644 index 0000000..8011b2b --- /dev/null +++ b/thirdparty/glm/gtx/matrix_query.hpp @@ -0,0 +1,77 @@ +/// @ref gtx_matrix_query +/// @file glm/gtx/matrix_query.hpp +/// +/// @see core (dependence) +/// @see gtx_vector_query (dependence) +/// +/// @defgroup gtx_matrix_query GLM_GTX_matrix_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query to evaluate matrix properties + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/vector_query.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_query + /// @{ + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a null matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an identity matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isIdentity(matType const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is a normalized matrix. + /// From GLM_GTX_matrix_query extension. + template + GLM_FUNC_DECL bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon); + + /// Return whether a matrix is an orthonormalized matrix. + /// From GLM_GTX_matrix_query extension. + template class matType> + GLM_FUNC_DECL bool isOrthogonal(matType const& m, T const& epsilon); + + /// @} +}//namespace glm + +#include "matrix_query.inl" diff --git a/thirdparty/glm/gtx/matrix_query.inl b/thirdparty/glm/gtx/matrix_query.inl new file mode 100644 index 0000000..77bd231 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_query.inl @@ -0,0 +1,113 @@ +/// @ref gtx_matrix_query + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m.length() ; ++i) + result = isNull(m[i], epsilon); + return result; + } + + template + GLM_FUNC_QUALIFIER bool isIdentity(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i = 0; result && i < m[0].length() ; ++i) + { + for(length_t j = 0; result && j < i ; ++j) + result = abs(m[i][j]) <= epsilon; + if(result) + result = abs(m[i][i] - 1) <= epsilon; + for(length_t j = i + 1; result && j < m.length(); ++j) + result = abs(m[i][j]) <= epsilon; + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<2, 2, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<3, 3, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon) + { + bool result(true); + for(length_t i = 0; result && i < m.length(); ++i) + result = isNormalized(m[i], epsilon); + for(length_t i = 0; result && i < m.length(); ++i) + { + typename mat<4, 4, T, Q>::col_type v; + for(length_t j = 0; j < m.length(); ++j) + v[j] = m[j][i]; + result = isNormalized(v, epsilon); + } + return result; + } + + template + GLM_FUNC_QUALIFIER bool isOrthogonal(mat const& m, T const& epsilon) + { + bool result = true; + for(length_t i(0); result && i < m.length() - 1; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(m[i], m[j], epsilon); + + if(result) + { + mat tmp = transpose(m); + for(length_t i(0); result && i < m.length() - 1 ; ++i) + for(length_t j(i + 1); result && j < m.length(); ++j) + result = areOrthogonal(tmp[i], tmp[j], epsilon); + } + return result; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/matrix_transform_2d.hpp b/thirdparty/glm/gtx/matrix_transform_2d.hpp new file mode 100644 index 0000000..5f9c540 --- /dev/null +++ b/thirdparty/glm/gtx/matrix_transform_2d.hpp @@ -0,0 +1,81 @@ +/// @ref gtx_matrix_transform_2d +/// @file glm/gtx/matrix_transform_2d.hpp +/// @author Miguel Ãngel Pérez Martínez +/// +/// @see core (dependence) +/// +/// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines functions that generate common 2d transformation matrices. + +#pragma once + +// Dependency: +#include "../mat3x3.hpp" +#include "../vec2.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_matrix_transform_2d is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_matrix_transform_2d extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_matrix_transform_2d + /// @{ + + /// Builds a translation 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a translation vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds a rotation 3 * 3 matrix created from an angle. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param angle Rotation angle expressed in radians. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle); + + /// Builds a scale 3 * 3 matrix created from a vector of 2 components. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param v Coordinates of a scale vector. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v); + + /// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param y Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y); + + /// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix. + /// + /// @param m Input matrix multiplied by this translation matrix. + /// @param x Shear factor. + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x); + + /// @} +}//namespace glm + +#include "matrix_transform_2d.inl" diff --git a/thirdparty/glm/gtx/matrix_transform_2d.inl b/thirdparty/glm/gtx/matrix_transform_2d.inl new file mode 100644 index 0000000..a68d24d --- /dev/null +++ b/thirdparty/glm/gtx/matrix_transform_2d.inl @@ -0,0 +1,68 @@ +/// @ref gtx_matrix_transform_2d +/// @author Miguel Ãngel Pérez Martínez + +#include "../trigonometric.hpp" + +namespace glm +{ + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result(m); + Result[2] = m[0] * v[0] + m[1] * v[1] + m[2]; + return Result; + } + + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( + mat<3, 3, T, Q> const& m, + T angle) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + mat<3, 3, T, Q> Result; + Result[0] = m[0] * c + m[1] * s; + Result[1] = m[0] * -s + m[1] * c; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( + mat<3, 3, T, Q> const& m, + vec<2, T, Q> const& v) + { + mat<3, 3, T, Q> Result; + Result[0] = m[0] * v[0]; + Result[1] = m[1] * v[1]; + Result[2] = m[2]; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( + mat<3, 3, T, Q> const& m, + T y) + { + mat<3, 3, T, Q> Result(1); + Result[0][1] = y; + return m * Result; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( + mat<3, 3, T, Q> const& m, + T x) + { + mat<3, 3, T, Q> Result(1); + Result[1][0] = x; + return m * Result; + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/mixed_product.hpp b/thirdparty/glm/gtx/mixed_product.hpp new file mode 100644 index 0000000..b242e35 --- /dev/null +++ b/thirdparty/glm/gtx/mixed_product.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_mixed_product +/// @file glm/gtx/mixed_product.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_mixed_product GLM_GTX_mixed_producte +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Mixed product of 3 vectors. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_mixed_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_mixed_product extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_mixed_product + /// @{ + + /// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension) + template + GLM_FUNC_DECL T mixedProduct( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3); + + /// @} +}// namespace glm + +#include "mixed_product.inl" diff --git a/thirdparty/glm/gtx/mixed_product.inl b/thirdparty/glm/gtx/mixed_product.inl new file mode 100644 index 0000000..e5cdbdb --- /dev/null +++ b/thirdparty/glm/gtx/mixed_product.inl @@ -0,0 +1,15 @@ +/// @ref gtx_mixed_product + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T mixedProduct + ( + vec<3, T, Q> const& v1, + vec<3, T, Q> const& v2, + vec<3, T, Q> const& v3 + ) + { + return dot(cross(v1, v2), v3); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/norm.hpp b/thirdparty/glm/gtx/norm.hpp new file mode 100644 index 0000000..dfaebb7 --- /dev/null +++ b/thirdparty/glm/gtx/norm.hpp @@ -0,0 +1,88 @@ +/// @ref gtx_norm +/// @file glm/gtx/norm.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// @see gtx_component_wise (dependence) +/// +/// @defgroup gtx_norm GLM_GTX_norm +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Various ways to compute vector norms. + +#pragma once + +// Dependency: +#include "../geometric.hpp" +#include "../gtx/quaternion.hpp" +#include "../gtx/component_wise.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_norm is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_norm extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_norm + /// @{ + + /// Returns the squared length of x. + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T length2(vec const& x); + + /// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1). + /// From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T distance2(vec const& p0, vec const& p1); + + //! Returns the L1 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L1 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& v); + + //! Returns the L2 norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the L2 norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x); + + //! Returns the L norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth); + + //! Returns the L norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, unsigned int Depth); + + //! Returns the LMax norm between x and y. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + //! Returns the LMax norm of v. + //! From GLM_GTX_norm extension. + template + GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x); + + /// @} +}//namespace glm + +#include "norm.inl" diff --git a/thirdparty/glm/gtx/norm.inl b/thirdparty/glm/gtx/norm.inl new file mode 100644 index 0000000..6db561b --- /dev/null +++ b/thirdparty/glm/gtx/norm.inl @@ -0,0 +1,95 @@ +/// @ref gtx_norm + +#include "../detail/qualifier.hpp" + +namespace glm{ +namespace detail +{ + template + struct compute_length2 + { + GLM_FUNC_QUALIFIER static T call(vec const& v) + { + return dot(v, v); + } + }; +}//namespace detail + + template + GLM_FUNC_QUALIFIER genType length2(genType x) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return x * x; + } + + template + GLM_FUNC_QUALIFIER T length2(vec const& v) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); + return detail::compute_length2::value>::call(v); + } + + template + GLM_FUNC_QUALIFIER T distance2(T p0, T p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T distance2(vec const& p0, vec const& p1) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); + return length2(p1 - p0); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z); + } + + template + GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& v) + { + return abs(v.x) + abs(v.y) + abs(v.z); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b + ) + { + return length(b - a); + } + + template + GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& v) + { + return length(v); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth) + { + return pow(pow(abs(y.x - x.x), T(Depth)) + pow(abs(y.y - x.y), T(Depth)) + pow(abs(y.z - x.z), T(Depth)), T(1) / T(Depth)); + } + + template + GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& v, unsigned int Depth) + { + return pow(pow(abs(v.x), T(Depth)) + pow(abs(v.y), T(Depth)) + pow(abs(v.z), T(Depth)), T(1) / T(Depth)); + } + + template + GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) + { + return compMax(abs(b - a)); + } + + template + GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& v) + { + return compMax(abs(v)); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/normal.hpp b/thirdparty/glm/gtx/normal.hpp new file mode 100644 index 0000000..068682f --- /dev/null +++ b/thirdparty/glm/gtx/normal.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_normal +/// @file glm/gtx/normal.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_normal GLM_GTX_normal +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute the normal of a triangle. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normal is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normal extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normal + /// @{ + + /// Computes triangle normal from triangle points. + /// + /// @see gtx_normal + template + GLM_FUNC_DECL vec<3, T, Q> triangleNormal(vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3); + + /// @} +}//namespace glm + +#include "normal.inl" diff --git a/thirdparty/glm/gtx/normal.inl b/thirdparty/glm/gtx/normal.inl new file mode 100644 index 0000000..74f9fc9 --- /dev/null +++ b/thirdparty/glm/gtx/normal.inl @@ -0,0 +1,15 @@ +/// @ref gtx_normal + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> triangleNormal + ( + vec<3, T, Q> const& p1, + vec<3, T, Q> const& p2, + vec<3, T, Q> const& p3 + ) + { + return normalize(cross(p1 - p2, p1 - p3)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/normalize_dot.hpp b/thirdparty/glm/gtx/normalize_dot.hpp new file mode 100644 index 0000000..5195802 --- /dev/null +++ b/thirdparty/glm/gtx/normalize_dot.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_normalize_dot +/// @file glm/gtx/normalize_dot.hpp +/// +/// @see core (dependence) +/// @see gtx_fast_square_root (dependence) +/// +/// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Dot product of vectors that need to be normalize with a single square root. + +#pragma once + +// Dependency: +#include "../gtx/fast_square_root.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_normalize_dot is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_normalize_dot extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_normalize_dot + /// @{ + + /// Normalize parameters and returns the dot product of x and y. + /// It's faster that dot(normalize(x), normalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T normalizeDot(vec const& x, vec const& y); + + /// Normalize parameters and returns the dot product of x and y. + /// Faster that dot(fastNormalize(x), fastNormalize(y)). + /// + /// @see gtx_normalize_dot extension. + template + GLM_FUNC_DECL T fastNormalizeDot(vec const& x, vec const& y); + + /// @} +}//namespace glm + +#include "normalize_dot.inl" diff --git a/thirdparty/glm/gtx/normalize_dot.inl b/thirdparty/glm/gtx/normalize_dot.inl new file mode 100644 index 0000000..7bcd9a5 --- /dev/null +++ b/thirdparty/glm/gtx/normalize_dot.inl @@ -0,0 +1,16 @@ +/// @ref gtx_normalize_dot + +namespace glm +{ + template + GLM_FUNC_QUALIFIER T normalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); + } + + template + GLM_FUNC_QUALIFIER T fastNormalizeDot(vec const& x, vec const& y) + { + return glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/number_precision.hpp b/thirdparty/glm/gtx/number_precision.hpp new file mode 100644 index 0000000..3a606bd --- /dev/null +++ b/thirdparty/glm/gtx/number_precision.hpp @@ -0,0 +1,61 @@ +/// @ref gtx_number_precision +/// @file glm/gtx/number_precision.hpp +/// +/// @see core (dependence) +/// @see gtc_type_precision (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_number_precision GLM_GTX_number_precision +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defined size types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_number_precision is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_number_precision extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + ///////////////////////////// + // Unsigned int vector types + + /// @addtogroup gtx_number_precision + /// @{ + + typedef u8 u8vec1; //!< \brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u16 u16vec1; //!< \brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u32 u32vec1; //!< \brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + typedef u64 u64vec1; //!< \brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float vector types + + typedef f32 f32vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + ////////////////////// + // Float matrix types + + typedef f32 f32mat1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f32 f32mat1x1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + typedef f64 f64mat1x1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) + + /// @} +}//namespace gtx +}//namespace glm + +#include "number_precision.inl" diff --git a/thirdparty/glm/gtx/number_precision.inl b/thirdparty/glm/gtx/number_precision.inl new file mode 100644 index 0000000..b39d71c --- /dev/null +++ b/thirdparty/glm/gtx/number_precision.inl @@ -0,0 +1,6 @@ +/// @ref gtx_number_precision + +namespace glm +{ + +} diff --git a/thirdparty/glm/gtx/optimum_pow.hpp b/thirdparty/glm/gtx/optimum_pow.hpp new file mode 100644 index 0000000..9284a47 --- /dev/null +++ b/thirdparty/glm/gtx/optimum_pow.hpp @@ -0,0 +1,54 @@ +/// @ref gtx_optimum_pow +/// @file glm/gtx/optimum_pow.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Integer exponentiation of power functions. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_optimum_pow is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_optimum_pow extension included") +# endif +#endif + +namespace glm{ +namespace gtx +{ + /// @addtogroup gtx_optimum_pow + /// @{ + + /// Returns x raised to the power of 2. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow2(genType const& x); + + /// Returns x raised to the power of 3. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow3(genType const& x); + + /// Returns x raised to the power of 4. + /// + /// @see gtx_optimum_pow + template + GLM_FUNC_DECL genType pow4(genType const& x); + + /// @} +}//namespace gtx +}//namespace glm + +#include "optimum_pow.inl" diff --git a/thirdparty/glm/gtx/optimum_pow.inl b/thirdparty/glm/gtx/optimum_pow.inl new file mode 100644 index 0000000..a26c19c --- /dev/null +++ b/thirdparty/glm/gtx/optimum_pow.inl @@ -0,0 +1,22 @@ +/// @ref gtx_optimum_pow + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType pow2(genType const& x) + { + return x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow3(genType const& x) + { + return x * x * x; + } + + template + GLM_FUNC_QUALIFIER genType pow4(genType const& x) + { + return (x * x) * (x * x); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/orthonormalize.hpp b/thirdparty/glm/gtx/orthonormalize.hpp new file mode 100644 index 0000000..3e004fb --- /dev/null +++ b/thirdparty/glm/gtx/orthonormalize.hpp @@ -0,0 +1,49 @@ +/// @ref gtx_orthonormalize +/// @file glm/gtx/orthonormalize.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Orthonormalize matrices. + +#pragma once + +// Dependency: +#include "../vec3.hpp" +#include "../mat3x3.hpp" +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_orthonormalize is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_orthonormalize extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_orthonormalize + /// @{ + + /// Returns the orthonormalized matrix of m. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m); + + /// Orthonormalizes x according y. + /// + /// @see gtx_orthonormalize + template + GLM_FUNC_DECL vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y); + + /// @} +}//namespace glm + +#include "orthonormalize.inl" diff --git a/thirdparty/glm/gtx/orthonormalize.inl b/thirdparty/glm/gtx/orthonormalize.inl new file mode 100644 index 0000000..cb553ba --- /dev/null +++ b/thirdparty/glm/gtx/orthonormalize.inl @@ -0,0 +1,29 @@ +/// @ref gtx_orthonormalize + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m) + { + mat<3, 3, T, Q> r = m; + + r[0] = normalize(r[0]); + + T d0 = dot(r[0], r[1]); + r[1] -= r[0] * d0; + r[1] = normalize(r[1]); + + T d1 = dot(r[1], r[2]); + d0 = dot(r[0], r[2]); + r[2] -= r[0] * d0 + r[1] * d1; + r[2] = normalize(r[2]); + + return r; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y) + { + return normalize(x - y * dot(y, x)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/perpendicular.hpp b/thirdparty/glm/gtx/perpendicular.hpp new file mode 100644 index 0000000..72b77b6 --- /dev/null +++ b/thirdparty/glm/gtx/perpendicular.hpp @@ -0,0 +1,41 @@ +/// @ref gtx_perpendicular +/// @file glm/gtx/perpendicular.hpp +/// +/// @see core (dependence) +/// @see gtx_projection (dependence) +/// +/// @defgroup gtx_perpendicular GLM_GTX_perpendicular +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Perpendicular of a vector from other one + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/projection.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_perpendicular is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_perpendicular extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_perpendicular + /// @{ + + //! Projects x a perpendicular axis of Normal. + //! From GLM_GTX_perpendicular extension. + template + GLM_FUNC_DECL genType perp(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "perpendicular.inl" diff --git a/thirdparty/glm/gtx/perpendicular.inl b/thirdparty/glm/gtx/perpendicular.inl new file mode 100644 index 0000000..1e72f33 --- /dev/null +++ b/thirdparty/glm/gtx/perpendicular.inl @@ -0,0 +1,10 @@ +/// @ref gtx_perpendicular + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType perp(genType const& x, genType const& Normal) + { + return x - proj(x, Normal); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/polar_coordinates.hpp b/thirdparty/glm/gtx/polar_coordinates.hpp new file mode 100644 index 0000000..76beb82 --- /dev/null +++ b/thirdparty/glm/gtx/polar_coordinates.hpp @@ -0,0 +1,48 @@ +/// @ref gtx_polar_coordinates +/// @file glm/gtx/polar_coordinates.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Conversion from Euclidean space to polar space and revert. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_polar_coordinates is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_polar_coordinates extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_polar_coordinates + /// @{ + + /// Convert Euclidean to Polar coordinates, x is the latitude, y the longitude and z the xz distance. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> polar( + vec<3, T, Q> const& euclidean); + + /// Convert Polar to Euclidean coordinates. + /// + /// @see gtx_polar_coordinates + template + GLM_FUNC_DECL vec<3, T, Q> euclidean( + vec<2, T, Q> const& polar); + + /// @} +}//namespace glm + +#include "polar_coordinates.inl" diff --git a/thirdparty/glm/gtx/polar_coordinates.inl b/thirdparty/glm/gtx/polar_coordinates.inl new file mode 100644 index 0000000..371c8dd --- /dev/null +++ b/thirdparty/glm/gtx/polar_coordinates.inl @@ -0,0 +1,36 @@ +/// @ref gtx_polar_coordinates + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> polar + ( + vec<3, T, Q> const& euclidean + ) + { + T const Length(length(euclidean)); + vec<3, T, Q> const tmp(euclidean / Length); + T const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z)); + + return vec<3, T, Q>( + asin(tmp.y), // latitude + atan(tmp.x, tmp.z), // longitude + xz_dist); // xz distance + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> euclidean + ( + vec<2, T, Q> const& polar + ) + { + T const latitude(polar.x); + T const longitude(polar.y); + + return vec<3, T, Q>( + cos(latitude) * sin(longitude), + sin(latitude), + cos(latitude) * cos(longitude)); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/projection.hpp b/thirdparty/glm/gtx/projection.hpp new file mode 100644 index 0000000..678f3ad --- /dev/null +++ b/thirdparty/glm/gtx/projection.hpp @@ -0,0 +1,43 @@ +/// @ref gtx_projection +/// @file glm/gtx/projection.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_projection GLM_GTX_projection +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependency: +#include "../geometric.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_projection is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_projection extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_projection + /// @{ + + /// Projects x on Normal. + /// + /// @param[in] x A vector to project + /// @param[in] Normal A normal that doesn't need to be of unit length. + /// + /// @see gtx_projection + template + GLM_FUNC_DECL genType proj(genType const& x, genType const& Normal); + + /// @} +}//namespace glm + +#include "projection.inl" diff --git a/thirdparty/glm/gtx/projection.inl b/thirdparty/glm/gtx/projection.inl new file mode 100644 index 0000000..f23f884 --- /dev/null +++ b/thirdparty/glm/gtx/projection.inl @@ -0,0 +1,10 @@ +/// @ref gtx_projection + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType proj(genType const& x, genType const& Normal) + { + return glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/quaternion.hpp b/thirdparty/glm/gtx/quaternion.hpp new file mode 100644 index 0000000..5c2b5ad --- /dev/null +++ b/thirdparty/glm/gtx/quaternion.hpp @@ -0,0 +1,174 @@ +/// @ref gtx_quaternion +/// @file glm/gtx/quaternion.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_quaternion GLM_GTX_quaternion +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extented quaternion types and functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/constants.hpp" +#include "../gtc/quaternion.hpp" +#include "../ext/quaternion_exponential.hpp" +#include "../gtx/norm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_quaternion extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_quaternion + /// @{ + + /// Create an identity quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL GLM_CONSTEXPR qua quat_identity(); + + /// Compute a cross product between a quaternion and a vector. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + qua const& q, + vec<3, T, Q> const& v); + + //! Compute a cross product between a vector and a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> cross( + vec<3, T, Q> const& v, + qua const& q); + + //! Compute a point on a path according squad equation. + //! q1 and q2 are control points; s1 and s2 are intermediate control points. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua squad( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h); + + //! Returns an intermediate control point for squad interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua intermediate( + qua const& prev, + qua const& curr, + qua const& next); + + //! Returns quarternion square root. + /// + /// @see gtx_quaternion + //template + //qua sqrt( + // qua const& q); + + //! Rotates a 3 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + qua const& q, + vec<3, T, Q> const& v); + + /// Rotates a 4 components vector by a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + qua const& q, + vec<4, T, Q> const& v); + + /// Extract the real component of a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL T extractRealComponent( + qua const& q); + + /// Converts a quaternion to a 3 * 3 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL mat<3, 3, T, Q> toMat3( + qua const& x){return mat3_cast(x);} + + /// Converts a quaternion to a 4 * 4 matrix. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL mat<4, 4, T, Q> toMat4( + qua const& x){return mat4_cast(x);} + + /// Converts a 3 * 3 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua toQuat( + mat<3, 3, T, Q> const& x){return quat_cast(x);} + + /// Converts a 4 * 4 matrix to a quaternion. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua toQuat( + mat<4, 4, T, Q> const& x){return quat_cast(x);} + + /// Quaternion interpolation using the rotation short path. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua shortMix( + qua const& x, + qua const& y, + T const& a); + + /// Quaternion normalized linear interpolation. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua fastMix( + qua const& x, + qua const& y, + T const& a); + + /// Compute the rotation between two vectors. + /// @param orig vector, needs to be normalized + /// @param dest vector, needs to be normalized + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL qua rotation( + vec<3, T, Q> const& orig, + vec<3, T, Q> const& dest); + + /// Returns the squared length of x. + /// + /// @see gtx_quaternion + template + GLM_FUNC_DECL GLM_CONSTEXPR T length2(qua const& q); + + /// @} +}//namespace glm + +#include "quaternion.inl" diff --git a/thirdparty/glm/gtx/quaternion.inl b/thirdparty/glm/gtx/quaternion.inl new file mode 100644 index 0000000..d125bcc --- /dev/null +++ b/thirdparty/glm/gtx/quaternion.inl @@ -0,0 +1,159 @@ +/// @ref gtx_quaternion + +#include +#include "../gtc/constants.hpp" + +namespace glm +{ + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua quat_identity() + { + return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& v, qua const& q) + { + return inverse(q) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> cross(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER qua squad + ( + qua const& q1, + qua const& q2, + qua const& s1, + qua const& s2, + T const& h) + { + return mix(mix(q1, q2, h), mix(s1, s2, h), static_cast(2) * (static_cast(1) - h) * h); + } + + template + GLM_FUNC_QUALIFIER qua intermediate + ( + qua const& prev, + qua const& curr, + qua const& next + ) + { + qua invQuat = inverse(curr); + return exp((log(next * invQuat) + log(prev * invQuat)) / static_cast(-4)) * curr; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua const& q, vec<3, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate(qua const& q, vec<4, T, Q> const& v) + { + return q * v; + } + + template + GLM_FUNC_QUALIFIER T extractRealComponent(qua const& q) + { + T w = static_cast(1) - q.x * q.x - q.y * q.y - q.z * q.z; + if(w < T(0)) + return T(0); + else + return -sqrt(w); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T length2(qua const& q) + { + return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + } + + template + GLM_FUNC_QUALIFIER qua shortMix(qua const& x, qua const& y, T const& a) + { + if(a <= static_cast(0)) return x; + if(a >= static_cast(1)) return y; + + T fCos = dot(x, y); + qua y2(y); //BUG!!! qua y2; + if(fCos < static_cast(0)) + { + y2 = -y; + fCos = -fCos; + } + + //if(fCos > 1.0f) // problem + T k0, k1; + if(fCos > (static_cast(1) - epsilon())) + { + k0 = static_cast(1) - a; + k1 = static_cast(0) + a; //BUG!!! 1.0f + a; + } + else + { + T fSin = sqrt(T(1) - fCos * fCos); + T fAngle = atan(fSin, fCos); + T fOneOverSin = static_cast(1) / fSin; + k0 = sin((static_cast(1) - a) * fAngle) * fOneOverSin; + k1 = sin((static_cast(0) + a) * fAngle) * fOneOverSin; + } + + return qua( + k0 * x.w + k1 * y2.w, + k0 * x.x + k1 * y2.x, + k0 * x.y + k1 * y2.y, + k0 * x.z + k1 * y2.z); + } + + template + GLM_FUNC_QUALIFIER qua fastMix(qua const& x, qua const& y, T const& a) + { + return glm::normalize(x * (static_cast(1) - a) + (y * a)); + } + + template + GLM_FUNC_QUALIFIER qua rotation(vec<3, T, Q> const& orig, vec<3, T, Q> const& dest) + { + T cosTheta = dot(orig, dest); + vec<3, T, Q> rotationAxis; + + if(cosTheta >= static_cast(1) - epsilon()) { + // orig and dest point in the same direction + return quat_identity(); + } + + if(cosTheta < static_cast(-1) + epsilon()) + { + // special case when vectors in opposite directions : + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + // This implementation favors a rotation around the Up axis (Y), + // since it's often what you want to do. + rotationAxis = cross(vec<3, T, Q>(0, 0, 1), orig); + if(length2(rotationAxis) < epsilon()) // bad luck, they were parallel, try again! + rotationAxis = cross(vec<3, T, Q>(1, 0, 0), orig); + + rotationAxis = normalize(rotationAxis); + return angleAxis(pi(), rotationAxis); + } + + // Implementation from Stan Melax's Game Programming Gems 1 article + rotationAxis = cross(orig, dest); + + T s = sqrt((T(1) + cosTheta) * static_cast(2)); + T invs = static_cast(1) / s; + + return qua( + s * static_cast(0.5f), + rotationAxis.x * invs, + rotationAxis.y * invs, + rotationAxis.z * invs); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/range.hpp b/thirdparty/glm/gtx/range.hpp new file mode 100644 index 0000000..93bcb9a --- /dev/null +++ b/thirdparty/glm/gtx/range.hpp @@ -0,0 +1,98 @@ +/// @ref gtx_range +/// @file glm/gtx/range.hpp +/// @author Joshua Moerman +/// +/// @defgroup gtx_range GLM_GTX_range +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines begin and end for vectors and matrices. Useful for range-based for loop. +/// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements). + +#pragma once + +// Dependencies +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_range is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_range extension included") +# endif +#endif + +#include "../gtc/type_ptr.hpp" +#include "../gtc/vec1.hpp" + +namespace glm +{ + /// @addtogroup gtx_range + /// @{ + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +# endif + + template + inline length_t components(vec<1, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<2, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<3, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(vec<4, T, Q> const& v) + { + return v.length(); + } + + template + inline length_t components(genType const& m) + { + return m.length() * m[0].length(); + } + + template + inline typename genType::value_type const * begin(genType const& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type const * end(genType const& v) + { + return begin(v) + components(v); + } + + template + inline typename genType::value_type * begin(genType& v) + { + return value_ptr(v); + } + + template + inline typename genType::value_type * end(genType& v) + { + return begin(v) + components(v); + } + +# if GLM_COMPILER & GLM_COMPILER_VC +# pragma warning(pop) +# endif + + /// @} +}//namespace glm diff --git a/thirdparty/glm/gtx/raw_data.hpp b/thirdparty/glm/gtx/raw_data.hpp new file mode 100644 index 0000000..86cbe77 --- /dev/null +++ b/thirdparty/glm/gtx/raw_data.hpp @@ -0,0 +1,51 @@ +/// @ref gtx_raw_data +/// @file glm/gtx/raw_data.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_raw_data GLM_GTX_raw_data +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Projection of a vector to other one + +#pragma once + +// Dependencies +#include "../ext/scalar_uint_sized.hpp" +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_raw_data is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_raw_data extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_raw_data + /// @{ + + //! Type for byte numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint8 byte; + + //! Type for word numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint16 word; + + //! Type for dword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint32 dword; + + //! Type for qword numbers. + //! From GLM_GTX_raw_data extension. + typedef detail::uint64 qword; + + /// @} +}// namespace glm + +#include "raw_data.inl" diff --git a/thirdparty/glm/gtx/raw_data.inl b/thirdparty/glm/gtx/raw_data.inl new file mode 100644 index 0000000..c740317 --- /dev/null +++ b/thirdparty/glm/gtx/raw_data.inl @@ -0,0 +1,2 @@ +/// @ref gtx_raw_data + diff --git a/thirdparty/glm/gtx/rotate_normalized_axis.hpp b/thirdparty/glm/gtx/rotate_normalized_axis.hpp new file mode 100644 index 0000000..2103ca0 --- /dev/null +++ b/thirdparty/glm/gtx/rotate_normalized_axis.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_rotate_normalized_axis +/// @file glm/gtx/rotate_normalized_axis.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform +/// @see gtc_quaternion +/// +/// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Quaternions and matrices rotations around normalized axis. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_normalized_axis is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_normalized_axis extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_normalized_axis + /// @{ + + /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. + /// + /// @param m Input matrix multiplied by this rotation matrix. + /// @param angle Rotation angle expressed in radians. + /// @param axis Rotation axis, must be normalized. + /// @tparam T Value type used to build the matrix. Currently supported: half (not recommended), float or double. + /// + /// @see gtx_rotate_normalized_axis + /// @see - rotate(T angle, T x, T y, T z) + /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) + /// @see - rotate(T angle, vec<3, T, Q> const& v) + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotateNormalizedAxis( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& axis); + + /// Rotates a quaternion from a vector of 3 components normalized axis and an angle. + /// + /// @param q Source orientation + /// @param angle Angle expressed in radians. + /// @param axis Normalized axis of the rotation, must be normalized. + /// + /// @see gtx_rotate_normalized_axis + template + GLM_FUNC_DECL qua rotateNormalizedAxis( + qua const& q, + T const& angle, + vec<3, T, Q> const& axis); + + /// @} +}//namespace glm + +#include "rotate_normalized_axis.inl" diff --git a/thirdparty/glm/gtx/rotate_normalized_axis.inl b/thirdparty/glm/gtx/rotate_normalized_axis.inl new file mode 100644 index 0000000..b2e9278 --- /dev/null +++ b/thirdparty/glm/gtx/rotate_normalized_axis.inl @@ -0,0 +1,58 @@ +/// @ref gtx_rotate_normalized_axis + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotateNormalizedAxis + ( + mat<4, 4, T, Q> const& m, + T const& angle, + vec<3, T, Q> const& v + ) + { + T const a = angle; + T const c = cos(a); + T const s = sin(a); + + vec<3, T, Q> const axis(v); + + vec<3, T, Q> const temp((static_cast(1) - c) * axis); + + mat<4, 4, T, Q> Rotate; + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + mat<4, 4, T, Q> Result; + Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + Result[3] = m[3]; + return Result; + } + + template + GLM_FUNC_QUALIFIER qua rotateNormalizedAxis + ( + qua const& q, + T const& angle, + vec<3, T, Q> const& v + ) + { + vec<3, T, Q> const Tmp(v); + + T const AngleRad(angle); + T const Sin = sin(AngleRad * T(0.5)); + + return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); + //return gtc::quaternion::cross(q, tquat(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/rotate_vector.hpp b/thirdparty/glm/gtx/rotate_vector.hpp new file mode 100644 index 0000000..dcd5b95 --- /dev/null +++ b/thirdparty/glm/gtx/rotate_vector.hpp @@ -0,0 +1,123 @@ +/// @ref gtx_rotate_vector +/// @file glm/gtx/rotate_vector.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Function to directly rotate a vector + +#pragma once + +// Dependency: +#include "../gtx/transform.hpp" +#include "../gtc/epsilon.hpp" +#include "../ext/vector_relational.hpp" +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_rotate_vector is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_rotate_vector extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_rotate_vector + /// @{ + + /// Returns Spherical interpolation between two vectors + /// + /// @param x A first vector + /// @param y A second vector + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// + /// @see gtx_rotate_vector + template + GLM_FUNC_DECL vec<3, T, Q> slerp( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a); + + //! Rotate a two dimensional vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<2, T, Q> rotate( + vec<2, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotate( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a four dimensional vector around an axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotate( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal); + + //! Rotate a three dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateX( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateY( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a three dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<3, T, Q> rotateZ( + vec<3, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the X axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateX( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Y axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateY( + vec<4, T, Q> const& v, + T const& angle); + + //! Rotate a four dimensional vector around the Z axis. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL vec<4, T, Q> rotateZ( + vec<4, T, Q> const& v, + T const& angle); + + //! Build a rotation matrix from a normal and a up vector. + //! From GLM_GTX_rotate_vector extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> orientation( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up); + + /// @} +}//namespace glm + +#include "rotate_vector.inl" diff --git a/thirdparty/glm/gtx/rotate_vector.inl b/thirdparty/glm/gtx/rotate_vector.inl new file mode 100644 index 0000000..f8136e7 --- /dev/null +++ b/thirdparty/glm/gtx/rotate_vector.inl @@ -0,0 +1,187 @@ +/// @ref gtx_rotate_vector + +namespace glm +{ + template + GLM_FUNC_QUALIFIER vec<3, T, Q> slerp + ( + vec<3, T, Q> const& x, + vec<3, T, Q> const& y, + T const& a + ) + { + // get cosine of angle between vectors (-1 -> 1) + T CosAlpha = dot(x, y); + // get angle (0 -> pi) + T Alpha = acos(CosAlpha); + // get sine of angle between vectors (0 -> 1) + T SinAlpha = sin(Alpha); + // this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi + T t1 = sin((static_cast(1) - a) * Alpha) / SinAlpha; + T t2 = sin(a * Alpha) / SinAlpha; + + // interpolate src vectors + return x * t1 + y * t2; + } + + template + GLM_FUNC_QUALIFIER vec<2, T, Q> rotate + ( + vec<2, T, Q> const& v, + T const& angle + ) + { + vec<2, T, Q> Result; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotate + ( + vec<3, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return mat<3, 3, T, Q>(glm::rotate(angle, normal)) * v; + } + /* + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateGTX( + const vec<3, T, Q>& x, + T angle, + const vec<3, T, Q>& normal) + { + const T Cos = cos(radians(angle)); + const T Sin = sin(radians(angle)); + return x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin; + } + */ + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotate + ( + vec<4, T, Q> const& v, + T const& angle, + vec<3, T, Q> const& normal + ) + { + return rotate(angle, normal) * v; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateX + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result(v); + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateY + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<3, T, Q> rotateZ + ( + vec<3, T, Q> const& v, + T const& angle + ) + { + vec<3, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateX + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.y = v.y * Cos - v.z * Sin; + Result.z = v.y * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateY + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos + v.z * Sin; + Result.z = -v.x * Sin + v.z * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER vec<4, T, Q> rotateZ + ( + vec<4, T, Q> const& v, + T const& angle + ) + { + vec<4, T, Q> Result = v; + T const Cos(cos(angle)); + T const Sin(sin(angle)); + + Result.x = v.x * Cos - v.y * Sin; + Result.y = v.x * Sin + v.y * Cos; + return Result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientation + ( + vec<3, T, Q> const& Normal, + vec<3, T, Q> const& Up + ) + { + if(all(equal(Normal, Up, epsilon()))) + return mat<4, 4, T, Q>(static_cast(1)); + + vec<3, T, Q> RotationAxis = cross(Up, Normal); + T Angle = acos(dot(Normal, Up)); + + return rotate(Angle, RotationAxis); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/scalar_multiplication.hpp b/thirdparty/glm/gtx/scalar_multiplication.hpp new file mode 100644 index 0000000..496ba19 --- /dev/null +++ b/thirdparty/glm/gtx/scalar_multiplication.hpp @@ -0,0 +1,75 @@ +/// @ref gtx +/// @file glm/gtx/scalar_multiplication.hpp +/// @author Joshua Moerman +/// +/// Include to use the features of this extension. +/// +/// Enables scalar multiplication for all types +/// +/// Since GLSL is very strict about types, the following (often used) combinations do not work: +/// double * vec4 +/// int * vec4 +/// vec4 / int +/// So we'll fix that! Of course "float * vec4" should remain the same (hence the enable_if magic) + +#pragma once + +#include "../detail/setup.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_scalar_multiplication is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_scalar_multiplication extension included") +# endif +#endif + +#include "../vec2.hpp" +#include "../vec3.hpp" +#include "../vec4.hpp" +#include "../mat2x2.hpp" +#include + +namespace glm +{ + template + using return_type_scalar_multiplication = typename std::enable_if< + !std::is_same::value // T may not be a float + && std::is_arithmetic::value, Vec // But it may be an int or double (no vec3 or mat3, ...) + >::type; + +#define GLM_IMPLEMENT_SCAL_MULT(Vec) \ + template \ + return_type_scalar_multiplication \ + operator*(T const& s, Vec rh){ \ + return rh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator*(Vec lh, T const& s){ \ + return lh *= static_cast(s); \ + } \ + \ + template \ + return_type_scalar_multiplication \ + operator/(Vec lh, T const& s){ \ + return lh *= 1.0f / static_cast(s); \ + } + +GLM_IMPLEMENT_SCAL_MULT(vec2) +GLM_IMPLEMENT_SCAL_MULT(vec3) +GLM_IMPLEMENT_SCAL_MULT(vec4) + +GLM_IMPLEMENT_SCAL_MULT(mat2) +GLM_IMPLEMENT_SCAL_MULT(mat2x3) +GLM_IMPLEMENT_SCAL_MULT(mat2x4) +GLM_IMPLEMENT_SCAL_MULT(mat3x2) +GLM_IMPLEMENT_SCAL_MULT(mat3) +GLM_IMPLEMENT_SCAL_MULT(mat3x4) +GLM_IMPLEMENT_SCAL_MULT(mat4x2) +GLM_IMPLEMENT_SCAL_MULT(mat4x3) +GLM_IMPLEMENT_SCAL_MULT(mat4) + +#undef GLM_IMPLEMENT_SCAL_MULT +} // namespace glm diff --git a/thirdparty/glm/gtx/scalar_relational.hpp b/thirdparty/glm/gtx/scalar_relational.hpp new file mode 100644 index 0000000..8be9c57 --- /dev/null +++ b/thirdparty/glm/gtx/scalar_relational.hpp @@ -0,0 +1,36 @@ +/// @ref gtx_scalar_relational +/// @file glm/gtx/scalar_relational.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Extend a position from a source to a position at a defined length. + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_extend extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_scalar_relational + /// @{ + + + + /// @} +}//namespace glm + +#include "scalar_relational.inl" diff --git a/thirdparty/glm/gtx/scalar_relational.inl b/thirdparty/glm/gtx/scalar_relational.inl new file mode 100644 index 0000000..c2a121c --- /dev/null +++ b/thirdparty/glm/gtx/scalar_relational.inl @@ -0,0 +1,88 @@ +/// @ref gtx_scalar_relational + +namespace glm +{ + template + GLM_FUNC_QUALIFIER bool lessThan + ( + T const& x, + T const& y + ) + { + return x < y; + } + + template + GLM_FUNC_QUALIFIER bool lessThanEqual + ( + T const& x, + T const& y + ) + { + return x <= y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThan + ( + T const& x, + T const& y + ) + { + return x > y; + } + + template + GLM_FUNC_QUALIFIER bool greaterThanEqual + ( + T const& x, + T const& y + ) + { + return x >= y; + } + + template + GLM_FUNC_QUALIFIER bool equal + ( + T const& x, + T const& y + ) + { + return detail::compute_equal::is_iec559>::call(x, y); + } + + template + GLM_FUNC_QUALIFIER bool notEqual + ( + T const& x, + T const& y + ) + { + return !detail::compute_equal::is_iec559>::call(x, y); + } + + GLM_FUNC_QUALIFIER bool any + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool all + ( + bool const& x + ) + { + return x; + } + + GLM_FUNC_QUALIFIER bool not_ + ( + bool const& x + ) + { + return !x; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/spline.hpp b/thirdparty/glm/gtx/spline.hpp new file mode 100644 index 0000000..731c979 --- /dev/null +++ b/thirdparty/glm/gtx/spline.hpp @@ -0,0 +1,65 @@ +/// @ref gtx_spline +/// @file glm/gtx/spline.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_spline GLM_GTX_spline +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Spline functions + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/optimum_pow.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_spline is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_spline extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_spline + /// @{ + + /// Return a point from a catmull rom curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType catmullRom( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// Return a point from a hermite curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType hermite( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s); + + /// Return a point from a cubic curve. + /// @see gtx_spline extension. + template + GLM_FUNC_DECL genType cubic( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s); + + /// @} +}//namespace glm + +#include "spline.inl" diff --git a/thirdparty/glm/gtx/spline.inl b/thirdparty/glm/gtx/spline.inl new file mode 100644 index 0000000..c3fd056 --- /dev/null +++ b/thirdparty/glm/gtx/spline.inl @@ -0,0 +1,60 @@ +/// @ref gtx_spline + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType catmullRom + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s; + typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2); + typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2); + + } + + template + GLM_FUNC_QUALIFIER genType hermite + ( + genType const& v1, + genType const& t1, + genType const& v2, + genType const& t2, + typename genType::value_type const& s + ) + { + typename genType::value_type s2 = pow2(s); + typename genType::value_type s3 = pow3(s); + + typename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1); + typename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2; + typename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s; + typename genType::value_type f4 = s3 - s2; + + return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2; + } + + template + GLM_FUNC_QUALIFIER genType cubic + ( + genType const& v1, + genType const& v2, + genType const& v3, + genType const& v4, + typename genType::value_type const& s + ) + { + return ((v1 * s + v2) * s + v3) * s + v4; + } +}//namespace glm diff --git a/thirdparty/glm/gtx/std_based_type.hpp b/thirdparty/glm/gtx/std_based_type.hpp new file mode 100644 index 0000000..cd3be8c --- /dev/null +++ b/thirdparty/glm/gtx/std_based_type.hpp @@ -0,0 +1,68 @@ +/// @ref gtx_std_based_type +/// @file glm/gtx/std_based_type.hpp +/// +/// @see core (dependence) +/// @see gtx_extented_min_max (dependence) +/// +/// @defgroup gtx_std_based_type GLM_GTX_std_based_type +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Adds vector types based on STL value types. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_std_based_type is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_std_based_type extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_std_based_type + /// @{ + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4; + + /// Vector type based of one std::size_t component. + /// @see GLM_GTX_std_based_type + typedef vec<1, std::size_t, defaultp> size1_t; + + /// Vector type based of two std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<2, std::size_t, defaultp> size2_t; + + /// Vector type based of three std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<3, std::size_t, defaultp> size3_t; + + /// Vector type based of four std::size_t components. + /// @see GLM_GTX_std_based_type + typedef vec<4, std::size_t, defaultp> size4_t; + + /// @} +}//namespace glm + +#include "std_based_type.inl" diff --git a/thirdparty/glm/gtx/std_based_type.inl b/thirdparty/glm/gtx/std_based_type.inl new file mode 100644 index 0000000..9c34bdb --- /dev/null +++ b/thirdparty/glm/gtx/std_based_type.inl @@ -0,0 +1,6 @@ +/// @ref gtx_std_based_type + +namespace glm +{ + +} diff --git a/thirdparty/glm/gtx/string_cast.hpp b/thirdparty/glm/gtx/string_cast.hpp new file mode 100644 index 0000000..27846bf --- /dev/null +++ b/thirdparty/glm/gtx/string_cast.hpp @@ -0,0 +1,52 @@ +/// @ref gtx_string_cast +/// @file glm/gtx/string_cast.hpp +/// +/// @see core (dependence) +/// @see gtx_integer (dependence) +/// @see gtx_quaternion (dependence) +/// +/// @defgroup gtx_string_cast GLM_GTX_string_cast +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Setup strings for GLM type values +/// +/// This extension is not supported with CUDA + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_string_cast is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_string_cast extension included") +# endif +#endif + +#if(GLM_COMPILER & GLM_COMPILER_CUDA) +# error "GLM_GTX_string_cast is not supported on CUDA compiler" +#endif + +namespace glm +{ + /// @addtogroup gtx_string_cast + /// @{ + + /// Create a string from a GLM vector or matrix typed variable. + /// @see gtx_string_cast extension. + template + GLM_FUNC_DECL std::string to_string(genType const& x); + + /// @} +}//namespace glm + +#include "string_cast.inl" diff --git a/thirdparty/glm/gtx/string_cast.inl b/thirdparty/glm/gtx/string_cast.inl new file mode 100644 index 0000000..f67751d --- /dev/null +++ b/thirdparty/glm/gtx/string_cast.inl @@ -0,0 +1,492 @@ +/// @ref gtx_string_cast + +#include +#include + +namespace glm{ +namespace detail +{ + template + struct cast + { + typedef T value_type; + }; + + template <> + struct cast + { + typedef double value_type; + }; + + GLM_FUNC_QUALIFIER std::string format(const char* msg, ...) + { + std::size_t const STRING_BUFFER(4096); + char text[STRING_BUFFER]; + va_list list; + + if(msg == GLM_NULLPTR) + return std::string(); + + va_start(list, msg); +# if (GLM_COMPILER & GLM_COMPILER_VC) + vsprintf_s(text, STRING_BUFFER, msg, list); +# else// + std::vsprintf(text, msg, list); +# endif// + va_end(list); + + return std::string(text); + } + + static const char* LabelTrue = "true"; + static const char* LabelFalse = "false"; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%d";} + }; + + template + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%f";} + }; + +# if GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; + + template<> + struct literal + { + GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} + }; +# endif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC + + template + struct prefix{}; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "d";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "b";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i8";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i16";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "u64";} + }; + + template<> + struct prefix + { + GLM_FUNC_QUALIFIER static char const * value() {return "i64";} + }; + + template + struct compute_to_string + {}; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, bool, Q> const& x) + { + return detail::format("bvec1(%s)", + x[0] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, bool, Q> const& x) + { + return detail::format("bvec2(%s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, bool, Q> const& x) + { + return detail::format("bvec3(%s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, bool, Q> const& x) + { + return detail::format("bvec4(%s, %s, %s, %s)", + x[0] ? detail::LabelTrue : detail::LabelFalse, + x[1] ? detail::LabelTrue : detail::LabelFalse, + x[2] ? detail::LabelTrue : detail::LabelFalse, + x[3] ? detail::LabelTrue : detail::LabelFalse); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<1, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec1(%s)", + PrefixStr, + LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec2(%s, %s)", + PrefixStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec3(%s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(vec<4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%svec4(%s, %s, %s, %s)", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0]), + static_cast::value_type>(x[1]), + static_cast::value_type>(x[2]), + static_cast::value_type>(x[3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x2((%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x3((%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<2, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x2((%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<3, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 2, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))", + PrefixStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr, + LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 3, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2])); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(mat<4, 4, T, Q> const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), + static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), + static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3]), + static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2]), static_cast::value_type>(x[3][3])); + } + }; + + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(qua const& q) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%squat(%s, {%s, %s, %s})", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(q.w), + static_cast::value_type>(q.x), + static_cast::value_type>(q.y), + static_cast::value_type>(q.z)); + } + }; + + template + struct compute_to_string > + { + GLM_FUNC_QUALIFIER static std::string call(tdualquat const& x) + { + char const * PrefixStr = prefix::value(); + char const * LiteralStr = literal::is_iec559>::value(); + std::string FormatStr(detail::format("%sdualquat((%s, {%s, %s, %s}), (%s, {%s, %s, %s}))", + PrefixStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr, + LiteralStr, LiteralStr, LiteralStr, LiteralStr)); + + return detail::format(FormatStr.c_str(), + static_cast::value_type>(x.real.w), + static_cast::value_type>(x.real.x), + static_cast::value_type>(x.real.y), + static_cast::value_type>(x.real.z), + static_cast::value_type>(x.dual.w), + static_cast::value_type>(x.dual.x), + static_cast::value_type>(x.dual.y), + static_cast::value_type>(x.dual.z)); + } + }; + +}//namespace detail + +template +GLM_FUNC_QUALIFIER std::string to_string(matType const& x) +{ + return detail::compute_to_string::call(x); +} + +}//namespace glm diff --git a/thirdparty/glm/gtx/texture.hpp b/thirdparty/glm/gtx/texture.hpp new file mode 100644 index 0000000..20585e6 --- /dev/null +++ b/thirdparty/glm/gtx/texture.hpp @@ -0,0 +1,46 @@ +/// @ref gtx_texture +/// @file glm/gtx/texture.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_texture GLM_GTX_texture +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/integer.hpp" +#include "../gtx/component_wise.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_texture is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_texture extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_texture + /// @{ + + /// Compute the number of mipmaps levels necessary to create a mipmap complete texture + /// + /// @param Extent Extent of the texture base level mipmap + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + template + T levels(vec const& Extent); + + /// @} +}// namespace glm + +#include "texture.inl" + diff --git a/thirdparty/glm/gtx/texture.inl b/thirdparty/glm/gtx/texture.inl new file mode 100644 index 0000000..593c826 --- /dev/null +++ b/thirdparty/glm/gtx/texture.inl @@ -0,0 +1,17 @@ +/// @ref gtx_texture + +namespace glm +{ + template + inline T levels(vec const& Extent) + { + return glm::log2(compMax(Extent)) + static_cast(1); + } + + template + inline T levels(T Extent) + { + return vec<1, T, defaultp>(Extent).x; + } +}//namespace glm + diff --git a/thirdparty/glm/gtx/transform.hpp b/thirdparty/glm/gtx/transform.hpp new file mode 100644 index 0000000..0279fc8 --- /dev/null +++ b/thirdparty/glm/gtx/transform.hpp @@ -0,0 +1,60 @@ +/// @ref gtx_transform +/// @file glm/gtx/transform.hpp +/// +/// @see core (dependence) +/// @see gtc_matrix_transform (dependence) +/// @see gtx_transform +/// @see gtx_transform2 +/// +/// @defgroup gtx_transform GLM_GTX_transform +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/matrix_transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform + /// @{ + + /// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> translate( + vec<3, T, Q> const& v); + + /// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> rotate( + T angle, + vec<3, T, Q> const& v); + + /// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components. + /// @see gtc_matrix_transform + /// @see gtx_transform + template + GLM_FUNC_DECL mat<4, 4, T, Q> scale( + vec<3, T, Q> const& v); + + /// @} +}// namespace glm + +#include "transform.inl" diff --git a/thirdparty/glm/gtx/transform.inl b/thirdparty/glm/gtx/transform.inl new file mode 100644 index 0000000..48ee680 --- /dev/null +++ b/thirdparty/glm/gtx/transform.inl @@ -0,0 +1,23 @@ +/// @ref gtx_transform + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(vec<3, T, Q> const& v) + { + return translate(mat<4, 4, T, Q>(static_cast(1)), v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(T angle, vec<3, T, Q> const& v) + { + return rotate(mat<4, 4, T, Q>(static_cast(1)), angle, v); + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(vec<3, T, Q> const& v) + { + return scale(mat<4, 4, T, Q>(static_cast(1)), v); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/transform2.hpp b/thirdparty/glm/gtx/transform2.hpp new file mode 100644 index 0000000..0d8ba9d --- /dev/null +++ b/thirdparty/glm/gtx/transform2.hpp @@ -0,0 +1,89 @@ +/// @ref gtx_transform2 +/// @file glm/gtx/transform2.hpp +/// +/// @see core (dependence) +/// @see gtx_transform (dependence) +/// +/// @defgroup gtx_transform2 GLM_GTX_transform2 +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Add extra transformation matrices + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtx/transform.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_transform2 is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_transform2 extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_transform2 + /// @{ + + //! Transforms a matrix with a shearing on X axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T y); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T x); + + //! Transforms a matrix with a shearing on X axis + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T y, T z); + + //! Transforms a matrix with a shearing on Y axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T x, T z); + + //! Transforms a matrix with a shearing on Z axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T x, T y); + + //template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(const mat<4, 4, T, Q> & m, shearPlane, planePoint, angle) + // Identity + tan(angle) * cross(Normal, OnPlaneVector) 0 + // - dot(PointOnPlane, normal) * OnPlaneVector 1 + + // Reflect functions seem to don't work + //template mat<3, 3, T, Q> reflect2D(const mat<3, 3, T, Q> & m, const vec<3, T, Q>& normal){return reflect2DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + //template mat<4, 4, T, Q> reflect3D(const mat<4, 4, T, Q> & m, const vec<3, T, Q>& normal){return reflect3DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<3, 3, T, Q> proj2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal); + + //! Build planar projection matrix along normal axis. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> proj3D(mat<4, 4, T, Q> const & m, vec<3, T, Q> const& normal); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(T scale, T bias); + + //! Build a scale bias matrix. + //! From GLM_GTX_transform2 extension. + template + GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias); + + /// @} +}// namespace glm + +#include "transform2.inl" diff --git a/thirdparty/glm/gtx/transform2.inl b/thirdparty/glm/gtx/transform2.inl new file mode 100644 index 0000000..2b53198 --- /dev/null +++ b/thirdparty/glm/gtx/transform2.inl @@ -0,0 +1,125 @@ +/// @ref gtx_transform2 + +namespace glm +{ + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[1][0] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T s) + { + mat<3, 3, T, Q> r(1); + r[0][1] = s; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[0][1] = s; + r[0][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[1][0] = s; + r[1][2] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T s, T t) + { + mat<4, 4, T, Q> r(1); + r[2][0] = s; + r[2][1] = t; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; + r[0][1] = -static_cast(2) * normal.x * normal.y; + r[0][2] = -static_cast(2) * normal.x * normal.z; + + r[1][0] = -static_cast(2) * normal.x * normal.y; + r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; + r[1][2] = -static_cast(2) * normal.y * normal.z; + + r[2][0] = -static_cast(2) * normal.x * normal.z; + r[2][1] = -static_cast(2) * normal.y * normal.z; + r[2][2] = static_cast(1) - static_cast(2) * normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<3, 3, T, Q> proj2D( + const mat<3, 3, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<3, 3, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> proj3D( + const mat<4, 4, T, Q>& m, + const vec<3, T, Q>& normal) + { + mat<4, 4, T, Q> r(static_cast(1)); + r[0][0] = static_cast(1) - normal.x * normal.x; + r[0][1] = - normal.x * normal.y; + r[0][2] = - normal.x * normal.z; + r[1][0] = - normal.x * normal.y; + r[1][1] = static_cast(1) - normal.y * normal.y; + r[1][2] = - normal.y * normal.z; + r[2][0] = - normal.x * normal.z; + r[2][1] = - normal.y * normal.z; + r[2][2] = static_cast(1) - normal.z * normal.z; + return m * r; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(T scale, T bias) + { + mat<4, 4, T, Q> result; + result[3] = vec<4, T, Q>(vec<3, T, Q>(bias), static_cast(1)); + result[0][0] = scale; + result[1][1] = scale; + result[2][2] = scale; + return result; + } + + template + GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias) + { + return m * scaleBias(scale, bias); + } +}//namespace glm + diff --git a/thirdparty/glm/gtx/type_aligned.hpp b/thirdparty/glm/gtx/type_aligned.hpp new file mode 100644 index 0000000..2ae522c --- /dev/null +++ b/thirdparty/glm/gtx/type_aligned.hpp @@ -0,0 +1,982 @@ +/// @ref gtx_type_aligned +/// @file glm/gtx/type_aligned.hpp +/// +/// @see core (dependence) +/// @see gtc_quaternion (dependence) +/// +/// @defgroup gtx_type_aligned GLM_GTX_type_aligned +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines aligned types. + +#pragma once + +// Dependency: +#include "../gtc/type_precision.hpp" +#include "../gtc/quaternion.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_aligned is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_aligned extension included") +# endif +#endif + +namespace glm +{ + /////////////////////////// + // Signed int vector types + + /// @addtogroup gtx_type_aligned + /// @{ + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8); + + + /// Low qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1); + + /// Low qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2); + + /// Low qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4); + + /// Low qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8); + + + /// Medium qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1); + + /// Medium qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2); + + /// Medium qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4); + + /// Medium qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8); + + + /// High qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1); + + /// High qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2); + + /// High qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4); + + /// High qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1); + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2); + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4); + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16); + + + /// Default qualifier 8 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1); + + /// Default qualifier 8 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2); + + /// Default qualifier 8 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4); + + /// Default qualifier 8 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4); + + + /// Default qualifier 16 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2); + + /// Default qualifier 16 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4); + + /// Default qualifier 16 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8); + + /// Default qualifier 16 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8); + + + /// Default qualifier 32 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4); + + /// Default qualifier 32 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8); + + /// Default qualifier 32 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16); + + /// Default qualifier 32 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16); + + + /// Default qualifier 64 bit signed integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8); + + /// Default qualifier 64 bit signed integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16); + + /// Default qualifier 64 bit signed integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32); + + /// Default qualifier 64 bit signed integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32); + + + ///////////////////////////// + // Unsigned int vector types + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8); + + + /// Low qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1); + + /// Low qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2); + + /// Low qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4); + + /// Low qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8); + + + /// Medium qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1); + + /// Medium qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2); + + /// Medium qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4); + + /// Medium qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8); + + + /// High qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1); + + /// High qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2); + + /// High qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4); + + /// High qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1); + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2); + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4); + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16); + + + /// Default qualifier 8 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1); + + /// Default qualifier 8 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2); + + /// Default qualifier 8 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4); + + /// Default qualifier 8 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4); + + + /// Default qualifier 16 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2); + + /// Default qualifier 16 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4); + + /// Default qualifier 16 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8); + + /// Default qualifier 16 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8); + + + /// Default qualifier 32 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4); + + /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8); + + /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16); + + /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16); + + + /// Default qualifier 64 bit unsigned integer aligned scalar type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8); + + /// Default qualifier 64 bit unsigned integer aligned vector of 2 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16); + + /// Default qualifier 64 bit unsigned integer aligned vector of 3 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32); + + /// Default qualifier 64 bit unsigned integer aligned vector of 4 components type. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32); + + + ////////////////////// + // Float vector types + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4); + + /// 32 bit single-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8); + + /// 64 bit double-qualifier floating-point aligned scalar. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8); + +# endif//GLM_FORCE_SINGLE_ONLY + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16); + + + /// Single-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4); + + /// Single-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8); + + /// Single-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16); + + /// Single-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16); + + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned vector of 1 component. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8); + + /// Double-qualifier floating-point aligned vector of 2 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16); + + /// Double-qualifier floating-point aligned vector of 3 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32); + + /// Double-qualifier floating-point aligned vector of 4 components. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + ////////////////////// + // Float matrix types + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 fmat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 fmat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f32mat1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16); + + + /// Single-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f32 f32mat1x1; + + /// Single-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16); + + /// Single-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16); + + /// Single-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16); + + /// Single-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16); + + /// Single-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16); + + /// Single-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16); + + /// Single-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16); + + /// Single-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16); + + /// Single-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16); + + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef detail::tmat1x1 f64mat1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32); + + + /// Double-qualifier floating-point aligned 1x1 matrix. + /// @see gtx_type_aligned + //typedef f64 f64mat1x1; + + /// Double-qualifier floating-point aligned 2x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32); + + /// Double-qualifier floating-point aligned 2x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32); + + /// Double-qualifier floating-point aligned 2x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32); + + /// Double-qualifier floating-point aligned 3x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32); + + /// Double-qualifier floating-point aligned 3x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32); + + /// Double-qualifier floating-point aligned 3x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32); + + /// Double-qualifier floating-point aligned 4x2 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32); + + /// Double-qualifier floating-point aligned 4x3 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32); + + /// Double-qualifier floating-point aligned 4x4 matrix. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + + ////////////////////////// + // Quaternion types + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(quat, aligned_fquat, 16); + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32); + + /// Single-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16); + +# ifndef GLM_FORCE_SINGLE_ONLY + + /// Double-qualifier floating-point aligned quaternion. + /// @see gtx_type_aligned + GLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32); + +# endif//GLM_FORCE_SINGLE_ONLY + + /// @} +}//namespace glm + +#include "type_aligned.inl" diff --git a/thirdparty/glm/gtx/type_aligned.inl b/thirdparty/glm/gtx/type_aligned.inl new file mode 100644 index 0000000..54c1b81 --- /dev/null +++ b/thirdparty/glm/gtx/type_aligned.inl @@ -0,0 +1,6 @@ +/// @ref gtc_type_aligned + +namespace glm +{ + +} diff --git a/thirdparty/glm/gtx/type_trait.hpp b/thirdparty/glm/gtx/type_trait.hpp new file mode 100644 index 0000000..56685c8 --- /dev/null +++ b/thirdparty/glm/gtx/type_trait.hpp @@ -0,0 +1,85 @@ +/// @ref gtx_type_trait +/// @file glm/gtx/type_trait.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_type_trait GLM_GTX_type_trait +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Defines traits for each type. + +#pragma once + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_type_trait is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_type_trait extension included") +# endif +#endif + +// Dependency: +#include "../detail/qualifier.hpp" +#include "../gtc/quaternion.hpp" +#include "../gtx/dual_quaternion.hpp" + +namespace glm +{ + /// @addtogroup gtx_type_trait + /// @{ + + template + struct type + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = 0; + static length_t const cols = 0; + static length_t const rows = 0; + }; + + template + struct type > + { + static bool const is_vec = true; + static bool const is_mat = false; + static bool const is_quat = false; + static length_t const components = L; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = true; + static bool const is_quat = false; + static length_t const components = C; + static length_t const cols = C; + static length_t const rows = R; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 4; + }; + + template + struct type > + { + static bool const is_vec = false; + static bool const is_mat = false; + static bool const is_quat = true; + static length_t const components = 8; + }; + + /// @} +}//namespace glm + +#include "type_trait.inl" diff --git a/thirdparty/glm/gtx/type_trait.inl b/thirdparty/glm/gtx/type_trait.inl new file mode 100644 index 0000000..045de95 --- /dev/null +++ b/thirdparty/glm/gtx/type_trait.inl @@ -0,0 +1,61 @@ +/// @ref gtx_type_trait + +namespace glm +{ + template + bool const type::is_vec; + template + bool const type::is_mat; + template + bool const type::is_quat; + template + length_t const type::components; + template + length_t const type::cols; + template + length_t const type::rows; + + // vec + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // mat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + template + length_t const type >::cols; + template + length_t const type >::rows; + + // tquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; + + // tdualquat + template + bool const type >::is_vec; + template + bool const type >::is_mat; + template + bool const type >::is_quat; + template + length_t const type >::components; +}//namespace glm diff --git a/thirdparty/glm/gtx/vec_swizzle.hpp b/thirdparty/glm/gtx/vec_swizzle.hpp new file mode 100644 index 0000000..1c49abc --- /dev/null +++ b/thirdparty/glm/gtx/vec_swizzle.hpp @@ -0,0 +1,2782 @@ +/// @ref gtx_vec_swizzle +/// @file glm/gtx/vec_swizzle.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vec_swizzle GLM_GTX_vec_swizzle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Functions to perform swizzle operation. + +#pragma once + +#include "../glm.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vec_swizzle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vec_swizzle extension included") +# endif +#endif + +namespace glm { + // xx + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<1, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.x); + } + + // xy + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.y); + } + + // xz + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.z); + } + + // xw + template + GLM_INLINE glm::vec<2, T, Q> xw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.x, v.w); + } + + // yx + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.x); + } + + // yy + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<2, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.y); + } + + // yz + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.z); + } + + // yw + template + GLM_INLINE glm::vec<2, T, Q> yw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.y, v.w); + } + + // zx + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + template + GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.x); + } + + // zy + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + template + GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.y); + } + + // zz + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<3, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + template + GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.z); + } + + // zw + template + GLM_INLINE glm::vec<2, T, Q> zw(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.z, v.w); + } + + // wx + template + GLM_INLINE glm::vec<2, T, Q> wx(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.x); + } + + // wy + template + GLM_INLINE glm::vec<2, T, Q> wy(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.y); + } + + // wz + template + GLM_INLINE glm::vec<2, T, Q> wz(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.z); + } + + // ww + template + GLM_INLINE glm::vec<2, T, Q> ww(const glm::vec<4, T, Q> &v) { + return glm::vec<2, T, Q>(v.w, v.w); + } + + // xxx + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<1, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.x); + } + + // xxy + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.y); + } + + // xxz + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.z); + } + + // xxw + template + GLM_INLINE glm::vec<3, T, Q> xxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.x, v.w); + } + + // xyx + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.x); + } + + // xyy + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.y); + } + + // xyz + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.z); + } + + // xyw + template + GLM_INLINE glm::vec<3, T, Q> xyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.y, v.w); + } + + // xzx + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.x); + } + + // xzy + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.y); + } + + // xzz + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.z); + } + + // xzw + template + GLM_INLINE glm::vec<3, T, Q> xzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.z, v.w); + } + + // xwx + template + GLM_INLINE glm::vec<3, T, Q> xwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.x); + } + + // xwy + template + GLM_INLINE glm::vec<3, T, Q> xwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.y); + } + + // xwz + template + GLM_INLINE glm::vec<3, T, Q> xwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.z); + } + + // xww + template + GLM_INLINE glm::vec<3, T, Q> xww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.x, v.w, v.w); + } + + // yxx + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.x); + } + + // yxy + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.y); + } + + // yxz + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.z); + } + + // yxw + template + GLM_INLINE glm::vec<3, T, Q> yxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.x, v.w); + } + + // yyx + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.x); + } + + // yyy + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<2, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.y); + } + + // yyz + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.z); + } + + // yyw + template + GLM_INLINE glm::vec<3, T, Q> yyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.y, v.w); + } + + // yzx + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.x); + } + + // yzy + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.y); + } + + // yzz + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.z); + } + + // yzw + template + GLM_INLINE glm::vec<3, T, Q> yzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.z, v.w); + } + + // ywx + template + GLM_INLINE glm::vec<3, T, Q> ywx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.x); + } + + // ywy + template + GLM_INLINE glm::vec<3, T, Q> ywy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.y); + } + + // ywz + template + GLM_INLINE glm::vec<3, T, Q> ywz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.z); + } + + // yww + template + GLM_INLINE glm::vec<3, T, Q> yww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.y, v.w, v.w); + } + + // zxx + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.x); + } + + // zxy + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.y); + } + + // zxz + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.z); + } + + // zxw + template + GLM_INLINE glm::vec<3, T, Q> zxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.x, v.w); + } + + // zyx + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.x); + } + + // zyy + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.y); + } + + // zyz + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.z); + } + + // zyw + template + GLM_INLINE glm::vec<3, T, Q> zyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.y, v.w); + } + + // zzx + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.x); + } + + // zzy + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.y); + } + + // zzz + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<3, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.z); + } + + // zzw + template + GLM_INLINE glm::vec<3, T, Q> zzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.z, v.w); + } + + // zwx + template + GLM_INLINE glm::vec<3, T, Q> zwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.x); + } + + // zwy + template + GLM_INLINE glm::vec<3, T, Q> zwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.y); + } + + // zwz + template + GLM_INLINE glm::vec<3, T, Q> zwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.z); + } + + // zww + template + GLM_INLINE glm::vec<3, T, Q> zww(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.z, v.w, v.w); + } + + // wxx + template + GLM_INLINE glm::vec<3, T, Q> wxx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.x); + } + + // wxy + template + GLM_INLINE glm::vec<3, T, Q> wxy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.y); + } + + // wxz + template + GLM_INLINE glm::vec<3, T, Q> wxz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.z); + } + + // wxw + template + GLM_INLINE glm::vec<3, T, Q> wxw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.x, v.w); + } + + // wyx + template + GLM_INLINE glm::vec<3, T, Q> wyx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.x); + } + + // wyy + template + GLM_INLINE glm::vec<3, T, Q> wyy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.y); + } + + // wyz + template + GLM_INLINE glm::vec<3, T, Q> wyz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.z); + } + + // wyw + template + GLM_INLINE glm::vec<3, T, Q> wyw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.y, v.w); + } + + // wzx + template + GLM_INLINE glm::vec<3, T, Q> wzx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.x); + } + + // wzy + template + GLM_INLINE glm::vec<3, T, Q> wzy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.y); + } + + // wzz + template + GLM_INLINE glm::vec<3, T, Q> wzz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.z); + } + + // wzw + template + GLM_INLINE glm::vec<3, T, Q> wzw(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.z, v.w); + } + + // wwx + template + GLM_INLINE glm::vec<3, T, Q> wwx(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.x); + } + + // wwy + template + GLM_INLINE glm::vec<3, T, Q> wwy(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.y); + } + + // wwz + template + GLM_INLINE glm::vec<3, T, Q> wwz(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.z); + } + + // www + template + GLM_INLINE glm::vec<3, T, Q> www(const glm::vec<4, T, Q> &v) { + return glm::vec<3, T, Q>(v.w, v.w, v.w); + } + + // xxxx + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<1, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); + } + + // xxxy + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); + } + + // xxxz + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); + } + + // xxxw + template + GLM_INLINE glm::vec<4, T, Q> xxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.x, v.w); + } + + // xxyx + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); + } + + // xxyy + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); + } + + // xxyz + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); + } + + // xxyw + template + GLM_INLINE glm::vec<4, T, Q> xxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.y, v.w); + } + + // xxzx + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); + } + + // xxzy + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); + } + + // xxzz + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); + } + + // xxzw + template + GLM_INLINE glm::vec<4, T, Q> xxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.z, v.w); + } + + // xxwx + template + GLM_INLINE glm::vec<4, T, Q> xxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.x); + } + + // xxwy + template + GLM_INLINE glm::vec<4, T, Q> xxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.y); + } + + // xxwz + template + GLM_INLINE glm::vec<4, T, Q> xxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.z); + } + + // xxww + template + GLM_INLINE glm::vec<4, T, Q> xxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.x, v.w, v.w); + } + + // xyxx + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); + } + + // xyxy + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); + } + + // xyxz + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); + } + + // xyxw + template + GLM_INLINE glm::vec<4, T, Q> xyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.x, v.w); + } + + // xyyx + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); + } + + // xyyy + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); + } + + // xyyz + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); + } + + // xyyw + template + GLM_INLINE glm::vec<4, T, Q> xyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.y, v.w); + } + + // xyzx + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); + } + + // xyzy + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); + } + + // xyzz + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); + } + + // xyzw + template + GLM_INLINE glm::vec<4, T, Q> xyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.z, v.w); + } + + // xywx + template + GLM_INLINE glm::vec<4, T, Q> xywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.x); + } + + // xywy + template + GLM_INLINE glm::vec<4, T, Q> xywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.y); + } + + // xywz + template + GLM_INLINE glm::vec<4, T, Q> xywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.z); + } + + // xyww + template + GLM_INLINE glm::vec<4, T, Q> xyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.y, v.w, v.w); + } + + // xzxx + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); + } + + // xzxy + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); + } + + // xzxz + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); + } + + // xzxw + template + GLM_INLINE glm::vec<4, T, Q> xzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.x, v.w); + } + + // xzyx + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); + } + + // xzyy + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); + } + + // xzyz + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); + } + + // xzyw + template + GLM_INLINE glm::vec<4, T, Q> xzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.y, v.w); + } + + // xzzx + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); + } + + // xzzy + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); + } + + // xzzz + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); + } + + // xzzw + template + GLM_INLINE glm::vec<4, T, Q> xzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.z, v.w); + } + + // xzwx + template + GLM_INLINE glm::vec<4, T, Q> xzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.x); + } + + // xzwy + template + GLM_INLINE glm::vec<4, T, Q> xzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.y); + } + + // xzwz + template + GLM_INLINE glm::vec<4, T, Q> xzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.z); + } + + // xzww + template + GLM_INLINE glm::vec<4, T, Q> xzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.z, v.w, v.w); + } + + // xwxx + template + GLM_INLINE glm::vec<4, T, Q> xwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.x); + } + + // xwxy + template + GLM_INLINE glm::vec<4, T, Q> xwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.y); + } + + // xwxz + template + GLM_INLINE glm::vec<4, T, Q> xwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.z); + } + + // xwxw + template + GLM_INLINE glm::vec<4, T, Q> xwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.x, v.w); + } + + // xwyx + template + GLM_INLINE glm::vec<4, T, Q> xwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.x); + } + + // xwyy + template + GLM_INLINE glm::vec<4, T, Q> xwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.y); + } + + // xwyz + template + GLM_INLINE glm::vec<4, T, Q> xwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.z); + } + + // xwyw + template + GLM_INLINE glm::vec<4, T, Q> xwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.y, v.w); + } + + // xwzx + template + GLM_INLINE glm::vec<4, T, Q> xwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.x); + } + + // xwzy + template + GLM_INLINE glm::vec<4, T, Q> xwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.y); + } + + // xwzz + template + GLM_INLINE glm::vec<4, T, Q> xwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.z); + } + + // xwzw + template + GLM_INLINE glm::vec<4, T, Q> xwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.z, v.w); + } + + // xwwx + template + GLM_INLINE glm::vec<4, T, Q> xwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.x); + } + + // xwwy + template + GLM_INLINE glm::vec<4, T, Q> xwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.y); + } + + // xwwz + template + GLM_INLINE glm::vec<4, T, Q> xwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.z); + } + + // xwww + template + GLM_INLINE glm::vec<4, T, Q> xwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.x, v.w, v.w, v.w); + } + + // yxxx + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); + } + + // yxxy + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); + } + + // yxxz + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); + } + + // yxxw + template + GLM_INLINE glm::vec<4, T, Q> yxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.x, v.w); + } + + // yxyx + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); + } + + // yxyy + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); + } + + // yxyz + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); + } + + // yxyw + template + GLM_INLINE glm::vec<4, T, Q> yxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.y, v.w); + } + + // yxzx + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); + } + + // yxzy + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); + } + + // yxzz + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); + } + + // yxzw + template + GLM_INLINE glm::vec<4, T, Q> yxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.z, v.w); + } + + // yxwx + template + GLM_INLINE glm::vec<4, T, Q> yxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.x); + } + + // yxwy + template + GLM_INLINE glm::vec<4, T, Q> yxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.y); + } + + // yxwz + template + GLM_INLINE glm::vec<4, T, Q> yxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.z); + } + + // yxww + template + GLM_INLINE glm::vec<4, T, Q> yxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.x, v.w, v.w); + } + + // yyxx + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); + } + + // yyxy + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); + } + + // yyxz + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); + } + + // yyxw + template + GLM_INLINE glm::vec<4, T, Q> yyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.x, v.w); + } + + // yyyx + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); + } + + // yyyy + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<2, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); + } + + // yyyz + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); + } + + // yyyw + template + GLM_INLINE glm::vec<4, T, Q> yyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.y, v.w); + } + + // yyzx + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); + } + + // yyzy + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); + } + + // yyzz + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); + } + + // yyzw + template + GLM_INLINE glm::vec<4, T, Q> yyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.z, v.w); + } + + // yywx + template + GLM_INLINE glm::vec<4, T, Q> yywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.x); + } + + // yywy + template + GLM_INLINE glm::vec<4, T, Q> yywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.y); + } + + // yywz + template + GLM_INLINE glm::vec<4, T, Q> yywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.z); + } + + // yyww + template + GLM_INLINE glm::vec<4, T, Q> yyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.y, v.w, v.w); + } + + // yzxx + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); + } + + // yzxy + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); + } + + // yzxz + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); + } + + // yzxw + template + GLM_INLINE glm::vec<4, T, Q> yzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.x, v.w); + } + + // yzyx + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); + } + + // yzyy + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); + } + + // yzyz + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); + } + + // yzyw + template + GLM_INLINE glm::vec<4, T, Q> yzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.y, v.w); + } + + // yzzx + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); + } + + // yzzy + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); + } + + // yzzz + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); + } + + // yzzw + template + GLM_INLINE glm::vec<4, T, Q> yzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.z, v.w); + } + + // yzwx + template + GLM_INLINE glm::vec<4, T, Q> yzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.x); + } + + // yzwy + template + GLM_INLINE glm::vec<4, T, Q> yzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.y); + } + + // yzwz + template + GLM_INLINE glm::vec<4, T, Q> yzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.z); + } + + // yzww + template + GLM_INLINE glm::vec<4, T, Q> yzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.z, v.w, v.w); + } + + // ywxx + template + GLM_INLINE glm::vec<4, T, Q> ywxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.x); + } + + // ywxy + template + GLM_INLINE glm::vec<4, T, Q> ywxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.y); + } + + // ywxz + template + GLM_INLINE glm::vec<4, T, Q> ywxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.z); + } + + // ywxw + template + GLM_INLINE glm::vec<4, T, Q> ywxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.x, v.w); + } + + // ywyx + template + GLM_INLINE glm::vec<4, T, Q> ywyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.x); + } + + // ywyy + template + GLM_INLINE glm::vec<4, T, Q> ywyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.y); + } + + // ywyz + template + GLM_INLINE glm::vec<4, T, Q> ywyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.z); + } + + // ywyw + template + GLM_INLINE glm::vec<4, T, Q> ywyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.y, v.w); + } + + // ywzx + template + GLM_INLINE glm::vec<4, T, Q> ywzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.x); + } + + // ywzy + template + GLM_INLINE glm::vec<4, T, Q> ywzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.y); + } + + // ywzz + template + GLM_INLINE glm::vec<4, T, Q> ywzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.z); + } + + // ywzw + template + GLM_INLINE glm::vec<4, T, Q> ywzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.z, v.w); + } + + // ywwx + template + GLM_INLINE glm::vec<4, T, Q> ywwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.x); + } + + // ywwy + template + GLM_INLINE glm::vec<4, T, Q> ywwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.y); + } + + // ywwz + template + GLM_INLINE glm::vec<4, T, Q> ywwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.z); + } + + // ywww + template + GLM_INLINE glm::vec<4, T, Q> ywww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.y, v.w, v.w, v.w); + } + + // zxxx + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); + } + + // zxxy + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); + } + + // zxxz + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); + } + + // zxxw + template + GLM_INLINE glm::vec<4, T, Q> zxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.x, v.w); + } + + // zxyx + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); + } + + // zxyy + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); + } + + // zxyz + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); + } + + // zxyw + template + GLM_INLINE glm::vec<4, T, Q> zxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.y, v.w); + } + + // zxzx + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); + } + + // zxzy + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); + } + + // zxzz + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); + } + + // zxzw + template + GLM_INLINE glm::vec<4, T, Q> zxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.z, v.w); + } + + // zxwx + template + GLM_INLINE glm::vec<4, T, Q> zxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.x); + } + + // zxwy + template + GLM_INLINE glm::vec<4, T, Q> zxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.y); + } + + // zxwz + template + GLM_INLINE glm::vec<4, T, Q> zxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.z); + } + + // zxww + template + GLM_INLINE glm::vec<4, T, Q> zxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.x, v.w, v.w); + } + + // zyxx + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); + } + + // zyxy + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); + } + + // zyxz + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); + } + + // zyxw + template + GLM_INLINE glm::vec<4, T, Q> zyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.x, v.w); + } + + // zyyx + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); + } + + // zyyy + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); + } + + // zyyz + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); + } + + // zyyw + template + GLM_INLINE glm::vec<4, T, Q> zyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.y, v.w); + } + + // zyzx + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); + } + + // zyzy + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); + } + + // zyzz + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); + } + + // zyzw + template + GLM_INLINE glm::vec<4, T, Q> zyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.z, v.w); + } + + // zywx + template + GLM_INLINE glm::vec<4, T, Q> zywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.x); + } + + // zywy + template + GLM_INLINE glm::vec<4, T, Q> zywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.y); + } + + // zywz + template + GLM_INLINE glm::vec<4, T, Q> zywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.z); + } + + // zyww + template + GLM_INLINE glm::vec<4, T, Q> zyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.y, v.w, v.w); + } + + // zzxx + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); + } + + // zzxy + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); + } + + // zzxz + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); + } + + // zzxw + template + GLM_INLINE glm::vec<4, T, Q> zzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.x, v.w); + } + + // zzyx + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); + } + + // zzyy + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); + } + + // zzyz + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); + } + + // zzyw + template + GLM_INLINE glm::vec<4, T, Q> zzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.y, v.w); + } + + // zzzx + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); + } + + // zzzy + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); + } + + // zzzz + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<3, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + template + GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); + } + + // zzzw + template + GLM_INLINE glm::vec<4, T, Q> zzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.z, v.w); + } + + // zzwx + template + GLM_INLINE glm::vec<4, T, Q> zzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.x); + } + + // zzwy + template + GLM_INLINE glm::vec<4, T, Q> zzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.y); + } + + // zzwz + template + GLM_INLINE glm::vec<4, T, Q> zzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.z); + } + + // zzww + template + GLM_INLINE glm::vec<4, T, Q> zzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.z, v.w, v.w); + } + + // zwxx + template + GLM_INLINE glm::vec<4, T, Q> zwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.x); + } + + // zwxy + template + GLM_INLINE glm::vec<4, T, Q> zwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.y); + } + + // zwxz + template + GLM_INLINE glm::vec<4, T, Q> zwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.z); + } + + // zwxw + template + GLM_INLINE glm::vec<4, T, Q> zwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.x, v.w); + } + + // zwyx + template + GLM_INLINE glm::vec<4, T, Q> zwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.x); + } + + // zwyy + template + GLM_INLINE glm::vec<4, T, Q> zwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.y); + } + + // zwyz + template + GLM_INLINE glm::vec<4, T, Q> zwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.z); + } + + // zwyw + template + GLM_INLINE glm::vec<4, T, Q> zwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.y, v.w); + } + + // zwzx + template + GLM_INLINE glm::vec<4, T, Q> zwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.x); + } + + // zwzy + template + GLM_INLINE glm::vec<4, T, Q> zwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.y); + } + + // zwzz + template + GLM_INLINE glm::vec<4, T, Q> zwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.z); + } + + // zwzw + template + GLM_INLINE glm::vec<4, T, Q> zwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.z, v.w); + } + + // zwwx + template + GLM_INLINE glm::vec<4, T, Q> zwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.x); + } + + // zwwy + template + GLM_INLINE glm::vec<4, T, Q> zwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.y); + } + + // zwwz + template + GLM_INLINE glm::vec<4, T, Q> zwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.z); + } + + // zwww + template + GLM_INLINE glm::vec<4, T, Q> zwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.z, v.w, v.w, v.w); + } + + // wxxx + template + GLM_INLINE glm::vec<4, T, Q> wxxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.x); + } + + // wxxy + template + GLM_INLINE glm::vec<4, T, Q> wxxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.y); + } + + // wxxz + template + GLM_INLINE glm::vec<4, T, Q> wxxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.z); + } + + // wxxw + template + GLM_INLINE glm::vec<4, T, Q> wxxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.x, v.w); + } + + // wxyx + template + GLM_INLINE glm::vec<4, T, Q> wxyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.x); + } + + // wxyy + template + GLM_INLINE glm::vec<4, T, Q> wxyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.y); + } + + // wxyz + template + GLM_INLINE glm::vec<4, T, Q> wxyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.z); + } + + // wxyw + template + GLM_INLINE glm::vec<4, T, Q> wxyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.y, v.w); + } + + // wxzx + template + GLM_INLINE glm::vec<4, T, Q> wxzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.x); + } + + // wxzy + template + GLM_INLINE glm::vec<4, T, Q> wxzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.y); + } + + // wxzz + template + GLM_INLINE glm::vec<4, T, Q> wxzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.z); + } + + // wxzw + template + GLM_INLINE glm::vec<4, T, Q> wxzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.z, v.w); + } + + // wxwx + template + GLM_INLINE glm::vec<4, T, Q> wxwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.x); + } + + // wxwy + template + GLM_INLINE glm::vec<4, T, Q> wxwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.y); + } + + // wxwz + template + GLM_INLINE glm::vec<4, T, Q> wxwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.z); + } + + // wxww + template + GLM_INLINE glm::vec<4, T, Q> wxww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.x, v.w, v.w); + } + + // wyxx + template + GLM_INLINE glm::vec<4, T, Q> wyxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.x); + } + + // wyxy + template + GLM_INLINE glm::vec<4, T, Q> wyxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.y); + } + + // wyxz + template + GLM_INLINE glm::vec<4, T, Q> wyxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.z); + } + + // wyxw + template + GLM_INLINE glm::vec<4, T, Q> wyxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.x, v.w); + } + + // wyyx + template + GLM_INLINE glm::vec<4, T, Q> wyyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.x); + } + + // wyyy + template + GLM_INLINE glm::vec<4, T, Q> wyyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.y); + } + + // wyyz + template + GLM_INLINE glm::vec<4, T, Q> wyyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.z); + } + + // wyyw + template + GLM_INLINE glm::vec<4, T, Q> wyyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.y, v.w); + } + + // wyzx + template + GLM_INLINE glm::vec<4, T, Q> wyzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.x); + } + + // wyzy + template + GLM_INLINE glm::vec<4, T, Q> wyzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.y); + } + + // wyzz + template + GLM_INLINE glm::vec<4, T, Q> wyzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.z); + } + + // wyzw + template + GLM_INLINE glm::vec<4, T, Q> wyzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.z, v.w); + } + + // wywx + template + GLM_INLINE glm::vec<4, T, Q> wywx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.x); + } + + // wywy + template + GLM_INLINE glm::vec<4, T, Q> wywy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.y); + } + + // wywz + template + GLM_INLINE glm::vec<4, T, Q> wywz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.z); + } + + // wyww + template + GLM_INLINE glm::vec<4, T, Q> wyww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.y, v.w, v.w); + } + + // wzxx + template + GLM_INLINE glm::vec<4, T, Q> wzxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.x); + } + + // wzxy + template + GLM_INLINE glm::vec<4, T, Q> wzxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.y); + } + + // wzxz + template + GLM_INLINE glm::vec<4, T, Q> wzxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.z); + } + + // wzxw + template + GLM_INLINE glm::vec<4, T, Q> wzxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.x, v.w); + } + + // wzyx + template + GLM_INLINE glm::vec<4, T, Q> wzyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.x); + } + + // wzyy + template + GLM_INLINE glm::vec<4, T, Q> wzyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.y); + } + + // wzyz + template + GLM_INLINE glm::vec<4, T, Q> wzyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.z); + } + + // wzyw + template + GLM_INLINE glm::vec<4, T, Q> wzyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.y, v.w); + } + + // wzzx + template + GLM_INLINE glm::vec<4, T, Q> wzzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.x); + } + + // wzzy + template + GLM_INLINE glm::vec<4, T, Q> wzzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.y); + } + + // wzzz + template + GLM_INLINE glm::vec<4, T, Q> wzzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.z); + } + + // wzzw + template + GLM_INLINE glm::vec<4, T, Q> wzzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.z, v.w); + } + + // wzwx + template + GLM_INLINE glm::vec<4, T, Q> wzwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.x); + } + + // wzwy + template + GLM_INLINE glm::vec<4, T, Q> wzwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.y); + } + + // wzwz + template + GLM_INLINE glm::vec<4, T, Q> wzwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.z); + } + + // wzww + template + GLM_INLINE glm::vec<4, T, Q> wzww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.z, v.w, v.w); + } + + // wwxx + template + GLM_INLINE glm::vec<4, T, Q> wwxx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.x); + } + + // wwxy + template + GLM_INLINE glm::vec<4, T, Q> wwxy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.y); + } + + // wwxz + template + GLM_INLINE glm::vec<4, T, Q> wwxz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.z); + } + + // wwxw + template + GLM_INLINE glm::vec<4, T, Q> wwxw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.x, v.w); + } + + // wwyx + template + GLM_INLINE glm::vec<4, T, Q> wwyx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.x); + } + + // wwyy + template + GLM_INLINE glm::vec<4, T, Q> wwyy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.y); + } + + // wwyz + template + GLM_INLINE glm::vec<4, T, Q> wwyz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.z); + } + + // wwyw + template + GLM_INLINE glm::vec<4, T, Q> wwyw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.y, v.w); + } + + // wwzx + template + GLM_INLINE glm::vec<4, T, Q> wwzx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.x); + } + + // wwzy + template + GLM_INLINE glm::vec<4, T, Q> wwzy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.y); + } + + // wwzz + template + GLM_INLINE glm::vec<4, T, Q> wwzz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.z); + } + + // wwzw + template + GLM_INLINE glm::vec<4, T, Q> wwzw(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.z, v.w); + } + + // wwwx + template + GLM_INLINE glm::vec<4, T, Q> wwwx(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.x); + } + + // wwwy + template + GLM_INLINE glm::vec<4, T, Q> wwwy(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.y); + } + + // wwwz + template + GLM_INLINE glm::vec<4, T, Q> wwwz(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.z); + } + + // wwww + template + GLM_INLINE glm::vec<4, T, Q> wwww(const glm::vec<4, T, Q> &v) { + return glm::vec<4, T, Q>(v.w, v.w, v.w, v.w); + } + +} diff --git a/thirdparty/glm/gtx/vector_angle.hpp b/thirdparty/glm/gtx/vector_angle.hpp new file mode 100644 index 0000000..9ae4371 --- /dev/null +++ b/thirdparty/glm/gtx/vector_angle.hpp @@ -0,0 +1,57 @@ +/// @ref gtx_vector_angle +/// @file glm/gtx/vector_angle.hpp +/// +/// @see core (dependence) +/// @see gtx_quaternion (dependence) +/// @see gtx_epsilon (dependence) +/// +/// @defgroup gtx_vector_angle GLM_GTX_vector_angle +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Compute angle between vectors + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../gtc/epsilon.hpp" +#include "../gtx/quaternion.hpp" +#include "../gtx/rotate_vector.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_angle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_angle extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_angle + /// @{ + + //! Returns the absolute angle between two vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T angle(vec const& x, vec const& y); + + //! Returns the oriented angle between two 2d vectors. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y); + + //! Returns the oriented angle between two 3d vectors based from a reference axis. + //! Parameters need to be normalized. + /// @see gtx_vector_angle extension. + template + GLM_FUNC_DECL T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref); + + /// @} +}// namespace glm + +#include "vector_angle.inl" diff --git a/thirdparty/glm/gtx/vector_angle.inl b/thirdparty/glm/gtx/vector_angle.inl new file mode 100644 index 0000000..a1f957a --- /dev/null +++ b/thirdparty/glm/gtx/vector_angle.inl @@ -0,0 +1,44 @@ +/// @ref gtx_vector_angle + +namespace glm +{ + template + GLM_FUNC_QUALIFIER genType angle + ( + genType const& x, + genType const& y + ) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), genType(-1), genType(1))); + } + + template + GLM_FUNC_QUALIFIER T angle(vec const& x, vec const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); + return acos(clamp(dot(x, y), T(-1), T(1))); + } + + //! \todo epsilon is hard coded to 0.01 + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + + if(all(epsilonEqual(y, glm::rotate(x, Angle), T(0.0001)))) + return Angle; + else + return -Angle; + } + + template + GLM_FUNC_QUALIFIER T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); + + T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); + return mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0)); + } +}//namespace glm diff --git a/thirdparty/glm/gtx/vector_query.hpp b/thirdparty/glm/gtx/vector_query.hpp new file mode 100644 index 0000000..77c7b97 --- /dev/null +++ b/thirdparty/glm/gtx/vector_query.hpp @@ -0,0 +1,66 @@ +/// @ref gtx_vector_query +/// @file glm/gtx/vector_query.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_vector_query GLM_GTX_vector_query +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Query informations of vector types + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include +#include + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_vector_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_vector_query extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_vector_query + /// @{ + + //! Check whether two vectors are collinears. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areCollinear(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether two vectors are orthogonals. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon); + + //! Check whether a vector is normalized. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNormalized(vec const& v, T const& epsilon); + + //! Check whether a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool isNull(vec const& v, T const& epsilon); + + //! Check whether a each component of a vector is null. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL vec isCompNull(vec const& v, T const& epsilon); + + //! Check whether two vectors are orthonormal. + /// @see gtx_vector_query extensions. + template + GLM_FUNC_DECL bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon); + + /// @} +}// namespace glm + +#include "vector_query.inl" diff --git a/thirdparty/glm/gtx/vector_query.inl b/thirdparty/glm/gtx/vector_query.inl new file mode 100644 index 0000000..d1a5c9b --- /dev/null +++ b/thirdparty/glm/gtx/vector_query.inl @@ -0,0 +1,154 @@ +/// @ref gtx_vector_query + +#include + +namespace glm{ +namespace detail +{ + template + struct compute_areCollinear{}; + + template + struct compute_areCollinear<2, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<2, T, Q> const& v0, vec<2, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0, static_cast(0)), vec<3, T, Q>(v1, static_cast(0)))) < epsilon; + } + }; + + template + struct compute_areCollinear<3, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, T const& epsilon) + { + return length(cross(v0, v1)) < epsilon; + } + }; + + template + struct compute_areCollinear<4, T, Q> + { + GLM_FUNC_QUALIFIER static bool call(vec<4, T, Q> const& v0, vec<4, T, Q> const& v1, T const& epsilon) + { + return length(cross(vec<3, T, Q>(v0), vec<3, T, Q>(v1))) < epsilon; + } + }; + + template + struct compute_isCompNull{}; + + template + struct compute_isCompNull<2, T, Q> + { + GLM_FUNC_QUALIFIER static vec<2, bool, Q> call(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon)); + } + }; + + template + struct compute_isCompNull<3, T, Q> + { + GLM_FUNC_QUALIFIER static vec<3, bool, Q> call(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon)); + } + }; + + template + struct compute_isCompNull<4, T, Q> + { + GLM_FUNC_QUALIFIER static vec<4, bool, Q> call(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + (abs(v.x) < epsilon), + (abs(v.y) < epsilon), + (abs(v.z) < epsilon), + (abs(v.w) < epsilon)); + } + }; + +}//namespace detail + + template + GLM_FUNC_QUALIFIER bool areCollinear(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areCollinear' only accept floating-point inputs"); + + return detail::compute_areCollinear::call(v0, v1, epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areOrthogonal' only accept floating-point inputs"); + + return abs(dot(v0, v1)) <= max( + static_cast(1), + length(v0)) * max(static_cast(1), length(v1)) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNormalized(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNormalized' only accept floating-point inputs"); + + return abs(length(v) - static_cast(1)) <= static_cast(2) * epsilon; + } + + template + GLM_FUNC_QUALIFIER bool isNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNull' only accept floating-point inputs"); + + return length(v) <= epsilon; + } + + template + GLM_FUNC_QUALIFIER vec isCompNull(vec const& v, T const& epsilon) + { + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isCompNull' only accept floating-point inputs"); + + return detail::compute_isCompNull::call(v, epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<2, bool, Q> isCompNull(vec<2, T, Q> const& v, T const& epsilon) + { + return vec<2, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<3, bool, Q> isCompNull(vec<3, T, Q> const& v, T const& epsilon) + { + return vec<3, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon); + } + + template + GLM_FUNC_QUALIFIER vec<4, bool, Q> isCompNull(vec<4, T, Q> const& v, T const& epsilon) + { + return vec<4, bool, Q>( + abs(v.x) < epsilon, + abs(v.y) < epsilon, + abs(v.z) < epsilon, + abs(v.w) < epsilon); + } + + template + GLM_FUNC_QUALIFIER bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon) + { + return isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon); + } + +}//namespace glm diff --git a/thirdparty/glm/gtx/wrap.hpp b/thirdparty/glm/gtx/wrap.hpp new file mode 100644 index 0000000..ad4eb3f --- /dev/null +++ b/thirdparty/glm/gtx/wrap.hpp @@ -0,0 +1,37 @@ +/// @ref gtx_wrap +/// @file glm/gtx/wrap.hpp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_wrap GLM_GTX_wrap +/// @ingroup gtx +/// +/// Include to use the features of this extension. +/// +/// Wrapping mode of texture coordinates. + +#pragma once + +// Dependency: +#include "../glm.hpp" +#include "../ext/scalar_common.hpp" +#include "../ext/vector_common.hpp" +#include "../gtc/vec1.hpp" + +#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) +# ifndef GLM_ENABLE_EXPERIMENTAL +# pragma message("GLM: GLM_GTX_wrap is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") +# else +# pragma message("GLM: GLM_GTX_wrap extension included") +# endif +#endif + +namespace glm +{ + /// @addtogroup gtx_wrap + /// @{ + + /// @} +}// namespace glm + +#include "wrap.inl" diff --git a/thirdparty/glm/gtx/wrap.inl b/thirdparty/glm/gtx/wrap.inl new file mode 100644 index 0000000..4be3b4c --- /dev/null +++ b/thirdparty/glm/gtx/wrap.inl @@ -0,0 +1,6 @@ +/// @ref gtx_wrap + +namespace glm +{ + +}//namespace glm diff --git a/thirdparty/glm/integer.hpp b/thirdparty/glm/integer.hpp new file mode 100644 index 0000000..8817db3 --- /dev/null +++ b/thirdparty/glm/integer.hpp @@ -0,0 +1,212 @@ +/// @ref core +/// @file glm/integer.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.8 Integer Functions +/// +/// @defgroup core_func_integer Integer functions +/// @ingroup core +/// +/// Provides GLSL functions on integer types +/// +/// These all operate component-wise. The description is per component. +/// The notation [a, b] means the set of bits from bit-number a through bit-number +/// b, inclusive. The lowest-order bit is bit 0. +/// +/// Include to use these core features. + +#pragma once + +#include "detail/qualifier.hpp" +#include "common.hpp" +#include "vector_relational.hpp" + +namespace glm +{ + /// @addtogroup core_func_integer + /// @{ + + /// Adds 32-bit unsigned integer x and y, returning the sum + /// modulo pow(2, 32). The value carry is set to 0 if the sum was + /// less than pow(2, 32), or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL uaddCarry man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec uaddCarry( + vec const& x, + vec const& y, + vec & carry); + + /// Subtracts the 32-bit unsigned integer y from x, returning + /// the difference if non-negative, or pow(2, 32) plus the difference + /// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL usubBorrow man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec usubBorrow( + vec const& x, + vec const& y, + vec & borrow); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL umulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void umulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Multiplies 32-bit integers x and y, producing a 64-bit + /// result. The 32 least-significant bits are returned in lsb. + /// The 32 most-significant bits are returned in msb. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL imulExtended man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL void imulExtended( + vec const& x, + vec const& y, + vec & msb, + vec & lsb); + + /// Extracts bits [offset, offset + bits - 1] from value, + /// returning them in the least significant bits of the result. + /// For unsigned data types, the most significant bits of the + /// result will be set to zero. For signed data types, the + /// most significant bits will be set to the value of bit offset + base - 1. + /// + /// If bits is zero, the result will be zero. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used + /// to store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL bitfieldExtract man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldExtract( + vec const& Value, + int Offset, + int Bits); + + /// Returns the insertion the bits least-significant bits of insert into base. + /// + /// The result will have bits [offset, offset + bits - 1] taken + /// from bits [0, bits - 1] of insert, and all other bits taken + /// directly from the corresponding bits of base. If bits is + /// zero, the result will simply be base. The result will be + /// undefined if offset or bits is negative, or if the sum of + /// offset and bits is greater than the number of bits used to + /// store the operand. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldInsert man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldInsert( + vec const& Base, + vec const& Insert, + int Offset, + int Bits); + + /// Returns the reversal of the bits of value. + /// The bit numbered n of the result will be taken from bit (bits - 1) - n of value, + /// where bits is the total number of bits used to represent value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitfieldReverse man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitfieldReverse(vec const& v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam genType Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int bitCount(genType v); + + /// Returns the number of bits set to 1 in the binary representation of value. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar or vector types. + /// + /// @see GLSL bitCount man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec bitCount(vec const& v); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findLSB(genIUType x); + + /// Returns the bit number of the least significant bit set to + /// 1 in the binary representation of value. + /// If value is zero, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findLSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findLSB(vec const& v); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam genIUType Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL int findMSB(genIUType x); + + /// Returns the bit number of the most significant bit in the binary representation of value. + /// For positive integers, the result will be the bit number of the most significant bit set to 1. + /// For negative integers, the result will be the bit number of the most significant + /// bit set to 0. For a value of zero or negative one, -1 will be returned. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T Signed or unsigned integer scalar types. + /// + /// @see GLSL findMSB man page + /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions + template + GLM_FUNC_DECL vec findMSB(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_integer.inl" diff --git a/thirdparty/glm/mat2x2.hpp b/thirdparty/glm/mat2x2.hpp new file mode 100644 index 0000000..96bec96 --- /dev/null +++ b/thirdparty/glm/mat2x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x2.hpp + +#pragma once +#include "./ext/matrix_double2x2.hpp" +#include "./ext/matrix_double2x2_precision.hpp" +#include "./ext/matrix_float2x2.hpp" +#include "./ext/matrix_float2x2_precision.hpp" + diff --git a/thirdparty/glm/mat2x3.hpp b/thirdparty/glm/mat2x3.hpp new file mode 100644 index 0000000..d68dc25 --- /dev/null +++ b/thirdparty/glm/mat2x3.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x3.hpp + +#pragma once +#include "./ext/matrix_double2x3.hpp" +#include "./ext/matrix_double2x3_precision.hpp" +#include "./ext/matrix_float2x3.hpp" +#include "./ext/matrix_float2x3_precision.hpp" + diff --git a/thirdparty/glm/mat2x4.hpp b/thirdparty/glm/mat2x4.hpp new file mode 100644 index 0000000..b04b738 --- /dev/null +++ b/thirdparty/glm/mat2x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat2x4.hpp + +#pragma once +#include "./ext/matrix_double2x4.hpp" +#include "./ext/matrix_double2x4_precision.hpp" +#include "./ext/matrix_float2x4.hpp" +#include "./ext/matrix_float2x4_precision.hpp" + diff --git a/thirdparty/glm/mat3x2.hpp b/thirdparty/glm/mat3x2.hpp new file mode 100644 index 0000000..c853153 --- /dev/null +++ b/thirdparty/glm/mat3x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat3x2.hpp + +#pragma once +#include "./ext/matrix_double3x2.hpp" +#include "./ext/matrix_double3x2_precision.hpp" +#include "./ext/matrix_float3x2.hpp" +#include "./ext/matrix_float3x2_precision.hpp" + diff --git a/thirdparty/glm/mat3x3.hpp b/thirdparty/glm/mat3x3.hpp new file mode 100644 index 0000000..fd4fa31 --- /dev/null +++ b/thirdparty/glm/mat3x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x3.hpp + +#pragma once +#include "./ext/matrix_double3x3.hpp" +#include "./ext/matrix_double3x3_precision.hpp" +#include "./ext/matrix_float3x3.hpp" +#include "./ext/matrix_float3x3_precision.hpp" diff --git a/thirdparty/glm/mat3x4.hpp b/thirdparty/glm/mat3x4.hpp new file mode 100644 index 0000000..6342bf5 --- /dev/null +++ b/thirdparty/glm/mat3x4.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat3x4.hpp + +#pragma once +#include "./ext/matrix_double3x4.hpp" +#include "./ext/matrix_double3x4_precision.hpp" +#include "./ext/matrix_float3x4.hpp" +#include "./ext/matrix_float3x4_precision.hpp" diff --git a/thirdparty/glm/mat4x2.hpp b/thirdparty/glm/mat4x2.hpp new file mode 100644 index 0000000..e013e46 --- /dev/null +++ b/thirdparty/glm/mat4x2.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x2.hpp + +#pragma once +#include "./ext/matrix_double4x2.hpp" +#include "./ext/matrix_double4x2_precision.hpp" +#include "./ext/matrix_float4x2.hpp" +#include "./ext/matrix_float4x2_precision.hpp" + diff --git a/thirdparty/glm/mat4x3.hpp b/thirdparty/glm/mat4x3.hpp new file mode 100644 index 0000000..205725a --- /dev/null +++ b/thirdparty/glm/mat4x3.hpp @@ -0,0 +1,8 @@ +/// @ref core +/// @file glm/mat4x3.hpp + +#pragma once +#include "./ext/matrix_double4x3.hpp" +#include "./ext/matrix_double4x3_precision.hpp" +#include "./ext/matrix_float4x3.hpp" +#include "./ext/matrix_float4x3_precision.hpp" diff --git a/thirdparty/glm/mat4x4.hpp b/thirdparty/glm/mat4x4.hpp new file mode 100644 index 0000000..3515f7f --- /dev/null +++ b/thirdparty/glm/mat4x4.hpp @@ -0,0 +1,9 @@ +/// @ref core +/// @file glm/mat4x4.hpp + +#pragma once +#include "./ext/matrix_double4x4.hpp" +#include "./ext/matrix_double4x4_precision.hpp" +#include "./ext/matrix_float4x4.hpp" +#include "./ext/matrix_float4x4_precision.hpp" + diff --git a/thirdparty/glm/matrix.hpp b/thirdparty/glm/matrix.hpp new file mode 100644 index 0000000..6badf53 --- /dev/null +++ b/thirdparty/glm/matrix.hpp @@ -0,0 +1,161 @@ +/// @ref core +/// @file glm/matrix.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions +/// +/// @defgroup core_func_matrix Matrix functions +/// @ingroup core +/// +/// Provides GLSL matrix functions. +/// +/// Include to use these core features. + +#pragma once + +// Dependencies +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" +#include "vec2.hpp" +#include "vec3.hpp" +#include "vec4.hpp" +#include "mat2x2.hpp" +#include "mat2x3.hpp" +#include "mat2x4.hpp" +#include "mat3x2.hpp" +#include "mat3x3.hpp" +#include "mat3x4.hpp" +#include "mat4x2.hpp" +#include "mat4x3.hpp" +#include "mat4x4.hpp" + +namespace glm { +namespace detail +{ + template + struct outerProduct_trait{}; + + template + struct outerProduct_trait<2, 2, T, Q> + { + typedef mat<2, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 3, T, Q> + { + typedef mat<3, 2, T, Q> type; + }; + + template + struct outerProduct_trait<2, 4, T, Q> + { + typedef mat<4, 2, T, Q> type; + }; + + template + struct outerProduct_trait<3, 2, T, Q> + { + typedef mat<2, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 3, T, Q> + { + typedef mat<3, 3, T, Q> type; + }; + + template + struct outerProduct_trait<3, 4, T, Q> + { + typedef mat<4, 3, T, Q> type; + }; + + template + struct outerProduct_trait<4, 2, T, Q> + { + typedef mat<2, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 3, T, Q> + { + typedef mat<3, 4, T, Q> type; + }; + + template + struct outerProduct_trait<4, 4, T, Q> + { + typedef mat<4, 4, T, Q> type; + }; +}//namespace detail + + /// @addtogroup core_func_matrix + /// @{ + + /// Multiply matrix x by matrix y component-wise, i.e., + /// result[i][j] is the scalar product of x[i][j] and y[i][j]. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL matrixCompMult man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat matrixCompMult(mat const& x, mat const& y); + + /// Treats the first parameter c as a column vector + /// and the second parameter r as a row vector + /// and does a linear algebraic matrix multiply c * r. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL outerProduct man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r); + + /// Returns the transposed matrix of x + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL transpose man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL typename mat::transpose_type transpose(mat const& x); + + /// Return the determinant of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL determinant man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL T determinant(mat const& m); + + /// Return the inverse of a squared matrix. + /// + /// @tparam C Integer between 1 and 4 included that qualify the number a column + /// @tparam R Integer between 1 and 4 included that qualify the number a row + /// @tparam T Floating-point or signed integer scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL inverse man page + /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions + template + GLM_FUNC_DECL mat inverse(mat const& m); + + /// @} +}//namespace glm + +#include "detail/func_matrix.inl" diff --git a/thirdparty/glm/packing.hpp b/thirdparty/glm/packing.hpp new file mode 100644 index 0000000..ca83ac1 --- /dev/null +++ b/thirdparty/glm/packing.hpp @@ -0,0 +1,173 @@ +/// @ref core +/// @file glm/packing.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions +/// @see gtc_packing +/// +/// @defgroup core_func_packing Floating-Point Pack and Unpack Functions +/// @ingroup core +/// +/// Provides GLSL functions to pack and unpack half, single and double-precision floating point values into more compact integer types. +/// +/// These functions do not operate component-wise, rather as described in each case. +/// +/// Include to use these core features. + +#pragma once + +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float4.hpp" + +namespace glm +{ + /// @addtogroup core_func_packing + /// @{ + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm2x16(vec2 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packUnorm4x8: round(clamp(c, 0, +1) * 255.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packUnorm4x8(vec4 const& v); + + /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. + /// Then, the results are packed into the returned 32-bit unsigned integer. + /// + /// The conversion for component c of v to fixed point is done as follows: + /// packSnorm4x8: round(clamp(c, -1, +1) * 127.0) + /// + /// The first component of the vector will be written to the least significant bits of the output; + /// the last component will be written to the most significant bits. + /// + /// @see GLSL packSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packSnorm4x8(vec4 const& v); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm2x16: f / 65535.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackUnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm2x16: clamp(f / 32767.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackSnorm2x16(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackUnorm4x8: f / 255.0 + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackUnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackUnorm4x8(uint p); + + /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. + /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. + /// + /// The conversion for unpacked fixed-point value f to floating point is done as follows: + /// unpackSnorm4x8: clamp(f / 127.0, -1, +1) + /// + /// The first component of the returned vector will be extracted from the least significant bits of the input; + /// the last component will be extracted from the most significant bits. + /// + /// @see GLSL unpackSnorm4x8 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec4 unpackSnorm4x8(uint p); + + /// Returns a double-qualifier value obtained by packing the components of v into a 64-bit value. + /// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified. + /// Otherwise, the bit- level representation of v is preserved. + /// The first vector component specifies the 32 least significant bits; + /// the second component specifies the 32 most significant bits. + /// + /// @see GLSL packDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL double packDouble2x32(uvec2 const& v); + + /// Returns a two-component unsigned integer vector representation of v. + /// The bit-level representation of v is preserved. + /// The first component of the vector contains the 32 least significant bits of the double; + /// the second component consists the 32 most significant bits. + /// + /// @see GLSL unpackDouble2x32 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uvec2 unpackDouble2x32(double v); + + /// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector + /// to the 16-bit floating-point representation found in the OpenGL Specification, + /// and then packing these two 16- bit integers into a 32-bit unsigned integer. + /// The first vector component specifies the 16 least-significant bits of the result; + /// the second component specifies the 16 most-significant bits. + /// + /// @see GLSL packHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL uint packHalf2x16(vec2 const& v); + + /// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, + /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, + /// and converting them to 32-bit floating-point values. + /// The first component of the vector is obtained from the 16 least-significant bits of v; + /// the second component is obtained from the 16 most-significant bits of v. + /// + /// @see GLSL unpackHalf2x16 man page + /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions + GLM_FUNC_DECL vec2 unpackHalf2x16(uint v); + + /// @} +}//namespace glm + +#include "detail/func_packing.inl" diff --git a/thirdparty/glm/simd/common.h b/thirdparty/glm/simd/common.h new file mode 100644 index 0000000..9b017cb --- /dev/null +++ b/thirdparty/glm/simd/common.h @@ -0,0 +1,240 @@ +/// @ref simd +/// @file glm/simd/common.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_add(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_add_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sub(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_sub_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_mul(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_mul_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ps(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_div(glm_f32vec4 a, glm_f32vec4 b) +{ + return _mm_div_ss(a, b); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div_lowp(glm_f32vec4 a, glm_f32vec4 b) +{ + return glm_vec4_mul(a, _mm_rcp_ps(b)); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_swizzle_xyzw(glm_f32vec4 a) +{ +# if GLM_ARCH & GLM_ARCH_AVX2_BIT + return _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0)); +# else + return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0)); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ss(a, b, c); +# else + return _mm_add_ss(_mm_mul_ss(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) +{ +# if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) + return _mm_fmadd_ps(a, b, c); +# else + return glm_vec4_add(glm_vec4_mul(a, b), c); +# endif +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_abs(glm_f32vec4 x) +{ + return _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF))); +} + +GLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSSE3_BIT + return _mm_sign_epi32(x, x); +# else + glm_ivec4 const sgn0 = _mm_srai_epi32(x, 31); + glm_ivec4 const inv0 = _mm_xor_si128(x, sgn0); + glm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x) +{ + glm_vec4 const zro0 = _mm_setzero_ps(); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0); + glm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f)); + glm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f)); + glm_vec4 const or0 = _mm_or_ps(and0, and1); + return or0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT); +# else + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_floor_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const sub0 = glm_vec4_sub(rnd0, and0); + return sub0; +# endif +} + +/* trunc TODO +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x) +{ + return glm_vec4(); +} +*/ + +//roundEven +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x) +{ + glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); + glm_vec4 const and0 = _mm_and_ps(sgn0, x); + glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); + glm_vec4 const add0 = glm_vec4_add(x, or0); + glm_vec4 const sub0 = glm_vec4_sub(add0, or0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x) +{ +# if GLM_ARCH & GLM_ARCH_SSE41_BIT + return _mm_ceil_ps(x); +# else + glm_vec4 const rnd0 = glm_vec4_round(x); + glm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0); + glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); + glm_vec4 const add0 = glm_vec4_add(rnd0, and0); + return add0; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x) +{ + glm_vec4 const flr0 = glm_vec4_floor(x); + glm_vec4 const sub0 = glm_vec4_sub(x, flr0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y) +{ + glm_vec4 const div0 = glm_vec4_div(x, y); + glm_vec4 const flr0 = glm_vec4_floor(div0); + glm_vec4 const mul0 = glm_vec4_mul(y, flr0); + glm_vec4 const sub0 = glm_vec4_sub(x, mul0); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal) +{ + glm_vec4 const min0 = _mm_min_ps(v, maxVal); + glm_vec4 const max0 = _mm_max_ps(min0, minVal); + return max0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a) +{ + glm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a); + glm_vec4 const mul0 = glm_vec4_mul(v1, sub0); + glm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0); + return mad0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x) +{ + glm_vec4 const cmp = _mm_cmple_ps(x, edge); + return _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps(); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x) +{ + glm_vec4 const sub0 = glm_vec4_sub(x, edge0); + glm_vec4 const sub1 = glm_vec4_sub(edge1, edge0); + glm_vec4 const div0 = glm_vec4_sub(sub0, sub1); + glm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f)); + glm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0); + glm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0); + glm_vec4 const mul1 = glm_vec4_mul(clp0, clp0); + glm_vec4 const mul2 = glm_vec4_mul(mul1, sub2); + return mul2; +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + glm_ivec4 const t3 = _mm_set1_epi32(int(0xFF000000)); // exponent mask + glm_ivec4 const t4 = _mm_and_si128(t2, t3); // exponent + glm_ivec4 const t5 = _mm_andnot_si128(t3, t2); // fraction + glm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4); + glm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128()); + glm_ivec4 const And = _mm_and_si128(Equal, Nequal); + return _mm_castsi128_ps(And); // exponent = all 1s and fraction != 0 +} + +// Agner Fog method +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x) +{ + glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer + glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit + return _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(int(0xFF000000)))); // exponent is all 1s, fraction is 0 +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/exponential.h b/thirdparty/glm/simd/exponential.h new file mode 100644 index 0000000..bc351d0 --- /dev/null +++ b/thirdparty/glm/simd/exponential.h @@ -0,0 +1,20 @@ +/// @ref simd +/// @file glm/simd/experimental.h + +#pragma once + +#include "platform.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ss(_mm_rsqrt_ss(x), x); +} + +GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sqrt_lowp(glm_f32vec4 x) +{ + return _mm_mul_ps(_mm_rsqrt_ps(x), x); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/geometric.h b/thirdparty/glm/simd/geometric.h new file mode 100644 index 0000000..07d7cbc --- /dev/null +++ b/thirdparty/glm/simd/geometric.h @@ -0,0 +1,124 @@ +/// @ref simd +/// @file glm/simd/geometric.h + +#pragma once + +#include "common.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2); +GLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2); + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x) +{ + glm_vec4 const dot0 = glm_vec4_dot(x, x); + glm_vec4 const sqt0 = _mm_sqrt_ps(dot0); + return sqt0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1) +{ + glm_vec4 const sub0 = _mm_sub_ps(p0, p1); + glm_vec4 const len0 = glm_vec4_length(sub0); + return len0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0); + return hadd1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1)); + glm_vec4 const add0 = _mm_add_ps(mul0, swp0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3)); + glm_vec4 const add1 = _mm_add_ps(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2) +{ +# if GLM_ARCH & GLM_ARCH_AVX_BIT + return _mm_dp_ps(v1, v2, 0xff); +# elif GLM_ARCH & GLM_ARCH_SSE3_BIT + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const had0 = _mm_hadd_ps(mul0, mul0); + glm_vec4 const had1 = _mm_hadd_ps(had0, had0); + return had1; +# else + glm_vec4 const mul0 = _mm_mul_ps(v1, v2); + glm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0); + glm_vec4 const add0 = _mm_add_ps(mov0, mul0); + glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1); + glm_vec4 const add1 = _mm_add_ss(add0, swp1); + return add1; +# endif +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2) +{ + glm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1)); + glm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2)); + glm_vec4 const mul0 = _mm_mul_ps(swp0, swp3); + glm_vec4 const mul1 = _mm_mul_ps(swp1, swp2); + glm_vec4 const sub0 = _mm_sub_ps(mul0, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v) +{ + glm_vec4 const dot0 = glm_vec4_dot(v, v); + glm_vec4 const isr0 = _mm_rsqrt_ps(dot0); + glm_vec4 const mul0 = _mm_mul_ps(v, isr0); + return mul0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref) +{ + glm_vec4 const dot0 = glm_vec4_dot(Nref, I); + glm_vec4 const sgn0 = glm_vec4_sign(dot0); + glm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f)); + glm_vec4 const mul1 = _mm_mul_ps(N, mul0); + return mul1; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(N, dot0); + glm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f)); + glm_vec4 const sub0 = _mm_sub_ps(I, mul1); + return sub0; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta) +{ + glm_vec4 const dot0 = glm_vec4_dot(N, I); + glm_vec4 const mul0 = _mm_mul_ps(eta, eta); + glm_vec4 const mul1 = _mm_mul_ps(dot0, dot0); + glm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0); + glm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1); + glm_vec4 const mul2 = _mm_mul_ps(sub0, sub1); + + if(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0) + return _mm_set1_ps(0.0f); + + glm_vec4 const sqt0 = _mm_sqrt_ps(mul2); + glm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0); + glm_vec4 const mul4 = _mm_mul_ps(mad0, N); + glm_vec4 const mul5 = _mm_mul_ps(eta, I); + glm_vec4 const sub2 = _mm_sub_ps(mul5, mul4); + + return sub2; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/integer.h b/thirdparty/glm/simd/integer.h new file mode 100644 index 0000000..9381418 --- /dev/null +++ b/thirdparty/glm/simd/integer.h @@ -0,0 +1,115 @@ +/// @ref simd +/// @file glm/simd/integer.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + //Reg1 = _mm_unpacklo_epi64(x, y); + Reg1 = x; + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y) +{ + glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); + glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); + glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); + glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); + glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); + + glm_uvec4 Reg1; + glm_uvec4 Reg2; + + // REG1 = x; + // REG2 = y; + Reg1 = _mm_unpacklo_epi64(x, y); + + //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); + //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); + Reg2 = _mm_slli_si128(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask4); + + //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); + //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); + Reg2 = _mm_slli_si128(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask3); + + //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); + //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); + Reg2 = _mm_slli_epi32(Reg1, 4); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask2); + + //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); + //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); + Reg2 = _mm_slli_epi32(Reg1, 2); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask1); + + //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); + //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg1 = _mm_or_si128(Reg2, Reg1); + Reg1 = _mm_and_si128(Reg1, Mask0); + + //return REG1 | (REG2 << 1); + Reg2 = _mm_slli_epi32(Reg1, 1); + Reg2 = _mm_srli_si128(Reg2, 8); + Reg1 = _mm_or_si128(Reg1, Reg2); + + return Reg1; +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/matrix.h b/thirdparty/glm/simd/matrix.h new file mode 100644 index 0000000..b6c42ea --- /dev/null +++ b/thirdparty/glm/simd/matrix.h @@ -0,0 +1,1028 @@ +/// @ref simd +/// @file glm/simd/matrix.h + +#pragma once + +#include "geometric.h" + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +GLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_mul_ps(in1[0], in2[0]); + out[1] = _mm_mul_ps(in1[1], in2[1]); + out[2] = _mm_mul_ps(in1[2], in2[2]); + out[3] = _mm_mul_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_add_ps(in1[0], in2[0]); + out[1] = _mm_add_ps(in1[1], in2[1]); + out[2] = _mm_add_ps(in1[2], in2[2]); + out[3] = _mm_add_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + out[0] = _mm_sub_ps(in1[0], in2[0]); + out[1] = _mm_sub_ps(in1[1], in2[1]); + out[2] = _mm_sub_ps(in1[2], in2[2]); + out[3] = _mm_sub_ps(in1[3], in2[3]); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v) +{ + __m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(m[0], v0); + __m128 m1 = _mm_mul_ps(m[1], v1); + __m128 m2 = _mm_mul_ps(m[2], v2); + __m128 m3 = _mm_mul_ps(m[3], v3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + return a2; +} + +GLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4]) +{ + __m128 i0 = m[0]; + __m128 i1 = m[1]; + __m128 i2 = m[2]; + __m128 i3 = m[3]; + + __m128 m0 = _mm_mul_ps(v, i0); + __m128 m1 = _mm_mul_ps(v, i1); + __m128 m2 = _mm_mul_ps(v, i2); + __m128 m3 = _mm_mul_ps(v, i3); + + __m128 u0 = _mm_unpacklo_ps(m0, m1); + __m128 u1 = _mm_unpackhi_ps(m0, m1); + __m128 a0 = _mm_add_ps(u0, u1); + + __m128 u2 = _mm_unpacklo_ps(m2, m3); + __m128 u3 = _mm_unpackhi_ps(m2, m3); + __m128 a1 = _mm_add_ps(u2, u3); + + __m128 f0 = _mm_movelh_ps(a0, a1); + __m128 f1 = _mm_movehl_ps(a1, a0); + __m128 f2 = _mm_add_ps(f0, f1); + + return f2; +} + +GLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) +{ + { + __m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[0] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[1] = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[2] = a2; + } + + { + //(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3)) + __m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 m0 = _mm_mul_ps(in1[0], e0); + __m128 m1 = _mm_mul_ps(in1[1], e1); + __m128 m2 = _mm_mul_ps(in1[2], e2); + __m128 m3 = _mm_mul_ps(in1[3], e3); + + __m128 a0 = _mm_add_ps(m0, m1); + __m128 a1 = _mm_add_ps(m2, m3); + __m128 a2 = _mm_add_ps(a0, a1); + + out[3] = a2; + } +} + +GLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44); + __m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE); + __m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44); + __m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE); + + out[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88); + out[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD); + out[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88); + out[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + return Det0; +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128( + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3))); + __m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2))); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2))); + __m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0))); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0))); + __m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1))); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2))); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0))); + __m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3))); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4]) +{ + // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add) + + //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + + // First 2 columns + __m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); + + // Second 2 columns + __m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3)); + __m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2)); + __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); + + // Columns subtraction + __m128 SubE = _mm_sub_ps(MulA, MulB); + + // Last 2 rows + __m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2)); + __m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0)); + __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); + __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); + + //vec<4, T, Q> DetCof( + // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), + // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), + // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); + + __m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0)); + __m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1)); + __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); + + __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); + __m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1]; + __m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2)); + __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); + + __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); + + __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); + __m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0)); + __m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3)); + __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); + + __m128 AddRes = _mm_add_ps(SubRes, MulFacC); + __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); + + //return m[0][0] * DetCof[0] + // + m[0][1] * DetCof[1] + // + m[0][2] * DetCof[2] + // + m[0][3] * DetCof[3]; + + return glm_vec4_dot(m[0], DetCof); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0); + //__m128 Rcp0 = _mm_rcp_ps(Det0); + + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} + +GLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4]) +{ + __m128 Fac0; + { + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac0 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac1; + { + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac1 = _mm_sub_ps(Mul00, Mul01); + } + + + __m128 Fac2; + { + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac2 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac3; + { + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac3 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac4; + { + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac4 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 Fac5; + { + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); + + __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); + __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); + + __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); + __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); + Fac5 = _mm_sub_ps(Mul00, Mul01); + } + + __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); + __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); + + // m[1][0] + // m[0][0] + // m[0][0] + // m[0][0] + __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][1] + // m[0][1] + // m[0][1] + // m[0][1] + __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][2] + // m[0][2] + // m[0][2] + // m[0][2] + __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); + + // m[1][3] + // m[0][3] + // m[0][3] + // m[0][3] + __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); + __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); + + // col0 + // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), + // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), + // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), + // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), + __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); + __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); + __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); + __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); + __m128 Add00 = _mm_add_ps(Sub00, Mul02); + __m128 Inv0 = _mm_mul_ps(SignB, Add00); + + // col1 + // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), + // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), + // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), + // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), + __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); + __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); + __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); + __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); + __m128 Add01 = _mm_add_ps(Sub01, Mul05); + __m128 Inv1 = _mm_mul_ps(SignA, Add01); + + // col2 + // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), + // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), + // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), + // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), + __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); + __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); + __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); + __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); + __m128 Add02 = _mm_add_ps(Sub02, Mul08); + __m128 Inv2 = _mm_mul_ps(SignB, Add02); + + // col3 + // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), + // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), + // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), + // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); + __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); + __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); + __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); + __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); + __m128 Add03 = _mm_add_ps(Sub03, Mul11); + __m128 Inv3 = _mm_mul_ps(SignA, Add03); + + __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); + + // valType Determinant = m[0][0] * Inverse[0][0] + // + m[0][1] * Inverse[1][0] + // + m[0][2] * Inverse[2][0] + // + m[0][3] * Inverse[3][0]; + __m128 Det0 = glm_vec4_dot(in[0], Row2); + __m128 Rcp0 = _mm_rcp_ps(Det0); + //__m128 Rcp0 = _mm_div_ps(one, Det0); + // Inverse /= Determinant; + out[0] = _mm_mul_ps(Inv0, Rcp0); + out[1] = _mm_mul_ps(Inv1, Rcp0); + out[2] = _mm_mul_ps(Inv2, Rcp0); + out[3] = _mm_mul_ps(Inv3, Rcp0); +} +/* +GLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4]) +{ + float a = glm::radians(Angle); + float c = cos(a); + float s = sin(a); + + glm::vec4 AxisA(v[0], v[1], v[2], float(0)); + __m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x); + __m128 AxisC = detail::sse_nrm_ps(AxisB); + + __m128 Cos0 = _mm_set_ss(c); + __m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 Sin0 = _mm_set_ss(s); + __m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0)); + + // vec<3, T, Q> temp = (valType(1) - c) * axis; + __m128 Temp0 = _mm_sub_ps(one, CosA); + __m128 Temp1 = _mm_mul_ps(Temp0, AxisC); + + //Rotate[0][0] = c + temp[0] * axis[0]; + //Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; + //Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; + __m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 TmpA0 = _mm_mul_ps(Axis0, AxisC); + __m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0)); + __m128 TmpA1 = _mm_add_ps(CosA0, TmpA0); + __m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f); + __m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3)); + __m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2); + __m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3); + + //Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; + //Rotate[1][1] = c + temp[1] * axis[1]; + //Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; + __m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 TmpB0 = _mm_mul_ps(Axis1, AxisC); + __m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1)); + __m128 TmpB1 = _mm_add_ps(CosA1, TmpB0); + __m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f); + __m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2)); + __m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2); + __m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3); + + //Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; + //Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; + //Rotate[2][2] = c + temp[2] * axis[2]; + __m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 TmpC0 = _mm_mul_ps(Axis2, AxisC); + __m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1)); + __m128 TmpC1 = _mm_add_ps(CosA2, TmpC0); + __m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f); + __m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1)); + __m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2); + __m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3); + + __m128 Result[4]; + Result[0] = TmpA4; + Result[1] = TmpB4; + Result[2] = TmpC4; + Result[3] = _mm_set_ps(1, 0, 0, 0); + + //mat<4, 4, valType> Result; + //Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; + //Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; + //Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; + //Result[3] = m[3]; + //return Result; + sse_mul_ps(in, Result, out); +} +*/ +GLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const& c, __m128 const& r, __m128 out[4]) +{ + out[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0))); + out[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1))); + out[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2))); + out[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3))); +} + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/neon.h b/thirdparty/glm/simd/neon.h new file mode 100644 index 0000000..6c38b06 --- /dev/null +++ b/thirdparty/glm/simd/neon.h @@ -0,0 +1,155 @@ +/// @ref simd_neon +/// @file glm/simd/neon.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_NEON_BIT +#include + +namespace glm { + namespace neon { + static float32x4_t dupq_lane(float32x4_t vsrc, int lane) { + switch(lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + case 0: return vdupq_laneq_f32(vsrc, 0); + case 1: return vdupq_laneq_f32(vsrc, 1); + case 2: return vdupq_laneq_f32(vsrc, 2); + case 3: return vdupq_laneq_f32(vsrc, 3); +#else + case 0: return vdupq_n_f32(vgetq_lane_f32(vsrc, 0)); + case 1: return vdupq_n_f32(vgetq_lane_f32(vsrc, 1)); + case 2: return vdupq_n_f32(vgetq_lane_f32(vsrc, 2)); + case 3: return vdupq_n_f32(vgetq_lane_f32(vsrc, 3)); +#endif + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); + } + + static float32x2_t dup_lane(float32x4_t vsrc, int lane) { + switch(lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + case 0: return vdup_laneq_f32(vsrc, 0); + case 1: return vdup_laneq_f32(vsrc, 1); + case 2: return vdup_laneq_f32(vsrc, 2); + case 3: return vdup_laneq_f32(vsrc, 3); +#else + case 0: return vdup_n_f32(vgetq_lane_f32(vsrc, 0)); + case 1: return vdup_n_f32(vgetq_lane_f32(vsrc, 1)); + case 2: return vdup_n_f32(vgetq_lane_f32(vsrc, 2)); + case 3: return vdup_n_f32(vgetq_lane_f32(vsrc, 3)); +#endif + } + assert(!"Unreachable code executed!"); + return vdup_n_f32(0.0f); + } + + static float32x4_t copy_lane(float32x4_t vdst, int dlane, float32x4_t vsrc, int slane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + switch(dlane) { + case 0: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 0, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 0, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 0, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 0, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 1: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 1, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 1, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 1, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 1, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 2: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 2, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 2, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 2, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 2, vsrc, 3); + } + assert(!"Unreachable code executed!"); + case 3: + switch(slane) { + case 0: return vcopyq_laneq_f32(vdst, 3, vsrc, 0); + case 1: return vcopyq_laneq_f32(vdst, 3, vsrc, 1); + case 2: return vcopyq_laneq_f32(vdst, 3, vsrc, 2); + case 3: return vcopyq_laneq_f32(vdst, 3, vsrc, 3); + } + assert(!"Unreachable code executed!"); + } +#else + + float l; + switch(slane) { + case 0: l = vgetq_lane_f32(vsrc, 0); break; + case 1: l = vgetq_lane_f32(vsrc, 1); break; + case 2: l = vgetq_lane_f32(vsrc, 2); break; + case 3: l = vgetq_lane_f32(vsrc, 3); break; + default: + assert(!"Unreachable code executed!"); + } + switch(dlane) { + case 0: return vsetq_lane_f32(l, vdst, 0); + case 1: return vsetq_lane_f32(l, vdst, 1); + case 2: return vsetq_lane_f32(l, vdst, 2); + case 3: return vsetq_lane_f32(l, vdst, 3); + } +#endif + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); + } + + static float32x4_t mul_lane(float32x4_t v, float32x4_t vlane, int lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT + switch(lane) { + case 0: return vmulq_laneq_f32(v, vlane, 0); break; + case 1: return vmulq_laneq_f32(v, vlane, 1); break; + case 2: return vmulq_laneq_f32(v, vlane, 2); break; + case 3: return vmulq_laneq_f32(v, vlane, 3); break; + default: + assert(!"Unreachable code executed!"); + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); +#else + return vmulq_f32(v, dupq_lane(vlane, lane)); +#endif + } + + static float32x4_t madd_lane(float32x4_t acc, float32x4_t v, float32x4_t vlane, int lane) { +#if GLM_ARCH & GLM_ARCH_ARMV8_BIT +#ifdef GLM_CONFIG_FORCE_FMA +# define FMADD_LANE(acc, x, y, L) do { asm volatile ("fmla %0.4s, %1.4s, %2.4s" : "+w"(acc) : "w"(x), "w"(dup_lane(y, L))); } while(0) +#else +# define FMADD_LANE(acc, x, y, L) do { acc = vmlaq_laneq_f32(acc, x, y, L); } while(0) +#endif + + switch(lane) { + case 0: + FMADD_LANE(acc, v, vlane, 0); + return acc; + case 1: + FMADD_LANE(acc, v, vlane, 1); + return acc; + case 2: + FMADD_LANE(acc, v, vlane, 2); + return acc; + case 3: + FMADD_LANE(acc, v, vlane, 3); + return acc; + default: + assert(!"Unreachable code executed!"); + } + assert(!"Unreachable code executed!"); + return vdupq_n_f32(0.0f); +# undef FMADD_LANE +#else + return vaddq_f32(acc, vmulq_f32(v, dupq_lane(vlane, lane))); +#endif + } + } //namespace neon +} // namespace glm +#endif // GLM_ARCH & GLM_ARCH_NEON_BIT diff --git a/thirdparty/glm/simd/packing.h b/thirdparty/glm/simd/packing.h new file mode 100644 index 0000000..609163e --- /dev/null +++ b/thirdparty/glm/simd/packing.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/packing.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/simd/platform.h b/thirdparty/glm/simd/platform.h new file mode 100644 index 0000000..ad25cc1 --- /dev/null +++ b/thirdparty/glm/simd/platform.h @@ -0,0 +1,398 @@ +#pragma once + +/////////////////////////////////////////////////////////////////////////////////// +// Platform + +#define GLM_PLATFORM_UNKNOWN 0x00000000 +#define GLM_PLATFORM_WINDOWS 0x00010000 +#define GLM_PLATFORM_LINUX 0x00020000 +#define GLM_PLATFORM_APPLE 0x00040000 +//#define GLM_PLATFORM_IOS 0x00080000 +#define GLM_PLATFORM_ANDROID 0x00100000 +#define GLM_PLATFORM_CHROME_NACL 0x00200000 +#define GLM_PLATFORM_UNIX 0x00400000 +#define GLM_PLATFORM_QNXNTO 0x00800000 +#define GLM_PLATFORM_WINCE 0x01000000 +#define GLM_PLATFORM_CYGWIN 0x02000000 + +#ifdef GLM_FORCE_PLATFORM_UNKNOWN +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#elif defined(__CYGWIN__) +# define GLM_PLATFORM GLM_PLATFORM_CYGWIN +#elif defined(__QNXNTO__) +# define GLM_PLATFORM GLM_PLATFORM_QNXNTO +#elif defined(__APPLE__) +# define GLM_PLATFORM GLM_PLATFORM_APPLE +#elif defined(WINCE) +# define GLM_PLATFORM GLM_PLATFORM_WINCE +#elif defined(_WIN32) +# define GLM_PLATFORM GLM_PLATFORM_WINDOWS +#elif defined(__native_client__) +# define GLM_PLATFORM GLM_PLATFORM_CHROME_NACL +#elif defined(__ANDROID__) +# define GLM_PLATFORM GLM_PLATFORM_ANDROID +#elif defined(__linux) +# define GLM_PLATFORM GLM_PLATFORM_LINUX +#elif defined(__unix) +# define GLM_PLATFORM GLM_PLATFORM_UNIX +#else +# define GLM_PLATFORM GLM_PLATFORM_UNKNOWN +#endif// + +/////////////////////////////////////////////////////////////////////////////////// +// Compiler + +#define GLM_COMPILER_UNKNOWN 0x00000000 + +// Intel +#define GLM_COMPILER_INTEL 0x00100000 +#define GLM_COMPILER_INTEL14 0x00100040 +#define GLM_COMPILER_INTEL15 0x00100050 +#define GLM_COMPILER_INTEL16 0x00100060 +#define GLM_COMPILER_INTEL17 0x00100070 + +// Visual C++ defines +#define GLM_COMPILER_VC 0x01000000 +#define GLM_COMPILER_VC12 0x01000001 +#define GLM_COMPILER_VC14 0x01000002 +#define GLM_COMPILER_VC15 0x01000003 +#define GLM_COMPILER_VC15_3 0x01000004 +#define GLM_COMPILER_VC15_5 0x01000005 +#define GLM_COMPILER_VC15_6 0x01000006 +#define GLM_COMPILER_VC15_7 0x01000007 +#define GLM_COMPILER_VC15_8 0x01000008 +#define GLM_COMPILER_VC15_9 0x01000009 +#define GLM_COMPILER_VC16 0x0100000A + +// GCC defines +#define GLM_COMPILER_GCC 0x02000000 +#define GLM_COMPILER_GCC46 0x020000D0 +#define GLM_COMPILER_GCC47 0x020000E0 +#define GLM_COMPILER_GCC48 0x020000F0 +#define GLM_COMPILER_GCC49 0x02000100 +#define GLM_COMPILER_GCC5 0x02000200 +#define GLM_COMPILER_GCC6 0x02000300 +#define GLM_COMPILER_GCC7 0x02000400 +#define GLM_COMPILER_GCC8 0x02000500 + +// CUDA +#define GLM_COMPILER_CUDA 0x10000000 +#define GLM_COMPILER_CUDA75 0x10000001 +#define GLM_COMPILER_CUDA80 0x10000002 +#define GLM_COMPILER_CUDA90 0x10000004 + +// SYCL +#define GLM_COMPILER_SYCL 0x00300000 + +// Clang +#define GLM_COMPILER_CLANG 0x20000000 +#define GLM_COMPILER_CLANG34 0x20000050 +#define GLM_COMPILER_CLANG35 0x20000060 +#define GLM_COMPILER_CLANG36 0x20000070 +#define GLM_COMPILER_CLANG37 0x20000080 +#define GLM_COMPILER_CLANG38 0x20000090 +#define GLM_COMPILER_CLANG39 0x200000A0 +#define GLM_COMPILER_CLANG40 0x200000B0 +#define GLM_COMPILER_CLANG41 0x200000C0 +#define GLM_COMPILER_CLANG42 0x200000D0 + +// Build model +#define GLM_MODEL_32 0x00000010 +#define GLM_MODEL_64 0x00000020 + +// Force generic C++ compiler +#ifdef GLM_FORCE_COMPILER_UNKNOWN +# define GLM_COMPILER GLM_COMPILER_UNKNOWN + +#elif defined(__INTEL_COMPILER) +# if __INTEL_COMPILER >= 1700 +# define GLM_COMPILER GLM_COMPILER_INTEL17 +# elif __INTEL_COMPILER >= 1600 +# define GLM_COMPILER GLM_COMPILER_INTEL16 +# elif __INTEL_COMPILER >= 1500 +# define GLM_COMPILER GLM_COMPILER_INTEL15 +# elif __INTEL_COMPILER >= 1400 +# define GLM_COMPILER GLM_COMPILER_INTEL14 +# elif __INTEL_COMPILER < 1400 +# error "GLM requires ICC 2013 SP1 or newer" +# endif + +// CUDA +#elif defined(__CUDACC__) +# if !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA) +# include // make sure version is defined since nvcc does not define it itself! +# endif +# if CUDA_VERSION >= 8000 +# define GLM_COMPILER GLM_COMPILER_CUDA80 +# elif CUDA_VERSION >= 7500 +# define GLM_COMPILER GLM_COMPILER_CUDA75 +# elif CUDA_VERSION >= 7000 +# define GLM_COMPILER GLM_COMPILER_CUDA70 +# elif CUDA_VERSION < 7000 +# error "GLM requires CUDA 7.0 or higher" +# endif + +// SYCL +#elif defined(__SYCL_DEVICE_ONLY__) +# define GLM_COMPILER GLM_COMPILER_SYCL + +// Clang +#elif defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ < 6) +# error "GLM requires Clang 3.4 / Apple Clang 6.0 or higher" +# elif __clang_major__ == 6 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 6 && __clang_minor__ >= 1 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ >= 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# endif +# else +# if ((__clang_major__ == 3) && (__clang_minor__ < 4)) || (__clang_major__ < 3) +# error "GLM requires Clang 3.4 or higher" +# elif __clang_major__ == 3 && __clang_minor__ == 4 +# define GLM_COMPILER GLM_COMPILER_CLANG34 +# elif __clang_major__ == 3 && __clang_minor__ == 5 +# define GLM_COMPILER GLM_COMPILER_CLANG35 +# elif __clang_major__ == 3 && __clang_minor__ == 6 +# define GLM_COMPILER GLM_COMPILER_CLANG36 +# elif __clang_major__ == 3 && __clang_minor__ == 7 +# define GLM_COMPILER GLM_COMPILER_CLANG37 +# elif __clang_major__ == 3 && __clang_minor__ == 8 +# define GLM_COMPILER GLM_COMPILER_CLANG38 +# elif __clang_major__ == 3 && __clang_minor__ >= 9 +# define GLM_COMPILER GLM_COMPILER_CLANG39 +# elif __clang_major__ == 4 && __clang_minor__ == 0 +# define GLM_COMPILER GLM_COMPILER_CLANG40 +# elif __clang_major__ == 4 && __clang_minor__ == 1 +# define GLM_COMPILER GLM_COMPILER_CLANG41 +# elif __clang_major__ == 4 && __clang_minor__ >= 2 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# elif __clang_major__ >= 4 +# define GLM_COMPILER GLM_COMPILER_CLANG42 +# endif +# endif + +// Visual C++ +#elif defined(_MSC_VER) +# if _MSC_VER >= 1920 +# define GLM_COMPILER GLM_COMPILER_VC16 +# elif _MSC_VER >= 1916 +# define GLM_COMPILER GLM_COMPILER_VC15_9 +# elif _MSC_VER >= 1915 +# define GLM_COMPILER GLM_COMPILER_VC15_8 +# elif _MSC_VER >= 1914 +# define GLM_COMPILER GLM_COMPILER_VC15_7 +# elif _MSC_VER >= 1913 +# define GLM_COMPILER GLM_COMPILER_VC15_6 +# elif _MSC_VER >= 1912 +# define GLM_COMPILER GLM_COMPILER_VC15_5 +# elif _MSC_VER >= 1911 +# define GLM_COMPILER GLM_COMPILER_VC15_3 +# elif _MSC_VER >= 1910 +# define GLM_COMPILER GLM_COMPILER_VC15 +# elif _MSC_VER >= 1900 +# define GLM_COMPILER GLM_COMPILER_VC14 +# elif _MSC_VER >= 1800 +# define GLM_COMPILER GLM_COMPILER_VC12 +# elif _MSC_VER < 1800 +# error "GLM requires Visual C++ 12 - 2013 or higher" +# endif//_MSC_VER + +// G++ +#elif defined(__GNUC__) || defined(__MINGW32__) +# if __GNUC__ >= 8 +# define GLM_COMPILER GLM_COMPILER_GCC8 +# elif __GNUC__ >= 7 +# define GLM_COMPILER GLM_COMPILER_GCC7 +# elif __GNUC__ >= 6 +# define GLM_COMPILER GLM_COMPILER_GCC6 +# elif __GNUC__ >= 5 +# define GLM_COMPILER GLM_COMPILER_GCC5 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 +# define GLM_COMPILER GLM_COMPILER_GCC49 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8 +# define GLM_COMPILER GLM_COMPILER_GCC48 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7 +# define GLM_COMPILER GLM_COMPILER_GCC47 +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 +# define GLM_COMPILER GLM_COMPILER_GCC46 +# elif ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)) || (__GNUC__ < 4) +# error "GLM requires GCC 4.6 or higher" +# endif + +#else +# define GLM_COMPILER GLM_COMPILER_UNKNOWN +#endif + +#ifndef GLM_COMPILER +# error "GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message." +#endif//GLM_COMPILER + +/////////////////////////////////////////////////////////////////////////////////// +// Instruction sets + +// User defines: GLM_FORCE_PURE GLM_FORCE_INTRINSICS GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2 + +#define GLM_ARCH_MIPS_BIT (0x10000000) +#define GLM_ARCH_PPC_BIT (0x20000000) +#define GLM_ARCH_ARM_BIT (0x40000000) +#define GLM_ARCH_ARMV8_BIT (0x01000000) +#define GLM_ARCH_X86_BIT (0x80000000) + +#define GLM_ARCH_SIMD_BIT (0x00001000) + +#define GLM_ARCH_NEON_BIT (0x00000001) +#define GLM_ARCH_SSE_BIT (0x00000002) +#define GLM_ARCH_SSE2_BIT (0x00000004) +#define GLM_ARCH_SSE3_BIT (0x00000008) +#define GLM_ARCH_SSSE3_BIT (0x00000010) +#define GLM_ARCH_SSE41_BIT (0x00000020) +#define GLM_ARCH_SSE42_BIT (0x00000040) +#define GLM_ARCH_AVX_BIT (0x00000080) +#define GLM_ARCH_AVX2_BIT (0x00000100) + +#define GLM_ARCH_UNKNOWN (0) +#define GLM_ARCH_X86 (GLM_ARCH_X86_BIT) +#define GLM_ARCH_SSE (GLM_ARCH_SSE_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_X86) +#define GLM_ARCH_SSE2 (GLM_ARCH_SSE2_BIT | GLM_ARCH_SSE) +#define GLM_ARCH_SSE3 (GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2) +#define GLM_ARCH_SSSE3 (GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3) +#define GLM_ARCH_SSE41 (GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3) +#define GLM_ARCH_SSE42 (GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41) +#define GLM_ARCH_AVX (GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42) +#define GLM_ARCH_AVX2 (GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX) +#define GLM_ARCH_ARM (GLM_ARCH_ARM_BIT) +#define GLM_ARCH_ARMV8 (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM | GLM_ARCH_ARMV8_BIT) +#define GLM_ARCH_NEON (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM) +#define GLM_ARCH_MIPS (GLM_ARCH_MIPS_BIT) +#define GLM_ARCH_PPC (GLM_ARCH_PPC_BIT) + +#if defined(GLM_FORCE_ARCH_UNKNOWN) || defined(GLM_FORCE_PURE) +# define GLM_ARCH GLM_ARCH_UNKNOWN +#elif defined(GLM_FORCE_NEON) +# if __ARM_ARCH >= 8 +# define GLM_ARCH (GLM_ARCH_ARMV8) +# else +# define GLM_ARCH (GLM_ARCH_NEON) +# endif +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX2) +# define GLM_ARCH (GLM_ARCH_AVX2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_AVX) +# define GLM_ARCH (GLM_ARCH_AVX) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE42) +# define GLM_ARCH (GLM_ARCH_SSE42) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE41) +# define GLM_ARCH (GLM_ARCH_SSE41) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSSE3) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE3) +# define GLM_ARCH (GLM_ARCH_SSE3) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE2) +# define GLM_ARCH (GLM_ARCH_SSE2) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_SSE) +# define GLM_ARCH (GLM_ARCH_SSE) +# define GLM_FORCE_INTRINSICS +#elif defined(GLM_FORCE_INTRINSICS) && !defined(GLM_FORCE_XYZW_ONLY) +# if defined(__AVX2__) +# define GLM_ARCH (GLM_ARCH_AVX2) +# elif defined(__AVX__) +# define GLM_ARCH (GLM_ARCH_AVX) +# elif defined(__SSE4_2__) +# define GLM_ARCH (GLM_ARCH_SSE42) +# elif defined(__SSE4_1__) +# define GLM_ARCH (GLM_ARCH_SSE41) +# elif defined(__SSSE3__) +# define GLM_ARCH (GLM_ARCH_SSSE3) +# elif defined(__SSE3__) +# define GLM_ARCH (GLM_ARCH_SSE3) +# elif defined(__SSE2__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86_FP) +# define GLM_ARCH (GLM_ARCH_SSE2) +# elif defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) +# define GLM_ARCH (GLM_ARCH_ARMV8) +# elif defined(__ARM_NEON) +# define GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON) +# elif defined(__arm__ ) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__mips__ ) +# define GLM_ARCH (GLM_ARCH_MIPS) +# elif defined(__powerpc__ ) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#else +# if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(__i386__) +# define GLM_ARCH (GLM_ARCH_X86) +# elif defined(__arm__) || defined(_M_ARM) +# define GLM_ARCH (GLM_ARCH_ARM) +# elif defined(__powerpc__) || defined(_M_PPC) +# define GLM_ARCH (GLM_ARCH_PPC) +# elif defined(__mips__) +# define GLM_ARCH (GLM_ARCH_MIPS) +# else +# define GLM_ARCH (GLM_ARCH_UNKNOWN) +# endif +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT +# include +#elif GLM_ARCH & GLM_ARCH_AVX_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE42_BIT +# if GLM_COMPILER & GLM_COMPILER_CLANG +# include +# endif +# include +#elif GLM_ARCH & GLM_ARCH_SSE41_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE3_BIT +# include +#elif GLM_ARCH & GLM_ARCH_SSE2_BIT +# include +#elif GLM_ARCH & GLM_ARCH_NEON_BIT +# include "neon.h" +#endif//GLM_ARCH + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + typedef __m128 glm_f32vec4; + typedef __m128i glm_i32vec4; + typedef __m128i glm_u32vec4; + typedef __m128d glm_f64vec2; + typedef __m128i glm_i64vec2; + typedef __m128i glm_u64vec2; + + typedef glm_f32vec4 glm_vec4; + typedef glm_i32vec4 glm_ivec4; + typedef glm_u32vec4 glm_uvec4; + typedef glm_f64vec2 glm_dvec2; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX_BIT + typedef __m256d glm_f64vec4; + typedef glm_f64vec4 glm_dvec4; +#endif + +#if GLM_ARCH & GLM_ARCH_AVX2_BIT + typedef __m256i glm_i64vec4; + typedef __m256i glm_u64vec4; +#endif + +#if GLM_ARCH & GLM_ARCH_NEON_BIT + typedef float32x4_t glm_f32vec4; + typedef int32x4_t glm_i32vec4; + typedef uint32x4_t glm_u32vec4; +#endif diff --git a/thirdparty/glm/simd/trigonometric.h b/thirdparty/glm/simd/trigonometric.h new file mode 100644 index 0000000..739b796 --- /dev/null +++ b/thirdparty/glm/simd/trigonometric.h @@ -0,0 +1,9 @@ +/// @ref simd +/// @file glm/simd/trigonometric.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT + diff --git a/thirdparty/glm/simd/vector_relational.h b/thirdparty/glm/simd/vector_relational.h new file mode 100644 index 0000000..f7385e9 --- /dev/null +++ b/thirdparty/glm/simd/vector_relational.h @@ -0,0 +1,8 @@ +/// @ref simd +/// @file glm/simd/vector_relational.h + +#pragma once + +#if GLM_ARCH & GLM_ARCH_SSE2_BIT + +#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT diff --git a/thirdparty/glm/trigonometric.hpp b/thirdparty/glm/trigonometric.hpp new file mode 100644 index 0000000..fcf07f8 --- /dev/null +++ b/thirdparty/glm/trigonometric.hpp @@ -0,0 +1,210 @@ +/// @ref core +/// @file glm/trigonometric.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions +/// +/// @defgroup core_func_trigonometric Angle and Trigonometry Functions +/// @ingroup core +/// +/// Function parameters specified as angle are assumed to be in units of radians. +/// In no case will any of these functions result in a divide by zero error. If +/// the divisor of a ratio is 0, then results will be undefined. +/// +/// These all operate component-wise. The description is per component. +/// +/// Include to use these core features. +/// +/// @see ext_vector_trigonometric + +#pragma once + +#include "detail/setup.hpp" +#include "detail/qualifier.hpp" + +namespace glm +{ + /// @addtogroup core_func_trigonometric + /// @{ + + /// Converts degrees to radians and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL radians man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec radians(vec const& degrees); + + /// Converts radians to degrees and returns the result. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL degrees man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec degrees(vec const& radians); + + /// The standard trigonometric sine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sin(vec const& angle); + + /// The standard trigonometric cosine function. + /// The values returned by this function will range from [-1, 1]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cos(vec const& angle); + + /// The standard trigonometric tangent function. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tan(vec const& angle); + + /// Arc sine. Returns an angle whose sine is x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asin man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asin(vec const& x); + + /// Arc cosine. Returns an angle whose sine is x. + /// The range of values returned by this function is [0, PI]. + /// Results are undefined if |x| > 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acos man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acos(vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y/x. + /// The signs of x and y are used to determine what + /// quadrant the angle is in. The range of values returned + /// by this function is [-PI, PI]. Results are undefined + /// if x and y are both 0. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y, vec const& x); + + /// Arc tangent. Returns an angle whose tangent is y_over_x. + /// The range of values returned by this function is [-PI/2, PI/2]. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atan man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atan(vec const& y_over_x); + + /// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL sinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec sinh(vec const& angle); + + /// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2 + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL cosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec cosh(vec const& angle); + + /// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle) + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL tanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec tanh(vec const& angle); + + /// Arc hyperbolic sine; returns the inverse of sinh. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL asinh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec asinh(vec const& x); + + /// Arc hyperbolic cosine; returns the non-negative inverse + /// of cosh. Results are undefined if x < 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL acosh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec acosh(vec const& x); + + /// Arc hyperbolic tangent; returns the inverse of tanh. + /// Results are undefined if abs(x) >= 1. + /// + /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector + /// @tparam T Floating-point scalar types + /// @tparam Q Value from qualifier enum + /// + /// @see GLSL atanh man page + /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions + template + GLM_FUNC_DECL vec atanh(vec const& x); + + /// @} +}//namespace glm + +#include "detail/func_trigonometric.inl" diff --git a/thirdparty/glm/vec2.hpp b/thirdparty/glm/vec2.hpp new file mode 100644 index 0000000..cd4e070 --- /dev/null +++ b/thirdparty/glm/vec2.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec2.hpp + +#pragma once +#include "./ext/vector_bool2.hpp" +#include "./ext/vector_bool2_precision.hpp" +#include "./ext/vector_float2.hpp" +#include "./ext/vector_float2_precision.hpp" +#include "./ext/vector_double2.hpp" +#include "./ext/vector_double2_precision.hpp" +#include "./ext/vector_int2.hpp" +#include "./ext/vector_int2_sized.hpp" +#include "./ext/vector_uint2.hpp" +#include "./ext/vector_uint2_sized.hpp" diff --git a/thirdparty/glm/vec3.hpp b/thirdparty/glm/vec3.hpp new file mode 100644 index 0000000..f5a927d --- /dev/null +++ b/thirdparty/glm/vec3.hpp @@ -0,0 +1,14 @@ +/// @ref core +/// @file glm/vec3.hpp + +#pragma once +#include "./ext/vector_bool3.hpp" +#include "./ext/vector_bool3_precision.hpp" +#include "./ext/vector_float3.hpp" +#include "./ext/vector_float3_precision.hpp" +#include "./ext/vector_double3.hpp" +#include "./ext/vector_double3_precision.hpp" +#include "./ext/vector_int3.hpp" +#include "./ext/vector_int3_sized.hpp" +#include "./ext/vector_uint3.hpp" +#include "./ext/vector_uint3_sized.hpp" diff --git a/thirdparty/glm/vec4.hpp b/thirdparty/glm/vec4.hpp new file mode 100644 index 0000000..c6ea9f1 --- /dev/null +++ b/thirdparty/glm/vec4.hpp @@ -0,0 +1,15 @@ +/// @ref core +/// @file glm/vec4.hpp + +#pragma once +#include "./ext/vector_bool4.hpp" +#include "./ext/vector_bool4_precision.hpp" +#include "./ext/vector_float4.hpp" +#include "./ext/vector_float4_precision.hpp" +#include "./ext/vector_double4.hpp" +#include "./ext/vector_double4_precision.hpp" +#include "./ext/vector_int4.hpp" +#include "./ext/vector_int4_sized.hpp" +#include "./ext/vector_uint4.hpp" +#include "./ext/vector_uint4_sized.hpp" + diff --git a/thirdparty/glm/vector_relational.hpp b/thirdparty/glm/vector_relational.hpp new file mode 100644 index 0000000..a0fe17e --- /dev/null +++ b/thirdparty/glm/vector_relational.hpp @@ -0,0 +1,121 @@ +/// @ref core +/// @file glm/vector_relational.hpp +/// +/// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions +/// +/// @defgroup core_func_vector_relational Vector Relational Functions +/// @ingroup core +/// +/// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to +/// operate on scalars and produce scalar Boolean results. For vector results, +/// use the following built-in functions. +/// +/// In all cases, the sizes of all the input and return vectors for any particular +/// call must match. +/// +/// Include to use these core features. +/// +/// @see ext_vector_relational + +#pragma once + +#include "detail/qualifier.hpp" +#include "detail/setup.hpp" + +namespace glm +{ + /// @addtogroup core_func_vector_relational + /// @{ + + /// Returns the component-wise comparison result of x < y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x <= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL lessThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x > y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThan man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x >= y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point or integer scalar type. + /// + /// @see GLSL greaterThanEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x == y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL equal man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y); + + /// Returns the component-wise comparison of result x != y. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// @tparam T A floating-point, integer or bool scalar type. + /// + /// @see GLSL notEqual man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y); + + /// Returns true if any component of x is true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL any man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool any(vec const& v); + + /// Returns true if all components of x are true. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL all man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR bool all(vec const& v); + + /// Returns the component-wise logical complement of x. + /// /!\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead. + /// + /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. + /// + /// @see GLSL not man page + /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions + template + GLM_FUNC_DECL GLM_CONSTEXPR vec not_(vec const& v); + + /// @} +}//namespace glm + +#include "detail/func_vector_relational.inl" diff --git a/thirdparty/imgui/CMakeLists.txt b/thirdparty/imgui/CMakeLists.txt new file mode 100644 index 0000000..471ba4d --- /dev/null +++ b/thirdparty/imgui/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(imgui STATIC + imgui.cpp + imgui_demo.cpp + imgui_draw.cpp + imgui_tables.cpp + imgui_widgets.cpp + imconfig.h + imgui.h + imgui_internal.h + imstb_rectpack.h + imstb_textedit.h + imstb_truetype.h +) + +target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(imgui PROPERTIES FOLDER "thirdparty") \ No newline at end of file diff --git a/thirdparty/imgui/LICENSE.txt b/thirdparty/imgui/LICENSE.txt new file mode 100644 index 0000000..780533d --- /dev/null +++ b/thirdparty/imgui/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2021 Omar Cornut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/thirdparty/imgui/imconfig.h b/thirdparty/imgui/imconfig.h new file mode 100644 index 0000000..7082c55 --- /dev/null +++ b/thirdparty/imgui/imconfig.h @@ -0,0 +1,123 @@ +//----------------------------------------------------------------------------- +// COMPILE-TIME OPTIONS FOR DEAR IMGUI +// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. +// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. +//----------------------------------------------------------------------------- +// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) +// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. +//----------------------------------------------------------------------------- +// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp +// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. +// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. +// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +//---- Define assertion handler. Defaults to calling assert(). +// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. +//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) +//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts + +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows +// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +//#define IMGUI_API __declspec( dllexport ) +//#define IMGUI_API __declspec( dllimport ) + +//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//---- Disable all of Dear ImGui or don't implement standard windows. +// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. +//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. +//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. +//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger and other debug tools: ShowMetricsWindow() and ShowStackToolWindow() will be empty. + +//---- Don't implement some functions to reduce linkage requirements. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) +//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) +//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). +//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). +//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) +//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. +//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available + +//---- Include imgui_user.h at the end of imgui.h as a convenience +//#define IMGUI_INCLUDE_IMGUI_USER_H + +//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) +//#define IMGUI_USE_BGRA_PACKED_COLOR + +//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) +//#define IMGUI_USE_WCHAR32 + +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) +// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. +// #define IMGUI_USE_STB_SPRINTF + +//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) +// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). +// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. +//#define IMGUI_ENABLE_FREETYPE + +//---- Use stb_truetype to build and rasterize the font atlas (default) +// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. +//#define IMGUI_ENABLE_STB_TRUETYPE + +//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. +// This will be inlined as part of ImVec2 and ImVec4 class declarations. +/* +#define IM_VEC2_CLASS_EXTRA \ + ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ + operator MyVec2() const { return MyVec2(x,y); } + +#define IM_VEC4_CLASS_EXTRA \ + ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ + operator MyVec4() const { return MyVec4(x,y,z,w); } +*/ + +//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. +// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). +// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. +// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. +//#define ImDrawIdx unsigned int + +//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) +//struct ImDrawList; +//struct ImDrawCmd; +//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); +//#define ImDrawCallback MyImDrawCallback + +//---- Debug Tools: Macro to break in Debugger +// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) +//#define IM_DEBUG_BREAK IM_ASSERT(0) +//#define IM_DEBUG_BREAK __debugbreak() + +//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), +// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) +// This adds a small runtime cost which is why it is not enabled by default. +//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID + +//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. +/* +namespace ImGui +{ + void MyFunction(const char* name, const MyMatrix44& v); +} +*/ diff --git a/thirdparty/imgui/imgui.cpp b/thirdparty/imgui/imgui.cpp new file mode 100644 index 0000000..d7653d4 --- /dev/null +++ b/thirdparty/imgui/imgui.cpp @@ -0,0 +1,12627 @@ +// dear imgui, v1.86 +// (main code and documentation) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/4451 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues + +// Getting Started? +// - For first-time users having issues compiling/linking/running or issues loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. + +// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. +// See LICENSE.txt for copyright and licensing details (standard MIT License). +// This library is free but needs your support to sustain development and maintenance. +// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com". +// Individuals: you can support continued development via donations. See docs/README or web page. + +// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. +// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without +// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't +// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you +// to a better solution or official support for them. + +/* + +Index of this file: + +DOCUMENTATION + +- MISSION STATEMENT +- END-USER GUIDE +- PROGRAMMER GUIDE + - READ FIRST + - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + - HOW A SIMPLE APPLICATION MAY LOOK LIKE + - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS +- API BREAKING CHANGES (read me when you update!) +- FREQUENTLY ASKED QUESTIONS (FAQ) + - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) + +CODE +(search for "[SECTION]" in the code to find them) + +// [SECTION] INCLUDES +// [SECTION] FORWARD DECLARATIONS +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +// [SECTION] MISC HELPERS/UTILITIES (File functions) +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// [SECTION] ImGuiStorage +// [SECTION] ImGuiTextFilter +// [SECTION] ImGuiTextBuffer +// [SECTION] ImGuiListClipper +// [SECTION] STYLING +// [SECTION] RENDER HELPERS +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] ERROR CHECKING +// [SECTION] LAYOUT +// [SECTION] SCROLLING +// [SECTION] TOOLTIPS +// [SECTION] POPUPS +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +// [SECTION] DRAG AND DROP +// [SECTION] LOGGING/CAPTURING +// [SECTION] SETTINGS +// [SECTION] VIEWPORTS +// [SECTION] PLATFORM DEPENDENT HELPERS +// [SECTION] METRICS/DEBUGGER WINDOW +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) + +*/ + +//----------------------------------------------------------------------------- +// DOCUMENTATION +//----------------------------------------------------------------------------- + +/* + + MISSION STATEMENT + ================= + + - Easy to use to create code-driven and data-driven tools. + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. + - Easy to hack and improve. + - Minimize setup and maintenance. + - Minimize state storage on user side. + - Portable, minimize dependencies, run on target (consoles, phones, etc.). + - Efficient runtime and memory consumption. + + Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes: + + - Doesn't look fancy, doesn't animate. + - Limited layout features, intricate layouts are typically crafted in code. + + + END-USER GUIDE + ============== + + - Double-click on title bar to collapse window. + - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). + - Click and drag on any empty space to move window. + - TAB/SHIFT+TAB to cycle through keyboard editable fields. + - CTRL+Click on a slider or drag box to input value as text. + - Use mouse wheel to scroll. + - Text editor: + - Hold SHIFT or use mouse to select text. + - CTRL+Left/Right to word jump. + - CTRL+Shift+Left/Right to select words. + - CTRL+A our Double-Click to select all. + - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ + - CTRL+Z,CTRL+Y to undo/redo. + - ESCAPE to revert text to its original value. + - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) + - Controls are automatically adjusted for OSX to match standard OSX text editing operations. + - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. + - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets + + + PROGRAMMER GUIDE + ================ + + READ FIRST + ---------- + - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) + - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or + destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. + - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. + - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. + - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. + - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. + For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI, + where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. + - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. + - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). + If you get an assert, read the messages and comments around the assert. + - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). + + + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + ---------------------------------------------- + - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master". + - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file. + - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. + If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed + from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will + likely be a comment about it. Please report any issue to the GitHub page! + - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file. + - Try to keep your copy of Dear ImGui reasonably up to date. + + + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + --------------------------------------------------------------- + - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. + - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder. + - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system. + It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL). + - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. + - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. + - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. + Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" + phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render(). + - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code. + - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. + + + HOW A SIMPLE APPLICATION MAY LOOK LIKE + -------------------------------------- + EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). + The sub-folders in examples/ contain examples applications following this structure. + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Application main loop + while (true) + { + // Feed inputs to dear imgui, start new frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // Any application code here + ImGui::Text("Hello, world!"); + + // Render dear imgui into screen + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + g_pSwapChain->Present(1, 0); + } + + // Shutdown + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Build and load the texture atlas into a texture + // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) + int width, height; + unsigned char* pixels = NULL; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + // At this point you've got the texture data and you need to upload that to your graphic system: + // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. + // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. + MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) + io.Fonts->SetTexID((void*)texture); + + // Application main loop + while (true) + { + // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. + // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends) + io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) + io.DisplaySize.x = 1920.0f; // set the current display width + io.DisplaySize.y = 1280.0f; // set the current display height here + io.MousePos = my_mouse_pos; // set the mouse position + io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states + io.MouseDown[1] = my_mouse_buttons[1]; + + // Call NewFrame(), after this point you can use ImGui::* functions anytime + // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere) + ImGui::NewFrame(); + + // Most of your application code here + ImGui::Text("Hello, world!"); + MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); + MyGameRender(); // may use any Dear ImGui functions as well! + + // Render dear imgui, swap buffers + // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) + ImGui::EndFrame(); + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + MyImGuiRenderFunction(draw_data); + SwapBuffers(); + } + + // Shutdown + ImGui::DestroyContext(); + + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, + you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + Please read the FAQ and example applications for details about this! + + + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + --------------------------------------------- + The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. + + void void MyImGuiRenderFunction(ImDrawData* draw_data) + { + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // The texture for the draw call is specified by pcmd->GetTexID(). + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); + + // We are using scissoring to clip some objects. All low-level graphics API should support it. + // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches + // (some elements visible outside their bounds) but you can fix that once everything else works! + // - Clipping coordinates are provided in imgui coordinates space: + // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size + // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. + // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) + ImVec2 pos = draw_data->DisplayPos; + MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); + + // Render 'pcmd->ElemCount/3' indexed triangles. + // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); + } + idx_buffer += pcmd->ElemCount; + } + } + } + + + USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS + ------------------------------------------ + - The gamepad/keyboard navigation is fairly functional and keeps being improved. + - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse! + - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 + - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. + - Keyboard: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. + NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag + will be set. For more advanced uses, you may want to read from: + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). + - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. + Please reach out if you think the game vs navigation input sharing could be improved. + - Gamepad: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. + - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). + Note that io.NavInputs[] is cleared by EndFrame(). + - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: + 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. + - We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. + Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets + - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo + to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + - Mouse: + - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse moving back and forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) + + + API BREAKING CHANGES + ==================== + + Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. + Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. + When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. + You can read releases logs https://github.com/ocornut/imgui/releases for more details. + + - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings + - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function. + - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful. + - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019): + - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList() + - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder + - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID(). + - if you are using official backends from the source tree: you have nothing to do. + - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID(). + - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags. + - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft + - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight + - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc. + flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API. + breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners": + - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use) + - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use) + - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use) + - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f. + this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok. + the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts. + legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise). + - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018): + - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY() + - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing. + - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future. + - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'. + - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed. + - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). + - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). + - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). + - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): + - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). + - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg + - ImGuiInputTextCallback -> use ImGuiTextEditCallback + - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData + - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete). + - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added! + - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API. + - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures + - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018): + - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend + - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow) + - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT + - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT + - removed redirecting functions names that were marked obsolete in 1.61 (May 2018): + - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision. + - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter. + - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed). + - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). + - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. + - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. + - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. + - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! + - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). + replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). + worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: + - if you omitted the 'power' parameter (likely!), you are not affected. + - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. + - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. + see https://github.com/ocornut/imgui/issues/3361 for all details. + kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used. + for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. + - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. + - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. + - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79] + - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. + - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). + - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. + - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. + - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. + - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): + - ShowTestWindow() -> use ShowDemoWindow() + - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) + - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) + - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) + - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() + - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg + - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding + - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap + - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS + - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API. + - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). + - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): + - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed + - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) + - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() + - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) + - ImFont::Glyph -> use ImFontGlyph + - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. + if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. + The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). + If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. + - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). + - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). + - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. + - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have + overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. + This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. + Please reach out if you are affected. + - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). + - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). + - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. + - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). + - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). + - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value! + - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). + - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). + - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. + - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. + - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. + - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). + - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. + If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. + - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) + - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. + NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. + Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. + - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). + - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). + - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). + - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. + - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. + - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. + - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). + - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports. + when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call. + in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. + - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. + - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. + - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. + - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", + consistent with other functions. Kept redirection functions (will obsolete). + - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. + - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch). + - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. + - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. + - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. + - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. + - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. + - 2018/02/07 (1.60) - reorganized context handling to be more explicit, + - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. + - removed Shutdown() function, as DestroyContext() serve this purpose. + - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. + - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. + - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. + - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. + - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. + - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. + - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). + - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags + - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. + - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. + - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). + - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). + - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). + - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). + - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). + - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. + - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. + Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. + - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. + - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. + - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. + - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); + - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. + - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. + removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. + IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly) + IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior] + - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! + - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). + - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). + - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! + - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). + - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). + - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. + - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. + - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. + - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). + - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete). + - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). + - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. + - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))' + - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse + - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. + - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild(). + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal. + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. + - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. + - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. + - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. + - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. + GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. + GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! + - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize + - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. + - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason + - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. + you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. + - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. + this necessary change will break your rendering function! the fix should be very easy. sorry for that :( + - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. + - the signature of the io.RenderDrawListsFn handler has changed! + old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) + new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). + parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' + ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. + ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. + - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. + - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! + - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. + - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). + - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. + - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry! + - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). + - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). + - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. + - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. + - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. + - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. + - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior + - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() + - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) + - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. + - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. + - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. + - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier); + you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID() + - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) + - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets + - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) + - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) + - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility + - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() + - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) + - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) + - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() + - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn + - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) + - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite + - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes + + + FREQUENTLY ASKED QUESTIONS (FAQ) + ================================ + + Read all answers online: + https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) + Read all answers locally (with a text editor or ideally a Markdown viewer): + docs/FAQ.md + Some answers are copied down here to facilitate searching in code. + + Q&A: Basics + =========== + + Q: Where is the documentation? + A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++. + - Run the examples/ and explore them. + - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. + - The demo covers most features of Dear ImGui, so you can read the code and see its output. + - See documentation and comments at the top of imgui.cpp + effectively imgui.h. + - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the + examples/ folder to explain how to integrate Dear ImGui with your own engine/application. + - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. + - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. + - Your programming IDE is your friend, find the type or function declaration to find comments + associated with it. + + Q: What is this library called? + Q: Which version should I get? + >> This library is called "Dear ImGui", please don't call it "ImGui" :) + >> See https://www.dearimgui.org/faq for details. + + Q&A: Integration + ================ + + Q: How to get started? + A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. + + Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application? + A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this. + + Q. How can I enable keyboard controls? + Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) + Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around... + Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries... + >> See https://www.dearimgui.org/faq + + Q&A: Usage + ---------- + + Q: About the ID Stack system.. + - Why is my widget not reacting when I click on it? + - How can I have widgets with an empty label? + - How can I have multiple widgets with the same label? + - How can I have multiple windows with the same label? + Q: How can I display an image? What is ImTextureID, how does it works? + Q: How can I use my own math types instead of ImVec2/ImVec4? + Q: How can I interact with standard C++ types (such as std::string and std::vector)? + Q: How can I display custom shapes? (using low-level ImDrawList API) + >> See https://www.dearimgui.org/faq + + Q&A: Fonts, Text + ================ + + Q: How should I handle DPI in my application? + Q: How can I load a different font than the default? + Q: How can I easily use icons in my application? + Q: How can I load multiple fonts? + Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? + >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md + + Q&A: Concerns + ============= + + Q: Who uses Dear ImGui? + Q: Can you create elaborate/serious tools with Dear ImGui? + Q: Can you reskin the look of Dear ImGui? + Q: Why using C++ (as opposed to C)? + >> See https://www.dearimgui.org/faq + + Q&A: Community + ============== + + Q: How can I help? + A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui! + We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. + This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project. + - Individuals: you can support continued development via PayPal donations. See README. + - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt + and see how you want to help and can help! + - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. + You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately). + +*/ + +//------------------------------------------------------------------------- +// [SECTION] INCLUDES +//------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// System includes +#include // toupper +#include // vsnprintf, sscanf, printf +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled +#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif + +// [Windows] OS specific includes (optional) +#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_FUNCTIONS +#endif +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef __MINGW32__ +#include // _wfopen, OpenClipboard +#else +#include +#endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif +#endif + +// [Apple] OS specific includes +#if defined(__APPLE__) +#include +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association. +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// Debug options +#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL +#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window +#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower) + +// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. +static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in +static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear + +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend) +static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow(). +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. +static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. + +//------------------------------------------------------------------------- +// [SECTION] FORWARD DECLARATIONS +//------------------------------------------------------------------------- + +static void SetCurrentWindow(ImGuiWindow* window); +static void FindHoveredWindow(); +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); + +// Settings +static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); +static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); + +// Platform Dependents default implementation for IO functions +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); + +namespace ImGui +{ +// Navigation +static void NavUpdate(); +static void NavUpdateWindowing(); +static void NavUpdateWindowingOverlay(); +static void NavUpdateCancelRequest(); +static void NavUpdateCreateMoveRequest(); +static void NavUpdateCreateTabbingRequest(); +static float NavUpdatePageUpPageDown(); +static inline void NavUpdateAnyRequestFlag(); +static void NavUpdateCreateWrappingRequest(); +static void NavEndFrame(); +static bool NavScoreItem(ImGuiNavItemData* result); +static void NavApplyItemToResult(ImGuiNavItemData* result); +static void NavProcessItem(); +static void NavProcessItemForTabbingRequest(ImGuiID id); +static ImVec2 NavCalcPreferredRefPos(); +static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static void NavRestoreLayer(ImGuiNavLayer layer); +static void NavRestoreHighlightAfterMove(); +static int FindWindowFocusIndex(ImGuiWindow* window); + +// Error Checking and Debug Tools +static void ErrorCheckNewFrameSanityChecks(); +static void ErrorCheckEndFrameSanityChecks(); +static void UpdateDebugToolItemPicker(); +static void UpdateDebugToolStackQueries(); + +// Misc +static void UpdateSettings(); +static void UpdateMouseInputs(); +static void UpdateMouseWheel(); +static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); +static void RenderWindowOuterBorders(ImGuiWindow* window); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); +static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); +static void RenderDimmedBackgrounds(); +static ImGuiWindow* FindBlockingModal(ImGuiWindow* window); + +// Viewports +static void UpdateViewportsNewFrame(); + +} + +//----------------------------------------------------------------------------- +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +//----------------------------------------------------------------------------- + +// DLL users: +// - Heaps and globals are not shared across DLL boundaries! +// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from. +// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL). +// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in). + +// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. +// - ImGui::CreateContext() will automatically set this pointer if it is NULL. +// Change to a different context by calling ImGui::SetCurrentContext(). +// - Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts: +// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace. +// - DLL users: read comments above. +#ifndef GImGui +ImGuiContext* GImGui = NULL; +#endif + +// Memory Allocator functions. Use SetAllocatorFunctions() to change them. +// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - DLL users: read comments above. +#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } +#else +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } +#endif +static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper; +static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; +static void* GImAllocatorUserData = NULL; + +//----------------------------------------------------------------------------- +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +//----------------------------------------------------------------------------- + +ImGuiStyle::ImGuiStyle() +{ + Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. + DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + WindowPadding = ImVec2(8,8); // Padding within a window + WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. + WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. + WindowMinSize = ImVec2(32,32); // Minimum window size + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text + WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. + ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows + ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. + PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows + PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. + FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) + FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). + FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. + ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines + ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) + CellPadding = ImVec2(4,2); // Padding within a table cell + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar + ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar + GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar + GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize = 0.0f; // Thickness of border around tabs. + TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. + SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. + AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering. + AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). + CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + + // Default theme + ImGui::StyleColorsDark(this); +} + +// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you. +// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. +void ImGuiStyle::ScaleAllSizes(float scale_factor) +{ + WindowPadding = ImFloor(WindowPadding * scale_factor); + WindowRounding = ImFloor(WindowRounding * scale_factor); + WindowMinSize = ImFloor(WindowMinSize * scale_factor); + ChildRounding = ImFloor(ChildRounding * scale_factor); + PopupRounding = ImFloor(PopupRounding * scale_factor); + FramePadding = ImFloor(FramePadding * scale_factor); + FrameRounding = ImFloor(FrameRounding * scale_factor); + ItemSpacing = ImFloor(ItemSpacing * scale_factor); + ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); + CellPadding = ImFloor(CellPadding * scale_factor); + TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); + IndentSpacing = ImFloor(IndentSpacing * scale_factor); + ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); + ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); + ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); + GrabMinSize = ImFloor(GrabMinSize * scale_factor); + GrabRounding = ImFloor(GrabRounding * scale_factor); + LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); + TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); + DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); + MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); +} + +ImGuiIO::ImGuiIO() +{ + // Most fields are initialized with zero + memset(this, 0, sizeof(*this)); + IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it here. + + // Settings + ConfigFlags = ImGuiConfigFlags_None; + BackendFlags = ImGuiBackendFlags_None; + DisplaySize = ImVec2(-1.0f, -1.0f); + DeltaTime = 1.0f / 60.0f; + IniSavingRate = 5.0f; + IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). + LogFilename = "imgui_log.txt"; + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + UserData = NULL; + + Fonts = NULL; + FontGlobalScale = 1.0f; + FontDefault = NULL; + FontAllowUserScaling = false; + DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + // Miscellaneous options + MouseDrawCursor = false; +#ifdef __APPLE__ + ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag +#else + ConfigMacOSXBehaviors = false; +#endif + ConfigInputTextCursorBlink = true; + ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; + ConfigMemoryCompactTimer = 60.0f; + + // Platform Functions + BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; + ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; + ImeWindowHandle = NULL; + + // Input (NB: we already have memset zero the entire structure!) + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseDragThreshold = 6.0f; + for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; +} + +// Pass in translated ASCII characters for text input. +// - with glfw you can get those from the callback set in glfwSetCharCallback() +// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message +void ImGuiIO::AddInputCharacter(unsigned int c) +{ + if (c != 0) + InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); +} + +// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so +// we should save the high surrogate. +void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) +{ + if (c == 0 && InputQueueSurrogate == 0) + return; + + if ((c & 0xFC00) == 0xD800) // High surrogate, must save + { + if (InputQueueSurrogate != 0) + InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); + InputQueueSurrogate = c; + return; + } + + ImWchar cp = c; + if (InputQueueSurrogate != 0) + { + if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate + { + InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); + } + else + { +#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF + cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar +#else + cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); +#endif + } + + InputQueueSurrogate = 0; + } + InputQueueCharacters.push_back(cp); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + while (*utf8_chars != 0) + { + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + if (c != 0) + InputQueueCharacters.push_back((ImWchar)c); + } +} + +void ImGuiIO::ClearInputCharacters() +{ + InputQueueCharacters.resize(0); +} + +void ImGuiIO::ClearInputKeys() +{ + memset(KeysDown, 0, sizeof(KeysDown)); + for (int n = 0; n < IM_ARRAYSIZE(KeysDownDuration); n++) + KeysDownDuration[n] = KeysDownDurationPrev[n] = -1.0f; + KeyCtrl = KeyShift = KeyAlt = KeySuper = false; + KeyMods = KeyModsPrev = ImGuiKeyModFlags_None; + for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++) + NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f; +} + +void ImGuiIO::AddFocusEvent(bool focused) +{ + // We intentionally overwrite this and process in NewFrame(), in order to give a chance + // to multi-viewports backends to queue AddFocusEvent(false),AddFocusEvent(true) in same frame. + AppFocusLost = !focused; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +//----------------------------------------------------------------------------- + +ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) +{ + IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau() + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + { + ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + return p_closest; +} + +// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp +static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + ImVec2 p_current(x4, y4); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + else if (level < 10) + { + float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; + float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; + float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; + float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; + float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; + float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol +// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. +ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) +{ + IM_ASSERT(tess_tol > 0.0f); + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + return p_closest; +} + +ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) +{ + ImVec2 ap = p - a; + ImVec2 ab_dir = b - a; + float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) + return a; + float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + if (dot > ab_len_sqr) + return b; + return a + ab_dir * dot / ab_len_sqr; +} + +bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; + bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; + bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; + return ((b1 == b2) && (b2 == b3)); +} + +void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) +{ + ImVec2 v0 = b - a; + ImVec2 v1 = c - a; + ImVec2 v2 = p - a; + const float denom = v0.x * v1.y - v1.x * v0.y; + out_v = (v2.x * v1.y - v1.x * v2.y) / denom; + out_w = (v0.x * v2.y - v2.x * v0.y) / denom; + out_u = 1.0f - out_v - out_w; +} + +ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + ImVec2 proj_ab = ImLineClosestPoint(a, b, p); + ImVec2 proj_bc = ImLineClosestPoint(b, c, p); + ImVec2 proj_ca = ImLineClosestPoint(c, a, p); + float dist2_ab = ImLengthSqr(p - proj_ab); + float dist2_bc = ImLengthSqr(p - proj_bc); + float dist2_ca = ImLengthSqr(p - proj_ca); + float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); + if (m == dist2_ab) + return proj_ab; + if (m == dist2_bc) + return proj_bc; + return proj_ca; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +//----------------------------------------------------------------------------- + +// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. +int ImStricmp(const char* str1, const char* str2) +{ + int d; + while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } + return d; +} + +int ImStrnicmp(const char* str1, const char* str2, size_t count) +{ + int d = 0; + while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } + return d; +} + +void ImStrncpy(char* dst, const char* src, size_t count) +{ + if (count < 1) + return; + if (count > 1) + strncpy(dst, src, count - 1); + dst[count - 1] = 0; +} + +char* ImStrdup(const char* str) +{ + size_t len = strlen(str); + void* buf = IM_ALLOC(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + IM_FREE(dst); + dst = (char*)IM_ALLOC(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); +} + +const char* ImStrchrRange(const char* str, const char* str_end, char c) +{ + const char* p = (const char*)memchr(str, (int)c, str_end - str); + return p; +} + +int ImStrlenW(const ImWchar* str) +{ + //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit + int n = 0; + while (*str++) n++; + return n; +} + +// Find end-of-line. Return pointer will point to either first \n, either str_end. +const char* ImStreolRange(const char* str, const char* str_end) +{ + const char* p = (const char*)memchr(str, '\n', str_end - str); + return p ? p : str_end; +} + +const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line +{ + while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') + buf_mid_line--; + return buf_mid_line; +} + +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) +{ + if (!needle_end) + needle_end = needle + strlen(needle); + + const char un0 = (char)toupper(*needle); + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) + { + if (toupper(*haystack) == un0) + { + const char* b = needle + 1; + for (const char* a = haystack + 1; b < needle_end; a++, b++) + if (toupper(*a) != toupper(*b)) + break; + if (b == needle_end) + return haystack; + } + haystack++; + } + return NULL; +} + +// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible. +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') // Leading blanks + p++; + char* p_start = p; + while (*p != 0) // Find end of string + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks + p--; + if (p_start != buf) // Copy memory if we had leading blanks + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; // Zero terminate +} + +const char* ImStrSkipBlank(const char* str) +{ + while (str[0] == ' ' || str[0] == '\t') + str++; + return str; +} + +// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). +// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. +// B) When buf==NULL vsnprintf() will return the output size. +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) +// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are +// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "stb_sprintf.h" +#endif + +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + +int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) +{ +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} +#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +// CRC32 needs a 1KB lookup table (not cache friendly) +// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: +// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. +static const ImU32 GCrc32LookupTable[256] = +{ + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +}; + +// Known size hash +// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed) +{ + ImU32 crc = ~seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + while (data_size-- != 0) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; + return ~crc; +} + +// Zero-terminated string hash, with support for ### to reset back to seed value +// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. +// Because this syntax is rarely used we are optimizing for the common case. +// - If we reach ### in the string we discard the hash so far and reset to the seed. +// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed) +{ + seed = ~seed; + ImU32 crc = seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + if (data_size != 0) + { + while (data_size-- != 0) + { + unsigned char c = *data++; + if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + else + { + while (unsigned char c = *data++) + { + if (c == '#' && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + return ~crc; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (File functions) +//----------------------------------------------------------------------------- + +// Default file functions +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +ImFileHandle ImFileOpen(const char* filename, const char* mode) +{ +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. + // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! + const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + ImVector buf; + buf.resize(filename_wsize + mode_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); + return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); +#else + return fopen(filename, mode); +#endif +} + +// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way. +bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; } +ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; } +ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); } +ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); } +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +// Helper: Load file content into memory +// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() +// This can't really be used with "rt" because fseek size won't match read size. +void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) +{ + IM_ASSERT(filename && mode); + if (out_file_size) + *out_file_size = 0; + + ImFileHandle f; + if ((f = ImFileOpen(filename, mode)) == NULL) + return NULL; + + size_t file_size = (size_t)ImFileGetSize(f); + if (file_size == (size_t)-1) + { + ImFileClose(f); + return NULL; + } + + void* file_data = IM_ALLOC(file_size + padding_bytes); + if (file_data == NULL) + { + ImFileClose(f); + return NULL; + } + if (ImFileRead(file_data, 1, file_size, f) != file_size) + { + ImFileClose(f); + IM_FREE(file_data); + return NULL; + } + if (padding_bytes > 0) + memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); + + ImFileClose(f); + if (out_file_size) + *out_file_size = file_size; + + return file_data; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +//----------------------------------------------------------------------------- + +// Convert UTF-8 to 32-bit character, process single character input. +// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). +// We handle UTF-8 decoding error by skipping forward. +int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) +{ + static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 }; + static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 }; + static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 }; + static const int shiftc[] = { 0, 18, 12, 6, 0 }; + static const int shifte[] = { 0, 6, 4, 2, 0 }; + int len = lengths[*(const unsigned char*)in_text >> 3]; + int wanted = len + !len; + + if (in_text_end == NULL) + in_text_end = in_text + wanted; // Max length, nulls will be taken into account. + + // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here, + // so it is fast even with excessive branching. + unsigned char s[4]; + s[0] = in_text + 0 < in_text_end ? in_text[0] : 0; + s[1] = in_text + 1 < in_text_end ? in_text[1] : 0; + s[2] = in_text + 2 < in_text_end ? in_text[2] : 0; + s[3] = in_text + 3 < in_text_end ? in_text[3] : 0; + + // Assume a four-byte character and load four bytes. Unused bits are shifted out. + *out_char = (uint32_t)(s[0] & masks[len]) << 18; + *out_char |= (uint32_t)(s[1] & 0x3f) << 12; + *out_char |= (uint32_t)(s[2] & 0x3f) << 6; + *out_char |= (uint32_t)(s[3] & 0x3f) << 0; + *out_char >>= shiftc[len]; + + // Accumulate the various error conditions. + int e = 0; + e = (*out_char < mins[len]) << 6; // non-canonical encoding + e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half? + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range? + e |= (s[1] & 0xc0) >> 2; + e |= (s[2] & 0xc0) >> 4; + e |= (s[3] ) >> 6; + e ^= 0x2a; // top two bits of each tail byte correct? + e >>= shifte[len]; + + if (e) + { + // No bytes are consumed when *in_text == 0 || in_text == in_text_end. + // One byte is consumed in case of invalid first byte of in_text. + // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes. + // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s. + wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]); + *out_char = IM_UNICODE_CODEPOINT_INVALID; + } + + return wanted; +} + +int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) +{ + ImWchar* buf_out = buf; + ImWchar* buf_end = buf + buf_size; + while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + *buf_out++ = (ImWchar)c; + } + *buf_out = 0; + if (in_text_remaining) + *in_text_remaining = in_text; + return (int)(buf_out - buf); +} + +int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) +{ + int char_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + char_count++; + } + return char_count; +} + +// Based on stb_to_utf8() from github.com/nothings/stb/ +static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c) +{ + if (c < 0x80) + { + buf[0] = (char)c; + return 1; + } + if (c < 0x800) + { + if (buf_size < 2) return 0; + buf[0] = (char)(0xc0 + (c >> 6)); + buf[1] = (char)(0x80 + (c & 0x3f)); + return 2; + } + if (c < 0x10000) + { + if (buf_size < 3) return 0; + buf[0] = (char)(0xe0 + (c >> 12)); + buf[1] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[2] = (char)(0x80 + ((c ) & 0x3f)); + return 3; + } + if (c <= 0x10FFFF) + { + if (buf_size < 4) return 0; + buf[0] = (char)(0xf0 + (c >> 18)); + buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[3] = (char)(0x80 + ((c ) & 0x3f)); + return 4; + } + // Invalid code point, the max unicode is 0x10FFFF + return 0; +} + +const char* ImTextCharToUtf8(char out_buf[5], unsigned int c) +{ + int count = ImTextCharToUtf8_inline(out_buf, 5, c); + out_buf[count] = 0; + return out_buf; +} + +// Not optimal but we very rarely use this function. +int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) +{ + unsigned int unused = 0; + return ImTextCharFromUtf8(&unused, in_text, in_text_end); +} + +static inline int ImTextCountUtf8BytesFromChar(unsigned int c) +{ + if (c < 0x80) return 1; + if (c < 0x800) return 2; + if (c < 0x10000) return 3; + if (c <= 0x10FFFF) return 4; + return 3; +} + +int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +{ + char* buf_p = out_buf; + const char* buf_end = out_buf + out_buf_size; + while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + *buf_p++ = (char)c; + else + buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c); + } + *buf_p = 0; + return (int)(buf_p - out_buf); +} + +int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) +{ + int bytes_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + bytes_count++; + else + bytes_count += ImTextCountUtf8BytesFromChar(c); + } + return bytes_count; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// Note: The Convert functions are early design which are not consistent with other API. +//----------------------------------------------------------------------------- + +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b) +{ + float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; + int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); + return IM_COL32(r, g, b, 0xFF); +} + +ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) +{ + float s = 1.0f / 255.0f; + return ImVec4( + ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); +} + +ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) +{ + ImU32 out; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; + return out; +} + +// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 +// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) +{ + float K = 0.f; + if (g < b) + { + ImSwap(g, b); + K = -1.f; + } + if (r < g) + { + ImSwap(r, g); + K = -2.f / 6.f - K; + } + + const float chroma = r - (g < b ? g : b); + out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); + out_s = chroma / (r + 1e-20f); + out_v = r; +} + +// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 +// also http://en.wikipedia.org/wiki/HSL_and_HSV +void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) +{ + if (s == 0.0f) + { + // gray + out_r = out_g = out_b = v; + return; + } + + h = ImFmod(h, 1.0f) / (60.0f / 360.0f); + int i = (int)h; + float f = h - (float)i; + float p = v * (1.0f - s); + float q = v * (1.0f - s * f); + float t = v * (1.0f - s * (1.0f - f)); + + switch (i) + { + case 0: out_r = v; out_g = t; out_b = p; break; + case 1: out_r = q; out_g = v; out_b = p; break; + case 2: out_r = p; out_g = v; out_b = t; break; + case 3: out_r = p; out_g = q; out_b = v; break; + case 4: out_r = t; out_g = p; out_b = v; break; + case 5: default: out_r = v; out_g = p; out_b = q; break; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStorage +// Helper: Key->value storage +//----------------------------------------------------------------------------- + +// std::lower_bound but without the bullshit +static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector& data, ImGuiID key) +{ + ImGuiStorage::ImGuiStoragePair* first = data.Data; + ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size; + size_t count = (size_t)(last - first); + while (count > 0) + { + size_t count2 = count >> 1; + ImGuiStorage::ImGuiStoragePair* mid = first + count2; + if (mid->key < key) + { + first = ++mid; + count -= count2 + 1; + } + else + { + count = count2; + } + } + return first; +} + +// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. +void ImGuiStorage::BuildSortByKey() +{ + struct StaticFunc + { + static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) + { + // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. + if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; + if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; + return 0; + } + }; + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID); +} + +int ImGuiStorage::GetInt(ImGuiID key, int default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_i; +} + +bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const +{ + return GetInt(key, default_val ? 1 : 0) != 0; +} + +float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_f; +} + +void* ImGuiStorage::GetVoidPtr(ImGuiID key) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return NULL; + return it->val_p; +} + +// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. +int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_i; +} + +bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) +{ + return (bool*)GetIntRef(key, default_val ? 1 : 0); +} + +float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_f; +} + +void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_p; +} + +// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) +void ImGuiStorage::SetInt(ImGuiID key, int val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_i = val; +} + +void ImGuiStorage::SetBool(ImGuiID key, bool val) +{ + SetInt(key, val ? 1 : 0); +} + +void ImGuiStorage::SetFloat(ImGuiID key, float val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_f = val; +} + +void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_p = val; +} + +void ImGuiStorage::SetAllInt(int v) +{ + for (int i = 0; i < Data.Size; i++) + Data[i].val_i = v; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextFilter +//----------------------------------------------------------------------------- + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) +{ + if (default_filter) + { + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); + Build(); + } + else + { + InputBuf[0] = 0; + CountGrep = 0; + } +} + +bool ImGuiTextFilter::Draw(const char* label, float width) +{ + if (width != 0.0f) + ImGui::SetNextItemWidth(width); + bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); + if (value_changed) + Build(); + return value_changed; +} + +void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector* out) const +{ + out->resize(0); + const char* wb = b; + const char* we = wb; + while (we < e) + { + if (*we == separator) + { + out->push_back(ImGuiTextRange(wb, we)); + wb = we + 1; + } + we++; + } + if (wb != we) + out->push_back(ImGuiTextRange(wb, we)); +} + +void ImGuiTextFilter::Build() +{ + Filters.resize(0); + ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf)); + input_range.split(',', &Filters); + + CountGrep = 0; + for (int i = 0; i != Filters.Size; i++) + { + ImGuiTextRange& f = Filters[i]; + while (f.b < f.e && ImCharIsBlankA(f.b[0])) + f.b++; + while (f.e > f.b && ImCharIsBlankA(f.e[-1])) + f.e--; + if (f.empty()) + continue; + if (Filters[i].b[0] != '-') + CountGrep += 1; + } +} + +bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const +{ + if (Filters.empty()) + return true; + + if (text == NULL) + text = ""; + + for (int i = 0; i != Filters.Size; i++) + { + const ImGuiTextRange& f = Filters[i]; + if (f.empty()) + continue; + if (f.b[0] == '-') + { + // Subtract + if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) + return false; + } + else + { + // Grep + if (ImStristr(text, text_end, f.b, f.e) != NULL) + return true; + } + } + + // Implicit * grep + if (CountGrep == 0) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextBuffer +//----------------------------------------------------------------------------- + +// On some platform vsnprintf() takes va_list by reference and modifies it. +// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. +#ifndef va_copy +#if defined(__GNUC__) || defined(__clang__) +#define va_copy(dest, src) __builtin_va_copy(dest, src) +#else +#define va_copy(dest, src) (dest = src) +#endif +#endif + +char ImGuiTextBuffer::EmptyString[1] = { 0 }; + +void ImGuiTextBuffer::append(const char* str, const char* str_end) +{ + int len = str_end ? (int)(str_end - str) : (int)strlen(str); + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + memcpy(&Buf[write_off - 1], str, (size_t)len); + Buf[write_off - 1 + len] = 0; +} + +void ImGuiTextBuffer::appendf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + appendfv(fmt, args); + va_end(args); +} + +// Helper: Text buffer for logging/accumulating text +void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) +{ + va_list args_copy; + va_copy(args_copy, args); + + int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. + if (len <= 0) + { + va_end(args_copy); + return; + } + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); + va_end(args_copy); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiListClipper +// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed +// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) +//----------------------------------------------------------------------------- + +// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell. +// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous. +static bool GetSkipItemForListClipping() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy helper to calculate coarse clipping of large list of evenly sized items. +// This legacy API is not ideal because it assume we will return a single contiguous rectangle. +// Prefer using ImGuiListClipper which can returns non-contiguous ranges. +void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (GetSkipItemForListClipping()) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + // We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect + // We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly. + ImRect rect = window->ClipRect; + if (g.NavMoveScoringItems) + rect.Add(g.NavScoringNoClipRect); + if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) + rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((rect.Min.y - pos.y) / items_height); + int end = (int)((rect.Max.y - pos.y) / items_height); + + // When performing a navigation request, ensure we have one item extra in the direction we are moving to + // FIXME: Verify this works with tabbing + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) + end++; + + start = ImClamp(start, 0, items_count); + end = ImClamp(end + 1, start, items_count); + *out_items_display_start = start; + *out_items_display_end = end; +} +#endif + +static void ImGuiListClipper_SortAndFuseRanges(ImVector& ranges, int offset = 0) +{ + if (ranges.Size - offset <= 1) + return; + + // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries) + for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end) + for (int i = offset; i < sort_end + offset; ++i) + if (ranges[i].Min > ranges[i + 1].Min) + ImSwap(ranges[i], ranges[i + 1]); + + // Now fuse ranges together as much as possible. + for (int i = 1 + offset; i < ranges.Size; i++) + { + IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert); + if (ranges[i - 1].Max < ranges[i].Min) + continue; + ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min); + ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max); + ranges.erase(ranges.Data + i); + i--; + } +} + +static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height) +{ + // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. + // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. + // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek? + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float off_y = pos_y - window->DC.CursorPos.y; + window->DC.CursorPos.y = pos_y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + if (ImGuiOldColumns* columns = window->DC.CurrentColumns) + columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly + if (ImGuiTable* table = g.CurrentTable) + { + if (table->IsInsideRow) + ImGui::TableEndRow(table); + table->RowPosY2 = window->DC.CursorPos.y; + const int row_increase = (int)((off_y / line_height) + 0.5f); + //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow() + table->RowBgColorCounter += row_increase; + } +} + +static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n) +{ + // StartPosY starts from ItemsFrozen hence the subtraction + // Perform the add and multiply with double to allow seeking through larger ranges + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; + float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight); + ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight); +} + +ImGuiListClipper::ImGuiListClipper() +{ + memset(this, 0, sizeof(*this)); + ItemsCount = -1; +} + +ImGuiListClipper::~ImGuiListClipper() +{ + End(); +} + +// Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1 +// Use case B: Begin() called from constructor with items_height>0 +// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. +void ImGuiListClipper::Begin(int items_count, float items_height) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (ImGuiTable* table = g.CurrentTable) + if (table->IsInsideRow) + ImGui::TableEndRow(table); + + StartPosY = window->DC.CursorPos.y; + ItemsHeight = items_height; + ItemsCount = items_count; + DisplayStart = -1; + DisplayEnd = 0; + + // Acquire temporary buffer + if (++g.ClipperTempDataStacked > g.ClipperTempData.Size) + g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData()); + ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->Reset(this); + data->LossynessOffset = window->DC.CursorStartPosLossyness.y; + TempData = data; +} + +void ImGuiListClipper::End() +{ + // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user. + ImGuiContext& g = *GImGui; + if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0) + ImGuiListClipper_SeekCursorForItem(this, ItemsCount); + ItemsCount = -1; + + // Restore temporary buffer and fix back pointers which may be invalidated when nesting + if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData) + { + IM_ASSERT(data->ListClipper == this); + data->StepNo = data->Ranges.Size; + if (--g.ClipperTempDataStacked > 0) + { + data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->ListClipper->TempData = data; + } + TempData = NULL; + } +} + +void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max) +{ + ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; + IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet. + IM_ASSERT(item_min <= item_max); + if (item_min < item_max) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_min, item_max)); +} + +bool ImGuiListClipper::Step() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; + + ImGuiTable* table = g.CurrentTable; + if (table && table->IsInsideRow) + ImGui::TableEndRow(table); + + // No items + if (ItemsCount == 0 || GetSkipItemForListClipping()) + return (void)End(), false; + + // While we are in frozen row state, keep displaying items one by one, unclipped + // FIXME: Could be stored as a table-agnostic state. + if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows) + { + DisplayStart = data->ItemsFrozen; + DisplayEnd = data->ItemsFrozen + 1; + if (DisplayStart >= ItemsCount) + return (void)End(), false; + data->ItemsFrozen++; + return true; + } + + // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height) + bool calc_clipping = false; + if (data->StepNo == 0) + { + StartPosY = window->DC.CursorPos.y; + if (ItemsHeight <= 0.0f) + { + // Submit the first item (or range) so we can measure its height (generally the first range is 0..1) + data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1)); + DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); + DisplayEnd = ImMin(data->Ranges[0].Max, ItemsCount); + if (DisplayStart == DisplayEnd) + return (void)End(), false; + data->StepNo = 1; + return true; + } + calc_clipping = true; // If on the first step with known item height, calculate clipping. + } + + // Step 1: Let the clipper infer height from first range + if (ItemsHeight <= 0.0f) + { + IM_ASSERT(data->StepNo == 1); + if (table) + IM_ASSERT(table->RowPosY1 == StartPosY && table->RowPosY2 == window->DC.CursorPos.y); + + ItemsHeight = (window->DC.CursorPos.y - StartPosY) / (float)(DisplayEnd - DisplayStart); + bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); + if (affected_by_floating_point_precision) + ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. + + IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); + calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. + } + + // Step 0 or 1: Calculate the actual ranges of visible elements. + const int already_submitted = DisplayEnd; + if (calc_clipping) + { + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, ItemsCount)); + } + else + { + // Add range selected to be included for navigation + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); + if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(ItemsCount - 1, ItemsCount)); + + // Add focused/active item + ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]); + if (g.NavId != 0 && window->NavLastIds[0] == g.NavId) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0)); + + // Add visible range + const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0; + const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0; + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max)); + } + + // Convert position ranges to item index ranges + // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping. + // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list, + // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted. + for (int i = 0; i < data->Ranges.Size; i++) + if (data->Ranges[i].PosToIndexConvert) + { + int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight); + int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight) + 0.999999f); + data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, ItemsCount - 1); + data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, ItemsCount); + data->Ranges[i].PosToIndexConvert = false; + } + ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo); + } + + // Step 0+ (if item height is given in advance) or 1+: Display the next range in line. + if (data->StepNo < data->Ranges.Size) + { + DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); + DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, ItemsCount); + if (DisplayStart > already_submitted) //-V1051 + ImGuiListClipper_SeekCursorForItem(this, DisplayStart); + data->StepNo++; + return true; + } + + // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), + // Advance the cursor to the end of the list and then returns 'false' to end the loop. + if (ItemsCount < INT_MAX) + ImGuiListClipper_SeekCursorForItem(this, ItemsCount); + ItemsCount = -1; + + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] STYLING +//----------------------------------------------------------------------------- + +ImGuiStyle& ImGui::GetStyle() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->Style; +} + +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = style.Colors[idx]; + c.w *= style.Alpha * alpha_mul; + return ColorConvertFloat4ToU32(c); +} + +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = col; + c.w *= style.Alpha; + return ColorConvertFloat4ToU32(c); +} + +const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) +{ + ImGuiStyle& style = GImGui->Style; + return style.Colors[idx]; +} + +ImU32 ImGui::GetColorU32(ImU32 col) +{ + ImGuiStyle& style = GImGui->Style; + if (style.Alpha >= 1.0f) + return col; + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 +void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); +} + +void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = col; +} + +void ImGui::PopStyleColor(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + ImGuiColorMod& backup = g.ColorStack.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorStack.pop_back(); + count--; + } +} + +struct ImGuiStyleVarInfo +{ + ImGuiDataType Type; + ImU32 Count; + ImU32 Offset; + void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign +}; + +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + { + ImGuiContext& g = *GImGui; + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + { + ImGuiContext& g = *GImGui; + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); +} + +void ImGui::PopStyleVar(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. + ImGuiStyleMod& backup = g.StyleVarStack.back(); + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); + void* data = info->GetVarPtr(&g.Style); + if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + g.StyleVarStack.pop_back(); + count--; + } +} + +const char* ImGui::GetStyleColorName(ImGuiCol idx) +{ + // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; + switch (idx) + { + case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; + case ImGuiCol_WindowBg: return "WindowBg"; + case ImGuiCol_ChildBg: return "ChildBg"; + case ImGuiCol_PopupBg: return "PopupBg"; + case ImGuiCol_Border: return "Border"; + case ImGuiCol_BorderShadow: return "BorderShadow"; + case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; + case ImGuiCol_TitleBg: return "TitleBg"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; + case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; + case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; + case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; + case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; + case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; + case ImGuiCol_CheckMark: return "CheckMark"; + case ImGuiCol_SliderGrab: return "SliderGrab"; + case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; + case ImGuiCol_Button: return "Button"; + case ImGuiCol_ButtonHovered: return "ButtonHovered"; + case ImGuiCol_ButtonActive: return "ButtonActive"; + case ImGuiCol_Header: return "Header"; + case ImGuiCol_HeaderHovered: return "HeaderHovered"; + case ImGuiCol_HeaderActive: return "HeaderActive"; + case ImGuiCol_Separator: return "Separator"; + case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; + case ImGuiCol_SeparatorActive: return "SeparatorActive"; + case ImGuiCol_ResizeGrip: return "ResizeGrip"; + case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; + case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; + case ImGuiCol_PlotLines: return "PlotLines"; + case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; + case ImGuiCol_PlotHistogram: return "PlotHistogram"; + case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; + case ImGuiCol_TableHeaderBg: return "TableHeaderBg"; + case ImGuiCol_TableBorderStrong: return "TableBorderStrong"; + case ImGuiCol_TableBorderLight: return "TableBorderLight"; + case ImGuiCol_TableRowBg: return "TableRowBg"; + case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt"; + case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; + case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; + } + IM_ASSERT(0); + return "Unknown"; +} + + +//----------------------------------------------------------------------------- +// [SECTION] RENDER HELPERS +// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, +// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. +// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. +//----------------------------------------------------------------------------- + +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +{ + const char* text_display_end = text; + if (!text_end) + text_end = (const char*)-1; + + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + return text_display_end; +} + +// Internal ImGui functions to render text +// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Hide anything after a '##' string + const char* text_display_end; + if (hide_text_after_hash) + { + text_display_end = FindRenderedTextEnd(text, text_end); + } + else + { + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + text_display_end = text_end; + } + + if (text != text_display_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_display_end); + } +} + +void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + + if (text != text_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_end); + } +} + +// Default clip_rect uses (pos_min,pos_max) +// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; + bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); + + // Render + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + } +} + +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); +} + + +// Another overly complex function until we reorganize everything into a nice all-in-one helper. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +{ + ImGuiContext& g = *GImGui; + if (text_end_full == NULL) + text_end_full = FindRenderedTextEnd(text); + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); + + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); + //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. + if (text_size.x > pos_max.x - pos_min.x) + { + // Hello wo... + // | | | + // min max ellipsis_max + // <-> this is generally some padding value + + const ImFont* font = draw_list->_Data->Font; + const float font_size = draw_list->_Data->FontSize; + const char* text_end_ellipsis = NULL; + + ImWchar ellipsis_char = font->EllipsisChar; + int ellipsis_char_count = 1; + if (ellipsis_char == (ImWchar)-1) + { + ellipsis_char = font->DotChar; + ellipsis_char_count = 3; + } + const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); + + float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side + float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis + + if (ellipsis_char_count > 1) + { + // Full ellipsis size without free spacing after it. + const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); + ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; + ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; + } + + // We can now claim the space between pos_max.x and ellipsis_max.x + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); + float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; + if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) + { + // Always display at least 1 character if there's no room for character + ellipsis + text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); + text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; + } + while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) + { + // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) + text_end_ellipsis--; + text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte + } + + // Render text, render ellipsis + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + float ellipsis_x = pos_min.x + text_size_clipped_x; + if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) + for (int i = 0; i < ellipsis_char_count; i++) + { + font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); + ellipsis_x += ellipsis_glyph_width; + } + } + else + { + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + } + + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_end_full); +} + +// Render a rectangle shaped with optional rounding and borders +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); + const float border_size = g.Style.FrameBorderSize; + if (border && border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } +} + +void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const float border_size = g.Style.FrameBorderSize; + if (border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } +} + +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +{ + ImGuiContext& g = *GImGui; + if (id != g.NavId) + return; + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + return; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.NavHideHighlightOneFrame) + return; + + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + ImRect display_rect = bb; + display_rect.ClipWith(window->ClipRect); + if (flags & ImGuiNavHighlightFlags_TypeDefault) + { + const float THICKNESS = 2.0f; + const float DISTANCE = 3.0f + THICKNESS * 0.5f; + display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); + bool fully_visible = window->ClipRect.Contains(display_rect); + if (!fully_visible) + window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS); + if (!fully_visible) + window->DrawList->PopClipRect(); + } + if (flags & ImGuiNavHighlightFlags_TypeThin) + { + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +//----------------------------------------------------------------------------- + +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL) +{ + memset(this, 0, sizeof(*this)); + Name = ImStrdup(name); + NameBufLen = (int)strlen(name) + 1; + ID = ImHashStr(name); + IDStack.push_back(ID); + MoveId = GetID("#MOVE"); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + AutoFitFramesX = AutoFitFramesY = -1; + AutoPosLastDirection = ImGuiDir_None; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + LastFrameActive = -1; + LastTimeActive = -1.0f; + FontWindowScale = 1.0f; + SettingsOffset = -1; + DrawList = &DrawListInst; + DrawList->_Data = &context->DrawListSharedData; + DrawList->_OwnerName = Name; +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + ColumnsStorage.clear_destruct(); +} + +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGui::KeepAliveID(id); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGui::KeepAliveID(id); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); + return id; +} + +ImGuiID ImGuiWindow::GetID(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGui::KeepAliveID(id); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + ImGui::KeepAliveID(id); + return id; +} + +static void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; + if (window) + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +void ImGui::GcCompactTransientMiscBuffers() +{ + ImGuiContext& g = *GImGui; + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); + TableGcCompactSettings(); +} + +// Free up/compact internal window buffers, we can use this when a window becomes unused. +// Not freed: +// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) +// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. +void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + window->MemoryCompacted = true; + window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; + window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; + window->IDStack.clear(); + window->DrawList->_ClearFreeMemory(); + window->DC.ChildWindows.clear(); + window->DC.ItemWidthStack.clear(); + window->DC.TextWrapPosStack.clear(); +} + +void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. + // The other buffers tends to amortize much faster. + window->MemoryCompacted = false; + window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); + window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); + window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; +} + +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; + g.ActiveIdMouseButton = -1; + if (id != 0) + { + g.LastActiveId = id; + g.LastActiveIdTimer = 0.0f; + } + } + g.ActiveId = id; + g.ActiveIdAllowOverlap = false; + g.ActiveIdNoClearOnFocusLoss = false; + g.ActiveIdWindow = window; + g.ActiveIdHasBeenEditedThisFrame = false; + if (id) + { + g.ActiveIdIsAlive = id; + g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; + } + + // Clear declaration of inputs claimed by the widget + // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) + g.ActiveIdUsingMouseWheel = false; + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; +} + +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); // g.ActiveId = 0; +} + +void ImGui::SetHoveredID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.HoveredId = id; + g.HoveredIdAllowOverlap = false; + g.HoveredIdUsingMouseWheel = false; + if (id != 0 && g.HoveredIdPreviousFrame != id) + g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; +} + +ImGuiID ImGui::GetHoveredID() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; +} + +void ImGui::KeepAliveID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + g.ActiveIdIsAlive = id; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; +} + +void ImGui::MarkItemEdited(ImGuiID id) +{ + // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). + // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. + //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; +} + +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +{ + // An active popup disable hovering on other windows (apart from its own children) + // FIXME-OPT: This could be cached/stored within the window. + ImGuiContext& g = *GImGui; + if (g.NavWindow) + if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + // For the purpose of those flags we differentiate "standard popup" from "modal popup" + // NB: The order of those two tests is important because Modal windows are also Popups. + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + return false; + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return false; + } + return true; +} + +// This is roughly matching the behavior of internal-facing ItemHoverable() +// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() +// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavDisableMouseHover && !g.NavDisableHighlight) + { + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + if (!IsItemFocused()) + return false; + } + else + { + // Test for bounding box overlap, as updated as ItemAdd() + ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; + if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function + + // Test if we are hovering the right window (our window could be behind another window) + // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable + // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was + // the test that has been running for a long while. + if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) + return false; + + // Test if another item is active (e.g. being dragged) + if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) + if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + // Test if interactions on this window are blocked by an active popup or modal. + // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. + if (!IsWindowContentHoverable(window, flags)) + return false; + + // Test if the item is disabled + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + // Special handling for calling after Begin() which represent the title bar or tab. + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) + return false; + } + + return true; +} + +// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; + if (g.NavDisableMouseHover) + return false; + if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + { + g.HoveredIdDisabled = true; + return false; + } + + // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level + // hover test in widgets code. We could also decide to split this function is two. + if (id != 0) + SetHoveredID(id); + + // When disabled we'll return false but still set HoveredId + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (item_flags & ImGuiItemFlags_Disabled) + { + // Release active id if turning disabled + if (g.ActiveId == id) + ClearActiveID(); + g.HoveredIdDisabled = true; + return false; + } + + if (id != 0) + { + // [DEBUG] Item Picker tool! + // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making + // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered + // items if we perform the test in ItemAdd(), but that would incur a small runtime cost. + // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd(). + if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) + GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); + if (g.DebugItemPickerBreakId == id) + IM_DEBUG_BREAK(); + } + + return true; +} + +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!bb.Overlaps(window->ClipRect)) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) + if (!g.LogEnabled) + return true; + return false; +} + +// This is also inlined in ItemAdd() +// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect! +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) +{ + ImGuiContext& g = *GImGui; + g.LastItemData.ID = item_id; + g.LastItemData.InFlags = in_flags; + g.LastItemData.StatusFlags = item_flags; + g.LastItemData.Rect = item_rect; +} + +float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) +{ + if (wrap_pos_x < 0.0f) + return 0.0f; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (wrap_pos_x == 0.0f) + { + // We could decide to setup a default wrapping max point for auto-resizing windows, + // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function? + //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) + // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x); + //else + wrap_pos_x = window->WorkRect.Max.x; + } + else if (wrap_pos_x > 0.0f) + { + wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space + } + + return ImMax(wrap_pos_x - pos.x, 1.0f); +} + +// IM_ALLOC() == ImGui::MemAlloc() +void* ImGui::MemAlloc(size_t size) +{ + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations++; + return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData); +} + +// IM_FREE() == ImGui::MemFree() +void ImGui::MemFree(void* ptr) +{ + if (ptr) + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations--; + return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData); +} + +const char* ImGui::GetClipboardText() +{ + ImGuiContext& g = *GImGui; + return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; +} + +void ImGui::SetClipboardText(const char* text) +{ + ImGuiContext& g = *GImGui; + if (g.IO.SetClipboardTextFn) + g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); +} + +const char* ImGui::GetVersion() +{ + return IMGUI_VERSION; +} + +// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif +} + +void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) +void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) +{ + *p_alloc_func = GImAllocatorAllocFunc; + *p_free_func = GImAllocatorFreeFunc; + *p_user_data = GImAllocatorUserData; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + if (GImGui == NULL) + SetCurrentContext(ctx); + Initialize(ctx); + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + if (ctx == NULL) + ctx = GImGui; + Shutdown(ctx); + if (GImGui == ctx) + SetCurrentContext(NULL); + IM_DELETE(ctx); +} + +// No specific ordering/dependency support, will see as needed +ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); + g.Hooks.push_back(*hook); + g.Hooks.back().HookId = ++g.HookIdNext; + return g.HookIdNext; +} + +// Deferred removal, avoiding issue with changing vector while iterating it +void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook_id != 0); + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].HookId == hook_id) + g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; +} + +// Call context hooks (used by e.g. test engine) +// We assume a small number of hooks so all stored in same array +void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) +{ + ImGuiContext& g = *ctx; + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].Type == hook_type) + g.Hooks[n].Callback(&g, &g.Hooks[n]); +} + +ImGuiIO& ImGui::GetIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->IO; +} + +// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() +ImDrawData* ImGui::GetDrawData() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL; +} + +double ImGui::GetTime() +{ + return GImGui->Time; +} + +int ImGui::GetFrameCount() +{ + return GImGui->FrameCount; +} + +static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) +{ + // Create the draw list on demand, because they are not frequently used for all viewports + ImGuiContext& g = *GImGui; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); + ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + if (draw_list == NULL) + { + draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); + draw_list->_OwnerName = drawlist_name; + viewport->DrawLists[drawlist_no] = draw_list; + } + + // Our ImDrawList system requires that there is always a command + if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) + { + draw_list->_ResetForNewFrame(); + draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; + } + return draw_list; +} + +ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); +} + +ImDrawList* ImGui::GetBackgroundDrawList() +{ + ImGuiContext& g = *GImGui; + return GetBackgroundDrawList(g.Viewports[0]); +} + +ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); +} + +ImDrawList* ImGui::GetForegroundDrawList() +{ + ImGuiContext& g = *GImGui; + return GetForegroundDrawList(g.Viewports[0]); +} + +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + +void ImGui::StartMouseMovingWindow(ImGuiWindow* window) +{ + // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. + // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. + // This is because we want ActiveId to be set even when the window is not permitted to move. + ImGuiContext& g = *GImGui; + FocusWindow(window); + SetActiveID(window->MoveId, window); + g.NavDisableHighlight = true; + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; + g.ActiveIdNoClearOnFocusLoss = true; + SetActiveIdUsingNavAndKeys(); + + bool can_move_window = true; + if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (can_move_window) + g.MovingWindow = window; +} + +// Handle mouse moving window +// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() +// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. +// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, +// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. +void ImGui::UpdateMouseMovingWindowNewFrame() +{ + ImGuiContext& g = *GImGui; + if (g.MovingWindow != NULL) + { + // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). + // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. + KeepAliveID(g.ActiveId); + IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); + ImGuiWindow* moving_window = g.MovingWindow->RootWindow; + if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) + { + ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; + if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) + { + MarkIniSettingsDirty(moving_window); + SetWindowPos(moving_window, pos, ImGuiCond_Always); + } + FocusWindow(g.MovingWindow); + } + else + { + g.MovingWindow = NULL; + ClearActiveID(); + } + } + else + { + // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. + if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) + { + KeepAliveID(g.ActiveId); + if (!g.IO.MouseDown[0]) + ClearActiveID(); + } + } +} + +// Initiate moving window when clicking on empty space or title bar. +// Handle left-click and right-click focus. +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + // Unless we just made a window/popup appear + if (g.NavWindow && g.NavWindow->Appearing) + return; + + // Click on empty space to focus window and start moving + // (after we're done with all our widgets) + if (g.IO.MouseClicked[0]) + { + // Handle the edge case of a popup being closed while clicking in its empty space. + // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more. + ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel); + + if (root_window != NULL && !is_closed_popup) + { + StartMouseMovingWindow(g.HoveredWindow); //-V595 + + // Cancel moving if clicked outside of title bar + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + + // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) + if (g.HoveredIdDisabled) + g.MovingWindow = NULL; + } + else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } + } + + // With right mouse button we close popups without changing focus based on where the mouse is aimed + // Instead, focus will be restored to the window under the bottom-most closed popup. + // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) + if (g.IO.MouseClicked[1]) + { + // Find the top-most window between HoveredWindow and the top-most Modal Window. + // This is where we can trim the popup stack. + ImGuiWindow* modal = GetTopMostPopupModal(); + bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal)); + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); + } +} + +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->Active) && (!window->Hidden); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&g.IO.MousePos)) + g.IO.MousePos = g.MouseLastValidPos = ImFloor(g.IO.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) + g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; + else + g.IO.MouseDelta = ImVec2(0.0f, 0.0f); + + // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + g.IO.MousePosPrev = g.IO.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; + g.IO.MouseClickedCount[i] = 0; // Will be filled below + g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; + g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; + g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; + if (g.IO.MouseClicked[i]) + { + bool is_repeated_click = false; + if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) + is_repeated_click = true; + } + if (is_repeated_click) + g.IO.MouseClickedLastCount[i]++; + else + g.IO.MouseClickedLastCount[i] = 1; + g.IO.MouseClickedTime[i] = g.Time; + g.IO.MouseClickedPos[i] = g.IO.MousePos; + g.IO.MouseClickedCount[i] = g.IO.MouseClickedLastCount[i]; + g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (g.IO.MouseDown[i]) + { + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); + g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); + g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); + } + + // We provide io.MouseDoubleClicked[] as a legacy service + g.IO.MouseDoubleClicked[i] = (g.IO.MouseClickedCount[i] == 2); + + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + if (g.IO.MouseClicked[i]) + g.NavDisableMouseHover = false; + } +} + +static void StartLockWheelingWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WheelingWindow == window) + return; + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; + g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER; +} + +void ImGui::UpdateMouseWheel() +{ + ImGuiContext& g = *GImGui; + + // Reset the locked window if we move the mouse or after the timer elapses + if (g.WheelingWindow != NULL) + { + g.WheelingWindowTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowTimer = 0.0f; + if (g.WheelingWindowTimer <= 0.0f) + { + g.WheelingWindow = NULL; + g.WheelingWindowTimer = 0.0f; + } + } + + if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) + return; + + if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel)) + return; + + ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!window || window->Collapsed) + return; + + // Zoom / Scale window + // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. + if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + StartLockWheelingWindow(window); + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + if (window == window->RootWindow) + { + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + SetWindowPos(window, window->Pos + offset, 0); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + } + return; + } + + // Mouse wheel scrolling + // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent + if (g.IO.KeyCtrl) + return; + + // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead + // (we avoid doing it on OSX as it the OS input layer handles this already) + const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors; + const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel; + const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH; + + // Vertical Mouse Wheel scrolling + if (wheel_y != 0.0f) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel_y * scroll_step); + } + } + + // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held + if (wheel_x != 0.0f) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel_x * scroll_step); + } + } +} + +// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); + + // Find the window hovered by mouse: + // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. + // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. + // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + bool clear_hovered_windows = false; + FindHoveredWindow(); + + // Modal windows prevents mouse from hovering behind them. + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) + clear_hovered_windows = true; + + // Disabled mouse? + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + clear_hovered_windows = true; + + // We track click ownership. When clicked outside of a window the click is owned by the application and + // won't report hovering nor request capture even while dragging over our windows afterward. + const bool has_open_popup = (g.OpenPopupStack.Size > 0); + const bool has_open_modal = (modal_window != NULL); + int mouse_earliest_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + if (io.MouseClicked[i]) + { + io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup; + io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal; + } + mouse_any_down |= io.MouseDown[i]; + if (io.MouseDown[i]) + if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down]) + mouse_earliest_down = i; + } + const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down]; + const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down]; + + // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. + // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail && !mouse_dragging_extern_payload) + clear_hovered_windows = true; + + if (clear_hovered_windows) + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app) + // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag + if (g.WantCaptureMouseNextFrame != -1) + { + io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0); + } + else + { + io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup; + io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal; + } + + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) + if (g.WantCaptureKeyboardNextFrame != -1) + io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + io.WantCaptureKeyboard = true; + + // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible + io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +ImGuiKeyModFlags ImGui::GetMergedKeyModFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None; + if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; } + if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; } + if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; } + if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; } + return key_mod_flags; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + ImGuiContext& g = *GImGui; + + // Remove pending delete hooks before frame start. + // This deferred removal avoid issues of removal while iterating the hook vector + for (int n = g.Hooks.Size - 1; n >= 0; n--) + if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) + g.Hooks.erase(&g.Hooks[n]); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePre); + + // Check and assert for various common IO and Configuration mistakes + ErrorCheckNewFrameSanityChecks(); + + // Load settings on first frame, save settings when modified (after a delay) + UpdateSettings(); + + g.Time += g.IO.DeltaTime; + g.WithinFrameScope = true; + g.FrameCount += 1; + g.TooltipOverrideCount = 0; + g.WindowsActiveCount = 0; + g.MenusIdSubmittedThisFrame.resize(0); + + // Calculate frame-rate for the user, as a purely luxurious feature + g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; + g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; + g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); + g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame)); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX; + + UpdateViewportsNewFrame(); + + // Setup current font and draw list shared data + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); + ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + virtual_space.Add(g.Viewports[n]->GetMainRect()); + g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); + g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; + if (g.Style.AntiAliasedLines) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; + if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex; + if (g.Style.AntiAliasedFill) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; + if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; + + // Mark rendering data as invalid to prevent user who may have a handle on it to use it. + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataP.Clear(); + } + + // Drag and drop keep the source ID alive so even if the source disappear our state is consistent + if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) + KeepAliveID(g.DragDropPayload.SourceId); + + // Update HoveredId data + if (!g.HoveredIdPreviousFrame) + g.HoveredIdTimer = 0.0f; + if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) + g.HoveredIdNotActiveTimer = 0.0f; + if (g.HoveredId) + g.HoveredIdTimer += g.IO.DeltaTime; + if (g.HoveredId && g.ActiveId != g.HoveredId) + g.HoveredIdNotActiveTimer += g.IO.DeltaTime; + g.HoveredIdPreviousFrame = g.HoveredId; + g.HoveredIdPreviousFrameUsingMouseWheel = g.HoveredIdUsingMouseWheel; + g.HoveredId = 0; + g.HoveredIdAllowOverlap = false; + g.HoveredIdUsingMouseWheel = false; + g.HoveredIdDisabled = false; + + // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) + if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) + ClearActiveID(); + if (g.ActiveId) + g.ActiveIdTimer += g.IO.DeltaTime; + g.LastActiveIdTimer += g.IO.DeltaTime; + g.ActiveIdPreviousFrame = g.ActiveId; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; + g.ActiveIdIsAlive = 0; + g.ActiveIdHasBeenEditedThisFrame = false; + g.ActiveIdPreviousFrameIsAlive = false; + g.ActiveIdIsJustActivated = false; + if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) + g.TempInputId = 0; + if (g.ActiveId == 0) + { + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; + } + + // Drag and drop + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropWithinSource = false; + g.DragDropWithinTarget = false; + g.DragDropHoldJustPressedId = 0; + + // Close popups on focus lost (currently wip/opt-in) + //if (g.IO.AppFocusLost) + // ClosePopupsExceptModals(); + + // Clear buttons state when focus is lost + // (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle) + if (g.IO.AppFocusLost) + { + g.IO.ClearInputKeys(); + g.IO.AppFocusLost = false; + } + + // Update keyboard input state + // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools + g.IO.KeyMods = GetMergedKeyModFlags(); + memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) + g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + // Update gamepad/keyboard navigation + NavUpdate(); + + // Update mouse input state + UpdateMouseInputs(); + + // Find hovered window + // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) + UpdateHoveredWindowAndCaptureFlags(); + + // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) + UpdateMouseMovingWindowNewFrame(); + + // Background darkening/whitening + if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) + g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); + else + g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); + + g.MouseCursor = ImGuiMouseCursor_Arrow; + g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + + // Mouse wheel scrolling, scale + UpdateMouseWheel(); + + // Mark all windows as not visible and compact unused memory. + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + window->WasActive = window->Active; + window->BeginCount = 0; + window->Active = false; + window->WriteAccessed = false; + + // Garbage collect transient buffers of recently unused windows + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + + // Garbage collect transient buffers of recently unused tables + for (int i = 0; i < g.TablesLastTimeActive.Size; i++) + if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) + TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); + for (int i = 0; i < g.TablesTempData.Size; i++) + if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) + TableGcCompactTransientBuffers(&g.TablesTempData[i]); + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); + g.GcCompactAll = false; + + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.NavWindow && !g.NavWindow->WasActive) + FocusTopMostWindowUnderOne(NULL, NULL); + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_None); + g.GroupStack.resize(0); + + // [DEBUG] Update debug features + UpdateDebugToolItemPicker(); + UpdateDebugToolStackQueries(); + + // Create implicit/fallback window - which we will only render it if the user has added something to it. + // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // This fallback is particularly important as it avoid ImGui:: calls from crashing. + g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); +} + +void ImGui::Initialize(ImGuiContext* context) +{ + ImGuiContext& g = *context; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow type + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + } + + // Add .ini handle for ImGuiTable type + TableSettingsInstallHandler(context); + + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + g.Viewports.push_back(viewport); + +#ifdef IMGUI_HAS_DOCK +#endif + + g.Initialized = true; +} + +// This function is merely here to free heap allocations. +void ImGui::Shutdown(ImGuiContext* context) +{ + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + ImGuiContext& g = *context; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + + // Cleanup of other data are conditional on actually having initialized Dear ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + { + ImGuiContext* backup_context = GImGui; + SetCurrentContext(&g); + SaveIniSettingsToDisk(g.IO.IniFilename); + SetCurrentContext(backup_context); + } + + CallContextHooks(&g, ImGuiContextHookType_Shutdown); + + // Clear everything else + g.Windows.clear_delete(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + g.ColorStack.clear(); + g.StyleVarStack.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + + g.Viewports.clear_delete(); + + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); + + g.ClipperTempData.clear_destruct(); + + g.Tables.Clear(); + g.TablesTempData.clear_destruct(); + g.DrawChannelsTempMergeBuffer.clear(); + + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.ClearFreeMemory(); + + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile) + { +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); + g.LogFile = NULL; + } + g.LogBuffer.clear(); + + g.Initialized = false; +} + +// FIXME: Add a more explicit sort order in the window structure. +static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) +{ + const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; + const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; + if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) + return d; + return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); +} + +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window) +{ + out_sorted_windows->push_back(window); + if (window->Active) + { + int count = window->DC.ChildWindows.Size; + ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + for (int i = 0; i < count; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (child->Active) + AddWindowToSortBuffer(out_sorted_windows, child); + } + } +} + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) +{ + // Remove trailing command if unused. + // Technically we could return directly instead of popping, but this make things looks neat in Metrics/Debugger window as well. + draw_list->_PopUnusedDrawCmd(); + if (draw_list->CmdBuffer.Size == 0) + return; + + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + // May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) + // If this assert triggers because you are drawing lots of stuff manually: + // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. + // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. + // - If you want large meshes with more than 64K vertices, you can either: + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // Most example backends already support this from 1.71. Pre-1.71 backends won't. + // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. + // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Your own engine or render API may use different parameters or function calls to specify index sizes. + // 2 and 4 bytes indices are generally supported by most graphics API. + // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching + // the 64K limit to split your draw commands in multiple draw lists. + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + out_list->push_back(draw_list); +} + +static void AddWindowToDrawData(ImGuiWindow* window, int layer) +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + g.IO.MetricsRenderWindows++; + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList); + for (int i = 0; i < window->DC.ChildWindows.Size; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, layer); + } +} + +static inline int GetWindowDisplayLayer(ImGuiWindow* window) +{ + return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; +} + +// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) +static inline void AddRootWindowToDrawData(ImGuiWindow* window) +{ + AddWindowToDrawData(window, GetWindowDisplayLayer(window)); +} + +void ImDrawDataBuilder::FlattenIntoSingleLayer() +{ + int n = Layers[0].Size; + int size = n; + for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) + size += Layers[i].Size; + Layers[0].resize(size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) + { + ImVector& layer = Layers[layer_n]; + if (layer.empty()) + continue; + memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); + n += layer.Size; + layer.resize(0); + } +} + +static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector* draw_lists) +{ + ImGuiIO& io = ImGui::GetIO(); + ImDrawData* draw_data = &viewport->DrawDataP; + draw_data->Valid = true; + draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; + draw_data->CmdListsCount = draw_lists->Size; + draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; + draw_data->DisplayPos = viewport->Pos; + draw_data->DisplaySize = viewport->Size; + draw_data->FramebufferScale = io.DisplayFramebufferScale; + for (int n = 0; n < draw_lists->Size; n++) + { + draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; + } +} + +// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. +// - When using this function it is sane to ensure that float are perfectly rounded to integer values, +// so that e.g. (int)(max.x-min.x) in user's render produce correct result. +// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): +// some frequently called functions which to modify both channels and clipping simultaneously tend to use the +// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. +void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +void ImGui::PopClipRect() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PopClipRect(); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport(); + ImRect viewport_rect = viewport->GetMainRect(); + + // Draw behind window by moving the draw command at the FRONT of the draw list + { + // We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows, + // and draw list have been trimmed already, hence the explicit recreation of a draw command if missing. + ImDrawList* draw_list = window->RootWindow->DrawList; + if (draw_list->CmdBuffer.Size == 0) + draw_list->AddDrawCmd(); + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged + draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); + ImDrawCmd cmd = draw_list->CmdBuffer.back(); + IM_ASSERT(cmd.ElemCount == 6); + draw_list->CmdBuffer.pop_back(); + draw_list->CmdBuffer.push_front(cmd); + draw_list->PopClipRect(); + } +} + +ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* bottom_most_visible_window = parent_window; + for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + if (!IsWindowWithinBeginStackOf(window, parent_window)) + break; + if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window)) + bottom_most_visible_window = window; + } + return bottom_most_visible_window; +} + +static void ImGui::RenderDimmedBackgrounds() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal(); + const bool dim_bg_for_modal = (modal_window != NULL); + const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active); + if (!dim_bg_for_modal && !dim_bg_for_window_list) + return; + + if (dim_bg_for_modal) + { + // Draw dimming behind modal or a begin stack child, whichever comes first in draw order. + ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window); + RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio)); + } + else if (dim_bg_for_window_list) + { + // Draw dimming behind CTRL+Tab target window + RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio)); + + // Draw border around CTRL+Tab target window + ImGuiWindow* window = g.NavWindowingTargetAnim; + ImGuiViewport* viewport = GetMainViewport(); + float distance = g.FontSize; + ImRect bb = window->Rect(); + bb.Expand(distance); + if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y) + bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward + if (window->DrawList->CmdBuffer.Size == 0) + window->DrawList->AddDrawCmd(); + window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); + window->DrawList->PopClipRect(); + } +} + +// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. +void ImGui::EndFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + // Don't process EndFrame() multiple times. + if (g.FrameCountEnded == g.FrameCount) + return; + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePre); + + ErrorCheckEndFrameSanityChecks(); + + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) + { + g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); + g.PlatformImeLastPos = g.PlatformImePos; + } + + // Hide implicit/fallback "Debug" window if it hasn't been used + g.WithinFrameScopeWithImplicitWindow = false; + if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) + g.CurrentWindow->Active = false; + End(); + + // Update navigation: CTRL+Tab, wrap-around requests + NavEndFrame(); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + g.DragDropWithinSource = true; + SetTooltip("..."); + g.DragDropWithinSource = false; + } + + // End frame + g.WithinFrameScope = false; + g.FrameCountEnded = g.FrameCount; + + // Initiate moving window + handle left-click and right-click focus + UpdateMouseMovingWindowEndFrame(); + + // Sort the window list so that all child windows are after their parent + // We cannot do that on FocusWindow() because children may not exist yet + g.WindowsTempSortBuffer.resize(0); + g.WindowsTempSortBuffer.reserve(g.Windows.Size); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it + continue; + AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); + } + + // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. + IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); + g.Windows.swap(g.WindowsTempSortBuffer); + g.IO.MetricsActiveWindows = g.WindowsActiveCount; + + // Unlock font atlas + g.IO.Fonts->Locked = false; + + // Clear Input data for next frame + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; + g.IO.InputQueueCharacters.resize(0); + g.IO.KeyModsPrev = g.IO.KeyMods; // doing it here is better than in NewFrame() as we'll tolerate backend writing to KeyMods. If we want to firmly disallow it we should detect it. + memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePost); +} + +// Prepare the data for rendering so you can call GetDrawData() +// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all: +// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend) +void ImGui::Render() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded != g.FrameCount) + EndFrame(); + const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); + g.FrameCountRendered = g.FrameCount; + g.IO.MetricsRenderWindows = 0; + + CallContextHooks(&g, ImGuiContextHookType_RenderPre); + + // Add background ImDrawList (for each active viewport) + for (int n = 0; n != g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.Clear(); + if (viewport->DrawLists[0] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + } + + // Draw modal/window whitening backgrounds + if (first_render_of_frame) + RenderDimmedBackgrounds(); + + // Add ImDrawList to render + ImGuiWindow* windows_to_render_top_most[2]; + windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); + for (int n = 0; n != g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) + AddRootWindowToDrawData(window); + } + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) + if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window + AddRootWindowToDrawData(windows_to_render_top_most[n]); + + // Setup ImDrawData structures for end-user + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.FlattenIntoSingleLayer(); + + // Draw software mouse cursor if requested by io.MouseDrawCursor flag + if (g.IO.MouseDrawCursor && first_render_of_frame) + RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + + // Add foreground ImDrawList (for each active viewport) + if (viewport->DrawLists[1] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); + + SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]); + ImDrawData* draw_data = &viewport->DrawDataP; + g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; + g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; + } + + CallContextHooks(&g, ImGuiContextHookType_RenderPost); +} + +// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. +// CalcTextSize("") should return ImVec2(0.0f, g.FontSize) +ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) +{ + ImGuiContext& g = *GImGui; + + const char* text_display_end; + if (hide_text_after_double_hash) + text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string + else + text_display_end = text_end; + + ImFont* font = g.Font; + const float font_size = g.FontSize; + if (text == text_display_end) + return ImVec2(0.0f, font_size); + ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + + // Round + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); + + return text_size; +} + +// Find window given position, search front-to-back +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// called, aka before the next Begin(). Moving window isn't affected. +static void FindHoveredWindow() +{ + ImGuiContext& g = *GImGui; + + ImGuiWindow* hovered_window = NULL; + ImGuiWindow* hovered_window_ignoring_moving_window = NULL; + if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) + hovered_window = g.MovingWindow; + + ImVec2 padding_regular = g.Style.TouchExtraPadding; + ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (!window->Active || window->Hidden) + continue; + if (window->Flags & ImGuiWindowFlags_NoMouseInputs) + continue; + + // Using the clipped AABB, a child window will typically be clipped by its parent (not always) + ImRect bb(window->OuterRectClipped); + if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + bb.Expand(padding_regular); + else + bb.Expand(padding_for_resize); + if (!bb.Contains(g.IO.MousePos)) + continue; + + // Support for one rectangular hole in any given window + // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) + if (window->HitTestHoleSize.x != 0) + { + ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y); + ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y); + if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos)) + continue; + } + + if (hovered_window == NULL) + hovered_window = window; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) + hovered_window_ignoring_moving_window = window; + if (hovered_window && hovered_window_ignoring_moving_window) + break; + } + + g.HoveredWindow = hovered_window; + g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; +} + +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; +} + +int ImGui::GetKeyIndex(ImGuiKey imgui_key) +{ + IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); + ImGuiContext& g = *GImGui; + return g.IO.KeyMap[imgui_key]; +} + +// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]! +// Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! +bool ImGui::IsKeyDown(int user_key_index) +{ + if (user_key_index < 0) + return false; + ImGuiContext& g = *GImGui; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDown[user_key_index]; +} + +// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) +// t1 = current time (e.g.: g.Time) +// An event is triggered at: +// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N +int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) +{ + if (t1 == 0.0f) + return 1; + if (t0 >= t1) + return 0; + if (repeat_rate <= 0.0f) + return (t0 < repeat_delay) && (t1 >= repeat_delay); + const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); + const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); + const int count = count_t1 - count_t0; + return count; +} + +int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + if (key_index < 0) + return 0; + IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[key_index]; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); +} + +bool ImGui::IsKeyPressed(int user_key_index, bool repeat) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) + return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[user_key_index]; + if (t == 0.0f) + return true; + if (repeat && t > g.IO.KeyRepeatDelay) + return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + return false; +} + +bool ImGui::IsKeyReleased(int user_key_index) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float t = g.IO.MouseDownDuration[button]; + if (t == 0.0f) + return true; + + if (repeat && t > g.IO.KeyRepeatDelay) + { + // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. + int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); + if (amount > 0) + return true; + } + return false; +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button]; +} + +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2; +} + +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button]; +} + +// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); +} + +ImVec2 ImGui::GetMousePos() +{ + ImGuiContext& g = *GImGui; + return g.IO.MousePos; +} + +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} + +bool ImGui::IsAnyMouseDown() +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} + +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + +void ImGui::CaptureKeyboardFromApp(bool capture) +{ + GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; +} + +void ImGui::CaptureMouseFromApp(bool capture) +{ + GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; +} + +bool ImGui::IsItemActive() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + return g.ActiveId == g.LastItemData.ID; + return false; +} + +bool ImGui::IsItemActivated() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID) + return true; + return false; +} + +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; + return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID); +} + +bool ImGui::IsItemDeactivatedAfterEdit() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); +} + +// == GetItemID() == GetFocusID() +bool ImGui::IsItemFocused() +{ + ImGuiContext& g = *GImGui; + if (g.NavId != g.LastItemData.ID || g.NavId == 0) + return false; + return true; +} + +// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()! +// Most widgets have specific reactions based on mouse-up/down state, mouse position etc. +bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); +} + +bool ImGui::IsItemToggledOpen() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; +} + +bool ImGui::IsItemToggledSelection() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; +} + +bool ImGui::IsAnyItemHovered() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; +} + +bool ImGui::IsAnyItemActive() +{ + ImGuiContext& g = *GImGui; + return g.ActiveId != 0; +} + +bool ImGui::IsAnyItemFocused() +{ + ImGuiContext& g = *GImGui; + return g.NavId != 0 && !g.NavDisableHighlight; +} + +bool ImGui::IsItemVisible() +{ + ImGuiContext& g = *GImGui; + return g.CurrentWindow->ClipRect.Overlaps(g.LastItemData.Rect); +} + +bool ImGui::IsItemEdited() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0; +} + +// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework. +void ImGui::SetItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.LastItemData.ID; + if (g.HoveredId == id) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == id) + g.ActiveIdAllowOverlap = true; +} + +void ImGui::SetItemUsingMouseWheel() +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.LastItemData.ID; + if (g.HoveredId == id) + g.HoveredIdUsingMouseWheel = true; + if (g.ActiveId == id) + g.ActiveIdUsingMouseWheel = true; +} + +void ImGui::SetActiveIdUsingNavAndKeys() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId != 0); + g.ActiveIdUsingNavDirMask = ~(ImU32)0; + g.ActiveIdUsingNavInputMask = ~(ImU32)0; + g.ActiveIdUsingKeyInputMask = ~(ImU64)0; + NavMoveRequestCancel(); +} + +ImVec2 ImGui::GetItemRectMin() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.GetSize(); +} + +bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + + flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; + flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + + // Size + const ImVec2 content_avail = GetContentRegionAvail(); + ImVec2 size = ImFloor(size_arg); + const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); + if (size.x <= 0.0f) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + SetNextWindowSize(size); + + // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. + if (name) + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%s_%08X", parent_window->Name, name, id); + else + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%08X", parent_window->Name, id); + + const float backup_border_size = g.Style.ChildBorderSize; + if (!border) + g.Style.ChildBorderSize = 0.0f; + bool ret = Begin(g.TempBuffer, NULL, flags); + g.Style.ChildBorderSize = backup_border_size; + + ImGuiWindow* child_window = g.CurrentWindow; + child_window->ChildId = id; + child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; + + // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. + // While this is not really documented/defined, it seems that the expected thing to do. + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; + + // Process navigation-in immediately so NavInit can run on first frame + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll)) + { + FocusWindow(child_window); + NavInitWindow(child_window, false); + SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item + g.ActiveIdSource = ImGuiInputSource_Nav; + } + return ret; +} + +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); +} + +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + IM_ASSERT(id != 0); + return BeginChildEx(NULL, id, size_arg, border, extra_flags); +} + +void ImGui::EndChild() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + IM_ASSERT(g.WithinEndChild == false); + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls + + g.WithinEndChild = true; + if (window->BeginCount > 1) + { + End(); + } + else + { + ImVec2 sz = window->Size; + if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f + sz.x = ImMax(4.0f, sz.x); + if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) + sz.y = ImMax(4.0f, sz.y); + End(); + + ImGuiWindow* parent_window = g.CurrentWindow; + ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); + ItemSize(sz); + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + { + ItemAdd(bb, window->ChildId); + RenderNavHighlight(bb, window->ChildId); + + // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) + if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + } + else + { + // Not navigable into + ItemAdd(bb, 0); + } + if (g.HoveredWindow == window) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + } + g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return +} + +// Helper to create a child window / scrolling region that looks like a normal widget frame. +bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + PopStyleVar(3); + PopStyleColor(); + return ret; +} + +void ImGui::EndChildFrame() +{ + EndChild(); +} + +static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) +{ + window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); + window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); + window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); +} + +ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); +} + +ImGuiWindow* ImGui::FindWindowByName(const char* name) +{ + ImGuiID id = ImHashStr(name); + return FindWindowByID(id); +} + +static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y)); + if (settings->Size.x > 0 && settings->Size.y > 0) + window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y)); + window->Collapsed = settings->Collapsed; +} + +static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) +{ + ImGuiContext& g = *GImGui; + + const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0; + const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; + if ((just_created || child_flag_changed) && !new_is_explicit_child) + { + IM_ASSERT(!g.WindowsFocusOrder.contains(window)); + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + else if (!just_created && child_flag_changed && new_is_explicit_child) + { + IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); + for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) + g.WindowsFocusOrder[n]->FocusOrder--; + g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); + window->FocusOrder = -1; + } + window->IsExplicitChild = new_is_explicit_child; +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + + // Create window the first time + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->Pos = main_viewport->Pos + ImVec2(60, 60); + + // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + { + // Retrieve settings from .ini file + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values + + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + window->AutoFitFramesX = window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } + else + { + if (window->Size.x <= 0.0f) + window->AutoFitFramesX = 2; + if (window->Size.y <= 0.0f) + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); + } + + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) + g.Windows.push_front(window); // Quite slow but rare and only once + else + g.Windows.push_back(window); + UpdateWindowInFocusOrderList(window, true, window->Flags); + + return window; +} + +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired) +{ + ImGuiContext& g = *GImGui; + ImVec2 new_size = size_desired; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + // Using -1,-1 on either X/Y axis to preserve the current size. + ImRect cr = g.NextWindowData.SizeConstraintRect; + new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; + new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; + if (g.NextWindowData.SizeCallback) + { + ImGuiSizeCallbackData data; + data.UserData = g.NextWindowData.SizeCallbackUserData; + data.Pos = window->Pos; + data.CurrentSize = window->SizeFull; + data.DesiredSize = new_size; + g.NextWindowData.SizeCallback(&data); + new_size = data.DesiredSize; + } + new_size.x = IM_FLOOR(new_size.x); + new_size.y = IM_FLOOR(new_size.y); + } + + // Minimum size + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { + ImGuiWindow* window_for_height = window; + const float decoration_up_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight(); + new_size = ImMax(new_size, g.Style.WindowMinSize); + new_size.y = ImMax(new_size.y, decoration_up_height + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + } + return new_size; +} + +static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal) +{ + bool preserve_old_content_sizes = false; + if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + preserve_old_content_sizes = true; + else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) + preserve_old_content_sizes = true; + if (preserve_old_content_sizes) + { + *content_size_current = window->ContentSize; + *content_size_ideal = window->ContentSizeIdeal; + return; + } + + content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x); + content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); +} + +static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + ImVec2 size_pad = window->WindowPadding * 2.0f; + ImVec2 size_desired = size_contents + size_pad + ImVec2(0.0f, decoration_up_height); + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Tooltip always resize + return size_desired; + } + else + { + // Maximum window size is determined by the viewport size or monitor size + const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; + const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; + ImVec2 size_min = style.WindowMinSize; + if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) + size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); + + // FIXME-VIEWPORT-WORKAREA: May want to use GetWorkSize() instead of Size depending on the type of windows? + ImVec2 avail_size = ImGui::GetMainViewport()->Size; + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f)); + + // When the window cannot fit all contents (either because of constraints, either because screen is too small), + // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. + ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - 0.0f < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_up_height < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + if (will_have_scrollbar_x) + size_auto_fit.y += style.ScrollbarSize; + if (will_have_scrollbar_y) + size_auto_fit.x += style.ScrollbarSize; + return size_auto_fit; + } +} + +ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window) +{ + ImVec2 size_contents_current; + ImVec2 size_contents_ideal; + CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal); + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal); + ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); + return size_final; +} + +static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) +{ + if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + return ImGuiCol_PopupBg; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + return ImGuiCol_ChildBg; + return ImGuiCol_WindowBg; +} + +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +{ + ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left + ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right + ImVec2 size_expected = pos_max - pos_min; + ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected); + *out_pos = pos_min; + if (corner_norm.x == 0.0f) + out_pos->x -= (size_constrained.x - size_expected.x); + if (corner_norm.y == 0.0f) + out_pos->y -= (size_constrained.y - size_expected.y); + *out_size = size_constrained; +} + +// Data for resizing from corner +struct ImGuiResizeGripDef +{ + ImVec2 CornerPosN; + ImVec2 InnerDir; + int AngleMin12, AngleMax12; +}; +static const ImGuiResizeGripDef resize_grip_def[4] = +{ + { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right + { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left + { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused) + { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused) +}; + +// Data for resizing from borders +struct ImGuiResizeBorderDef +{ + ImVec2 InnerDir; + ImVec2 SegmentN1, SegmentN2; + float OuterAngle; +}; +static const ImGuiResizeBorderDef resize_border_def[4] = +{ + { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left + { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right + { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up + { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down +}; + +static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) +{ + ImRect rect = window->Rect(); + if (thickness == 0.0f) + rect.Max -= ImVec2(1, 1); + if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } + if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } + IM_ASSERT(0); + return ImRect(); +} + +// 0..3: corners (Lower-right, Lower-left, Unused, Unused) +ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n < 4); + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Borders (Left, Right, Up, Down) +ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) +{ + IM_ASSERT(dir >= 0 && dir < 4); + int n = (int)dir + 4; + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Handle resize for: Resize Grips, Borders, Gamepad +// Return true when using auto-fit (double click on resize grip) +static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return false; + if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. + return false; + + bool ret_auto_fit = false; + const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; + const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; + + ImVec2 pos_target(FLT_MAX, FLT_MAX); + ImVec2 size_target(FLT_MAX, FLT_MAX); + + // Resize grips and borders are on layer 1 + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + // Manual resize grips + PushID("#RESIZE"); + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN); + + // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window + bool hovered, held; + ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size); + if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); + if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); + ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID() + ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); + if (hovered || held) + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; + + if (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0) + { + // Manual auto-fit when double-clicking + size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); + ret_auto_fit = true; + ClearActiveID(); + } + else if (held) + { + // Resize from any of the four corners + // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position + ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip + corner_target = ImClamp(corner_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target); + } + + // Only lower-left grip is visible before hovering/activating + if (resize_grip_n == 0 || held || hovered) + resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + } + for (int border_n = 0; border_n < resize_border_count; border_n++) + { + const ImGuiResizeBorderDef& def = resize_border_def[border_n]; + const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + + bool hovered, held; + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() + ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) + { + g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (held) + *border_held = border_n; + } + if (held) + { + ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX); + ImVec2 border_target = window->Pos; + border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; + border_target = ImClamp(border_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); + } + } + PopID(); + + // Restore nav layer + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + + // Navigation resize (keyboard/gamepad) + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) + { + ImVec2 nav_resize_delta; + if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); + if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + { + const float NAV_RESIZE_SPEED = 600.0f; + nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size); + g.NavWindowingToggleLayer = false; + g.NavDisableMouseHover = true; + resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); + // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. + size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); + } + } + + // Apply back modified position/size to window + if (size_target.x != FLT_MAX) + { + window->SizeFull = size_target; + MarkIniSettingsDirty(window); + } + if (pos_target.x != FLT_MAX) + { + window->Pos = ImFloor(pos_target); + MarkIniSettingsDirty(window); + } + + window->Size = window->SizeFull; + return ret_auto_fit; +} + +static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect) +{ + ImGuiContext& g = *GImGui; + ImVec2 size_for_clamping = window->Size; + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + size_for_clamping.y = window->TitleBarHeight(); + window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); +} + +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + + int border_held = window->ResizeBorderHeld; + if (border_held != -1) + { + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + +// Draw background and borders +// Draw and handle scrollbars +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + // Ensure that ScrollBar doesn't read last frame's SkipItems + IM_ASSERT(window->BeginCount == 0); + window->SkipItems = false; + + // Draw window + handle manual resize + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + if (window->Collapsed) + { + // Title bar only + float backup_border_size = style.FrameBorderSize; + g.Style.FrameBorderSize = window->WindowBorderSize; + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); + g.Style.FrameBorderSize = backup_border_size; + } + else + { + // Window background + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window)); + bool override_alpha = false; + float alpha = 1.0f; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) + { + alpha = g.NextWindowData.BgAlphaVal; + override_alpha = true; + } + if (override_alpha) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom); + } + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop); + } + + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + } + + // Scrollbars + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + // Render resize grips (after their input handling so we don't have a frame of latency) + if (!(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); + } + } + + // Borders + RenderWindowOuterBorders(window); + } +} + +// Render title text, collapse button, close button +void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + const bool has_close_button = (p_open != NULL); + const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); + + // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) + // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref? + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + // Layout buttons + // FIXME: Would be nice to generalize the subtleties expressed here into reusable code. + float pad_l = style.FramePadding.x; + float pad_r = style.FramePadding.x; + float button_sz = g.FontSize; + ImVec2 close_button_pos; + ImVec2 collapse_button_pos; + if (has_close_button) + { + pad_r += button_sz; + close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) + { + pad_r += button_sz; + collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) + { + collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); + pad_l += button_sz; + } + + // Collapse button (submitting first so it gets priority when choosing a navigation init fallback) + if (has_collapse_button) + if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos)) + window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function + + // Close button + if (has_close_button) + if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) + *p_open = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + g.CurrentItemFlags = item_flags_backup; + + // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f; + const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + + // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, + // while uncentered title text will still reach edges correctly. + if (pad_l > style.FramePadding.x) + pad_l += g.Style.ItemInnerSpacing.x; + if (pad_r > style.FramePadding.x) + pad_r += g.Style.ItemInnerSpacing.x; + if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f) + { + float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center + float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x); + pad_l = ImMax(pad_l, pad_extend * centerness); + pad_r = ImMax(pad_r, pad_extend * centerness); + } + + ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); + ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos; + marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x); + marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f; + if (marker_pos.x > layout_r.Min.x) + { + RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text)); + clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f)); + } + } + //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); +} + +void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) +{ + window->ParentWindow = parent_window; + window->RootWindow = window->RootWindowPopupTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + window->RootWindow = parent_window->RootWindow; + if (parent_window && (flags & ImGuiWindowFlags_Popup)) + window->RootWindowPopupTree = parent_window->RootWindowPopupTree; + if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) + window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; + while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) + { + IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); + window->RootWindowForNav = window->RootWindowForNav->ParentWindow; + } +} + +// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) +// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. +// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. +// - Window // FindBlockingModal() returns Modal1 +// - Window // .. returns Modal1 +// - Modal1 // .. returns Modal2 +// - Window // .. returns Modal2 +// - Window // .. returns Modal2 +// - Modal2 // .. returns Modal2 +static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= 0) + return NULL; + + // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. + for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--) + { + ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; + if (popup_window == NULL || !popup_window->WasActive || !(popup_window->Flags & ImGuiWindowFlags_Modal)) // Check WasActive, because this code may run before popup renders on current frame. + continue; + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. + break; + for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow) + if (IsWindowWithinBeginStackOf(window, parent)) + return popup_window; // Place window above its begin stack parent. + } + return NULL; +} + +// Push a new Dear ImGui window to add widgets to. +// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. +// - Begin/End can be called multiple times during the frame with the same window name to append content. +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. +// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. +// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. +bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required + IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet + + // Find or create + ImGuiWindow* window = FindWindowByName(name); + const bool window_just_created = (window == NULL); + if (window_just_created) + window = CreateNewWindow(name, flags); + else + UpdateWindowInFocusOrderList(window, window_just_created, flags); + + // Automatically disable manual moving/resizing when NoInputs is set + if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) + flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + + if (flags & ImGuiWindowFlags_NavFlattened) + IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); + + const int current_frame = g.FrameCount; + const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow); + + // Update the Appearing flag + bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed + window_just_activated_by_user |= (window != popup_ref.Window); + } + window->Appearing = window_just_activated_by_user; + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + + // Update Flags, LastFrameActive, BeginOrderXXX fields + if (first_begin_of_the_frame) + { + window->Flags = (ImGuiWindowFlags)flags; + window->LastFrameActive = current_frame; + window->LastTimeActive = (float)g.Time; + window->BeginOrderWithinParent = 0; + window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); + } + else + { + flags = window->Flags; + } + + // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack + ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window; + ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; + IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); + + // We allow window memory to be compacted so recreate the base stack when needed. + if (window->IDStack.Size == 0) + window->IDStack.push_back(window->ID); + + // Add to stack + // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() + g.CurrentWindow = window; + ImGuiWindowStackData window_stack_data; + window_stack_data.Window = window; + window_stack_data.ParentLastItemDataBackup = g.LastItemData; + window_stack_data.StackSizesOnBegin.SetToCurrentState(); + g.CurrentWindowStack.push_back(window_stack_data); + g.CurrentWindow = NULL; + if (flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount++; + + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + popup_ref.Window = window; + g.BeginPopupStack.push_back(popup_ref); + window->PopupId = popup_ref.PopupId; + } + + // Update ->RootWindow and others pointers (before any possible call to FocusWindow) + if (first_begin_of_the_frame) + { + UpdateWindowParentAndRootLinks(window, flags, parent_window); + window->ParentWindowInBeginStack = parent_window_in_stack; + } + + // Process SetNextWindow***() calls + // (FIXME: Consider splitting the HasXXX flags into X/Y components + bool window_pos_set_by_api = false; + bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) + { + window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; + if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) + { + // May be processed on the next frame if this is our first frame and we are measuring size + // FIXME: Look into removing the branch so everything can go through this same code path for consistency. + window->SetWindowPosVal = g.NextWindowData.PosVal; + window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + } + else + { + SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) + { + window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); + window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); + SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) + { + if (g.NextWindowData.ScrollVal.x >= 0.0f) + { + window->ScrollTarget.x = g.NextWindowData.ScrollVal.x; + window->ScrollTargetCenterRatio.x = 0.0f; + } + if (g.NextWindowData.ScrollVal.y >= 0.0f) + { + window->ScrollTarget.y = g.NextWindowData.ScrollVal.y; + window->ScrollTargetCenterRatio.y = 0.0f; + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) + window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; + else if (first_begin_of_the_frame) + window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) + SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) + FocusWindow(window); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); + + // When reusing window again multiple times a frame, just append content (don't need to setup again) + if (first_begin_of_the_frame) + { + // Initialize + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) + window->Active = true; + window->HasCloseButton = (p_open != NULL); + window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); + window->IDStack.resize(1); + window->DrawList->_ResetForNewFrame(); + window->DC.CurrentTableIdx = -1; + + // Restore buffer capacity when woken from a compacted state, to avoid + if (window->MemoryCompacted) + GcAwakeTransientWindowBuffers(window); + + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS + + // Update contents size from last frame for auto-fitting (or use explicit size) + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); + CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal); + if (window->HiddenFramesCanSkipItems > 0) + window->HiddenFramesCanSkipItems--; + if (window->HiddenFramesCannotSkipItems > 0) + window->HiddenFramesCannotSkipItems--; + if (window->HiddenFramesForRenderOnly > 0) + window->HiddenFramesForRenderOnly--; + + // Hide new windows for one frame until they calculate their size + if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) + window->HiddenFramesCannotSkipItems = 1; + + // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) + // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. + if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) + { + window->HiddenFramesCannotSkipItems = 1; + if (flags & ImGuiWindowFlags_AlwaysAutoResize) + { + if (!window_size_x_set_by_api) + window->Size.x = window->SizeFull.x = 0.f; + if (!window_size_y_set_by_api) + window->Size.y = window->SizeFull.y = 0.f; + window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f); + } + } + + // SELECT VIEWPORT + // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style) + SetCurrentWindow(window); + + // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) + + if (flags & ImGuiWindowFlags_ChildWindow) + window->WindowBorderSize = style.ChildBorderSize; + else + window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; + window->WindowPadding = style.WindowPadding; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + + // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + + // Collapse window by double-clicking on title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) + { + // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. + ImRect title_bar_rect = window->TitleBarRect(); + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2) + window->WantCollapseToggle = true; + if (window->WantCollapseToggle) + { + window->Collapsed = !window->Collapsed; + MarkIniSettingsDirty(window); + } + } + else + { + window->Collapsed = false; + } + window->WantCollapseToggle = false; + + // SIZE + + // Calculate auto-fit size, handle automatic resize + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. + if (!window_size_x_set_by_api) + { + window->SizeFull.x = size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api) + { + window->SizeFull.y = size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + } + else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + { + // Auto-fit may only grow window during the first few frames + // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) + { + window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) + { + window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + if (!window->Collapsed) + MarkIniSettingsDirty(window); + } + + // Apply minimum/maximum window size constraints and final size + window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); + window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + + // Decoration size + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + + // POSITION + + // Popup latch its initial position, will position itself when it appears next frame + if (window_just_activated_by_user) + { + window->AutoPosLastDirection = ImGuiDir_None; + if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos() + window->Pos = g.BeginPopupStack.back().OpenPopupPos; + } + + // Position child window + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT(parent_window && parent_window->Active); + window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; + parent_window->DC.ChildWindows.push_back(window); + if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = parent_window->DC.CursorPos; + } + + const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0); + if (window_pos_with_pivot) + SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) + else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = FindBestWindowPosForPopup(window); + + // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) + // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + ImRect viewport_rect(viewport->GetMainRect()); + ImRect viewport_work_rect(viewport->GetWorkRect()); + ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding); + + // Clamp position/size so window stays visible within its viewport or monitor + // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f) + ClampWindowRect(window, visibility_rect); + window->Pos = ImFloor(window->Pos); + + // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + // Large values tend to lead to variety of artifacts and are not recommended. + window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + + // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. + //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); + + // Apply window focus (new and reactivated windows are moved to front) + bool want_focus = false; + if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (flags & ImGuiWindowFlags_Popup) + want_focus = true; + else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) + want_focus = true; + + ImGuiWindow* modal = GetTopMostPopupModal(); + if (modal != NULL && !IsWindowWithinBeginStackOf(window, modal)) + { + // Avoid focusing a window that is created outside of active modal. This will prevent active modal from being closed. + // Since window is not focused it would reappear at the same display position like the last time it was visible. + // In case of completely new windows it would go to the top (over current modal), but input to such window would still be blocked by modal. + // Position window behind a modal that is not a begin-parent of this window. + want_focus = false; + if (window == window->RootWindow) + { + ImGuiWindow* blocking_modal = FindBlockingModal(window); + IM_ASSERT(blocking_modal != NULL); + BringWindowToDisplayBehind(window, blocking_modal); + } + } + } + + // Handle manual resize: Resize Grips, Borders, Gamepad + int border_held = -1; + ImU32 resize_grip_col[4] = {}; + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + if (!window->Collapsed) + if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) + use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; + window->ResizeBorderHeld = (signed char)border_held; + + // SCROLLBAR VISIBILITY + + // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). + if (!window->Collapsed) + { + // When reading the current size we need to read it after size constraints have been applied. + // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + if (window->ScrollbarX && !window->ScrollbarY) + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + } + + // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) + // Update various regions. Variables they depends on should be set above in this function. + // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. + + // Outer rectangle + // Not affected by window border size. Used by: + // - FindHoveredWindow() (w/ extra padding when border resize is enabled) + // - Begin() initial clipping rect for drawing window background and borders. + // - Begin() clipping whole child + const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + const ImRect outer_rect = window->Rect(); + const ImRect title_bar_rect = window->TitleBarRect(); + window->OuterRectClipped = outer_rect; + window->OuterRectClipped.ClipWith(host_rect); + + // Inner rectangle + // Not affected by window border size. Used by: + // - InnerClipRect + // - ScrollToRectEx() + // - NavUpdatePageUpPageDown() + // - Scrollbar() + window->InnerRect.Min.x = window->Pos.x; + window->InnerRect.Min.y = window->Pos.y + decoration_up_height; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; + + // Inner clipping rectangle. + // Will extend a little bit outside the normal work region. + // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. + // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + // Affected by window/frame border size. Used by: + // - Begin() initial clip rect + float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); + window->InnerClipRect.ClipWithFull(host_rect); + + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f); + else + window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f); + + // SCROLLING + + // Lock down maximum scrolling + // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate + // for right/bottom aligned items without creating a scrollbar. + window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); + window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); + + // Apply scrolling + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + + // DRAWING + + // Setup draw list and outer clipping rectangle + IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); + window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + PushClipRect(host_rect.Min, host_rect.Max, false); + + // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) + // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. + // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493) + { + bool render_decorations_in_parent = false; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) + { + // - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here) + // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs + ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL; + bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false; + bool parent_is_empty = parent_window->DrawList->VtxBuffer.Size > 0; + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_is_empty && !previous_child_overlapping) + render_decorations_in_parent = true; + } + if (render_decorations_in_parent) + window->DrawList = parent_window->DrawList; + + // Handle title bar, scrollbar, resize grips and resize borders + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size); + + if (render_decorations_in_parent) + window->DrawList = &window->DrawListInst; + } + + // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) + + // Work rectangle. + // Affected by window padding and border size. Used by: + // - Columns() for right-most edge + // - TreeNode(), CollapsingHeader() for right-most edge + // - BeginTabBar() for right-most edge + const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); + const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); + window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); + window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; + window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; + window->ParentWorkRect = window->WorkRect; + + // [LEGACY] Content Region + // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // Used by: + // - Mouse wheel scrolling + many other things + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + + // Setup drawing context + // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) + window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffset.x = 0.0f; + window->DC.ColumnsOffset.x = 0.0f; + + // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount. + // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64. + double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DC.ColumnsOffset.x; + double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + decoration_up_height; + window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y); + window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y)); + window->DC.CursorPos = window->DC.CursorStartPos; + window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; + window->DC.IdealMaxPos = window->DC.CursorStartPos; + window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; + window->DC.NavLayersActiveMaskNext = 0x00; + window->DC.NavHideHighlightOneFrame = false; + window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); + + window->DC.MenuBarAppending = false; + window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); + window->DC.TreeDepth = 0; + window->DC.TreeJumpToParentOnPopMask = 0x00; + window->DC.ChildWindows.resize(0); + window->DC.StateStorage = &window->StateStorage; + window->DC.CurrentColumns = NULL; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; + + window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.TextWrapPos = -1.0f; // disabled + window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPosStack.resize(0); + + if (window->AutoFitFramesX > 0) + window->AutoFitFramesX--; + if (window->AutoFitFramesY > 0) + window->AutoFitFramesY--; + + // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + if (want_focus) + { + FocusWindow(window); + NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls + } + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); + + // Clear hit test shape every frame + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; + + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + //if (g.NavWindow == window && g.ActiveId == 0) + if (g.ActiveId == window->MoveId) + if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + LogToClipboard(); + */ + + // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). + // This is useful to allow creating context menus on title bar only, etc. + SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID); +#endif + } + else + { + // Append + SetCurrentWindow(window); + } + + // Pull/inherit current state + window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inherit from parent only // -V595 + + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + + // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) + window->WriteAccessed = false; + window->BeginCount++; + g.NextWindowData.ClearFlags(); + + // Update visibility + if (first_begin_of_the_frame) + { + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow?? + { + const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (!g.LogEnabled && !nav_request) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; + } + + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; + } + + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) + window->HiddenFramesCanSkipItems = 1; + + // Update the Hidden flag + bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0); + + // Disable inputs for requested number of frames + if (window->DisableInputsFrames > 0) + { + window->DisableInputsFrames--; + window->Flags |= ImGuiWindowFlags_NoInputs; + } + + // Update the SkipItems flag, used to early out of all items functions (no layout required) + bool skip_items = false; + if (window->Collapsed || !window->Active || hidden_regular) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; + } + + return !window->SkipItems; +} + +void ImGui::End() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Error checking: verify that user hasn't called End() too many times! + if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); + return; + } + IM_ASSERT(g.CurrentWindowStack.Size > 0); + + // Error checking: verify that user doesn't directly call End() on a child window. + if (window->Flags & ImGuiWindowFlags_ChildWindow) + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + + // Close anything that is open + if (window->DC.CurrentColumns) + EndColumns(); + PopClipRect(); // Inner window clip rectangle + + // Stop logging + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging + LogFinish(); + + // Pop from window stack + g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount--; + if (window->Flags & ImGuiWindowFlags_Popup) + g.BeginPopupStack.pop_back(); + g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithCurrentState(); + g.CurrentWindowStack.pop_back(); + SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); + if (g.WindowsFocusOrder.back() == window) + return; + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; +} + +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) +{ + IM_ASSERT(window != NULL && behind_window != NULL); + ImGuiContext& g = *GImGui; + window = window->RootWindow; + behind_window = behind_window->RootWindow; + int pos_wnd = FindWindowDisplayIndex(window); + int pos_beh = FindWindowDisplayIndex(behind_window); + if (pos_wnd < pos_beh) + { + size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); + g.Windows[pos_beh - 1] = window; + } + else + { + size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); + g.Windows[pos_beh] = window; + } +} + +int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return g.Windows.index_from_ptr(g.Windows.find(window)); +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + if (g.NavWindow != window) + { + g.NavWindow = window; + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavFocusScopeId = 0; + g.NavIdIsAlive = false; + g.NavLayer = ImGuiNavLayer_Main; + g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); + //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); + } + + // Close popups if any + ClosePopupsOverWindow(window, false); + + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss) + ClearActiveID(); + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + + // Bring to front + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); +} + +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) +{ + ImGuiContext& g = *GImGui; + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + // Aim at root window behind us, if we are in a child window that's our own root (see #4640) + int offset = -1; + while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) + { + under_this_window = under_this_window->ParentWindow; + offset = 0; + } + start_idx = FindWindowFocusIndex(under_this_window) + offset; + } + for (int i = start_idx; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + IM_ASSERT(window == window->RootWindow); + if (window != ignore_window && window->WasActive) + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } + } + FocusWindow(NULL); +} + +// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.TexUvLines = atlas->TexUvLines; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; +} + +void ImGui::PushFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + if (!font) + font = GetDefaultFont(); + SetCurrentFont(font); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); +} + +void ImGui::PopFont() +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow->DrawList->PopTextureID(); + g.FontStack.pop_back(); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); +} + +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiItemFlags item_flags = g.CurrentItemFlags; + IM_ASSERT(item_flags == g.ItemFlagsStack.back()); + if (enabled) + item_flags |= option; + else + item_flags &= ~option; + g.CurrentItemFlags = item_flags; + g.ItemFlagsStack.push_back(item_flags); +} + +void ImGui::PopItemFlag() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); +} + +// BeginDisabled()/EndDisabled() +// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) +// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently. +// - Feedback welcome at https://github.com/ocornut/imgui/issues/211 +// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. +// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag() +void ImGui::BeginDisabled(bool disabled) +{ + ImGuiContext& g = *GImGui; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (!was_disabled && disabled) + { + g.DisabledAlphaBackup = g.Style.Alpha; + g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha); + } + if (was_disabled || disabled) + g.CurrentItemFlags |= ImGuiItemFlags_Disabled; + g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.DisabledStackSize++; +} + +void ImGui::EndDisabled() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DisabledStackSize > 0); + g.DisabledStackSize--; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + //PopItemFlag(); + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); + if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); +} + +// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); +} + +void ImGui::PopAllowKeyboardFocus() +{ + PopItemFlag(); +} + +void ImGui::PushButtonRepeat(bool repeat) +{ + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); +} + +void ImGui::PopButtonRepeat() +{ + PopItemFlag(); +} + +void ImGui::PushTextWrapPos(float wrap_pos_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos); + window->DC.TextWrapPos = wrap_pos_x; +} + +void ImGui::PopTextWrapPos() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); + window->DC.TextWrapPosStack.pop_back(); +} + +static ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy) +{ + ImGuiWindow* last_window = NULL; + while (last_window != window) + { + last_window = window; + window = window->RootWindow; + if (popup_hierarchy) + window = window->RootWindowPopupTree; + } + return window; +} + +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy) +{ + ImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy); + if (window_root == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + if (window == window_root) // end of chain + return false; + window = window->ParentWindow; + } + return false; +} + +bool ImGui::IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent) +{ + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + window = window->ParentWindowInBeginStack; + } + return false; +} + +bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below) +{ + ImGuiContext& g = *GImGui; + + // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array + const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below); + if (display_layer_delta != 0) + return display_layer_delta > 0; + + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* candidate_window = g.Windows[i]; + if (candidate_window == potential_above) + return true; + if (candidate_window == potential_below) + return false; + } + return false; +} + +bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) +{ + IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled)) == 0); // Flags not supported by this function + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.HoveredWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + if (ref_window == NULL) + return false; + + if ((flags & ImGuiHoveredFlags_AnyWindow) == 0) + { + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + bool result; + if (flags & ImGuiHoveredFlags_ChildWindows) + result = IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + result = (ref_window == cur_window); + if (!result) + return false; + } + + if (!IsWindowContentHoverable(ref_window, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId) + return false; + return true; +} + +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.NavWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + + if (ref_window == NULL) + return false; + if (flags & ImGuiFocusedFlags_AnyWindow) + return true; + + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + if (flags & ImGuiHoveredFlags_ChildWindows) + return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + return (ref_window == cur_window); +} + +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + +float ImGui::GetWindowWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.x; +} + +float ImGui::GetWindowHeight() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.y; +} + +ImVec2 ImGui::GetWindowPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return window->Pos; +} + +void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowPosAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); + + // Set + const ImVec2 old_pos = window->Pos; + window->Pos = ImFloor(pos); + ImVec2 offset = window->Pos - old_pos; + window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.IdealMaxPos += offset; + window->DC.CursorStartPos += offset; +} + +void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + SetWindowPos(window, pos, cond); +} + +void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowPos(window, pos, cond); +} + +ImVec2 ImGui::GetWindowSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Size; +} + +void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + if (size.x > 0.0f) + { + window->AutoFitFramesX = 0; + window->SizeFull.x = IM_FLOOR(size.x); + } + else + { + window->AutoFitFramesX = 2; + window->AutoFitOnlyGrows = false; + } + if (size.y > 0.0f) + { + window->AutoFitFramesY = 0; + window->SizeFull.y = IM_FLOOR(size.y); + } + else + { + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } +} + +void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) +{ + SetWindowSize(GImGui->CurrentWindow, size, cond); +} + +void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowSize(window, size, cond); +} + +void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) + return; + window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + window->Collapsed = collapsed; +} + +void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters + window->HitTestHoleSize = ImVec2ih(size); + window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); +} + +void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); +} + +bool ImGui::IsWindowCollapsed() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Collapsed; +} + +bool ImGui::IsWindowAppearing() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Appearing; +} + +void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowCollapsed(window, collapsed, cond); +} + +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + +void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; + g.NextWindowData.PosVal = pos; + g.NextWindowData.PosPivotVal = pivot; + g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; + g.NextWindowData.SizeVal = size; + g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; + g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); + g.NextWindowData.SizeCallback = custom_callback; + g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; +} + +// Content size = inner scrollable rectangle, padded with WindowPadding. +// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item. +void ImGui::SetNextWindowContentSize(const ImVec2& size) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; + g.NextWindowData.ContentSizeVal = ImFloor(size); +} + +void ImGui::SetNextWindowScroll(const ImVec2& scroll) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; + g.NextWindowData.ScrollVal = scroll; +} + +void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; + g.NextWindowData.CollapsedVal = collapsed; + g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; +} + +void ImGui::SetNextWindowBgAlpha(float alpha) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; + g.NextWindowData.BgAlphaVal = alpha; +} + +ImDrawList* ImGui::GetWindowDrawList() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DrawList; +} + +ImFont* ImGui::GetFont() +{ + return GImGui->Font; +} + +float ImGui::GetFontSize() +{ + return GImGui->FontSize; +} + +ImVec2 ImGui::GetFontTexUvWhitePixel() +{ + return GImGui->DrawListSharedData.TexUvWhitePixel; +} + +void ImGui::SetWindowFontScale(float scale) +{ + IM_ASSERT(scale > 0.0f); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->FontWindowScale = scale; + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +void ImGui::ActivateItem(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; + g.NavNextActivateFlags = ImGuiActivateFlags_None; +} + +void ImGui::PushFocusScope(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent); + window->DC.NavFocusScopeIdCurrent = id; +} + +void ImGui::PopFocusScope() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ? + window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back(); + g.FocusScopeStack.pop_back(); +} + +void ImGui::SetKeyboardFocusHere(int offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(offset >= -1); // -1 is allowed but not below + g.NavWindow = window; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + if (offset == -1) + { + NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); + } + else + { + g.NavTabbingDir = 1; + g.NavTabbingCounter = offset + 1; + } +} + +void ImGui::SetItemDefaultFocus() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!window->Appearing) + return; + if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResultId == 0) || g.NavLayer != window->DC.NavLayerCurrent) + return; + + g.NavInitRequest = false; + g.NavInitResultId = g.LastItemData.ID; + g.NavInitResultRectRel = WindowRectAbsToRel(window, g.LastItemData.Rect); + NavUpdateAnyRequestFlag(); + + // Scroll could be done in NavInitRequestApplyResult() via a opt-in flag (we however don't want regular init requests to scroll) + if (!IsItemVisible()) + ScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags_None); +} + +void ImGui::SetStateStorage(ImGuiStorage* tree) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->DC.StateStorage = tree ? tree : &window->StateStorage; +} + +ImGuiStorage* ImGui::GetStateStorage() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->DC.StateStorage; +} + +void ImGui::PushID(const char* str_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(str_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const void* ptr_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(ptr_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(int int_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(int_id); + window->IDStack.push_back(id); +} + +// Push a given id value ignoring the ID stack as a seed. +void ImGui::PushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL); + window->IDStack.push_back(id); +} + +// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call +// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level. +// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more) +ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) +{ + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + KeepAliveID(id); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +void ImGui::PopID() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? + window->IDStack.pop_back(); +} + +ImGuiID ImGui::GetID(const char* str_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id); +} + +ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id_begin, str_id_end); +} + +ImGuiID ImGui::GetID(const void* ptr_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(ptr_id); +} + +bool ImGui::IsRectVisible(const ImVec2& size) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); +} + +bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); +} + + +//----------------------------------------------------------------------------- +// [SECTION] ERROR CHECKING +//----------------------------------------------------------------------------- + +// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. +// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit +// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code +// may see different structures than what imgui.cpp sees, which is problematic. +// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui. +bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) +{ + bool error = false; + if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } + return !error; +} + +static void ImGui::ErrorCheckNewFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Check user IM_ASSERT macro + // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined! + // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. + // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) + // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong! + // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct! + if (true) IM_ASSERT(1); else IM_ASSERT(0); + + // Check user data + // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) + IM_ASSERT(g.Initialized); + IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); + IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); + IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); + IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); + for (int n = 0; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); + + // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) + if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); + + // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; +} + +static void ImGui::ErrorCheckEndFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() + // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). + // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will + // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. + // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // while still correctly asserting on mid-frame key press events. + const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); + IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mod_flags); + + // Recover from errors + //ErrorCheckEndFrameRecover(); + + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) + End(); + } + else + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + + IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); +} + +// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls. +// Must be called during or before EndFrame(). +// This is generally flawed as we are not necessarily End/Popping things in the right order. +// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. +// FIXME: Can't recover from interleaved BeginTabBar/Begin +void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations" + ImGuiContext& g = *GImGui; + while (g.CurrentWindowStack.Size > 0) //-V1044 + { + ErrorCheckEndWindowRecover(log_callback, user_data); + ImGuiWindow* window = g.CurrentWindow; + if (g.CurrentWindowStack.Size == 1) + { + IM_ASSERT(window->IsFallbackWindow); + break; + } + IM_ASSERT(window == g.CurrentWindow); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name); + EndChild(); + } + else + { + if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name); + End(); + } + } +} + +// Must be called before End()/EndChild() +void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + ImGuiContext& g = *GImGui; + while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow)) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name); + EndTable(); + } + + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin; + IM_ASSERT(window != NULL); + while (g.CurrentTabBar != NULL) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name); + EndTabBar(); + } + while (window->DC.TreeDepth > 0) + { + if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name); + TreePop(); + } + while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name); + EndGroup(); + } + while (window->IDStack.Size > 1) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name); + PopID(); + } + while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); + EndDisabled(); + } + while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col)); + PopStyleColor(); + } + while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name); + PopItemFlag(); + } + while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); + PopStyleVar(); + } + while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); + PopFocusScope(); + } +} + +// Save current stack sizes for later compare +void ImGuiStackSizes::SetToCurrentState() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + SizeOfIDStack = (short)window->IDStack.Size; + SizeOfColorStack = (short)g.ColorStack.Size; + SizeOfStyleVarStack = (short)g.StyleVarStack.Size; + SizeOfFontStack = (short)g.FontStack.Size; + SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; + SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; + SizeOfDisabledStack = (short)g.DisabledStackSize; +} + +// Compare to detect usage errors +void ImGuiStackSizes::CompareWithCurrentState() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_UNUSED(window); + + // Window stacks + // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!"); + IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!"); + IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); + IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); + IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); + IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!"); +} + + +//----------------------------------------------------------------------------- +// [SECTION] LAYOUT +//----------------------------------------------------------------------------- +// - ItemSize() +// - ItemAdd() +// - SameLine() +// - GetCursorScreenPos() +// - SetCursorScreenPos() +// - GetCursorPos(), GetCursorPosX(), GetCursorPosY() +// - SetCursorPos(), SetCursorPosX(), SetCursorPosY() +// - GetCursorStartPos() +// - Indent() +// - Unindent() +// - SetNextItemWidth() +// - PushItemWidth() +// - PushMultiItemsWidths() +// - PopItemWidth() +// - CalcItemWidth() +// - CalcItemSize() +// - GetTextLineHeight() +// - GetTextLineHeightWithSpacing() +// - GetFrameHeight() +// - GetFrameHeightWithSpacing() +// - GetContentRegionMax() +// - GetContentRegionMaxAbs() [Internal] +// - GetContentRegionAvail(), +// - GetWindowContentRegionMin(), GetWindowContentRegionMax() +// - BeginGroup() +// - EndGroup() +// Also see in imgui_widgets: tab bars, columns. +//----------------------------------------------------------------------------- + +// Advance cursor given item size for layout. +// Register minimum needed size so it can extend the bounding box used for auto-fit calculation. +// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. +void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // We increase the height in this function to accommodate for baseline offset. + // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, + // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. + const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; + const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); + + // Always align ourselves on pixel boundaries + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line + window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.y = line_height; + window->DC.CurrLineSize.y = 0.0f; + window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); + window->DC.CurrLineTextBaseOffset = 0.0f; + + // Horizontal layout mode + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) +{ + ItemSize(bb.GetSize(), text_baseline_y); +} + +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Set item data + // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set) + g.LastItemData.ID = id; + g.LastItemData.Rect = bb; + g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; + g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags; + g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; + + // Directional navigation processing + if (id != 0) + { + // Runs prior to clipping early-out + // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget + // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests + // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of + // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. + // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able + // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). + // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. + // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. + window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); + if (g.NavId == id || g.NavAnyRequest) + if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) + if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) + NavProcessItem(); + + // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something". + // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something". + // READ THE FAQ: https://dearimgui.org/faq + IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); + + // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd() +#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + if (id == g.DebugItemPickerBreakId) + { + IM_DEBUG_BREAK(); + g.DebugItemPickerBreakId = 0; + } +#endif + } + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); +#endif + + // Clipping test + const bool is_clipped = IsClippedEx(bb, id); + if (is_clipped) + return false; + //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) + if (IsMouseHoveringRect(bb.Min, bb.Max)) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; +} + +// Gets back to previous line and continue with horizontal layout +// offset_from_start_x == 0 : follow right after previous item +// offset_from_start_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float offset_from_start_x, float spacing_w) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + if (offset_from_start_x != 0.0f) + { + if (spacing_w < 0.0f) spacing_w = 0.0f; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + else + { + if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + window->DC.CurrLineSize = window->DC.PrevLineSize; + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; +} + +ImVec2 ImGui::GetCursorScreenPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; +} + +void ImGui::SetCursorScreenPos(const ImVec2& pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. +// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. +ImVec2 ImGui::GetCursorPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos - window->Pos + window->Scroll; +} + +float ImGui::GetCursorPosX() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; +} + +float ImGui::GetCursorPosY() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; +} + +void ImGui::SetCursorPos(const ImVec2& local_pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = window->Pos - window->Scroll + local_pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +void ImGui::SetCursorPosX(float x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); +} + +void ImGui::SetCursorPosY(float y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); +} + +ImVec2 ImGui::GetCursorStartPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorStartPos - window->Pos; +} + +void ImGui::Indent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +void ImGui::Unindent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +// Affect large frame+labels widgets only. +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; +} + +// FIXME: Remove the == 0.0f behavior? +void ImGui::PushItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PushMultiItemsWidths(int components, float w_full) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiStyle& style = g.Style; + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidthStack.push_back(w_item_last); + for (int i = 0; i < components - 2; i++) + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PopItemWidth() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + window->DC.ItemWidthStack.pop_back(); +} + +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). +// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() +float ImGui::CalcItemWidth() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float w; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + w = g.NextItemData.Width; + else + w = window->DC.ItemWidth; + if (w < 0.0f) + { + float region_max_x = GetContentRegionMaxAbs().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + } + w = IM_FLOOR(w); + return w; +} + +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). +// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. +// Note that only CalcItemWidth() is publicly exposed. +// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + + ImVec2 region_max; + if (size.x < 0.0f || size.y < 0.0f) + region_max = GetContentRegionMaxAbs(); + + if (size.x == 0.0f) + size.x = default_w; + else if (size.x < 0.0f) + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); + + if (size.y == 0.0f) + size.y = default_h; + else if (size.y < 0.0f) + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); + + return size; +} + +float ImGui::GetTextLineHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize; +} + +float ImGui::GetTextLineHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.ItemSpacing.y; +} + +float ImGui::GetFrameHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f; +} + +float ImGui::GetFrameHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! + +// FIXME: This is in window space (not screen space!). +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x - window->Pos.x; + return mx; +} + +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxAbs() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max; + if (window->DC.CurrentColumns || g.CurrentTable) + mx.x = window->WorkRect.Max.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +// In window space (not screen space!) +ImVec2 ImGui::GetWindowContentRegionMin() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Min - window->Pos; +} + +ImVec2 ImGui::GetWindowContentRegionMax() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Max - window->Pos; +} + +// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) +// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. +// FIXME-OPT: Could we safely early out on ->SkipItems? +void ImGui::BeginGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + g.GroupStack.resize(g.GroupStack.Size + 1); + ImGuiGroupData& group_data = g.GroupStack.back(); + group_data.WindowID = window->ID; + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupIndent = window->DC.Indent; + group_data.BackupGroupOffset = window->DC.GroupOffset; + group_data.BackupCurrLineSize = window->DC.CurrLineSize; + group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.EmitItem = true; + + window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; + window->DC.Indent = window->DC.GroupOffset; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls + + ImGuiGroupData& group_data = g.GroupStack.back(); + IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window? + + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.Indent = group_data.BackupIndent; + window->DC.GroupOffset = group_data.BackupGroupOffset; + window->DC.CurrLineSize = group_data.BackupCurrLineSize; + window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return + + if (!group_data.EmitItem) + { + g.GroupStack.pop_back(); + return; + } + + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize()); + ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); + + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. + // Also if you grep for LastItemId you'll notice it is only used in that context. + // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) + const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; + const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); + if (group_contains_curr_active_id) + g.LastItemData.ID = g.ActiveId; + else if (group_contains_prev_active_id) + g.LastItemData.ID = g.ActiveIdPreviousFrame; + g.LastItemData.Rect = group_bb; + + // Forward Hovered flag + const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0; + if (group_contains_curr_hovered_id) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + + // Forward Edited flag + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; + + // Forward Deactivated flag + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated; + + g.GroupStack.pop_back(); + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +} + + +//----------------------------------------------------------------------------- +// [SECTION] SCROLLING +//----------------------------------------------------------------------------- + +// Helper to snap on edges when aiming at an item very close to the edge, +// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. +// When we refactor the scrolling API this may be configurable with a flag? +// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. +static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) +{ + if (target <= snap_min + snap_threshold) + return ImLerp(snap_min, target, center_ratio); + if (target >= snap_max - snap_threshold) + return ImLerp(target, snap_max, center_ratio); + return target; +} + +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) +{ + ImVec2 scroll = window->Scroll; + if (window->ScrollTarget.x < FLT_MAX) + { + float decoration_total_width = window->ScrollbarSizes.x; + float center_x_ratio = window->ScrollTargetCenterRatio.x; + float scroll_target_x = window->ScrollTarget.x; + if (window->ScrollTargetEdgeSnapDist.x > 0.0f) + { + float snap_x_min = 0.0f; + float snap_x_max = window->ScrollMax.x + window->SizeFull.x - decoration_total_width; + scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio); + } + scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - decoration_total_width); + } + if (window->ScrollTarget.y < FLT_MAX) + { + float decoration_total_height = window->TitleBarHeight() + window->MenuBarHeight() + window->ScrollbarSizes.y; + float center_y_ratio = window->ScrollTargetCenterRatio.y; + float scroll_target_y = window->ScrollTarget.y; + if (window->ScrollTargetEdgeSnapDist.y > 0.0f) + { + float snap_y_min = 0.0f; + float snap_y_max = window->ScrollMax.y + window->SizeFull.y - decoration_total_height; + scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); + } + scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - decoration_total_height); + } + scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); + scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); + if (!window->Collapsed && !window->SkipItems) + { + scroll.x = ImMin(scroll.x, window->ScrollMax.x); + scroll.y = ImMin(scroll.y, window->ScrollMax.y); + } + return scroll; +} + +void ImGui::ScrollToItem(ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ScrollToRectEx(window, g.LastItemData.NavRect, flags); +} + +void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ScrollToRectEx(window, item_rect, flags); +} + +// Scroll to keep newly navigated item fully into view +ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] + + // Check that only one behavior is selected per axis + IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_)); + IM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_)); + + // Defaults + ImGuiScrollFlags in_flags = flags; + if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX) + flags |= ImGuiScrollFlags_KeepVisibleEdgeX; + if ((flags & ImGuiScrollFlags_MaskY_) == 0) + flags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY; + + const bool fully_visible_x = item_rect.Min.x >= window_rect.Min.x && item_rect.Max.x <= window_rect.Max.x; + const bool fully_visible_y = item_rect.Min.y >= window_rect.Min.y && item_rect.Max.y <= window_rect.Max.y; + const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= window_rect.GetWidth(); + const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= window_rect.GetHeight(); + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x) + { + if (item_rect.Min.x < window_rect.Min.x || !can_be_fully_visible_x) + SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f); + else if (item_rect.Max.x >= window_rect.Max.x) + SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX)) + { + float target_x = can_be_fully_visible_x ? ImFloor((item_rect.Min.x + item_rect.Max.x - window->InnerRect.GetWidth()) * 0.5f) : item_rect.Min.x; + SetScrollFromPosX(window, target_x - window->Pos.x, 0.0f); + } + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y) + { + if (item_rect.Min.y < window_rect.Min.y || !can_be_fully_visible_y) + SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f); + else if (item_rect.Max.y >= window_rect.Max.y) + SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY)) + { + float target_y = can_be_fully_visible_y ? ImFloor((item_rect.Min.y + item_rect.Max.y - window->InnerRect.GetHeight()) * 0.5f) : item_rect.Min.y; + SetScrollFromPosY(window, target_y - window->Pos.y, 0.0f); + } + + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + ImVec2 delta_scroll = next_scroll - window->Scroll; + + // Also scroll parent window to keep us into view if necessary + if (!(flags & ImGuiScrollFlags_NoScrollParent) && (window->Flags & ImGuiWindowFlags_ChildWindow)) + { + // FIXME-SCROLL: May be an option? + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterX | ImGuiScrollFlags_KeepVisibleCenterX)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX; + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterY | ImGuiScrollFlags_KeepVisibleCenterY)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskY_) | ImGuiScrollFlags_KeepVisibleEdgeY; + delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags); + } + + return delta_scroll; +} + +float ImGui::GetScrollX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.x; +} + +float ImGui::GetScrollY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.x; +} + +float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.y; +} + +void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x) +{ + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y) +{ + window->ScrollTarget.y = scroll_y; + window->ScrollTargetCenterRatio.y = 0.0f; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollX(float scroll_x) +{ + ImGuiContext& g = *GImGui; + SetScrollX(g.CurrentWindow, scroll_x); +} + +void ImGui::SetScrollY(float scroll_y) +{ + ImGuiContext& g = *GImGui; + SetScrollY(g.CurrentWindow, scroll_y); +} + +// Note that a local position will vary depending on initial scroll value, +// This is a little bit confusing so bear with us: +// - local_pos = (absolution_pos - window->Pos) +// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window, +// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area. +// - They mostly exists because of legacy API. +// Following the rules above, when trying to work with scrolling code, consider that: +// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect! +// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense +// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size +void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) +{ + IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); + window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.x = center_x_ratio; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) +{ + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect; + local_y -= decoration_up_height; + window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.y = center_y_ratio; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); +} + +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); +} + +// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x); + float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio); + SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); +} + +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y); + float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); + SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); +} + +//----------------------------------------------------------------------------- +// [SECTION] TOOLTIPS +//----------------------------------------------------------------------------- + +void ImGui::BeginTooltip() +{ + BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); +} + +void ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) +{ + ImGuiContext& g = *GImGui; + + if (g.DragDropWithinSource || g.DragDropWithinTarget) + { + // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) + // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. + // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. + //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( + tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; + } + + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + window->Hidden = true; + window->HiddenFramesCanSkipItems = 1; // FIXME: This may not be necessary? + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; + Begin(window_name, NULL, flags | extra_window_flags); +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls + End(); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); + TextV(fmt, args); + EndTooltip(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// [SECTION] POPUPS +//----------------------------------------------------------------------------- + +// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel +bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + if (popup_flags & ImGuiPopupFlags_AnyPopupId) + { + // Return true if any popup is open at the current BeginPopup() level of the popup stack + // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level. + IM_ASSERT(id == 0); + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + return g.OpenPopupStack.Size > 0; + else + return g.OpenPopupStack.Size > g.BeginPopupStack.Size; + } + else + { + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + { + // Return true if the popup is open anywhere in the popup stack + for (int n = 0; n < g.OpenPopupStack.Size; n++) + if (g.OpenPopupStack[n].PopupId == id) + return true; + return false; + } + else + { + // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query) + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; + } + } +} + +bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id); + if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0) + IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally + return IsPopupOpen(id, popup_flags); +} + +ImGuiWindow* ImGui::GetTopMostPopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if (popup->Flags & ImGuiWindowFlags_Modal) + return popup; + return NULL; +} + +ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup)) + return popup; + return NULL; +} + +void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags); +} + +void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + OpenPopupEx(id, popup_flags); +} + +// Mark popup as open (toggle toward open state). +// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. +// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) +void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + const int current_stack_size = g.BeginPopupStack.Size; + + if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) + if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId)) + return; + + ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.SourceWindow = g.NavWindow; + popup_ref.OpenFrameCount = g.FrameCount; + popup_ref.OpenParentId = parent_window->IDStack.back(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + + IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui + // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing + // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. + if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) + { + g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; + } + else + { + // Close child popups if any, then flag popup for open/reopen + ClosePopupToLevel(current_stack_size, false); + g.OpenPopupStack.push_back(popup_ref); + } + + // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). + // This is equivalent to what ClosePopupToLevel() does. + //if (g.OpenPopupStack[current_stack_size].PopupId == id) + // FocusWindow(parent_window); + } +} + +// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. +// This function closes any popups that are over 'ref_window'. +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size == 0) + return; + + // Don't close our own child popup windows. + int popup_count_to_keep = 0; + if (ref_window) + { + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + { + ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + + // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow) + // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3: + // Window -> Popup1 -> Popup2 -> Popup3 + // - Each popups may contain child windows, which is why we compare ->RootWindow! + // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child + bool ref_window_is_descendent_of_popup = false; + for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) + if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) + if (IsWindowWithinBeginStackOf(ref_window, popup_window)) + { + ref_window_is_descendent_of_popup = true; + break; + } + if (!ref_window_is_descendent_of_popup) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + } +} + +void ImGui::ClosePopupsExceptModals() +{ + ImGuiContext& g = *GImGui; + + int popup_count_to_keep; + for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--) + { + ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window; + if (!window || window->Flags & ImGuiWindowFlags_Modal) + break; + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + ClosePopupToLevel(popup_count_to_keep, true); +} + +void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup); + IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); + + // Trim open popup stack + ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow; + ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; + g.OpenPopupStack.resize(remaining); + + if (restore_focus_to_window_under_popup) + { + if (focus_window && !focus_window->WasActive && popup_window) + { + // Fallback + FocusTopMostWindowUnderOne(popup_window, NULL); + } + else + { + if (g.NavLayer == ImGuiNavLayer_Main && focus_window) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } + } +} + +// Close the popup we have begin-ed into. +void ImGui::CloseCurrentPopup() +{ + ImGuiContext& g = *GImGui; + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + return; + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +// Attention! BeginPopup() adds default flags which BeginPopupEx()! +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + char name[20]; + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + + flags |= ImGuiWindowFlags_Popup; + bool is_open = Begin(name, NULL, flags); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); +} + +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + // Center modal windows by default for increased visibility + // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) + // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + { + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + } + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse; + const bool is_open = Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + { + EndPopup(); + if (is_open) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + return false; + } + return is_open; +} + +void ImGui::EndPopup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.BeginPopupStack.Size > 0); + + // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) + if (g.NavWindow == window) + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + + // Child-popups don't need to be laid out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +// Helper to open a popup if mouse button is released over the item +// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() +void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + OpenPopupEx(id, popup_flags); + } +} + +// This is a helper to handle the simplest case of associating one named popup to one given widget. +// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. +// - To create a popup with a specific identifier, pass it in str_id. +// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. +// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// This is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// OpenPopupOnItemClick(str_id); +// return BeginPopup(id); +// Which is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) +// OpenPopup(id); +// return BeginPopup(id); +// The main difference being that this is tweaked to avoid computing the ID twice. +bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "window_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "void_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + if (GetTopMostPopupModal() == NULL) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) +// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor +// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. +// this allows us to have tooltips/popups displayed out of the parent viewport.) +ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +{ + ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + + // Combo Box policy (we want a connecting edge) + if (policy == ImGuiPopupPositionPolicy_ComboBox) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + // Tooltip and Default popup policy + // (Always first try the direction we used on the last frame, if any) + if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + + const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + + // If there not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) + if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) + continue; + if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) + continue; + + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; + + // Clamp top-left corner of popup + pos.x = ImMax(pos.x, r_outer.Min.x); + pos.y = ImMax(pos.y, r_outer.Min.y); + + *last_dir = dir; + return pos; + } + } + + // Fallback when not enough room: + *last_dir = ImGuiDir_None; + + // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + if (policy == ImGuiPopupPositionPolicy_Tooltip) + return ref_pos + ImVec2(2, 2); + + // Otherwise try to keep within display + ImVec2 pos = ref_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; +} + +// Note that this is used for popups, which can overlap the non work-area of individual viewports. +ImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(window); + ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect(); + ImVec2 padding = g.Style.DisplaySafeAreaPadding; + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + return r_screen; +} + +ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + ImRect r_outer = GetPopupAllowedExtentRect(window); + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. + // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. + IM_ASSERT(g.CurrentWindow == window); + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window; + float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). + ImRect r_avoid; + if (parent_window->DC.MenuBarAppending) + r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field + else + r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); + } + if (window->Flags & ImGuiWindowFlags_Popup) + { + ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Position tooltip (always follows mouse) + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); + ImRect r_avoid; + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); + else + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); + } + IM_ASSERT(0); + return window->Pos; +} + +//----------------------------------------------------------------------------- +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +//----------------------------------------------------------------------------- + +// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked. +// In our terminology those should be interchangeable. Those two functions are merely a legacy artifact, so at minimum naming should be clarified. +void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu); + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = focus_scope_id; + g.NavWindow->NavLastIds[nav_layer] = id; + g.NavWindow->NavRectRel[nav_layer] = rect_rel; +} + +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid. + // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text) + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + if (g.NavWindow != window) + g.NavInitRequest = false; + g.NavWindow = window; + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + window->NavLastIds[nav_layer] = id; + if (g.LastItemData.ID == id) + window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); + + if (g.ActiveIdSource == ImGuiInputSource_Nav) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; +} + +ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +{ + if (ImFabs(dx) > ImFabs(dy)) + return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; + return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; +} + +static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) +{ + if (a1 < b0) + return a1 - b0; + if (b1 < a0) + return a0 - b1; + return 0.0f; +} + +static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +{ + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + { + r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); + r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); + } + else // FIXME: PageUp/PageDown are leaving move_dir == None + { + r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); + r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); + } +} + +// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 +static bool ImGui::NavScoreItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + // FIXME: Those are not good variables names + ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle + const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) + g.NavScoringDebugCount++; + + // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring + if (window->ParentWindow == g.NavWindow) + { + IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); + if (!window->ClipRect.Overlaps(cand)) + return false; + cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + } + + // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) + // For example, this ensure that items in one column are not reached when moving vertically from items in another column. + NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + + // Compute distance between boxes + // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. + float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); + float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items + if (dby != 0.0f && dbx != 0.0f) + dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); + float dist_box = ImFabs(dbx) + ImFabs(dby); + + // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) + float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); + float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); + float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) + + // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + // For non-overlapping boxes, use distance between boxes + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + // For overlapping boxes with different centers, use distance between centers + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) + quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + +#if IMGUI_DEBUG_NAV_SCORING + char buf[128]; + if (IsMouseHoveringRect(cand.Min, cand.Max)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); + draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150)); + draw_list->AddText(cand.Max, ~0U, buf); + } + else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. + { + if (quadrant == g.NavMoveDir) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); + draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } +#endif + + // Is it in the quadrant we're interesting in moving to? + bool new_best = false; + const ImGuiDir move_dir = g.NavMoveDir; + if (quadrant == move_dir) + { + // Does it beat the current best candidate? + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + // Try using distance between center points to break ties + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items + // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), + // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. + if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance + new_best = true; + } + } + } + + // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches + // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) + // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. + // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. + // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match + if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + result->Window = window; + result->ID = g.LastItemData.ID; + result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; + result->InFlags = g.LastItemData.InFlags; + result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); +} + +// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) +// This is called after LastItemData is set. +static void ImGui::NavProcessItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = g.LastItemData.ID; + const ImRect nav_bb = g.LastItemData.NavRect; + const ImGuiItemFlags item_flags = g.LastItemData.InFlags; + + // Process Init Request + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) + { + // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback + const bool candidate_for_nav_default_focus = (item_flags & (ImGuiItemFlags_NoNavDefaultFocus | ImGuiItemFlags_Disabled)) == 0; + if (candidate_for_nav_default_focus || g.NavInitResultId == 0) + { + g.NavInitResultId = id; + g.NavInitResultRectRel = WindowRectAbsToRel(window, nav_bb); + } + if (candidate_for_nav_default_focus) + { + g.NavInitRequest = false; // Found a match, clear request + NavUpdateAnyRequestFlag(); + } + } + + // Process Move Request (scoring for navigation) + // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy) + if (g.NavMoveScoringItems) + { + const bool is_tab_stop = (item_flags & ImGuiItemFlags_Inputable) && (item_flags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) != 0; + if (is_tabbing) + { + if (is_tab_stop || (g.NavMoveFlags & ImGuiNavMoveFlags_FocusApi)) + NavProcessItemForTabbingRequest(id); + } + else if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) + { + ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + if (!is_tabbing) + { + if (NavScoreItem(result)) + NavApplyItemToResult(result); + + // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisible)) + NavApplyItemToResult(&g.NavMoveResultLocalVisible); + } + } + } + + // Update window-relative bounding box of navigated item + if (g.NavId == id) + { + g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. + g.NavLayer = window->DC.NavLayerCurrent; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + g.NavIdIsAlive = true; + window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) + } +} + +// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest(). +// Note that SetKeyboardFocusHere() API calls are considered tabbing requests! +// - Case 1: no nav/active id: set result to first eligible item, stop storing. +// - Case 2: tab forward: on ref id set counter, on counter elapse store result +// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request +// - Case 4: tab backward: store all results, on ref id pick prev, stop storing +// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested +void ImGui::NavProcessItemForTabbingRequest(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + + // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows) + ImGuiNavItemData* result = &g.NavMoveResultLocal; + if (g.NavTabbingDir == +1) + { + // Tab Forward or SetKeyboardFocusHere() with >= 0 + if (g.NavTabbingResultFirst.ID == 0) + NavApplyItemToResult(&g.NavTabbingResultFirst); + if (--g.NavTabbingCounter == 0) + NavMoveRequestResolveWithLastItem(result); + else if (g.NavId == id) + g.NavTabbingCounter = 1; + } + else if (g.NavTabbingDir == -1) + { + // Tab Backward + if (g.NavId == id) + { + if (result->ID) + { + g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); + } + } + else + { + NavApplyItemToResult(result); + } + } + else if (g.NavTabbingDir == 0) + { + // Tab Init + if (g.NavTabbingResultFirst.ID == 0) + NavMoveRequestResolveWithLastItem(&g.NavTabbingResultFirst); + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +// FIXME: ScoringRect is not set +void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + + if (move_flags & ImGuiNavMoveFlags_Tabbing) + move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; + + g.NavMoveSubmitted = g.NavMoveScoringItems = true; + g.NavMoveDir = move_dir; + g.NavMoveDirForDebug = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags; + g.NavMoveScrollFlags = scroll_flags; + g.NavMoveForwardToNextFrame = false; + g.NavMoveKeyMods = g.IO.KeyMods; + g.NavTabbingCounter = 0; + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisible.Clear(); + g.NavMoveResultOther.Clear(); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + g.NavMoveScoringItems = false; // Ensure request doesn't need more processing + NavApplyItemToResult(result); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); +} + +// Forward will reuse the move request again on the next frame (generally with modifications done to it) +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveForwardToNextFrame == false); + NavMoveRequestCancel(); + g.NavMoveForwardToNextFrame = true; + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded; + g.NavMoveScrollFlags = scroll_flags; +} + +// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire +// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY + // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it, NavEndFrame() will do the same test + if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) + g.NavMoveFlags |= wrap_flags; +} + +// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). +// This way we could find the last focused window among our children. It would be much less confusing this way? +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent = nav_window; + while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent = parent->ParentWindow; + if (parent && parent != nav_window) + parent->NavLastChildNavWindow = nav_window; +} + +// Restore the last focused child. +// Call when we are expected to land on the Main Layer (0) after FocusWindow() +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + return window; +} + +void ImGui::NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + if (layer == ImGuiNavLayer_Main) + g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); + ImGuiWindow* window = g.NavWindow; + if (window->NavLastIds[layer] != 0) + { + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + } + else + { + g.NavLayer = layer; + NavInitWindow(window, true); + } +} + +void ImGui::NavRestoreHighlightAfterMove() +{ + ImGuiContext& g = *GImGui; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +// This needs to be called before we submit any widget (aka in or before Begin) +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + + if (window->Flags & ImGuiWindowFlags_NoNavInputs) + { + g.NavId = g.NavFocusScopeId = 0; + return; + } + + bool init_for_nav = false; + if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + if (init_for_nav) + { + SetNavID(0, g.NavLayer, 0, ImRect()); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavInitResultRectRel = ImRect(); + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + g.NavFocusScopeId = 0; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window) + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + if (IsMousePosValid(&g.IO.MousePos)) + return g.IO.MousePos; + return g.MouseLastValidPos; + } + else + { + // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item + // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?) + ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]); + if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX)) + { + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + rect_rel.Translate(window->Scroll - next_scroll); + } + ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImGuiViewport* viewport = GetMainViewport(); + return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. + } +} + +float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) +{ + ImGuiContext& g = *GImGui; + if (mode == ImGuiInputReadMode_Down) + return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) + + const float t = g.IO.NavInputsDownDuration[n]; + if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. + return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); + if (t < 0.0f) + return 0.0f; + if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. + return (t == 0.0f) ? 1.0f : 0.0f; + if (mode == ImGuiInputReadMode_Repeat) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f); + if (mode == ImGuiInputReadMode_RepeatSlow) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); + if (mode == ImGuiInputReadMode_RepeatFast) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); + return 0.0f; +} + +ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) +{ + ImVec2 delta(0.0f, 0.0f); + if (dir_sources & ImGuiNavDirSourceFlags_RawKeyboard) + delta += ImVec2((float)IsKeyDown(GetKeyIndex(ImGuiKey_RightArrow)) - (float)IsKeyDown(GetKeyIndex(ImGuiKey_LeftArrow)), (float)IsKeyDown(GetKeyIndex(ImGuiKey_DownArrow)) - (float)IsKeyDown(GetKeyIndex(ImGuiKey_UpArrow))); + if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); + if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta *= slow_factor; + if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= fast_factor; + return delta; +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + io.WantSetMousePos = false; + //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); + + // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) + // (do it before we map Keyboard input!) + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad) + { + if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f + || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f) + g.NavInputSource = ImGuiInputSource_Gamepad; + } + + // Update Keyboard->Nav inputs mapping + if (nav_keyboard_active) + { + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0) + NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); + NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); + NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); + NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); + NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); + NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); + NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); + if (io.KeyCtrl) + io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; + if (io.KeyShift) + io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; + #undef NAV_MAP_KEY + } + memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) + io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f; + + // Process navigation init request (select first/default focus) + if (g.NavInitResultId != 0) + NavInitRequestApplyResult(); + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavJustMovedToId = 0; + + // Process navigation move request + if (g.NavMoveSubmitted) + NavMoveRequestApplyResult(); + g.NavTabbingCounter = 0; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + + // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) + bool set_mouse_pos = false; + if (g.NavMousePosDirty && g.NavIdIsAlive) + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + set_mouse_pos = true; + g.NavMousePosDirty = false; + IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); + + // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow) + NavSaveLastChildNavWindowIntoParent(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) + g.NavWindow->NavLastChildNavWindow = NULL; + + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) + NavUpdateWindowing(); + + // Set output flags for user application + io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); + io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + + // Process NavCancel input (to close a popup, get back to parent, clear focus) + NavUpdateCancelRequest(); + + // Process manual activation request + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavActivateInputId = 0; + g.NavActivateFlags = ImGuiActivateFlags_None; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); + bool input_down = IsNavInputDown(ImGuiNavInput_Input); + bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + bool input_pressed = input_down && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); + if (g.ActiveId == 0 && activate_pressed) + { + g.NavActivateId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferTweak; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed) + { + g.NavActivateInputId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) + g.NavActivatePressedId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + + // Process programmatic activation request + // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others) + if (g.NavNextActivateId != 0) + { + if (g.NavNextActivateFlags & ImGuiActivateFlags_PreferInput) + g.NavActivateInputId = g.NavNextActivateId; + else + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; + g.NavActivateFlags = g.NavNextActivateFlags; + } + g.NavNextActivateId = 0; + + // Process move requests + NavUpdateCreateMoveRequest(); + if (g.NavMoveDir == ImGuiDir_None) + NavUpdateCreateTabbingRequest(); + NavUpdateAnyRequestFlag(); + g.NavIdIsAlive = false; + + // Scrolling + if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + // *Fallback* manual-scroll with Nav directional keys when window has no navigable item + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const ImGuiDir move_dir = g.NavMoveDir; + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None) + { + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) + SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + // *Normal* Manual scroll with NavScrollXXX keys + // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. + ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f); + if (scroll_dir.x != 0.0f && window->ScrollbarX) + SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); + if (scroll_dir.y != 0.0f) + SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); + } + + // Always prioritize mouse highlight if navigation is disabled + if (!nav_keyboard_active && !nav_gamepad_active) + { + g.NavDisableHighlight = true; + g.NavDisableMouseHover = set_mouse_pos = false; + } + + // Update mouse position if requested + // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied) + if (set_mouse_pos && (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); + io.WantSetMousePos = true; + //IMGUI_DEBUG_LOG("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); + } + + // [DEBUG] + g.NavScoringDebugCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); + if (1) { for (int layer = 0; layer < 2; layer++) { ImRect r = WindowRectRelToAbs(g.NavWindow, g.NavWindow->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255,200,0,255)); } } // [DEBUG] + if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + } +#endif +} + +void ImGui::NavInitRequestApplyResult() +{ + // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) + ImGuiContext& g = *GImGui; + if (!g.NavWindow) + return; + + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); + g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result + if (g.NavInitRequestFromMove) + NavRestoreHighlightAfterMove(); +} + +void ImGui::NavUpdateCreateMoveRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiWindow* window = g.NavWindow; + + if (g.NavMoveForwardToNextFrame && window != NULL) + { + // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) + // (preserve most state, which were already set by the NavMoveRequestForward() function) + IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); + IM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); + } + else + { + // Initiate directional inputs request + g.NavMoveDir = ImGuiDir_None; + g.NavMoveFlags = ImGuiNavMoveFlags_None; + g.NavMoveScrollFlags = ImGuiScrollFlags_None; + if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } + } + g.NavMoveClipDir = g.NavMoveDir; + g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + } + + // Update PageUp/PageDown/Home/End scroll + // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + float scoring_rect_offset_y = 0.0f; + if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active) + scoring_rect_offset_y = NavUpdatePageUpPageDown(); + if (scoring_rect_offset_y != 0.0f) + { + g.NavScoringNoClipRect = window->InnerRect; + g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y); + } + + // [DEBUG] Always send a request +#if IMGUI_DEBUG_NAV_SCORING + if (io.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); + if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None) + { + g.NavMoveDir = g.NavMoveDirForDebug; + g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; + } +#endif + + // Submit + g.NavMoveForwardToNextFrame = false; + if (g.NavMoveDir != ImGuiDir_None) + NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); + + // Moving with no reference triggers a init request (will be used as a fallback if the direction fails to find a match) + if (g.NavMoveSubmitted && g.NavId == 0) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); + g.NavInitRequest = g.NavInitRequestFromMove = true; + g.NavInitResultId = 0; + g.NavDisableHighlight = false; + } + + // When using gamepad, we project the reference nav bounding box into window visible area. + // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative + // (can't focus a visible object like we can with the mouse). + if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL) + { + ImRect window_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1))); + if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n"); + float pad = window->CalcFontSize() * 0.5f; + window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item + window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel); + g.NavId = g.NavFocusScopeId = 0; + } + } + + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) + ImRect scoring_rect; + if (window != NULL) + { + ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); + scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); + scoring_rect.TranslateY(scoring_rect_offset_y); + scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.x); + scoring_rect.Max.x = scoring_rect.Min.x; + IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). + //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] + //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] + } + g.NavScoringRect = scoring_rect; + g.NavScoringNoClipRect.Add(scoring_rect); +} + +void ImGui::NavUpdateCreateTabbingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + IM_ASSERT(g.NavMoveDir == ImGuiDir_None); + if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs)) + return; + + const bool tab_pressed = IsKeyPressedMap(ImGuiKey_Tab, true) && !IsActiveIdUsingKey(ImGuiKey_Tab) && !g.IO.KeyCtrl && !g.IO.KeyAlt; + if (!tab_pressed) + return; + + // Initiate tabbing request + // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!) + // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests. + // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. + //// FIXME: We use (g.ActiveId == 0) but (g.NavDisableHighlight == false) might be righter once we can tab through anything + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down; + NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + g.NavTabbingResultFirst.Clear(); + g.NavTabbingCounter = -1; +} + +// Apply result from previous frame navigation directional move request. Always called from NavUpdate() +void ImGui::NavMoveRequestApplyResult() +{ + ImGuiContext& g = *GImGui; +#if IMGUI_DEBUG_NAV_SCORING + if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times + return; +#endif + + // Select which result to use + ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL; + + // Tabbing forward wrap + if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) + if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID) + result = &g.NavTabbingResultFirst; + + // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) + if (result == NULL) + { + if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); + return; + } + + // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. + if (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId) + result = &g.NavMoveResultLocalVisible; + + // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. + if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) + if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) + result = &g.NavMoveResultOther; + IM_ASSERT(g.NavWindow && result->Window); + + // Scroll to keep newly navigated item fully into view. + if (g.NavLayer == ImGuiNavLayer_Main) + { + if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY) + { + // FIXME: Should remove this + float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; + SetScrollY(result->Window, scroll_target); + } + else + { + ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel); + ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags); + } + } + + g.NavWindow = result->Window; + if (g.ActiveId != result->ID) + ClearActiveID(); + if (g.NavId != result->ID) + { + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = g.NavMoveKeyMods; + } + + // Focus + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + + // Tabbing: Activates Inputable or Focus non-Inputable + if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && (result->InFlags & ImGuiItemFlags_Inputable)) + { + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState; + g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; + } + + // Activate + if (g.NavMoveFlags & ImGuiNavMoveFlags_Activate) + { + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_None; + } + + // Enable nav highlight + if ((g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); +} + +// Process NavCancel input (to close a popup, get back to parent, clear focus) +// FIXME: In order to support e.g. Escape to clear a selection we'll need: +// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it. +// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept +static void ImGui::NavUpdateCancelRequest() +{ + ImGuiContext& g = *GImGui; + if (!IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + return; + + IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n"); + if (g.ActiveId != 0) + { + if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) + ClearActiveID(); + } + else if (g.NavLayer != ImGuiNavLayer_Main) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + NavRestoreHighlightAfterMove(); + } + else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + { + // Exit child window + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + ImRect child_rect = child_window->Rect(); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect)); + NavRestoreHighlightAfterMove(); + } + else if (g.OpenPopupStack.Size > 0) + { + // Close open popup/menu + if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else + { + // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = g.NavFocusScopeId = 0; + } +} + +// Handle PageUp/PageDown/Home/End keys +// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request +// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference +// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid? +static float ImGui::NavUpdatePageUpPageDown() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + ImGuiWindow* window = g.NavWindow; + if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL) + return 0.0f; + + const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); + const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); + const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); + const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); + if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out + return 0.0f; + + if (g.NavLayer != ImGuiNavLayer_Main) + NavRestoreLayer(ImGuiNavLayer_Main); + + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) + { + // Fallback manual-scroll when window has no navigable item + if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) + SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); + else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); + else if (home_pressed) + SetScrollY(window, 0.0f); + else if (end_pressed) + SetScrollY(window, window->ScrollMax.y); + } + else + { + ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + float nav_scoring_rect_offset_y = 0.0f; + if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (home_pressed) + { + // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y + // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result. + // Preserve current horizontal position if we have any. + nav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + else if (end_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + return nav_scoring_rect_offset_y; + } + return 0.0f; +} + +static void ImGui::NavEndFrame() +{ + ImGuiContext& g = *GImGui; + + // Show CTRL+TAB list window + if (g.NavWindowingTarget != NULL) + NavUpdateWindowingOverlay(); + + // Perform wrap-around in menus + // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly. + // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame. + const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY; + if (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & wanted_flags) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + NavUpdateCreateWrappingRequest(); +} + +static void ImGui::NavUpdateCreateWrappingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + + bool do_forward = false; + ImRect bb_rel = window->NavRectRel[g.NavLayer]; + ImGuiDir clip_dir = g.NavMoveDir; + const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row + clip_dir = ImGuiDir_Up; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(+bb_rel.GetHeight()); // Next row + clip_dir = ImGuiDir_Down; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column + clip_dir = ImGuiDir_Left; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column + clip_dir = ImGuiDir_Right; + } + do_forward = true; + } + if (!do_forward) + return; + window->NavRectRel[g.NavLayer] = bb_rel; + NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) + if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) + return g.WindowsFocusOrder[i]; + return NULL; +} + +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget); + if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) + return; + + const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); + ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); + if (!window_target) + window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); + if (window_target) // Don't reset windowing target if there's a single window in the list + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingToggleLayer = false; +} + +// Windowing management mode +// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) +// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + bool allow_windowing = (modal_window == NULL); + if (!allow_windowing) + g.NavWindowingTarget = NULL; + + // Fade out + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + // Start CTRL+Tab or Square+L/R window selection + const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && io.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab); + if (start_windowing_with_gamepad || start_windowing_with_keyboard) + if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; + g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; + g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; + } + + // Gamepad update + g.NavWindowingTimer += io.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) + { + // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } + + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) + if (!IsNavInputDown(ImGuiNavInput_Menu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } + + // Keyboard: Focus + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) + { + // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f + if (IsKeyPressedMap(ImGuiKey_Tab, true)) + NavUpdateWindowingHighlightWindow(io.KeyShift ? +1 : -1); + if (!io.KeyCtrl) + apply_focus_window = g.NavWindowingTarget; + } + + // Keyboard: Press and Release ALT to toggle menu layer + // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer. + // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway. + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + if (nav_keyboard_active && io.KeyMods == ImGuiKeyModFlags_Alt && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) == 0) + { + g.NavWindowingToggleLayer = true; + g.NavInputSource = ImGuiInputSource_Keyboard; + } + if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) + { + // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) + // We cancel toggling nav layer when other modifiers are pressed. (See #4439) + if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper) + g.NavWindowingToggleLayer = false; + + // Apply layer toggle on release + // Important: we don't assume that Alt was previously held in order to handle loss of focus when backend calls io.AddFocusEvent(false) + // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss. + if (!(io.KeyMods & ImGuiKeyModFlags_Alt) && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) && g.NavWindowingToggleLayer) + if (g.ActiveId == 0 || g.ActiveIdAllowOverlap) + if (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev)) + apply_toggle_layer = true; + if (!io.KeyAlt) + g.NavWindowingToggleLayer = false; + } + + // Move window + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + { + ImVec2 move_delta; + if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); + if (move_delta.x != 0.0f || move_delta.y != 0.0f) + { + const float NAV_MOVE_SPEED = 800.0f; + const float move_speed = ImFloor(NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well + ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow; + SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always); + MarkIniSettingsDirty(moving_window); + g.NavDisableMouseHover = true; + } + } + + // Apply final focus + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) + { + ClearActiveID(); + NavRestoreHighlightAfterMove(); + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window); + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + // If the window has ONLY a menu layer (no main layer), select it directly + // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, + // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since + // the target window as already been previewed once. + // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, + // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* + // won't be valid. + if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; + + // Apply menu/layer toggle + if (apply_toggle_layer && g.NavWindow) + { + ClearActiveID(); + + // Move to parent menu if necessary + ImGuiWindow* new_nav_window = g.NavWindow; + while (new_nav_window->ParentWindow + && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + new_nav_window = new_nav_window->ParentWindow; + if (new_nav_window != g.NavWindow) + { + ImGuiWindow* old_nav_window = g.NavWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; + } + + // Toggle layer + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + if (new_nav_layer != g.NavLayer) + { + // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?) + if (new_nav_layer == ImGuiNavLayer_Menu) + g.NavWindow->NavLastIds[new_nav_layer] = 0; + NavRestoreLayer(new_nav_layer); + NavRestoreHighlightAfterMove(); + } + } +} + +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return "(Popup)"; + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return "(Main menu bar)"; + return "(Untitled)"; +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingOverlay() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget != NULL); + + if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) + return; + + if (g.NavWindowingListWindow == NULL) + g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) + { + ImGuiWindow* window = g.WindowsFocusOrder[n]; + IM_ASSERT(window != NULL); // Fix static analyzers + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] DRAG AND DROP +//----------------------------------------------------------------------------- + +void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropAcceptFrameCount = -1; + + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); +} + +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +// If the item has an identifier: +// - This assume/require the item to be activated (typically via ButtonBehavior). +// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button. +// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag. +// If the item has no identifier: +// - Currently always assume left mouse button. +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button, + // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic). + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) + { + source_id = g.LastItemData.ID; + if (source_id != 0) + { + // Common path: items with ID + if (g.ActiveId != source_id) + return false; + if (g.ActiveIdMouseButton != -1) + mouse_button = g.ActiveIdMouseButton; + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + g.ActiveIdAllowOverlap = false; + } + else + { + // Uncommon path: items without ID + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + // Rely on keeping other window->LastItemXXX fields intact. + source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + + // Disable navigation and key inputs while dragging + cancel existing request if any + SetActiveIdUsingNavAndKeys(); + } + else + { + window = NULL; + source_id = ImHashStr("#SourceExtern"); + source_drag_active = true; + } + + if (source_drag_active) + { + if (!g.DragDropActive) + { + IM_ASSERT(source_id != 0); + ClearDragDrop(); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + if (payload.SourceId == g.ActiveId) + g.ActiveIdNoClearOnFocusLoss = true; + } + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSource = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + BeginTooltip(); + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + { + ImGuiWindow* tooltip_window = g.CurrentWindow; + tooltip_window->Hidden = tooltip_window->SkipItems = true; + tooltip_window->HiddenFramesCanSkipItems = 1; + } + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; + } + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?"); + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + EndTooltip(); + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSource = false; +} + +// Use 'cond' to choose to submit payload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); + } + else if (data_size > 0) + { + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy(payload.Data, data, data_size); + } + else + { + payload.Data = NULL; + } + payload.DataSize = (int)data_size; + } + payload.DataFrameCount = g.FrameCount; + + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); +} + +bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) + return false; + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) + return false; + if (window->SkipItems) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = bb; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +// We don't use BeginDragDropTargetCustom() and duplicate its code because: +// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. +// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. +// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow || window->SkipItems) + return false; + + const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect; + ImGuiID id = g.LastItemData.ID; + if (id == 0) + id = window->GetIDFromRectangle(display_rect); + if (g.DragDropPayload.SourceId == id) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = display_rect; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +bool ImGui::IsDragDropPayloadBeingAccepted() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive && g.DragDropAcceptIdPrev != 0; +} + +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. + // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); + ImRect r = g.DragDropTargetRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface <= g.DragDropAcceptIdCurrRectSurface) + { + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } + + // Render default drop visuals + // FIXME-DRAGDROP: Settle on a proper default visuals for drop target. + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + return &payload; +} + +const ImGuiPayload* ImGui::GetDragDropPayload() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive ? &g.DragDropPayload : NULL; +} + +// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinTarget); + g.DragDropWithinTarget = false; +} + +//----------------------------------------------------------------------------- +// [SECTION] LOGGING/CAPTURING +//----------------------------------------------------------------------------- +// All text output from the interface can be captured into tty/file/clipboard. +// By default, tree nodes are automatically opened during logging. +//----------------------------------------------------------------------------- + +// Pass text data straight to log (without being displayed) +static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args) +{ + if (g.LogFile) + { + g.LogBuffer.Buf.resize(0); + g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); + } + else + { + g.LogBuffer.appendfv(fmt, args); + } +} + +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + LogTextV(g, fmt, args); + va_end(args); +} + +void ImGui::LogTextV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogTextV(g, fmt, args); +} + +// Internal version that takes a position to decide on newline placement and pad items according to their depth. +// We split text into individual lines to add current tree level padding +// FIXME: This code is a little complicated perhaps, considering simplifying the whole system. +void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const char* prefix = g.LogNextPrefix; + const char* suffix = g.LogNextSuffix; + g.LogNextPrefix = g.LogNextSuffix = NULL; + + if (!text_end) + text_end = FindRenderedTextEnd(text, text_end); + + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); + if (ref_pos) + g.LogLinePosY = ref_pos->y; + if (log_new_line) + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } + + if (prefix) + LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. + + // Re-adjust padding if we have popped out of our starting depth + if (g.LogDepthRef > window->DC.TreeDepth) + g.LogDepthRef = window->DC.TreeDepth; + const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + + const char* text_remaining = text; + for (;;) + { + // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry. + // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured. + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_last_line = (line_end == text_end); + if (line_start != line_end || !is_last_line) + { + const int line_length = (int)(line_end - line_start); + const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1; + LogText("%*s%.*s", indentation, "", line_length, line_start); + g.LogLineFirstItem = false; + if (*line_end == '\n') + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } + } + if (is_last_line) + break; + text_remaining = line_end + 1; + } + + if (suffix) + LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); +} + +// Start logging/capturing text output +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.LogEnabled == false); + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); + g.LogEnabled = true; + g.LogType = type; + g.LogNextPrefix = g.LogNextSuffix = NULL; + g.LogDepthRef = window->DC.TreeDepth; + g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); + g.LogLinePosY = FLT_MAX; + g.LogLineFirstItem = true; +} + +// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText) +void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix) +{ + ImGuiContext& g = *GImGui; + g.LogNextPrefix = prefix; + g.LogNextSuffix = suffix; +} + +void ImGui::LogToTTY(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + LogBegin(ImGuiLogType_TTY, auto_open_depth); + g.LogFile = stdout; +#endif +} + +// Start logging/capturing text output to given file +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still + // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. + // By opening the file in binary mode "ab" we have consistent output everywhere. + if (!filename) + filename = g.IO.LogFilename; + if (!filename || !filename[0]) + return; + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) + { + IM_ASSERT(0); + return; + } + + LogBegin(ImGuiLogType_File, auto_open_depth); + g.LogFile = f; +} + +// Start logging/capturing text output to clipboard +void ImGui::LogToClipboard(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); +} + +void ImGui::LogToBuffer(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Buffer, auto_open_depth); +} + +void ImGui::LogFinish() +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogText(IM_NEWLINE); + switch (g.LogType) + { + case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + fflush(g.LogFile); +#endif + break; + case ImGuiLogType_File: + ImFileClose(g.LogFile); + break; + case ImGuiLogType_Buffer: + break; + case ImGuiLogType_Clipboard: + if (!g.LogBuffer.empty()) + SetClipboardText(g.LogBuffer.begin()); + break; + case ImGuiLogType_None: + IM_ASSERT(0); + break; + } + + g.LogEnabled = false; + g.LogType = ImGuiLogType_None; + g.LogFile = NULL; + g.LogBuffer.clear(); +} + +// Helper to display logging buttons +// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) +void ImGui::LogButtons() +{ + ImGuiContext& g = *GImGui; + + PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushAllowKeyboardFocus(false); + SetNextItemWidth(80.0f); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopAllowKeyboardFocus(); + PopID(); + + // Start logging at the end of the function so that the buttons don't appear in the log + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] SETTINGS +//----------------------------------------------------------------------------- +// - UpdateSettings() [Internal] +// - MarkIniSettingsDirty() [Internal] +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettings() [Internal] +// - FindOrCreateWindowSettings() [Internal] +// - FindSettingsHandler() [Internal] +// - ClearIniSettings() [Internal] +// - LoadIniSettingsFromDisk() +// - LoadIniSettingsFromMemory() +// - SaveIniSettingsToDisk() +// - SaveIniSettingsToMemory() +// - WindowSettingsHandler_***() [Internal] +//----------------------------------------------------------------------------- + +// Called by NewFrame() +void ImGui::UpdateSettings() +{ + // Load settings on first frame (if not explicitly loaded manually before) + ImGuiContext& g = *GImGui; + if (!g.SettingsLoaded) + { + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; + } + + // Save settings (with a delay after the last modification, so we don't spam disk too much) + if (g.SettingsDirtyTimer > 0.0f) + { + g.SettingsDirtyTimer -= g.IO.DeltaTime; + if (g.SettingsDirtyTimer <= 0.0f) + { + if (g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + else + g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. + g.SettingsDirtyTimer = 0.0f; + } + } +} + +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + +#if !IMGUI_DEBUG_INI_SETTINGS + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + + return settings; +} + +ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +{ + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) + return settings; + return CreateNewWindowSettings(name); +} + +ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + const ImGuiID type_hash = ImHashStr(type_name); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + return &g.SettingsHandlers[handler_n]; + return NULL; +} + +void ImGui::ClearIniSettings() +{ + ImGuiContext& g = *GImGui; + g.SettingsIniData.clear(); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ClearAllFn) + g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +{ + size_t file_data_size = 0; + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); + if (!file_data) + return; + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + IM_FREE(file_data); +} + +// Zero-tolerance, no error reporting, cheap .ini parsing +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()"); + //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); + + // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). + // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. + if (ini_size == 0) + ini_size = strlen(ini_data); + g.SettingsIniData.Buf.resize((int)ini_size + 1); + char* const buf = g.SettingsIniData.Buf.Data; + char* const buf_end = buf + ini_size; + memcpy(buf, ini_data, ini_size); + buf_end[0] = 0; + + // Call pre-read handlers + // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ReadInitFn) + g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); + + void* entry_data = NULL; + ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) + { + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; + while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') + line_end++; + line_end[0] = 0; + if (line[0] == ';') + continue; + if (line[0] == '[' && line_end > line && line_end[-1] == ']') + { + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; + char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (!type_end || !name_start) + continue; + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + entry_handler = FindSettingsHandler(type_start); + entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; + } + else if (entry_handler != NULL && entry_data != NULL) + { + // Let type handler parse the line + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + } + } + g.SettingsLoaded = true; + + // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary) + memcpy(buf, ini_data, ini_size); + + // Call post-read handlers + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ApplyAllFn) + g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::SaveIniSettingsToDisk(const char* ini_filename) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) + return; + + size_t ini_data_size = 0; + const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); +} + +// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer +const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + g.SettingsIniData.Buf.resize(0); + g.SettingsIniData.Buf.push_back(0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + { + ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; + handler->WriteAllFn(&g, handler, &g.SettingsIniData); + } + if (out_size) + *out_size = (size_t)g.SettingsIniData.size(); + return g.SettingsIniData.c_str(); +} + +static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + g.Windows[i]->SettingsOffset = -1; + g.SettingsWindows.clear(); +} + +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); + ImGuiID id = settings->ID; + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + settings->ID = id; + settings->WantApply = true; + return (void*)settings; +} + +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; + int x, y; + int i; + if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } +} + +// Apply to existing windows (if any) +static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->WantApply) + { + if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID)) + ApplyWindowSettings(window, settings); + settings->WantApply = false; + } +} + +static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + // Gather data from windows that were active during this session + // (if a window wasn't opened in this session we preserve its settings) + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + + ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = ImVec2ih(window->Pos); + settings->Size = ImVec2ih(window->SizeFull); + + settings->Collapsed = window->Collapsed; + } + + // Write to text buffer + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + { + const char* settings_name = settings->GetName(); + buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); + buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + buf->append("\n"); + } +} + + +//----------------------------------------------------------------------------- +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +//----------------------------------------------------------------------------- +// - GetMainViewport() +// - UpdateViewportsNewFrame() [Internal] +// (this section is more complete in the 'docking' branch) +//----------------------------------------------------------------------------- + +ImGuiViewport* ImGui::GetMainViewport() +{ + ImGuiContext& g = *GImGui; + return g.Viewports[0]; +} + +// Update viewports and monitor infos +static void ImGui::UpdateViewportsNewFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Viewports.Size == 1); + + // Update main viewport with current platform position. + // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent. + ImGuiViewportP* main_viewport = g.Viewports[0]; + main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp; + main_viewport->Pos = ImVec2(0.0f, 0.0f); + main_viewport->Size = g.IO.DisplaySize; + + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + + // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; + viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; + viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); + viewport->UpdateWorkRect(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- + +// (this section is filled in the 'docking' branch) + + +//----------------------------------------------------------------------------- +// [SECTION] PLATFORM DEPENDENT HELPERS +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) + +#ifdef _MSC_VER +#pragma comment(lib, "user32") +#pragma comment(lib, "kernel32") +#endif + +// Win32 clipboard implementation +// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + if (!::OpenClipboard(NULL)) + return NULL; + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return NULL; + } + if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) + { + int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); + g.ClipboardHandlerData.resize(buf_len); + ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); + } + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); + return g.ClipboardHandlerData.Data; +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!::OpenClipboard(NULL)) + return; + const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return; + } + WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); + ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); +} + +#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) + +#include // Use old API to avoid need for separate .mm file +static PasteboardRef main_clipboard = 0; + +// OSX clipboard implementation +// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardClear(main_clipboard); + CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); + if (cf_data) + { + PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); + CFRelease(cf_data); + } +} + +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardSynchronize(main_clipboard); + + ItemCount item_count = 0; + PasteboardGetItemCount(main_clipboard, &item_count); + for (ItemCount i = 0; i < item_count; i++) + { + PasteboardItemID item_id = 0; + PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); + CFArrayRef flavor_type_array = 0; + PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); + for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) + { + CFDataRef cf_data; + if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) + { + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + int length = (int)CFDataGetLength(cf_data); + g.ClipboardHandlerData.resize(length + 1); + CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data); + g.ClipboardHandlerData[length] = 0; + CFRelease(cf_data); + return g.ClipboardHandlerData.Data; + } + } + } + return NULL; +} + +#else + +// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + const char* text_end = text + strlen(text); + g.ClipboardHandlerData.resize((int)(text_end - text) + 1); + memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); + g.ClipboardHandlerData[(int)(text_end - text)] = 0; +} + +#endif + +// Win32 API IME support (for Asian languages, etc.) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif + +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +{ + // Notify OS Input Method Editor of text input position + ImGuiIO& io = ImGui::GetIO(); + if (HWND hwnd = (HWND)io.ImeWindowHandle) + if (HIMC himc = ::ImmGetContext(hwnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &cf); + ::ImmReleaseContext(hwnd, himc); + } +} + +#else + +static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} + +#endif + +//----------------------------------------------------------------------------- +// [SECTION] METRICS/DEBUGGER WINDOW +//----------------------------------------------------------------------------- +// - RenderViewportThumbnail() [Internal] +// - RenderViewportsThumbnails() [Internal] +// - MetricsHelpMarker() [Internal] +// - ShowMetricsWindow() +// - DebugNodeColumns() [Internal] +// - DebugNodeDrawList() [Internal] +// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal] +// - DebugNodeStorage() [Internal] +// - DebugNodeTabBar() [Internal] +// - DebugNodeViewport() [Internal] +// - DebugNodeWindow() [Internal] +// - DebugNodeWindowSettings() [Internal] +// - DebugNodeWindowsList() [Internal] +// - DebugNodeWindowsListByBeginStackParent() [Internal] +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_METRICS_WINDOW + +void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 scale = bb.GetSize() / viewport->Size; + ImVec2 off = bb.Min - viewport->Pos * scale; + float alpha_mul = 1.0f; + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* thumb_window = g.Windows[i]; + if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) + continue; + + ImRect thumb_r = thumb_window->Rect(); + ImRect title_r = thumb_window->TitleBarRect(); + thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale)); + title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height + thumb_r.ClipWithFull(bb); + title_r.ClipWithFull(bb); + const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul)); + window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul)); + window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); + window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name)); + } + draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); +} + +static void RenderViewportsThumbnails() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. + float SCALE = 1.0f / 8.0f; + ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + bb_full.Add(g.Viewports[n]->GetMainRect()); + ImVec2 p = window->DC.CursorPos; + ImVec2 off = p - bb_full.Min * SCALE; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); + ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); + } + ImGui::Dummy(bb_full.GetSize() * SCALE); +} + +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +#ifndef IMGUI_DISABLE_DEMO_WINDOWS +namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); } +#endif + +void ImGui::ShowMetricsWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + if (cfg->ShowStackTool) + ShowStackToolWindow(&cfg->ShowStackTool); + + if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); + return; + } + + // Basic info + Text("Dear ImGui %s", GetVersion()); + Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations); + //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } + + Separator(); + + // Debugging enums + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" }; + enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type + const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" }; + if (cfg->ShowWindowsRectsType < 0) + cfg->ShowWindowsRectsType = WRT_WorkRect; + if (cfg->ShowTablesRectsType < 0) + cfg->ShowTablesRectsType = TRT_WorkRect; + + struct Funcs + { + static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n) + { + if (rect_type == TRT_OuterRect) { return table->OuterRect; } + else if (rect_type == TRT_InnerRect) { return table->InnerRect; } + else if (rect_type == TRT_WorkRect) { return table->WorkRect; } + else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; } + else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; } + else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; } + else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table->LastOuterHeight); } + else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); } + else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; } + else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } // Note: y1/y2 not always accurate + else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); } + IM_ASSERT(0); + return ImRect(); + } + + static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) + { + if (rect_type == WRT_OuterRect) { return window->Rect(); } + else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } + else if (rect_type == WRT_InnerRect) { return window->InnerRect; } + else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == WRT_WorkRect) { return window->WorkRect; } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); } + else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } + IM_ASSERT(0); + return ImRect(); + } + }; + + // Tools + if (TreeNode("Tools")) + { + // Stack Tool is your best friend! + Checkbox("Show stack tool", &cfg->ShowStackTool); + SameLine(); + MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code."); + + Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); + Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count); + if (cfg->ShowWindowsRects && g.NavWindow != NULL) + { + BulletText("'%s':", g.NavWindow->Name); + Indent(); + for (int rect_n = 0; rect_n < WRT_Count; rect_n++) + { + ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); + Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); + } + Unindent(); + } + + Checkbox("Show tables rectangles", &cfg->ShowTablesRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count); + if (cfg->ShowTablesRects && g.NavWindow != NULL) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) + { + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow)) + continue; + + BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + Indent(); + char buf[128]; + for (int rect_n = 0; rect_n < TRT_Count; rect_n++) + { + if (rect_n >= TRT_ColumnsRect) + { + if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect) + continue; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, rect_n, column_n); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, rect_n, -1); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + Unindent(); + } + } + + // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. + if (Button("Item Picker..")) + DebugStartItemPicker(); + SameLine(); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); + + TreePop(); + } + + // Windows + if (TreeNode("Windows", "Windows (%d)", g.Windows.Size)) + { + //SetNextItemOpen(true, ImGuiCond_Once); + DebugNodeWindowsList(&g.Windows, "By display order"); + DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)"); + if (TreeNode("By submission order (begin stack)")) + { + // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship! + ImVector& temp_buffer = g.WindowsTempSortBuffer; + temp_buffer.resize(0); + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount) + temp_buffer.push_back(g.Windows[i]); + struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } }; + ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder); + DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL); + TreePop(); + } + + TreePop(); + } + + // DrawLists + int drawlist_count = 0; + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount(); + if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) + { + Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); + Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes); + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + { + ImGuiViewportP* viewport = g.Viewports[viewport_i]; + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + } + TreePop(); + } + + // Viewports + if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size)) + { + Indent(GetTreeNodeToLabelSpacing()); + RenderViewportsThumbnails(); + Unindent(GetTreeNodeToLabelSpacing()); + for (int i = 0; i < g.Viewports.Size; i++) + DebugNodeViewport(g.Viewports[i]); + TreePop(); + } + + // Details for Popups + if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + ImGuiWindow* window = g.OpenPopupStack[i].Window; + BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + } + TreePop(); + } + + // Details for TabBars + if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount())) + { + for (int n = 0; n < g.TabBars.GetMapSize(); n++) + if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n)) + { + PushID(tab_bar); + DebugNodeTabBar(tab_bar, "TabBar"); + PopID(); + } + TreePop(); + } + + // Details for Tables + if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount())) + { + for (int n = 0; n < g.Tables.GetMapSize(); n++) + if (ImGuiTable* table = g.Tables.TryGetMapData(n)) + DebugNodeTable(table); + TreePop(); + } + + // Details for Fonts +#ifndef IMGUI_DISABLE_DEMO_WINDOWS + ImFontAtlas* atlas = g.IO.Fonts; + if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } +#endif + + // Details for Docking +#ifdef IMGUI_HAS_DOCK + if (TreeNode("Docking")) + { + TreePop(); + } +#endif // #ifdef IMGUI_HAS_DOCK + + // Settings + if (TreeNode("Settings")) + { + if (SmallButton("Clear")) + ClearIniSettings(); + SameLine(); + if (SmallButton("Save to memory")) + SaveIniSettingsToMemory(); + SameLine(); + if (SmallButton("Save to disk")) + SaveIniSettingsToDisk(g.IO.IniFilename); + SameLine(); + if (g.IO.IniFilename) + Text("\"%s\"", g.IO.IniFilename); + else + TextUnformatted(""); + Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); + if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) + { + for (int n = 0; n < g.SettingsHandlers.Size; n++) + BulletText("%s", g.SettingsHandlers[n].TypeName); + TreePop(); + } + if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) + { + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + DebugNodeWindowSettings(settings); + TreePop(); + } + + if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) + { + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + DebugNodeTableSettings(settings); + TreePop(); + } + +#ifdef IMGUI_HAS_DOCK +#endif // #ifdef IMGUI_HAS_DOCK + + if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size())) + { + InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly); + TreePop(); + } + TreePop(); + } + + // Misc Details + if (TreeNode("Internal state")) + { + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); + + Text("WINDOWING"); + Indent(); + Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL"); + Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); + Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); + Unindent(); + + Text("ITEMS"); + Indent(); + Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); + Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInputMask: %llX", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdUsingNavInputMask, g.ActiveIdUsingKeyInputMask); + Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame + Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + Unindent(); + + Text("NAV,FOCUS"); + Indent(); + Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); + Text("NavActivateFlags: %04X", g.NavActivateFlags); + Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); + Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); + Unindent(); + + TreePop(); + } + + // Overlay: Display windows Rectangles and Begin Order + if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder) + { + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (!window->WasActive) + continue; + ImDrawList* draw_list = GetForegroundDrawList(window); + if (cfg->ShowWindowsRects) + { + ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + if (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + { + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = GetFontSize(); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); + } + } + } + + // Overlay: Display Tables Rectangles + if (cfg->ShowTablesRects) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) + { + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1) + continue; + ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow); + if (cfg->ShowTablesRectsType >= TRT_ColumnsRect) + { + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n); + ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255); + float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f; + draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + } + } + +#ifdef IMGUI_HAS_DOCK + // Overlay: Display Docking info + if (show_docking_nodes && g.IO.KeyCtrl) + { + } +#endif // #ifdef IMGUI_HAS_DOCK + + End(); +} + +// [DEBUG] List fonts in a font atlas and display its texture +void ImGui::ShowFontAtlas(ImFontAtlas* atlas) +{ + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + PushID(font); + DebugNodeFont(font); + PopID(); + } + if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); + Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); + TreePop(); + } +} + +// [DEBUG] Display contents of Columns +void ImGui::DebugNodeColumns(ImGuiOldColumns* columns) +{ + if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) + return; + BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); + TreePop(); +} + +// [DEBUG] Display contents of ImDrawList +void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label) +{ + ImGuiContext& g = *GImGui; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + int cmd_count = draw_list->CmdBuffer.Size; + if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL) + cmd_count--; + bool node_open = TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count); + if (draw_list == GetWindowDrawList()) + { + SameLine(); + TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_open) + TreePop(); + return; + } + + ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list + if (window && IsItemHovered() && fg_draw_list) + fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!node_open) + return; + + if (window && !window->WasActive) + TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); + + for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++) + { + if (pcmd->UserCallback) + { + BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + continue; + } + + char buf[300]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); + if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); + if (!pcmd_node_open) + continue; + + // Calculate approximate coverage area (touched pixel count) + // This will be in pixels squared as long there's no post-scaling happening to the renderer output. + const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset; + float total_area = 0.0f; + for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; ) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos; + total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); + } + + // Display vertex information summary. Hover to get all triangles drawn in wire-frame + ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); + Selectable(buf); + if (IsItemHovered() && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false); + + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. + ImGuiListClipper clipper; + clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++) + { + char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf); + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_i++) + { + const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; + triangle[n] = v.pos; + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + + Selectable(buf, false); + if (fg_draw_list && IsItemHovered()) + { + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + TreePop(); + } + TreePop(); +} + +// [DEBUG] Display mesh/aabb of a ImDrawCmd +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) +{ + IM_ASSERT(show_mesh || show_aabb); + + // Draw wire-frame version of all triangles + ImRect clip_rect = draw_cmd->ClipRect; + ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + ImDrawListFlags backup_flags = out_draw_list->Flags; + out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; ) + { + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list + ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset; + + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos)); + if (show_mesh) + out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles + } + // Draw bounding boxes + if (show_aabb) + { + out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU + out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles + } + out_draw_list->Flags = backup_flags; +} + +// [DEBUG] Display details for a single font, called by ShowStyleEditor(). +void ImGui::DebugNodeFont(ImFont* font) +{ + bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", + font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + SameLine(); + if (SmallButton("Set as default")) + GetIO().FontDefault = font; + if (!opened) + return; + + // Display preview text + PushFont(font); + Text("The quick brown fox jumps over the lazy dog"); + PopFont(); + + // Display details + SetNextItemWidth(GetFontSize() * 8); + DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); + SameLine(); MetricsHelpMarker( + "Note than the default embedded font is NOT meant to be scaled.\n\n" + "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " + "You may oversample them to get some flexibility with scaling. " + "You can also render at multiple sizes and select which one to use at runtime.\n\n" + "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); + Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + char c_str[5]; + Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); + Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); + const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface); + Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (font->ConfigData) + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + + // Display all glyphs of the fonts in separate pages of 256 characters + if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = font->FontSize * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + { + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) + { + base += 4096 - 256; + continue; + } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (glyph) + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (glyph && IsMouseHoveringRect(cell_p1, cell_p2)) + { + BeginTooltip(); + Text("Codepoint: U+%04X", base + n); + Separator(); + Text("Visible: %d", glyph->Visible); + Text("AdvanceX: %.1f", glyph->AdvanceX); + Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + EndTooltip(); + } + } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + TreePop(); + } + TreePop(); + } + TreePop(); +} + +// [DEBUG] Display contents of ImGuiStorage +void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label) +{ + if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) + return; + for (int n = 0; n < storage->Data.Size; n++) + { + const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; + BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. + } + TreePop(); +} + +// [DEBUG] Display contents of ImGuiTabBar +void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) +{ + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2); + p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); + p += ImFormatString(p, buf_end - p, " { "); + for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + p += ImFormatString(p, buf_end - p, "%s'%s'", + tab_n > 0 ? ", " : "", (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???"); + } + p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(label, "%s", buf); + if (!is_active) { PopStyleColor(); } + if (is_active && IsItemHovered()) + { + ImDrawList* draw_list = GetForegroundDrawList(); + draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + } + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + PushID(tab); + if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2); + if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine(); + Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", + tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???", tab->Offset, tab->Width, tab->ContentWidth); + PopID(); + } + TreePop(); + } +} + +void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) +{ + SetNextItemOpen(true, ImGuiCond_Once); + if (TreeNode("viewport0", "Viewport #%d", 0)) + { + ImGuiWindowFlags flags = viewport->Flags; + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", + viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); + BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, + (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", + (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", + (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + TreePop(); + } +} + +void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) +{ + if (window == NULL) + { + BulletText("%s: NULL", label); + return; + } + + ImGuiContext& g = *GImGui; + const bool is_active = window->WasActive; + ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None; + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered() && is_active) + GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) + return; + + if (window->MemoryCompacted) + TextDisabled("Note: some memory buffers have been compacted/freed."); + + ImGuiWindowFlags flags = window->Flags; + DebugNodeDrawList(window, window->DrawList, "DrawList"); + BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y); + BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, + (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", + (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", + (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); + BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); + BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + { + ImRect r = window->NavRectRel[layer]; + if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y) + { + BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]); + continue; + } + BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); + if (IsItemHovered()) + GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255)); + } + BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } + if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } + if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); } + if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) + { + for (int n = 0; n < window->ColumnsStorage.Size; n++) + DebugNodeColumns(&window->ColumnsStorage[n]); + TreePop(); + } + DebugNodeStorage(&window->StateStorage, "Storage"); + TreePop(); +} + +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) +{ + Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", + settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); +} + +void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) +{ + if (!TreeNode(label, "%s (%d)", label, windows->Size)) + return; + for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back + { + PushID((*windows)[i]); + DebugNodeWindow((*windows)[i], "Window"); + PopID(); + } + TreePop(); +} + +// FIXME-OPT: This is technically suboptimal, but it is simpler this way. +void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack) +{ + for (int i = 0; i < windows_size; i++) + { + ImGuiWindow* window = windows[i]; + if (window->ParentWindowInBeginStack != parent_in_begin_stack) + continue; + char buf[20]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); + //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); + DebugNodeWindow(window, buf); + Indent(); + DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); + Unindent(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) +//----------------------------------------------------------------------------- + +// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. +void ImGui::UpdateDebugToolItemPicker() +{ + ImGuiContext& g = *GImGui; + g.DebugItemPickerBreakId = 0; + if (!g.DebugItemPickerActive) + return; + + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + SetMouseCursor(ImGuiMouseCursor_Hand); + if (IsKeyPressedMap(ImGuiKey_Escape)) + g.DebugItemPickerActive = false; + if (IsMouseClicked(0) && hovered_id) + { + g.DebugItemPickerBreakId = hovered_id; + g.DebugItemPickerActive = false; + } + SetNextWindowBgAlpha(0.60f); + BeginTooltip(); + Text("HoveredId: 0x%08X", hovered_id); + Text("Press ESC to abort picking."); + TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); + EndTooltip(); +} + +// [DEBUG] Stack Tool: update queries. Called by NewFrame() +void ImGui::UpdateDebugToolStackQueries() +{ + ImGuiContext& g = *GImGui; + ImGuiStackTool* tool = &g.DebugStackTool; + + // Clear hook when stack tool is not visible + g.DebugHookIdInfo = 0; + if (g.FrameCount != tool->LastActiveFrame + 1) + return; + + // Update queries. The steps are: -1: query Stack, >= 0: query each stack item + // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time + const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId; + if (tool->QueryId != query_id) + { + tool->QueryId = query_id; + tool->StackLevel = -1; + tool->Results.resize(0); + } + if (query_id == 0) + return; + + // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result) + int stack_level = tool->StackLevel; + if (stack_level >= 0 && stack_level < tool->Results.Size) + if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2) + tool->StackLevel++; + + // Update hook + stack_level = tool->StackLevel; + if (stack_level == -1) + g.DebugHookIdInfo = query_id; + if (stack_level >= 0 && stack_level < tool->Results.Size) + { + g.DebugHookIdInfo = tool->Results[stack_level].ID; + tool->Results[stack_level].QueryFrameCount++; + } +} + +// [DEBUG] Stack tool: hooks called by GetID() family functions +void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackTool* tool = &g.DebugStackTool; + + // Step 0: stack query + // This assume that the ID was computed with the current ID stack, which tends to be the case for our widget. + if (tool->StackLevel == -1) + { + tool->StackLevel++; + tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo()); + for (int n = 0; n < window->IDStack.Size + 1; n++) + tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id; + return; + } + + // Step 1+: query for individual level + IM_ASSERT(tool->StackLevel >= 0); + if (tool->StackLevel != window->IDStack.Size) + return; + ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel]; + IM_ASSERT(info->ID == id && info->QueryFrameCount > 0); + + int data_len; + switch (data_type) + { + case ImGuiDataType_S32: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id); + break; + case ImGuiDataType_String: + data_len = data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id); + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "\"%.*s\"", data_len, (const char*)data_id); + break; + case ImGuiDataType_Pointer: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id); + break; + case ImGuiDataType_ID: + if (info->Desc[0] == 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one. + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id); + break; + default: + IM_ASSERT(0); + } + info->QuerySuccess = true; +} + +// Stack Tool: Display UI +void ImGui::ShowStackToolWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); + if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); + return; + } + + // Display hovered/active status + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + const ImGuiID active_id = g.ActiveId; +#ifdef IMGUI_ENABLE_TEST_ENGINE + Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : ""); +#else + Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id); +#endif + SameLine(); + MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details."); + + // Display decorated stack + ImGuiStackTool* tool = &g.DebugStackTool; + tool->LastActiveFrame = g.FrameCount; + if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders)) + { + const float id_width = CalcTextSize("0xDDDDDDDD").x; + TableSetupColumn("Seed", ImGuiTableColumnFlags_WidthFixed, id_width); + TableSetupColumn("PushID", ImGuiTableColumnFlags_WidthStretch); + TableSetupColumn("Result", ImGuiTableColumnFlags_WidthFixed, id_width); + TableHeadersRow(); + for (int n = 0; n < tool->Results.Size; n++) + { + ImGuiStackLevelInfo* info = &tool->Results[n]; + TableNextColumn(); + Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0); + + TableNextColumn(); + ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? FindWindowByID(info->ID) : NULL; + if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked) + Text("\"%s\" [window]", window->Name); + else if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id) + TextUnformatted(info->Desc); + else if (tool->StackLevel >= tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers. + { +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (const char* label = ImGuiTestEngine_FindItemDebugLabel(&g, info->ID)) // Source: ImGuiTestEngine's ItemInfo() + Text("??? \"%s\"", label); + else +#endif + TextUnformatted("???"); + } + + TableNextColumn(); + Text("0x%08X", info->ID); + if (n == tool->Results.Size - 1) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header)); + } + EndTable(); + } + End(); +} + +#else + +void ImGui::ShowMetricsWindow(bool*) {} +void ImGui::ShowFontAtlas(ImFontAtlas*) {} +void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} +void ImGui::DebugNodeFont(ImFont*) {} +void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} +void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} +void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {} +void ImGui::DebugNodeWindowsList(ImVector*, const char*) {} +void ImGui::DebugNodeViewport(ImGuiViewportP*) {} + +void ImGui::ShowStackToolWindow(bool*) {} +void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {} +void ImGui::UpdateDebugToolItemPicker() {} +void ImGui::UpdateDebugToolStackQueries() {} + +#endif // #ifndef IMGUI_DISABLE_METRICS_WINDOW + +//----------------------------------------------------------------------------- + +// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. +// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github. +#ifdef IMGUI_INCLUDE_IMGUI_USER_INL +#include "imgui_user.inl" +#endif + +//----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui.h b/thirdparty/imgui/imgui.h new file mode 100644 index 0000000..e986e6c --- /dev/null +++ b/thirdparty/imgui/imgui.h @@ -0,0 +1,2916 @@ +// dear imgui, v1.86 +// (headers) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/4451 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues + +// Getting Started? +// - For first-time users having issues compiling/linking/running or issues loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. + +/* + +Index of this file: +// [SECTION] Header mess +// [SECTION] Forward declarations and basic types +// [SECTION] Dear ImGui end-user API functions +// [SECTION] Flags & Enumerations +// [SECTION] Helpers: Memory allocations macros, ImVector<> +// [SECTION] ImGuiStyle +// [SECTION] ImGuiIO +// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) +// [SECTION] Obsolete functions and types + +*/ + +#pragma once + +// Configuration file with compile-time options (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system') +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#if !defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H) +#include "imconfig.h" +#endif + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +// Includes +#include // FLT_MIN, FLT_MAX +#include // va_list, va_start, va_end +#include // ptrdiff_t, NULL +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp + +// Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) +#define IMGUI_VERSION "1.86" +#define IMGUI_VERSION_NUM 18600 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) +#define IMGUI_HAS_TABLE + +// Define attributes of all API symbols declarations (e.g. for DLL under Windows) +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) +// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +// Helper Macros +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#endif +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) +#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 +#else +#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. +#endif + +// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif + +// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(IMGUI_DEBUG_PARANOID) +#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) +#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) +#else +#define IM_MSVC_RUNTIME_CHECKS_OFF +#define IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + +// Warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#endif +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward declarations and basic types +//----------------------------------------------------------------------------- + +// Forward declarations +struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. +struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) +struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back. +struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +struct ImFont; // Runtime data for a single font within a parent ImFontAtlas +struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontBuilderIO; // Opaque interface to a font builder (stb_truetype or FreeType). +struct ImFontConfig; // Configuration data when adding a font or merging fonts +struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) +struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui +struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame +struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) +struct ImGuiStorage; // Helper for key->value storage +struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table +struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor + +// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling +typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions +typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type +typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction +typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) +typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation +typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier +typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending) +typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling +typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() +typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build +typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. +typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags +typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() +typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() +typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() +typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. +typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() +typedef int ImGuiKeyModFlags; // -> enum ImGuiKeyModFlags_ // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super) +typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() +typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: For BeginTable() +typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() +typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() +typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport +typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() + +// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] +// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. +#ifndef ImTextureID +typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +#endif + +// ImDrawIdx: vertex index. [Compile-time configurable type] +// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). +// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) +#endif + +// Scalar data types +typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) +typedef signed char ImS8; // 8-bit signed integer +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +#if defined(_MSC_VER) && !defined(__clang__) +typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) +typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) +#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) +#include +typedef int64_t ImS64; // 64-bit signed integer (pre C++11) +typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) +#else +typedef signed long long ImS64; // 64-bit signed integer (post C++11) +typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) +#endif + +// Character types +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) +typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. +typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. +#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] +typedef ImWchar32 ImWchar; +#else +typedef ImWchar16 ImWchar; +#endif + +// Callback and functions types +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText() +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() + +// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] +// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImVec2 +{ + float x, y; + ImVec2() { x = y = 0.0f; } + ImVec2(float _x, float _y) { x = _x; y = _y; } + float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. + float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. +#ifdef IM_VEC2_CLASS_EXTRA + IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. +#endif +}; + +// ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] +struct ImVec4 +{ + float x, y, z, w; + ImVec4() { x = y = z = w = 0.0f; } + ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } +#ifdef IM_VEC4_CLASS_EXTRA + IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. +#endif +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +//----------------------------------------------------------------------------- +// [SECTION] Dear ImGui end-user API functions +// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Context creation and access + // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for details. + IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); + + // Main + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame! + IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). + IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. + + // Demo, Debug, Information + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. + IMGUI_API void ShowStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. + IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) + IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. + IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. + IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). + IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp) + + // Styles + IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) + IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style + + // Windows + // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // which clicking will set the boolean to false when clicked. + // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. + // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). + // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // - Note that the bottom of window stack always contains a window called "Debug". + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void End(); + + // Child Windows + // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. + // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). + // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value. + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API void EndChild(); + + // Windows Utilities + // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. + IMGUI_API bool IsWindowAppearing(); + IMGUI_API bool IsWindowCollapsed(); + IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! + IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) + IMGUI_API ImVec2 GetWindowSize(); // get current window size + IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) + IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) + + // Window manipulation + // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() + IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() + IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). + IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. + + // Content region + // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful. + // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates + + // Windows Scrolling + IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y + IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + + // Parameters stacks (shared) + IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font + IMGUI_API void PopFont(); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); + IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopAllowKeyboardFocus(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); + + // Parameters stacks (current window) + IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). + IMGUI_API void PopItemWidth(); + IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side) + IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PopTextWrapPos(); + + // Style read access + // - Use the style editor (ShowStyleEditor() function) to interactively see what the colors are) + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. + + // Cursor / Layout + // - By "cursor" we mean the current output position. + // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. + // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. + // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: + // Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() + // Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. + IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. + IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. + IMGUI_API void Spacing(); // add vertical spacing. + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void BeginGroup(); // lock horizontal starting position + IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) + IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) + IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. + IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: + IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. + IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) + IMGUI_API void SetCursorPosY(float local_y); // + IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (useful to work with ImDrawList API). generally top-left == GetMainViewport()->Pos == (0,0) in single viewport mode, and bottom-right == GetMainViewport()->Pos+Size == io.DisplaySize in single-viewport mode. + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates + IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) + IMGUI_API float GetTextLineHeight(); // ~ FontSize + IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) + IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 + IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) + + // ID stack/scopes + // Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui. + // - Those questions are answered and impacted by understanding of the ID stack system: + // - "Q: Why is my widget not reacting when I click on it?" + // - "Q: How can I have widgets with an empty label?" + // - "Q: How can I have multiple widgets with the same label?" + // - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely + // want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). + IMGUI_API void PopID(); // pop from the ID stack. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + + // Widgets: Text + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text + IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). + IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets + IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() + IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Widgets: Main + // - Most widgets return true when the value has been changed or when pressed/selected + // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button + IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding + IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, int* flags, int flags_value); + IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); + IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } + IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); + IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + + // Widgets: Combo Box + // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. + IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); + IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! + IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); + IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" + IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); + + // Widgets: Drag Sliders + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. + // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. + // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. + // - Legacy: Pre-1.78 there are DragXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + + // Widgets: Regular Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). + // - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + + // Widgets: Input with Keyboard + // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. + // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. + IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + + // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) + // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. + // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x + IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); + IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. + + // Widgets: Trees + // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. + IMGUI_API bool TreeNode(const char* label); + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). + IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " + IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. + IMGUI_API void TreePush(const void* ptr_id = NULL); // " + IMGUI_API void TreePop(); // ~ Unindent()+PopId() + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. + IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. + + // Widgets: Selectables + // - A selectable highlights when hovered, and can display another color when selected. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. + + // Widgets: List Boxes + // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. + // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth + // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region + IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! + IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); + IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); + + // Widgets: Data Plotting + // - Consider using ImPlot (https://github.com/epezent/implot) which is much better! + IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + + // Widgets: Value() Helpers. + // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + IMGUI_API void Value(const char* prefix, bool b); + IMGUI_API void Value(const char* prefix, int v); + IMGUI_API void Value(const char* prefix, unsigned int v); + IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); + + // Widgets: Menus + // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. + // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. + // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. + // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). + IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. + IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL + + // Tooltips + // - Tooltip are windows following the mouse. They do not take focus away. + IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). + IMGUI_API void EndTooltip(); + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). + IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Popups, Modals + // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. + // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. + // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). + // - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. + // This is sometimes leading to confusing mistakes. May rework this in the future. + + // Popups: begin/end functions + // - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window. + // - BeginPopupModal(): block every interactions behind the window, cannot be closed by user, add a dimming background, has a title bar. + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. + IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! + + // Popups: open/close functions + // - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. + // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). + // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). + // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. + IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). + IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) + IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. + + // Popups: open+begin combined functions helpers + // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. + // - They are convenient to easily create context menus, hence the name. + // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. + // - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). + + // Popups: query functions + // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. + IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. + + // Tables + // [BETA API] API may evolve slightly! If you use this, please update to the next version when it comes out! + // - Full-featured replacement for old Columns API. + // - See Demo->Tables for demo code. + // - See top of imgui_tables.cpp for general commentary. + // - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. + // The typical call flow is: + // - 1. Call BeginTable(). + // - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. + // - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. + // - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. + // - 5. Populate contents: + // - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. + // - If you are using tables as a sort of grid, where every columns is holding the same type of contents, + // you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). + // TableNextColumn() will automatically wrap-around into the next row if needed. + // - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! + // - Summary of possible call flow: + // -------------------------------------------------------------------------------------------------------- + // TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK + // TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK + // TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! + // TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! + // -------------------------------------------------------------------------------------------------------- + // - 5. Call EndTable() + IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); + IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! + IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. + IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. + IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. + + // Tables: Headers & Columns declaration + // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. + // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. + // Headers are required to perform: reordering, sorting, and opening the context menu. + // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. + // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in + // some advanced use cases (e.g. adding custom widgets in header row). + // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); + IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu + IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) + + // Tables: Sorting + // - Call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. + // - When 'SpecsDirty == true' you should sort your data. It will be true when sorting specs have changed + // since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, else you may + // wastefully sort your data every frame! + // - Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable(). + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). + + // Tables: Miscellaneous functions + // - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. + IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) + IMGUI_API int TableGetColumnIndex(); // return current column index. + IMGUI_API int TableGetRowIndex(); // return current row index. + IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. + IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column. + IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) + IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. + + // Legacy Columns API (prefer using Tables!) + // - You can also use SameLine(pos_x) to mimic simplified columns. + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column + IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column + IMGUI_API int GetColumnsCount(); + + // Tab Bars, Tabs + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar + IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. + IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. + + // Logging/Capture + // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. + IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) + IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file + IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard + IMGUI_API void LogFinish(); // stop logging (close file, etc.) + IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard + IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + IMGUI_API void LogTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Drag and Drop + // - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource(). + // - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget(). + // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) + // - An item can be both drag source and drop target. + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! + IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! + IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. + + // Disabling [BETA API] + // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) + // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) + // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. + IMGUI_API void BeginDisabled(bool disabled = true); + IMGUI_API void EndDisabled(); + + // Clipping + // - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only. + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + + // Focus, Activation + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + + // Item/Widgets Utilities and Query Functions + // - Most of the functions are referring to the previous Item that has been submitted. + // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. + IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) + IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this it NOT equivalent to the behavior of e.g. Button(). Read comments in function definition. + IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) + IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. + IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. + IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). + IMGUI_API bool IsAnyItemHovered(); // is any item hovered? + IMGUI_API bool IsAnyItemActive(); // is any item active? + IMGUI_API bool IsAnyItemFocused(); // is any item focused? + IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectSize(); // get size of last item + IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. + + // Viewports + // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. + // - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. + // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. + IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL. + + // Miscellaneous Utilities + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. + IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. + IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. + IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. + IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). + IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) + IMGUI_API ImGuiStorage* GetStateStorage(); + IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame + IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) + + // Text Utilities + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + + // Color Utilities + IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); + IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); + IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); + IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); + + // Inputs Utilities: Keyboard + // - For 'int user_key_index' you can use your own indices/enums according to how your backend/engine stored them in io.KeysDown[]. + // - We don't know the meaning of those value. You can use GetKeyIndex() to map a ImGuiKey_ value into the user index. + IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] + IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. + IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down)? + IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. + + // Inputs Utilities: Mouse + // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. + // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. + // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') + IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) + IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available + IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? + IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) + IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you + IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired cursor type + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. + + // Clipboard Utilities + // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. + IMGUI_API const char* GetClipboardText(); + IMGUI_API void SetClipboardText(const char* text); + + // Settings/.Ini Utilities + // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). + // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + // - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables). + IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). + IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. + IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). + IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. + + // Debug Utilities + // - This is used by the IMGUI_CHECKVERSION() macro. + IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. + + // Memory Allocators + // - Those functions are not reliant on the current context. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. + IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data = NULL); + IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data); + IMGUI_API void* MemAlloc(size_t size); + IMGUI_API void MemFree(void* ptr); + +} // namespace ImGui + +//----------------------------------------------------------------------------- +// [SECTION] Flags & Enumerations +//----------------------------------------------------------------------------- + +// Flags for ImGui::Begin() +enum ImGuiWindowFlags_ +{ + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar + ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip + ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window + ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node). + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame + ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). + ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. + ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) + ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + + // [Internal] + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. + ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() + + // [Obsolete] + //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by backend (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) +}; + +// Flags for ImGui::InputText() +enum ImGuiInputTextFlags_ +{ + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef + ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode + ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) + ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + ImGuiInputTextFlags_CallbackEdit = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + + // Obsolete names (will be removed soon) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior +#endif +}; + +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected + ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog +}; + +// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. +// - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat +// small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. +// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. +// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. +// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter +// and want to another another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag. +// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). +enum ImGuiPopupFlags_ +{ + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) + ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) + ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space + ImGuiPopupFlags_AnyPopupId = 1 << 7, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel +}; + +// Flags for ImGui::Selectable() +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too + ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 // (WIP) Hit testing to allow subsequent widgets to overlap this one +}; + +// Flags for ImGui::BeginCombo() +enum ImGuiComboFlags_ +{ + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default + ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() + ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) + ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible + ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible + ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button + ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}; + +// Flags for ImGui::BeginTabBar() +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}; + +// Flags for ImGui::BeginTabItem() +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() + ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab + ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab + ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) + ImGuiTabItemFlags_Trailing = 1 << 7 // Enforce the tab position to the right of the tab bar (before the scrolling buttons) +}; + +// Flags for ImGui::BeginTable() +// [BETA API] API may evolve slightly! If you use this, please update to the next version when it comes out! +// - Important! Sizing policies have complex and subtle side effects, more so than you would expect. +// Read comments/demos carefully + experiment with live demos to get acquainted with them. +// - The DEFAULT sizing policies are: +// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off. +// - When ScrollX is off: +// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. +// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. +// - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all). +// - Stretch Columns will share the remaining width. +// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// - When ScrollX is on: +// - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed +// - Columns sizing policy allowed: Fixed/Auto mostly. +// - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed. +// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. +// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. +// - Read on documentation at the top of imgui_tables.cpp for details. +enum ImGuiTableFlags_ +{ + // Features + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns. + ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) + ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. + ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. + ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. + ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + // Decorations + ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) + ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. + ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. + ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. + ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. + ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style + // Sizing Policy (read above for defaults) + ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. + ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. + ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). + // Sizing Extra Options + ImGuiTableFlags_NoHostExtendX = 1 << 16, // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. + ImGuiTableFlags_NoHostExtendY = 1 << 17, // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. + ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + // Clipping + ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + // Padding + ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outer-most padding. Generally desirable if you have headers. + ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outer-most padding. + ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + // Scrolling + ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + // Sorting + ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). + ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + + // [Internal] Combinations and masks + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame + + // Obsolete names (will be removed soon) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //, ImGuiTableFlags_ColumnsWidthFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_ColumnsWidthStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2020/12 + //, ImGuiTableFlags_SizingPolicyFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingPolicyStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2021/01 +#endif +}; + +// Flags for ImGui::TableSetupColumn() +enum ImGuiTableColumnFlags_ +{ + // Input configuration flags + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_Disabled = 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state) + ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column. + ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column. + ImGuiTableColumnFlags_WidthStretch = 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp). + ImGuiTableColumnFlags_WidthFixed = 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable). + ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. + ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. + ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. + ImGuiTableColumnFlags_NoClip = 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command). + ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). + ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. + ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu. + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. + ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). + ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. + ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0). + ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored. + + // Output status flags, read-only via TableGetColumnFlags() + ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags. + ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling. + ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs + ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse + + // [Internal] Combinations and masks + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30 // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) + + // Obsolete names (will be removed soon) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //ImGuiTableColumnFlags_WidthAuto = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, // Column will not stretch and keep resizing based on submitted contents. +#endif +}; + +// Flags for ImGui::TableNextRow() +enum ImGuiTableRowFlags_ +{ + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0 // Identify header row (set default background color + width of its contents accounted different for auto column width) +}; + +// Enum for ImGui::TableSetBgColor() +// Background colors are rendering in 3 layers: +// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set. +// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set. +// - Layer 2: draw with CellBg color if set. +// The purpose of the two row/columns layers is to let you decide if a background color changes should override or blend with the existing color. +// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows. +// If you set the color of RowBg0 target, your color will override the existing RowBg0 color. +// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. +enum ImGuiTableBgTarget_ +{ + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) + ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) + ImGuiTableBgTarget_CellBg = 3 // Set cell background color (top-most color) +}; + +// Flags for ImGui::IsWindowFocused() +enum ImGuiFocusedFlags_ +{ + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! + ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}; + +// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! +// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered + ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) + ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered + ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}; + +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_None = 0, + // BeginDragDropSource() flags + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. + ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) + // AcceptDragDropPayload() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. +}; + +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. + +// A primary data type +enum ImGuiDataType_ +{ + ImGuiDataType_S8, // signed char / char (with sensible compilers) + ImGuiDataType_U8, // unsigned char + ImGuiDataType_S16, // short + ImGuiDataType_U16, // unsigned short + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_COUNT +}; + +// A cardinal direction +enum ImGuiDir_ +{ + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}; + +// A sorting direction +enum ImGuiSortDirection_ +{ + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. + ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. +}; + +// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array +enum ImGuiKey_ +{ + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_KeyPadEnter, + ImGuiKey_A, // for text edit CTRL+A: select all + ImGuiKey_C, // for text edit CTRL+C: copy + ImGuiKey_V, // for text edit CTRL+V: paste + ImGuiKey_X, // for text edit CTRL+X: cut + ImGuiKey_Y, // for text edit CTRL+Y: redo + ImGuiKey_Z, // for text edit CTRL+Z: undo + ImGuiKey_COUNT +}; + +// To test io.KeyMods (which is a combination of individual fields io.KeyCtrl, io.KeyShift, io.KeyAlt set by user/backend) +enum ImGuiKeyModFlags_ +{ + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 +}; + +// Gamepad/Keyboard navigation +// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. +// Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Backend: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). +// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://dearimgui.org/controls_sheets. +enum ImGuiNavInput_ +{ + // Gamepad Mapping + ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) + ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) + ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) + ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) + ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) + ImGuiNavInput_DpadRight, // + ImGuiNavInput_DpadUp, // + ImGuiNavInput_DpadDown, // + ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down + ImGuiNavInput_LStickRight, // + ImGuiNavInput_LStickUp, // + ImGuiNavInput_LStickDown, // + ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + + // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. + // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. + ImGuiNavInput_KeyLeft_, // move left // = Arrow keys + ImGuiNavInput_KeyRight_, // move right + ImGuiNavInput_KeyUp_, // move up + ImGuiNavInput_KeyDown_, // move down + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyLeft_ +}; + +// Configuration flags stored in io.ConfigFlags. Set by user/application. +enum ImGuiConfigFlags_ +{ + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui backend to fill io.NavInputs[]. Backend also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. + + // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui) + ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. + ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. +}; + +// Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. +enum ImGuiBackendFlags_ +{ + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. +}; + +// Enumeration for PushStyleColor() / PopStyleColor() +enum ImGuiCol_ +{ + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, // Table header background + ImGuiCol_TableBorderStrong, // Table outer and header borders (prefer using Alpha=1.0 here) + ImGuiCol_TableBorderLight, // Table inner borders (prefer using Alpha=1.0 here) + ImGuiCol_TableRowBg, // Table row background (even rows) + ImGuiCol_TableRowBgAlt, // Table row background (odd rows) + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item + ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB + ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active + ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active + ImGuiCol_COUNT +}; + +// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. +// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. +// During initialization or between frames, feel free to just poke into ImGuiStyle directly. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. +// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +enum ImGuiStyleVar_ +{ + // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) + ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha + ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding + ImGuiStyleVar_WindowRounding, // float WindowRounding + ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize + ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize + ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign + ImGuiStyleVar_ChildRounding, // float ChildRounding + ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize + ImGuiStyleVar_PopupRounding, // float PopupRounding + ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize + ImGuiStyleVar_FramePadding, // ImVec2 FramePadding + ImGuiStyleVar_FrameRounding, // float FrameRounding + ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize + ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing + ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing + ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_CellPadding, // ImVec2 CellPadding + ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize + ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding + ImGuiStyleVar_GrabMinSize, // float GrabMinSize + ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign + ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_COUNT +}; + +// Flags for InvisibleButton() [extended in imgui_internal.h] +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) + ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button + + // [Internal] + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft +}; + +// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() +enum ImGuiColorEditFlags_ +{ + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on color square. + ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable color square preview next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview color square). + ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. + ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). + ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. + ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) + + // User Options (right-click on widget to change some of them). + ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. + ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). + ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. + ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " + ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " + ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. + ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. + ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. + ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + + // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to + // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. + ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + + // [Internal] Masks + ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] +#endif +}; + +// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. + ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) + ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget + ImGuiSliderFlags_InvalidMask_ = 0x7000000F // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp // [renamed in 1.79] +#endif +}; + +// Identify a mouse button. +// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. +enum ImGuiMouseButton_ +{ + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}; + +// Enumeration for GetMouseCursor() +// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) + ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border + ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. + ImGuiMouseCursor_COUNT +}; + +// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions +// Represent a condition. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +enum ImGuiCond_ +{ + ImGuiCond_None = 0, // No condition (always set the variable), same as _Always + ImGuiCond_Always = 1 << 0, // No condition (always set the variable) + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) + ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) + ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) +}; + +//----------------------------------------------------------------------------- +// [SECTION] Helpers: Memory allocations macros, ImVector<> +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +//----------------------------------------------------------------------------- + +struct ImNewWrapper {}; +inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) +#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } + +//----------------------------------------------------------------------------- +// ImVector<> +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +//----------------------------------------------------------------------------- +// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. +// - We use std-like naming convention here, which is a little unusual for this codebase. +// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. +// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +//----------------------------------------------------------------------------- + +IM_MSVC_RUNTIME_CHECKS_OFF +template +struct ImVector +{ + int Size; + int Capacity; + T* Data; + + // Provide standard typedefs but we don't use them ourselves. + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything + + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything + inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit. + inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit. + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int size_in_bytes() const { return Size * (int)sizeof(T); } + inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } + + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last > it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; } + inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStyle +//----------------------------------------------------------------------------- +// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. +//----------------------------------------------------------------------------- + +struct ImGuiStyle +{ + float Alpha; // Global alpha applies to everything in Dear ImGui. + float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + ImVec2 WindowPadding; // Padding within a window. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. + float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. + float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). + float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). + float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. + ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + ImVec2 CellPadding; // Padding within a table cell + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + float ScrollbarRounding; // Radius of grab corners for scrollbar. + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. + float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. + float TabMinWidthForCloseButton; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). + ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! + float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering. Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + ImVec4 Colors[ImGuiCol_COUNT]; + + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiIO +//----------------------------------------------------------------------------- +// Communicate most settings and inputs/outputs to Dear ImGui using this structure. +// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. +//----------------------------------------------------------------------------- + +struct ImGuiIO +{ + //------------------------------------------------------------------ + // Configuration (fill once) // Default value + //------------------------------------------------------------------ + + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. + ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size) + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. + float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. + const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + void* UserData; // = NULL // Store your own data for retrieval by callbacks. + + ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. + float FontGlobalScale; // = 1.0f // Global scale all fonts + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. + + // Miscellaneous options + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). + bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + + //------------------------------------------------------------------ + // Platform Functions + // (the imgui_impl_xxxx backend files are setting those up for you) + //------------------------------------------------------------------ + + // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL // User data for platform backend + void* BackendRendererUserData; // = NULL // User data for renderer backend + void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend + + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. + + //------------------------------------------------------------------ + // Input - Fill before calling NewFrame() + //------------------------------------------------------------------ + + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. + float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends. + bool KeyCtrl; // Keyboard modifier pressed: Control + bool KeyShift; // Keyboard modifier pressed: Shift + bool KeyAlt; // Keyboard modifier pressed: Alt + bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows + bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). + float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). + + // Functions + IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string + IMGUI_API void AddFocusEvent(bool focused); // Notifies Dear ImGui when hosting platform windows lose or gain input focus + IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually + IMGUI_API void ClearInputKeys(); // [Internal] Release all keys + + //------------------------------------------------------------------ + // Output - Updated by NewFrame() or EndFrame()/Render() + // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is + // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) + //------------------------------------------------------------------ + + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Rough estimate of application framerate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + //------------------------------------------------------------------ + // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! + //------------------------------------------------------------------ + + bool WantCaptureMouseUnlessPopupClose;// Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. + ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() + ImGuiKeyModFlags KeyModsPrev; // Previous key mods + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down + ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownOwnedUnlessPopupClose[5];//Track if button was clicked inside a dear imgui window. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point + float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) + float KeysDownDurationPrev[512]; // Previous duration the key has been down + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. + bool AppFocusLost; + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16 + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. + + IMGUI_API ImGuiIO(); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Misc data structures +//----------------------------------------------------------------------------- + +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. +// The callback function should return 0 by default. +// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration +// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB +// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only + ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only + void* UserData; // What user passed to InputText() // Read-only + + // Arguments for the different callback events + // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. + // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + int CursorPos; // // Read-write // [Completion,History,Always] + int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) + int SelectionEnd; // // Read-write // [Completion,History,Always] + + // Helper functions for text manipulation. + // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. + IMGUI_API ImGuiInputTextCallbackData(); + IMGUI_API void DeleteChars(int pos, int bytes_count); + IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); + void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } + void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } + bool HasSelection() const { return SelectionStart != SelectionEnd; } +}; + +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +struct ImGuiSizeCallbackData +{ + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +}; + +// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() +struct ImGuiPayload +{ + // Members + void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + int DataFrameCount; // Data timestamp + char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsPreview() const { return Preview; } + bool IsDelivery() const { return Delivery; } +}; + +// Sorting specification for one column of a table (sizeof == 12 bytes) +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) + ImS16 ColumnIndex; // Index of the column + ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) + ImGuiSortDirection SortDirection : 8; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending (you can use this or SortSign, whichever is more convenient for your sort function) + + ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +// Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +// Obtained by calling TableGetSortSpecs(). +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. +// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! +struct ImGuiTableSortSpecs +{ + const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. + int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. + bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. + + ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) +//----------------------------------------------------------------------------- + +// Helper: Unicode defines +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#endif + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. +// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +struct ImGuiOnceUponAFrame +{ + ImGuiOnceUponAFrame() { RefFrame = -1; } + mutable int RefFrame; + operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } +}; + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +struct ImGuiTextFilter +{ + IMGUI_API ImGuiTextFilter(const char* default_filter = ""); + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; + IMGUI_API void Build(); + void Clear() { InputBuf[0] = 0; Build(); } + bool IsActive() const { return !Filters.empty(); } + + // [Internal] + struct ImGuiTextRange + { + const char* b; + const char* e; + + ImGuiTextRange() { b = e = NULL; } + ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } + bool empty() const { return b == e; } + IMGUI_API void split(char separator, ImVector* out) const; + }; + char InputBuf[256]; + ImVectorFilters; + int CountGrep; +}; + +// Helper: Growable text buffer for logging/accumulating text +// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') +struct ImGuiTextBuffer +{ + ImVector Buf; + IMGUI_API static char EmptyString[1]; + + ImGuiTextBuffer() { } + inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } + const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } + const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } + bool empty() const { return Buf.Size <= 1; } + void clear() { Buf.clear(); } + void reserve(int capacity) { Buf.reserve(capacity); } + const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } + IMGUI_API void append(const char* str, const char* str_end = NULL); + IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); +}; + +// Helper: Key->Value storage +// Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1) +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) +// You can use it as custom user storage for temporary values. Declare your own storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +struct ImGuiStorage +{ + // [Internal] + struct ImGuiStoragePair + { + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; + ImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + ImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } + ImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } + }; + + ImVector Data; + + // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) + // - Set***() functions find pair, insertion on demand if missing. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. + void Clear() { Data.clear(); } + IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; + IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); + IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; + IMGUI_API void SetFloat(ImGuiID key, float val); + IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL + IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; + IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); + IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); + IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); + + // Use on your own storage if you know only integer are being stored (open/close all tree nodes) + IMGUI_API void SetAllInt(int val); + + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + IMGUI_API void BuildSortByKey(); +}; + +// Helper: Manually clip large list of items. +// If you have lots evenly spaced items and you have a random access to the list, you can perform coarse +// clipping based on visibility to only submit items that are in view. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally +// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily +// scale using lists with tens of thousands of items without a problem) +// Usage: +// ImGuiListClipper clipper; +// clipper.Begin(1000); // We have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// Generally what happens is: +// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. +// - User code submit that one element. +// - Clipper can measure the height of the first element +// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. +// - User code submit visible elements. +// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. +struct ImGuiListClipper +{ + int DisplayStart; // First item to display, updated by each call to Step() + int DisplayEnd; // End of items to display (exclusive) + int ItemsCount; // [Internal] Number of items + float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it + float StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + void* TempData; // [Internal] Internal data + + // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step) + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + IMGUI_API ImGuiListClipper(); + IMGUI_API ~ImGuiListClipper(); + IMGUI_API void Begin(int items_count, float items_height = -1.0f); + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + + // Call ForceDisplayRangeByIndices() before first call to Step() if you need a range of items to be displayed regardless of visibility. + IMGUI_API void ForceDisplayRangeByIndices(int item_min, int item_max); // item_max is exclusive e.g. use (42, 42+1) to make item 42 always visible BUT due to alignment/padding of certain items it is likely that an extra item may be included on either end of the display range. + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] +#endif +}; + +// Helpers macros to generate 32-bit encoded colors +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)<> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } + ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } + ImColor(const ImVec4& col) { Value = col; } + inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } + inline operator ImVec4() const { return Value; } + + // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. + inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } + static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. +//----------------------------------------------------------------------------- + +// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. +#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) +#endif + +// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] +// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, +// you can poke into the draw list for that! Draw callback may be useful for example to: +// A) Change your GPU render state, +// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' +// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly. +#ifndef ImDrawCallback +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +#endif + +// Special Draw callback value to request renderer backend to reset the graphics/render state. +// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. +// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. +// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) + +// Typically, 1 command = 1 GPU draw call (unless command is a callback) +// - VtxOffset/IdxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Pre-1.71 backends will typically ignore the VtxOffset/IdxOffset fields. +// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). +struct ImDrawCmd +{ + ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. + unsigned int IdxOffset; // 4 // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. + unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + void* UserCallbackData; // 4-8 // The draw callback code can access this. + + ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + + // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) + inline ImTextureID GetTexID() const { return TextureId; } +}; + +// Vertex layout +#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +#else +// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h +// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. +// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up. +// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. +IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; +#endif + +// [Internal] For use by ImDrawList +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; + +// [Internal] For use by ImDrawListSplitter +struct ImDrawChannel +{ + ImVector _CmdBuffer; + ImVector _IdxBuffer; +}; + + +// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. +// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. +struct ImDrawListSplitter +{ + int _Current; // Current channel number (0) + int _Count; // Number of active channels (1+) + ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) + + inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } + inline ~ImDrawListSplitter() { ClearFreeMemory(); } + inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame + IMGUI_API void ClearFreeMemory(); + IMGUI_API void Split(ImDrawList* draw_list, int count); + IMGUI_API void Merge(ImDrawList* draw_list); + IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); +}; + +// Flags for ImDrawList functions +// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused) +enum ImDrawFlags_ +{ + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason) + ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. + ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. + ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. + ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified. + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone +}; + +// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. +// It is however possible to temporarily alter flags between calls to ImDrawList:: functions. +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering. + ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). + ImDrawListFlags_AllowVtxOffset = 1 << 3 // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. +}; + +// Draw command list +// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame, +// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. +// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to +// access the current window draw list and draw custom primitives. +// You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). +// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +struct ImDrawList +{ + // This is what you have to render + ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those + ImVector VtxBuffer; // Vertex buffer. + ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + + // [Internal, used while building lists] + unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. + const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + const char* _OwnerName; // Pointer to owner window's name for debugging + ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImVector _ClipRectStack; // [Internal] + ImVector _TextureIdStack; // [Internal] + ImVector _Path; // [Internal] current path building + ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). + ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) + float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content + + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) + ImDrawList(const ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } + + ~ImDrawList() { _ClearFreeMemory(); } + IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + IMGUI_API void PushClipRectFullScreen(); + IMGUI_API void PopClipRect(); + IMGUI_API void PushTextureID(ImTextureID texture_id); + IMGUI_API void PopTextureID(); + inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } + inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } + + // Primitives + // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. + // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). + // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. + // In future versions we will use textures to provide cheaper and higher-quality circles. + // Use AddNgon() and AddNgonFilled() functions if you need to guaranteed a specific number of sides. + IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); + IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); + IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); + IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); + IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness); + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. + IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) + + // Image primitives + // - Read FAQ to understand what ImTextureID is. + // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. + // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. + IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); + + // Stateful path API, add points then finish with PathFillConvex() or PathStroke() + inline void PathClear() { _Path.Size = 0; } + inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. + inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0); + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); + + // Advanced + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. + IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible + IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. + + // Advanced: Channels + // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) + // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! + // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. + // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. + inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } + inline void ChannelsMerge() { _Splitter.Merge(this); } + inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } + + // Advanced: Primitives allocations + // - We render triangles (three vertices) + // - All primitives needs to be reserved via PrimReserve() beforehand. + IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); + IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) + IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); + IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } + inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } +#endif + + // [Internal helpers] + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _TryMergeDrawCmds(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; + IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); + IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); +}; + +// All draw data to render a Dear ImGui frame +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, +// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) +struct ImDrawData +{ + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + int CmdListsCount; // Number of ImDrawList* to render + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + + // Functions + ImDrawData() { Clear(); } + void Clear() { memset(this, 0, sizeof(*this)); } // The ImDrawList are owned by ImGuiContext! + IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! + IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. +}; + +//----------------------------------------------------------------------------- +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) +//----------------------------------------------------------------------------- + +struct ImFontConfig +{ + void* FontData; // // TTF/OTF data + int FontDataSize; // // TTF/OTF data size + bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + int FontNo; // 0 // Index of font within TTF/OTF file + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. + const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. + float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. + ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + + // [Internal] + char Name[40]; // Name (strictly to ease debugging) + ImFont* DstFont; + + IMGUI_API ImFontConfig(); +}; + +// Hold rendering data for one glyph. +// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) +struct ImFontGlyph +{ + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int Codepoint : 30; // 0x0000..0x10FFFF + float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float X0, Y0, X1, Y1; // Glyph corners + float U0, V0, U1, V1; // Texture coordinates +}; + +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { Clear(); } + inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } + inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array + inline void AddChar(ImWchar c) { SetBit(c); } // Add character + IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges +}; + +// See ImFontAtlas::AddCustomRectXXX functions. +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; // Input // Desired rectangle dimension + unsigned short X, Y; // Output // Packed position in Atlas + unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) + float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset + ImFont* Font; // Input // For custom font glyphs only: target font + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + bool IsPacked() const { return X != 0xFFFF; } +}; + +// Flags for ImFontAtlas build +enum ImFontAtlasFlags_ +{ + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two + ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) + ImFontAtlasFlags_NoBakedLines = 1 << 2 // Don't build thick line textures into the atlas (save a little texture memory). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). +}; + +// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: +// - One or more fonts. +// - Custom graphics data needed to render the shapes needed by Dear ImGui. +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. +// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. +// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. +// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// Common pitfalls: +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. +// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! +struct ImFontAtlas +{ + IMGUI_API ImFontAtlas(); + IMGUI_API ~ImFontAtlas(); + IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); + IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); + IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). + IMGUI_API void Clear(); // Clear all input and output. + + // Build atlas, retrieve pixel data. + // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // The pitch is always = Width * BytesPerPixels (1 or 4) + // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't built texture but effectively we should check TexID != 0 except that would be backend dependent... + void SetTexID(ImTextureID id) { TexID = id; } + + //------------------------------------------- + // Glyph Ranges + //------------------------------------------- + + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. + IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese + IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters + IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + + //------------------------------------------- + // [BETA] Custom Rectangles/Glyphs API + //------------------------------------------- + + // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. + // - After calling Build(), you can query the rectangle position and render your pixels. + // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of prefered texture format. + // - You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // - Read docs/FONTS.md for more details about using colorful icons. + // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. + IMGUI_API int AddCustomRectRegular(int width, int height); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } + + // [Internal] + IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + + //------------------------------------------- + // Members + //------------------------------------------- + + ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) + ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + + // [Internal] + // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool TexReady; // Set when texture was built matching current font input + bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. + unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight + unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + int TexWidth; // Texture width calculated during Build(). + int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. + ImVector ConfigData; // Configuration data + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines + + // [Internal] Font builder + const ImFontBuilderIO* FontBuilderIO; // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). + unsigned int FontBuilderFlags; // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig. + + // [Internal] Packing data + int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors + int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ +#endif +}; + +// Font runtime data and rendering +// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). +struct ImFont +{ + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) + + // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // // All glyphs. + const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + + // Members: Cold ~32/40 bytes + ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. + ImWchar EllipsisChar; // 2 // out // = '...' // Character used for ellipsis rendering. + ImWchar DotChar; // 2 // out // = '.' // Character used for ellipsis rendering (if a single '...' character isn't found) + bool DirtyLookupTables; // 1 // out // + float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] + int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + + // Methods + IMGUI_API ImFont(); + IMGUI_API ~ImFont(); + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + + // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. + // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + + // [Internal] Don't use! + IMGUI_API void BuildLookupTable(); + IMGUI_API void ClearOutputData(); + IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); + IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Viewports +//----------------------------------------------------------------------------- + +// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends. +enum ImGuiViewportFlags_ +{ + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) + ImGuiViewportFlags_OwnedByApp = 1 << 2 // Platform Window: is created/managed by the application (rather than a dear imgui backend) +}; + +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +// - About Main Area vs Work Area: +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Windows are generally trying to stay within the Work Area of their host viewport. +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + ImVec2 Pos; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) + ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) + ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + + ImGuiViewport() { memset(this, 0, sizeof(*this)); } + + // Helpers + ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Obsolete functions and types +// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.86 (from November 2021) + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Calculate coarse clipping for large list of evenly sized items. Prefer using ImGuiListClipper. + // OBSOLETED in 1.85 (from August 2021) + static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } + // OBSOLETED in 1.81 (from February 2021) + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } + // OBSOLETED in 1.79 (from August 2020) + static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! + // OBSOLETED in 1.78 (from June 2020) + // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags. + // For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power); + static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power); + static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } + static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } + static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } + static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } + // OBSOLETED in 1.77 (from June 2020) + static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } + // OBSOLETED in 1.72 (from April 2019) + static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } + // OBSOLETED in 1.71 (from June 2019) + static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } + // OBSOLETED in 1.70 (from May 2019) + static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } + + // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) + //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) + //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) + //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) + //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) +} + +// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() +typedef ImDrawFlags ImDrawCornerFlags; +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit + ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). + ImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight, // Was == 0x02 (1 << 1) prior to 1.82. + ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. + ImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. + ImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll, // Was == 0x0F prior to 1.82 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight +}; + +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) +#ifdef IMGUI_INCLUDE_IMGUI_USER_H +#include "imgui_user.h" +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui_demo.cpp b/thirdparty/imgui/imgui_demo.cpp new file mode 100644 index 0000000..9cbc503 --- /dev/null +++ b/thirdparty/imgui/imgui_demo.cpp @@ -0,0 +1,7860 @@ +// dear imgui, v1.86 +// (demo code) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for more details, documentation and comments. +// Get the latest version at https://github.com/ocornut/imgui + +// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase: +// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other +// coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available +// debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone +// in your team, likely leading you to poorer usage of the library. +// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). +// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. +// Thank you, +// -Your beloved friend, imgui_demo.cpp (which you won't delete) + +// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: +// In this demo code, we frequently use 'static' variables inside functions. A static variable persists across calls, +// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to +// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller +// in size. It also happens to be a convenient way of storing simple UI related information as long as your function +// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, +// but most of the real data you would be editing is likely going to be stored outside your functions. + +// The Demo code in this file is designed to be easy to copy-and-paste into your application! +// Because of this: +// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. +// - We try to declare static variables in the local scope, as close as possible to the code using them. +// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +// by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + +/* + +Index of this file: + +// [SECTION] Forward Declarations, Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// - sub section: ShowDemoWindowWidgets() +// - sub section: ShowDemoWindowLayout() +// - sub section: ShowDemoWindowPopups() +// - sub section: ShowDemoWindowTables() +// - sub section: ShowDemoWindowMisc() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +// System includes +#include // toupper +#include // INT_MIN, INT_MAX +#include // sqrtf, powf, cosf, sinf, floorf, ceilf +#include // vsnprintf, sscanf, printf +#include // NULL, malloc, free, atoi +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type +#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#endif + +// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" +#else +#define IM_NEWLINE "\n" +#endif + +// Helpers +#if defined(_MSC_VER) && !defined(snprintf) +#define snprintf _snprintf +#endif +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +// Format specifiers, printing 64-bit hasn't been decently standardized... +// In a real application you should be using PRId64 and PRIu64 from (non-windows) and on Windows define them yourself. +#ifdef _MSC_VER +#define IM_PRId64 "I64d" +#define IM_PRIu64 "I64u" +#else +#define IM_PRId64 "lld" +#define IM_PRIu64 "llu" +#endif + +// Helpers macros +// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +// but making an exception here as those are largely simplifying code... +// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) +#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) +#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifndef IMGUI_CDECL +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward Declarations, Helpers +//----------------------------------------------------------------------------- + +#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) + +// Forward Declarations +static void ShowExampleAppDocuments(bool* p_open); +static void ShowExampleAppMainMenuBar(); +static void ShowExampleAppConsole(bool* p_open); +static void ShowExampleAppLog(bool* p_open); +static void ShowExampleAppLayout(bool* p_open); +static void ShowExampleAppPropertyEditor(bool* p_open); +static void ShowExampleAppLongText(bool* p_open); +static void ShowExampleAppAutoResize(bool* p_open); +static void ShowExampleAppConstrainedResize(bool* p_open); +static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppFullscreen(bool* p_open); +static void ShowExampleAppWindowTitles(bool* p_open); +static void ShowExampleAppCustomRendering(bool* p_open); +static void ShowExampleMenuFile(); + +// Helper to display a little (?) mark which shows a tooltip when hovered. +// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) +static void HelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +// Helper to wire demo markers located in code to a interactive browser +typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data); +extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback; +extern void* GImGuiDemoMarkerCallbackUserData; +ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL; +void* GImGuiDemoMarkerCallbackUserData = NULL; +#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) + +// Helper to display basic user controls. +void ImGui::ShowUserGuide() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui::BulletText("Double-click on title bar to collapse window."); + ImGui::BulletText( + "Click and drag on lower corner to resize window\n" + "(double-click to auto fit window to its contents)."); + ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + ImGui::BulletText("CTRL+Tab to select a window."); + if (io.FontAllowUserScaling) + ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); + ImGui::BulletText("While inputing text:\n"); + ImGui::Indent(); + ImGui::BulletText("CTRL+Left/Right to word jump."); + ImGui::BulletText("CTRL+A or double-click to select all."); + ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); + ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("ESCAPE to revert."); + ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); + ImGui::Unindent(); + ImGui::BulletText("With keyboard navigation enabled:"); + ImGui::Indent(); + ImGui::BulletText("Arrow keys to navigate."); + ImGui::BulletText("Space to activate a widget."); + ImGui::BulletText("Return to input text into a widget."); + ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); + ImGui::BulletText("Alt to jump to the menu layer of a window."); + ImGui::Unindent(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Demo Window / ShowDemoWindow() +//----------------------------------------------------------------------------- +// - ShowDemoWindowWidgets() +// - ShowDemoWindowLayout() +// - ShowDemoWindowPopups() +// - ShowDemoWindowTables() +// - ShowDemoWindowColumns() +// - ShowDemoWindowMisc() +//----------------------------------------------------------------------------- + +// We split the contents of the big ShowDemoWindow() function into smaller functions +// (because the link time of very large functions grow non-linearly) +static void ShowDemoWindowWidgets(); +static void ShowDemoWindowLayout(); +static void ShowDemoWindowPopups(); +static void ShowDemoWindowTables(); +static void ShowDemoWindowColumns(); +static void ShowDemoWindowMisc(); + +// Demonstrate most Dear ImGui features (this is big function!) +// You may execute this function to experiment with the UI and understand what it does. +// You may then search for keywords in the code when you are interested by a specific feature. +void ImGui::ShowDemoWindow(bool* p_open) +{ + // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + // Most ImGui functions would normally just crash if the context is missing. + IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); + + // Examples Apps (accessible from the "Examples" menu) + static bool show_app_main_menu_bar = false; + static bool show_app_documents = false; + + static bool show_app_console = false; + static bool show_app_log = false; + static bool show_app_layout = false; + static bool show_app_property_editor = false; + static bool show_app_long_text = false; + static bool show_app_auto_resize = false; + static bool show_app_constrained_resize = false; + static bool show_app_simple_overlay = false; + static bool show_app_fullscreen = false; + static bool show_app_window_titles = false; + static bool show_app_custom_rendering = false; + + if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); + if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); + + if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_log) ShowExampleAppLog(&show_app_log); + if (show_app_layout) ShowExampleAppLayout(&show_app_layout); + if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); + if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); + if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); + if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); + if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); + if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); + + // Dear ImGui Apps (accessible from the "Tools" menu) + static bool show_app_metrics = false; + static bool show_app_stack_tool = false; + static bool show_app_style_editor = false; + static bool show_app_about = false; + + if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } + if (show_app_stack_tool) { ImGui::ShowStackToolWindow(&show_app_stack_tool); } + if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } + if (show_app_style_editor) + { + ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); + ImGui::ShowStyleEditor(); + ImGui::End(); + } + + // Demonstrate the various window flags. Typically you would just use the default! + static bool no_titlebar = false; + static bool no_scrollbar = false; + static bool no_menu = false; + static bool no_move = false; + static bool no_resize = false; + static bool no_collapse = false; + static bool no_close = false; + static bool no_nav = false; + static bool no_background = false; + static bool no_bring_to_front = false; + static bool unsaved_document = false; + + ImGuiWindowFlags window_flags = 0; + if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; + if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; + if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; + if (no_move) window_flags |= ImGuiWindowFlags_NoMove; + if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; + if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; + if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; + if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; + if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument; + if (no_close) p_open = NULL; // Don't pass our bool* to Begin + + // We specify a default position/size in case there's no data in the .ini file. + // We only do it to make the demo applications a little more welcoming, but typically this isn't required. + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); + + // Main body of the Demo window starts here. + if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) + { + // Early out if the window is collapsed, as an optimization. + ImGui::End(); + return; + } + + // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. + + // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) + //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); + + // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. + ImGui::PushItemWidth(ImGui::GetFontSize() * -12); + + // Menu Bar + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + IMGUI_DEMO_MARKER("Menu/File"); + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Examples")) + { + IMGUI_DEMO_MARKER("Menu/Examples"); + ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); + ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Log", NULL, &show_app_log); + ImGui::MenuItem("Simple layout", NULL, &show_app_layout); + ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); + ImGui::MenuItem("Long text display", NULL, &show_app_long_text); + ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); + ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); + ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); + ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); + ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); + ImGui::MenuItem("Documents", NULL, &show_app_documents); + ImGui::EndMenu(); + } + //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! + if (ImGui::BeginMenu("Tools")) + { + IMGUI_DEMO_MARKER("Menu/Tools"); +#ifndef IMGUI_DISABLE_METRICS_WINDOW + ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics); + ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool); +#endif + ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); + ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); + ImGui::Spacing(); + + IMGUI_DEMO_MARKER("Help"); + if (ImGui::CollapsingHeader("Help")) + { + ImGui::Text("ABOUT THIS DEMO:"); + ImGui::BulletText("Sections below are demonstrating many aspects of the library."); + ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); + ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" + "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); + ImGui::Separator(); + + ImGui::Text("PROGRAMMER GUIDE:"); + ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); + ImGui::BulletText("See comments in imgui.cpp."); + ImGui::BulletText("See example applications in the examples/ folder."); + ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::Separator(); + + ImGui::Text("USER GUIDE:"); + ImGui::ShowUserGuide(); + } + + IMGUI_DEMO_MARKER("Configuration"); + if (ImGui::CollapsingHeader("Configuration")) + { + ImGuiIO& io = ImGui::GetIO(); + + if (ImGui::TreeNode("Configuration##2")) + { + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::SameLine(); HelpMarker("Enable keyboard controls."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + { + // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: + if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) + { + ImGui::SameLine(); + ImGui::Text("<>"); + } + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; + } + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); + ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); + ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); + ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)"); + ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); + ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); + ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); + ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); + ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::Text("Also see Style->Rendering for rendering options."); + ImGui::TreePop(); + ImGui::Separator(); + } + + IMGUI_DEMO_MARKER("Configuration/Backend Flags"); + if (ImGui::TreeNode("Backend Flags")) + { + HelpMarker( + "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" + "Here we expose them as read-only fields to avoid breaking interactions with your backend."); + + // Make a local copy to avoid modifying actual backend flags. + ImGuiBackendFlags backend_flags = io.BackendFlags; + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::TreePop(); + ImGui::Separator(); + } + + IMGUI_DEMO_MARKER("Configuration/Style"); + if (ImGui::TreeNode("Style")) + { + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); + ImGui::ShowStyleEditor(); + ImGui::TreePop(); + ImGui::Separator(); + } + + IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); + if (ImGui::TreeNode("Capture/Logging")) + { + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " + "a window or a block. Tree nodes can be automatically expanded.\n" + "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); + ImGui::LogButtons(); + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); + if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) + { + ImGui::LogToClipboard(); + ImGui::LogText("Hello, world!"); + ImGui::LogFinish(); + } + ImGui::TreePop(); + } + } + + IMGUI_DEMO_MARKER("Window options"); + if (ImGui::CollapsingHeader("Window options")) + { + if (ImGui::BeginTable("split", 3)) + { + ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar); + ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar); + ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu); + ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move); + ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize); + ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse); + ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close); + ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); + ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); + ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); + ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); + ImGui::EndTable(); + } + } + + // All demo contents + ShowDemoWindowWidgets(); + ShowDemoWindowLayout(); + ShowDemoWindowPopups(); + ShowDemoWindowTables(); + ShowDemoWindowMisc(); + + // End of ShowDemoWindow() + ImGui::PopItemWidth(); + ImGui::End(); +} + +static void ShowDemoWindowWidgets() +{ + IMGUI_DEMO_MARKER("Widgets"); + if (!ImGui::CollapsingHeader("Widgets")) + return; + + static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom + if (disable_all) + ImGui::BeginDisabled(); + + IMGUI_DEMO_MARKER("Widgets/Basic"); + if (ImGui::TreeNode("Basic")) + { + IMGUI_DEMO_MARKER("Widgets/Basic/Button"); + static int clicked = 0; + if (ImGui::Button("Button")) + clicked++; + if (clicked & 1) + { + ImGui::SameLine(); + ImGui::Text("Thanks for clicking me!"); + } + + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox"); + static bool check = true; + ImGui::Checkbox("checkbox", &check); + + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); + static int e = 0; + ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio c", &e, 2); + + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)"); + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + ImGui::Button("Click"); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + // See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui::AlignTextToFramePadding(); + ImGui::Text("Hold to repeat:"); + ImGui::SameLine(); + + // Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)"); + static int counter = 0; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d", counter); + + IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips"); + ImGui::Text("Hover over me"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip"); + + ImGui::SameLine(); + ImGui::Text("- or me"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::EndTooltip(); + } + + ImGui::Separator(); + ImGui::LabelText("label", "Value"); + + { + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); + } + + { + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); + static char str0[128] = "Hello, world!"; + ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::SameLine(); HelpMarker( + "USER:\n" + "Hold SHIFT or use mouse to select text.\n" + "CTRL+Left/Right to word jump.\n" + "CTRL+A or double-click to select all.\n" + "CTRL+X,CTRL+C,CTRL+V clipboard.\n" + "CTRL+Z,CTRL+Y undo/redo.\n" + "ESCAPE to revert.\n\n" + "PROGRAMMER:\n" + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " + "in imgui_demo.cpp)."); + + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); + static int i0 = 123; + ImGui::InputInt("input int", &i0); + ImGui::SameLine(); HelpMarker( + "You can apply arithmetic operators +,*,/ on numerical values.\n" + " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" + "Use +- to subtract."); + + static float f0 = 0.001f; + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + + static double d0 = 999999.00000001; + ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); + + static float f1 = 1.e10f; + ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); + ImGui::SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" + " e.g. \"1e+8\" becomes \"100000000\"."); + + static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + ImGui::InputFloat3("input float3", vec4a); + } + + { + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); + static int i1 = 50, i2 = 42; + ImGui::DragInt("drag int", &i1, 1); + ImGui::SameLine(); HelpMarker( + "Click and drag to edit value.\n" + "Hold SHIFT/ALT for faster/slower edit.\n" + "Double-click or CTRL+click to input value."); + + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + + static float f1 = 1.00f, f2 = 0.0067f; + ImGui::DragFloat("drag float", &f1, 0.005f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + } + + { + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); + static int i1 = 0; + ImGui::SliderInt("slider int", &i1, -1, 3); + ImGui::SameLine(); HelpMarker("CTRL+click to input value."); + + static float f1 = 0.123f, f2 = 0.0f; + ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); + ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); + + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle"); + static float angle = 0.0f; + ImGui::SliderAngle("slider angle", &angle); + + // Using the format string to display a name instead of an integer. + // Here we completely omit '%d' from the format string, so it'll only display a name. + // This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)"); + enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; + static int elem = Element_Fire; + const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; + const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); + ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); + } + + { + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "Click and hold to use drag and drop.\n" + "Right-click on the color square to show options.\n" + "CTRL+click on individual component to input value.\n"); + + ImGui::ColorEdit4("color 2", col2); + } + + { + // Using the _simplified_ one-liner ListBox() api here + // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); + const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static int item_current = 1; + ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); + } + + ImGui::TreePop(); + } + + // Testing ImGuiOnceUponAFrame helper. + //static ImGuiOnceUponAFrame once; + //for (int i = 0; i < 5; i++) + // if (once) + // ImGui::Text("This will be displayed only once."); + + IMGUI_DEMO_MARKER("Widgets/Trees"); + if (ImGui::TreeNode("Trees")) + { + IMGUI_DEMO_MARKER("Widgets/Trees/Basic trees"); + if (ImGui::TreeNode("Basic trees")) + { + for (int i = 0; i < 5; i++) + { + // Use SetNextItemOpen() so set the default state of a node to be open. We could + // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if (i == 0) + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) + { + ImGui::Text("blah blah"); + ImGui::SameLine(); + if (ImGui::SmallButton("button")) {} + ImGui::TreePop(); + } + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Trees/Advanced, with Selectable nodes"); + if (ImGui::TreeNode("Advanced, with Selectable nodes")) + { + HelpMarker( + "This is a more typical looking tree with selectable nodes.\n" + "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); + static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + static bool align_label_with_current_x_position = false; + static bool test_drag_and_drop = false; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); + ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); + ImGui::Text("Hello!"); + if (align_label_with_current_x_position) + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + + // 'selection_mask' is dumb representation of what may be user-side selection state. + // You may retain selection state inside or outside your objects in whatever format you see fit. + // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end + /// of the loop. May be a pointer to your own node type, etc. + static int selection_mask = (1 << 2); + int node_clicked = -1; + for (int i = 0; i < 6; i++) + { + // Disable the default "open on single-click behavior" + set Selected flag according to our selection. + // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. + ImGuiTreeNodeFlags node_flags = base_flags; + const bool is_selected = (selection_mask & (1 << i)) != 0; + if (is_selected) + node_flags |= ImGuiTreeNodeFlags_Selected; + if (i < 3) + { + // Items 0..2 are Tree Node + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + if (node_open) + { + ImGui::BulletText("Blah blah\nBlah Blah"); + ImGui::TreePop(); + } + } + else + { + // Items 3..5 are Tree Leaves + // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + } + } + if (node_clicked != -1) + { + // Update selection state + // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if (ImGui::GetIO().KeyCtrl) + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + selection_mask = (1 << node_clicked); // Click to single-select + } + if (align_label_with_current_x_position) + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); + if (ImGui::TreeNode("Collapsing Headers")) + { + static bool closable_group = true; + ImGui::Checkbox("Show 2nd header", &closable_group); + if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("Some content %d", i); + } + if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("More content %d", i); + } + /* + if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + */ + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Bullets"); + if (ImGui::TreeNode("Bullets")) + { + ImGui::BulletText("Bullet point 1"); + ImGui::BulletText("Bullet point 2\nOn multiple lines"); + if (ImGui::TreeNode("Tree node")) + { + ImGui::BulletText("Another bullet point"); + ImGui::TreePop(); + } + ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); + ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text"); + if (ImGui::TreeNode("Text")) + { + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text"); + if (ImGui::TreeNode("Colorful Text")) + { + // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); + ImGui::TextDisabled("Disabled"); + ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); + if (ImGui::TreeNode("Word Wrapping")) + { + // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui::TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " + "for text wrapping follows simple rules suitable for English and possibly other languages."); + ImGui::Spacing(); + + static float wrap_width = 200.0f; + ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 2; n++) + { + ImGui::Text("Test paragraph %d:", n); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); + ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + if (n == 0) + ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + else + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + + // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); + ImGui::PopTextWrapPos(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text"); + if (ImGui::TreeNode("UTF-8 Text")) + { + // UTF-8 test with Japanese characters + // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) + // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + // can save your source files as 'UTF-8 without signature'). + // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + // Don't do this in your application! Please use u8"text in any language" in your application! + // Note that characters values are preserved even by InputText() if the font cannot be displayed, + // so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped( + "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " + "Read docs/FONTS.md for details."); + ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. + ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); + static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; + //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis + ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Images"); + if (ImGui::TreeNode("Images")) + { + ImGuiIO& io = ImGui::GetIO(); + ImGui::TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " + "Hover the texture for a zoomed view!"); + + // Below we are displaying the font texture because it is the only texture we have access to inside the demo! + // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that + // will be passed to the rendering backend via the ImDrawCmd structure. + // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + // of their respective source file to specify what they expect to be stored in ImTextureID, for example: + // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer + // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + // More: + // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + // to ImGui::Image(), and gather width/height through your own functions, etc. + // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + // it will help you debug issues if you are confused about it. + // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImTextureID my_tex_id = io.Fonts->TexID; + float my_tex_w = (float)io.Fonts->TexWidth; + float my_tex_h = (float)io.Fonts->TexHeight; + { + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left + ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white + ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + float region_sz = 32.0f; + float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; + float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; + float zoom = 4.0f; + if (region_x < 0.0f) { region_x = 0.0f; } + else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } + if (region_y < 0.0f) { region_y = 0.0f; } + else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } + ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); + ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); + ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); + ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); + ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); + ImGui::EndTooltip(); + } + } + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); + ImGui::TextWrapped("And now some textured buttons.."); + static int pressed_count = 0; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); + int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding) + ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible + ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left + ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture + ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col)) + pressed_count += 1; + ImGui::PopID(); + ImGui::SameLine(); + } + ImGui::NewLine(); + ImGui::Text("Pressed %d times.", pressed_count); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Combo"); + if (ImGui::TreeNode("Combo")) + { + // Expose flags as checkbox for the demo + static ImGuiComboFlags flags = 0; + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) + flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) + flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both + + // Using the generic BeginCombo() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current_idx = 0; // Here we store our selection data as an index. + const char* combo_preview_value = items[item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything) + if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + // Simplified one-liner Combo() API, using values packed in a single constant string + // This is a convenience for when the selection set is small and known at compile-time. + static int item_current_2 = 0; + ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + + // Simplified one-liner Combo() using an array of const char* + // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. + static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview + ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); + + // Simplified one-liner Combo() using an accessor function + struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } }; + static int item_current_4 = 0; + ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items)); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/List Boxes"); + if (ImGui::TreeNode("List boxes")) + { + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current_idx = 0; // Here we store our selection data as an index. + if (ImGui::BeginListBox("listbox 1")) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + // Custom size: use all width, 5 items tall + ImGui::Text("Full-width:"); + if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Selectables"); + if (ImGui::TreeNode("Selectables")) + { + // Selectable() has 2 overloads: + // - The one taking "bool selected" as a read-only selection information. + // When Selectable() has been clicked it returns true and you can alter selection state accordingly. + // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + // The earlier is more flexible, as in real application your selection may be stored in many different ways + // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); + if (ImGui::TreeNode("Basic")) + { + static bool selection[5] = { false, true, false, false, false }; + ImGui::Selectable("1. I am selectable", &selection[0]); + ImGui::Selectable("2. I am selectable", &selection[1]); + ImGui::Text("(I am not selectable)"); + ImGui::Selectable("4. I am selectable", &selection[3]); + if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) + if (ImGui::IsMouseDoubleClicked(0)) + selection[4] = !selection[4]; + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection"); + if (ImGui::TreeNode("Selection State: Single Selection")) + { + static int selected = -1; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selected == n)) + selected = n; + } + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection"); + if (ImGui::TreeNode("Selection State: Multiple Selection")) + { + HelpMarker("Hold CTRL and click to select multiple items."); + static bool selection[5] = { false, false, false, false, false }; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selection[n])) + { + if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held + memset(selection, 0, sizeof(selection)); + selection[n] ^= 1; + } + } + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more text into the same line"); + if (ImGui::TreeNode("Rendering more text into the same line")) + { + // Using the Selectable() override that takes "bool* p_selected" parameter, + // this function toggle your bool value automatically. + static bool selected[3] = { false, false, false }; + ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); + ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/In columns"); + if (ImGui::TreeNode("In columns")) + { + static bool selected[10] = {}; + + if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap + } + ImGui::EndTable(); + } + ImGui::Spacing(); + if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); + ImGui::TableNextColumn(); + ImGui::Text("Some other contents"); + ImGui::TableNextColumn(); + ImGui::Text("123456"); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); + if (ImGui::TreeNode("Grid")) + { + static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; + + // Add in a bit of silly fun... + const float time = (float)ImGui::GetTime(); + const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... + if (winning_state) + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); + + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + { + if (x > 0) + ImGui::SameLine(); + ImGui::PushID(y * 4 + x); + if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) + { + // Toggle clicked cell + toggle neighbors + selected[y][x] ^= 1; + if (x > 0) { selected[y][x - 1] ^= 1; } + if (x < 3) { selected[y][x + 1] ^= 1; } + if (y > 0) { selected[y - 1][x] ^= 1; } + if (y < 3) { selected[y + 1][x] ^= 1; } + } + ImGui::PopID(); + } + + if (winning_state) + ImGui::PopStyleVar(); + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); + if (ImGui::TreeNode("Alignment")) + { + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " + "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); + char name[32]; + sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); + if (x > 0) ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); + ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); + ImGui::PopStyleVar(); + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Text Input"); + if (ImGui::TreeNode("Text Input")) + { + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input"); + if (ImGui::TreeNode("Multi-line Text Input")) + { + // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize + // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. + static char text[1024 * 16] = + "/*\n" + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" + " the hexadecimal encoding of one offending instruction,\n" + " more formally, the invalid operand with locked CMPXCHG8B\n" + " instruction bug, is a design flaw in the majority of\n" + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" + " processors (all in the P5 microarchitecture).\n" + "*/\n\n" + "label:\n" + "\tlock cmpxchg8b eax\n"; + + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input"); + if (ImGui::TreeNode("Filtered Text Input")) + { + struct TextFilters + { + // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' + static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) + { + if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) + return 0; + return 1; + } + }; + + static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); + static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); + static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); + static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); + static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input"); + if (ImGui::TreeNode("Password Input")) + { + static char password[64] = "password123"; + ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Completion, History, Edit Callbacks")) + { + struct Funcs + { + static int MyCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) + { + data->InsertChars(data->CursorPos, ".."); + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) + { + if (data->EventKey == ImGuiKey_UpArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Up!"); + data->SelectAll(); + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Down!"); + data->SelectAll(); + } + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) + { + // Toggle casing of first character + char c = data->Buf[0]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; + data->BufDirty = true; + + // Increment a counter + int* p_int = (int*)data->UserData; + *p_int = *p_int + 1; + } + return 0; + } + }; + static char buf1[64]; + ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf2[64]; + ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf3[64]; + static int edit_count = 0; + ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); + ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits."); + ImGui::SameLine(); ImGui::Text("(%d)", edit_count); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback"); + if (ImGui::TreeNode("Resize Callback")) + { + // To wire InputText() with std::string or any other custom string type, + // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + struct Funcs + { + static int MyResizeCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + ImVector* my_str = (ImVector*)data->UserData; + IM_ASSERT(my_str->begin() == data->Buf); + my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + data->Buf = my_str->begin(); + } + return 0; + } + + // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) + { + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); + } + }; + + // For this demo we are using ImVector as a string container. + // Note that because we need to store a terminating zero character, our size/capacity are 1 more + // than usually reported by a typical string class. + static ImVector my_str; + if (my_str.empty()) + my_str.push_back(0); + Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); + ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + // Tabs + IMGUI_DEMO_MARKER("Widgets/Tabs"); + if (ImGui::TreeNode("Tabs")) + { + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic"); + if (ImGui::TreeNode("Basic")) + { + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button"); + if (ImGui::TreeNode("Advanced & Close Button")) + { + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + if (n > 0) { ImGui::SameLine(); } + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + // the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags"); + if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) + { + static ImVector active_tabs; + static int next_tab_id = 0; + if (next_tab_id == 0) // Initialize with some default tabs + for (int i = 0; i < 3; i++) + active_tabs.push_back(next_tab_id++); + + // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + // but they tend to make more sense together) + static bool show_leading_button = true; + static bool show_trailing_button = true; + ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); + ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); + + // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + // Demo a Leading TabItemButton(): click the "?" button to open a menu + if (show_leading_button) + if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) + ImGui::OpenPopup("MyHelpMenu"); + if (ImGui::BeginPopup("MyHelpMenu")) + { + ImGui::Selectable("Hello!"); + ImGui::EndPopup(); + } + + // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+") + // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if (show_trailing_button) + if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) + active_tabs.push_back(next_tab_id++); // Add new tab + + // Submit our regular tabs + for (int n = 0; n < active_tabs.Size; ) + { + bool open = true; + char name[16]; + snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); + if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", name); + ImGui::EndTabItem(); + } + + if (!open) + active_tabs.erase(active_tabs.Data + n); + else + n++; + } + + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // Plot/Graph widgets are not very good. + // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + IMGUI_DEMO_MARKER("Widgets/Plotting"); + if (ImGui::TreeNode("Plotting")) + { + static bool animate = true; + ImGui::Checkbox("Animate", &animate); + + // Plot as lines and plot as histogram + IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + + // Fill an array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + // and the sizeof() of your structure in the "stride" parameter. + static float values[90] = {}; + static int values_offset = 0; + static double refresh_time = 0.0; + if (!animate || refresh_time == 0.0) + refresh_time = ImGui::GetTime(); + while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo + { + static float phase = 0.0f; + values[values_offset] = cosf(phase); + values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); + phase += 0.10f * values_offset; + refresh_time += 1.0f / 60.0f; + } + + // Plots can display overlay texts + // (in this example, we will display an average value) + { + float average = 0.0f; + for (int n = 0; n < IM_ARRAYSIZE(values); n++) + average += values[n]; + average /= (float)IM_ARRAYSIZE(values); + char overlay[32]; + sprintf(overlay, "avg %f", average); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); + } + + // Use functions to generate output + // FIXME: This is rather awkward because current plot API only pass in indices. + // We probably want an API passing floats and user provide sample rate/count. + struct Funcs + { + static float Sin(void*, int i) { return sinf(i * 0.1f); } + static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } + }; + static int func_type = 0, display_count = 70; + ImGui::Separator(); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::Combo("func", &func_type, "Sin\0Saw\0"); + ImGui::SameLine(); + ImGui::SliderInt("Sample count", &display_count, 1, 400); + float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; + ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::Separator(); + + // Animate a simple progress bar + IMGUI_DEMO_MARKER("Widgets/Plotting/ProgressBar"); + static float progress = 0.0f, progress_dir = 1.0f; + if (animate) + { + progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; + if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } + if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + } + + // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, + // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Progress Bar"); + + float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); + char buf[32]; + sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Color"); + if (ImGui::TreeNode("Color/Picker Widgets")) + { + static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); + + static bool alpha_preview = true; + static bool alpha_half_preview = false; + static bool drag_and_drop = true; + static bool options_menu = true; + static bool hdr = false; + ImGui::Checkbox("With Alpha Preview", &alpha_preview); + ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); + ImGui::Checkbox("With Drag and Drop", &drag_and_drop); + ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); + ImGui::Text("Color widget:"); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "CTRL+click on individual component to input value.\n"); + ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); + ImGui::Text("Color widget HSV with Alpha:"); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); + ImGui::Text("Color widget with Float Display:"); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); + ImGui::Text("Color button with Picker:"); + ImGui::SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " + "be used for the tooltip and picker popup."); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); + ImGui::Text("Color button with Custom Picker Popup:"); + + // Generate a default palette. The palette will persist and can be edited. + static bool saved_palette_init = true; + static ImVec4 saved_palette[32] = {}; + if (saved_palette_init) + { + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, + saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + saved_palette[n].w = 1.0f; // Alpha + } + saved_palette_init = false; + } + + static ImVec4 backup_color; + bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + open_popup |= ImGui::Button("Palette"); + if (open_popup) + { + ImGui::OpenPopup("mypicker"); + backup_color = color; + } + if (ImGui::BeginPopup("mypicker")) + { + ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); + ImGui::Separator(); + ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Current"); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); + ImGui::Text("Previous"); + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) + color = backup_color; + ImGui::Separator(); + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::PushID(n); + if ((n % 8) != 0) + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + + // Allow user to drop colors into each palette entry. Note that ColorButton() is already a + // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::EndPopup(); + } + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)"); + ImGui::Text("Color button only:"); + static bool no_border = false; + ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); + ImGui::Text("Color picker:"); + static bool alpha = true; + static bool alpha_bar = true; + static bool side_preview = true; + static bool ref_color = false; + static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); + static int display_mode = 0; + static int picker_mode = 0; + ImGui::Checkbox("With Alpha", &alpha); + ImGui::Checkbox("With Alpha Bar", &alpha_bar); + ImGui::Checkbox("With Side Preview", &side_preview); + if (side_preview) + { + ImGui::SameLine(); + ImGui::Checkbox("With Ref Color", &ref_color); + if (ref_color) + { + ImGui::SameLine(); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); + } + } + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); + ImGui::SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " + "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex " + "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); + ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); + ImGuiColorEditFlags flags = misc_flags; + if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() + if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; + if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; + if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; + if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays + if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode + if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; + if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; + ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); + + ImGui::Text("Set defaults in code:"); + ImGui::SameLine(); HelpMarker( + "SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" + "encouraging you to persistently save values that aren't forward-compatible."); + if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); + if (ImGui::Button("Default: Float + HDR + Hue Wheel")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + + // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! + ImGui::Spacing(); + ImGui::Text("HSV encoded colors"); + ImGui::SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); + ImGui::Text("Color widget with InputHSV:"); + ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); + if (ImGui::TreeNode("Drag/Slider Flags")) + { + // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + static ImGuiSliderFlags flags = ImGuiSliderFlags_None; + ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); + ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); + ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); + ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); + ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); + ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + + // Drags + static float drag_f = 0.5f; + static int drag_i = 50; + ImGui::Text("Underlying float value: %f", drag_f); + ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); + ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); + + // Sliders + static float slider_f = 0.5f; + static int slider_i = 50; + ImGui::Text("Underlying float value: %f", slider_f); + ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); + ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Range Widgets"); + if (ImGui::TreeNode("Range Widgets")) + { + static float begin = 10, end = 90; + static int begin_i = 100, end_i = 1000; + ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); + ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Data Types"); + if (ImGui::TreeNode("Data Types")) + { + // DragScalar/InputScalar/SliderScalar functions allow various data types + // - signed/unsigned + // - 8/16/32/64-bits + // - integer/float/double + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + // to pass the type, and passing all arguments by pointer. + // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. + // In practice, if you frequently use a given type that is not covered by the normal API entry points, + // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + // and then pass their address to the generic function. For example: + // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + // { + // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + // } + + // Setup limits (as helper variables so we can take their address, as explained above) + // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + #ifndef LLONG_MIN + ImS64 LLONG_MIN = -9223372036854775807LL - 1; + ImS64 LLONG_MAX = 9223372036854775807LL; + ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); + #endif + const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; + const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; + const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; + const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; + const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; + const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; + const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; + const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; + const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; + const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; + + // State + static char s8_v = 127; + static ImU8 u8_v = 255; + static short s16_v = 32767; + static ImU16 u16_v = 65535; + static ImS32 s32_v = -1; + static ImU32 u32_v = (ImU32)-1; + static ImS64 s64_v = -1; + static ImU64 u64_v = (ImU64)-1; + static float f32_v = 0.123f; + static double f64_v = 90000.01234567890123456789; + + const float drag_speed = 0.2f; + static bool drag_clamp = false; + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); + ImGui::Text("Drags:"); + ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); + ImGui::SameLine(); HelpMarker( + "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n" + "You can override the clamping limits by using CTRL+Click to input a value."); + ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); + ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); + ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); + ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); + ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); + ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); + ImGui::Text("Sliders"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); + ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); + ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); + ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); + ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); + + ImGui::Text("Sliders (reverse)"); + ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); + ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); + ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); + ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); + ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); + static bool inputs_step = true; + ImGui::Text("Inputs"); + ImGui::Checkbox("Show step buttons", &inputs_step); + ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); + ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); + ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); + ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); + if (ImGui::TreeNode("Multi-component Widgets")) + { + static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static int vec4i[4] = { 1, 5, 100, 255 }; + + ImGui::InputFloat2("input float2", vec4f); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::InputInt2("input int2", vec4i); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); + ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat3("input float3", vec4f); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::InputInt3("input int3", vec4i); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); + ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat4("input float4", vec4f); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); + ImGui::InputInt4("input int4", vec4i); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); + ImGui::SliderInt4("slider int4", vec4i, 0, 255); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); + if (ImGui::TreeNode("Vertical Sliders")) + { + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); + ImGui::SameLine(); + + static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; + ImGui::PushID("set1"); + for (int i = 0; i < 7; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values[i]); + ImGui::PopStyleColor(4); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx * rows + ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); + ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::PopStyleVar(); + ImGui::PopID(); + } + ImGui::PopID(); + ImGui::PopStyleVar(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and drop"); + if (ImGui::TreeNode("Drag and Drop")) + { + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets"); + if (ImGui::TreeNode("Drag and drop in standard widgets")) + { + // ColorEdit widgets automatically act as drag source and drag target. + // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + // to allow your own widgets to use colors in their drag and drop interaction. + // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares."); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::ColorEdit4("color 2", col2); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items"); + if (ImGui::TreeNode("Drag and drop to copy/swap items")) + { + enum Mode + { + Mode_Copy, + Mode_Move, + Mode_Swap + }; + static int mode = 0; + if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); + if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + static const char* names[9] = + { + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }; + for (int n = 0; n < IM_ARRAYSIZE(names); n++) + { + ImGui::PushID(n); + if ((n % 3) != 0) + ImGui::SameLine(); + ImGui::Button(names[n], ImVec2(60, 60)); + + // Our buttons are both drag sources and drag targets here! + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + // Set payload to carry the index of our item (could be anything) + ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); + + // Display preview (could be anything, e.g. when dragging an image we could decide to display + // the filename and a small preview of the image, etc.) + if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } + if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } + if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } + ImGui::EndDragDropSource(); + } + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) + { + IM_ASSERT(payload->DataSize == sizeof(int)); + int payload_n = *(const int*)payload->Data; + if (mode == Mode_Copy) + { + names[n] = names[payload_n]; + } + if (mode == Mode_Move) + { + names[n] = names[payload_n]; + names[payload_n] = ""; + } + if (mode == Mode_Swap) + { + const char* tmp = names[n]; + names[n] = names[payload_n]; + names[payload_n] = tmp; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); + if (ImGui::TreeNode("Drag to reorder items (simple)")) + { + // Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " + "Instead we query when the item is held but not hovered, and order items accordingly."); + static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; + for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) + { + const char* item = item_names[n]; + ImGui::Selectable(item); + + if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) + { + int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); + if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) + { + item_names[n] = item_names[n_next]; + item_names[n_next] = item; + ImGui::ResetMouseDragDelta(); + } + } + } + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); + if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) + { + // Select an item type + const char* item_names[] = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + }; + static int item_type = 4; + static bool item_disabled = false; + ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); + ImGui::SameLine(); + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); + ImGui::Checkbox("Item Disabled", &item_disabled); + + // Submit selected item item so we can query their status in the code following it. + bool ret = false; + static bool b = false; + static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + static char str[16] = {}; + if (item_disabled) + ImGui::BeginDisabled(true); + if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction + if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button + if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) + if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox + if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) + if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) + if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input + if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item + if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } + if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + + // Display the values of IsItemHovered() and other common item state functions. + // Note that the ImGuiHoveredFlags_XXX flags can be combined. + // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + // we query every state in a single call to avoid storing them and to simplify the code. + ImGui::BulletText( + "Return value = %d\n" + "IsItemFocused() = %d\n" + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_AllowWhenDisabled) = %d\n" + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemEdited() = %d\n" + "IsItemActivated() = %d\n" + "IsItemDeactivated() = %d\n" + "IsItemDeactivatedAfterEdit() = %d\n" + "IsItemVisible() = %d\n" + "IsItemClicked() = %d\n" + "IsItemToggledOpen() = %d\n" + "GetItemRectMin() = (%.1f, %.1f)\n" + "GetItemRectMax() = (%.1f, %.1f)\n" + "GetItemRectSize() = (%.1f, %.1f)", + ret, + ImGui::IsItemFocused(), + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemEdited(), + ImGui::IsItemActivated(), + ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterEdit(), + ImGui::IsItemVisible(), + ImGui::IsItemClicked(), + ImGui::IsItemToggledOpen(), + ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, + ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, + ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y + ); + + if (item_disabled) + ImGui::EndDisabled(); + + char buf[1] = ""; + ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); + ImGui::SameLine(); + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)"); + if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) + { + static bool embed_all_inside_a_child_window = false; + ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); + if (embed_all_inside_a_child_window) + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); + + // Testing IsWindowFocused() function with its various flags. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + + // Testing IsWindowHovered() function with its various flags. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); + + ImGui::BeginChild("child", ImVec2(0, 50), true); + ImGui::Text("This is another child window for testing the _ChildWindows flag."); + ImGui::EndChild(); + if (embed_all_inside_a_child_window) + ImGui::EndChild(); + + // Calling IsItemHovered() after begin returns the hovered status of the title bar. + // This is useful in particular if you want to create a context menu associated to the title bar of a window. + static bool test_window = false; + ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); + if (test_window) + { + ImGui::Begin("Title bar Hovered/Active tests", &test_window); + if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() + { + if (ImGui::MenuItem("Close")) { test_window = false; } + ImGui::EndPopup(); + } + ImGui::Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + ImGui::IsItemHovered(), ImGui::IsItemActive()); + ImGui::End(); + } + + ImGui::TreePop(); + } + + // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd: + // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space) + if (disable_all) + ImGui::EndDisabled(); + + IMGUI_DEMO_MARKER("Widgets/Disable Block"); + if (ImGui::TreeNode("Disable block")) + { + ImGui::Checkbox("Disable entire section above", &disable_all); + ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section."); + ImGui::TreePop(); + } +} + +static void ShowDemoWindowLayout() +{ + IMGUI_DEMO_MARKER("Layout"); + if (!ImGui::CollapsingHeader("Layout & Scrolling")) + return; + + IMGUI_DEMO_MARKER("Layout/Child windows"); + if (ImGui::TreeNode("Child windows")) + { + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); + static bool disable_mouse_wheel = false; + static bool disable_menu = false; + ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); + ImGui::Checkbox("Disable Menu", &disable_menu); + + // Child 1: no border, enable horizontal scrollbar + { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), false, window_flags); + for (int i = 0; i < 100; i++) + ImGui::Text("%04d: scrollable region", i); + ImGui::EndChild(); + } + + ImGui::SameLine(); + + // Child 2: rounded border + { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + if (!disable_menu) + window_flags |= ImGuiWindowFlags_MenuBar; + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); + ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); + if (!disable_menu && ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) + { + for (int i = 0; i < 100; i++) + { + char buf[32]; + sprintf(buf, "%03d", i); + ImGui::TableNextColumn(); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + ImGui::EndTable(); + } + ImGui::EndChild(); + ImGui::PopStyleVar(); + } + + ImGui::Separator(); + + // Demonstrate a few extra things + // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) + // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + // You can also call SetNextWindowPos() to position the child window. The parent window will effectively + // layout from this position. + // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from + // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. + { + static int offset_x = 0; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); + ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); + for (int n = 0; n < 50; n++) + ImGui::Text("Some test %d", n); + ImGui::EndChild(); + bool child_is_hovered = ImGui::IsItemHovered(); + ImVec2 child_rect_min = ImGui::GetItemRectMin(); + ImVec2 child_rect_max = ImGui::GetItemRectMax(); + ImGui::PopStyleColor(); + ImGui::Text("Hovered: %d", child_is_hovered); + ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Widgets Width"); + if (ImGui::TreeNode("Widgets Width")) + { + static float f = 0.0f; + static bool show_indented_items = true; + ImGui::Checkbox("Show indented items", &show_indented_items); + + // Use SetNextItemWidth() to set the width of a single upcoming item. + // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. + // In real code use you'll probably want to choose width values that are proportional to your font size + // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + + ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); + ImGui::SameLine(); HelpMarker("Fixed width."); + ImGui::PushItemWidth(100); + ImGui::DragFloat("float##1b", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##1b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + + ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); + ImGui::PushItemWidth(-100); + ImGui::DragFloat("float##2a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##2b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + + ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); + ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::DragFloat("float##3a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##3b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + + ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus half"); + ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::DragFloat("float##4a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##4b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + + // Demonstrate using PushItemWidth to surround three items. + // Calling SetNextItemWidth() before each of them would have the same effect. + ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); + ImGui::SameLine(); HelpMarker("Align to right edge"); + ImGui::PushItemWidth(-FLT_MIN); + ImGui::DragFloat("##float5a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##5b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout"); + if (ImGui::TreeNode("Basic Horizontal Layout")) + { + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); + + // Text + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine"); + ImGui::Text("Two items: Hello"); ImGui::SameLine(); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Adjust spacing + ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Button + ImGui::AlignTextToFramePadding(); + ImGui::Text("Normal buttons"); ImGui::SameLine(); + ImGui::Button("Banana"); ImGui::SameLine(); + ImGui::Button("Apple"); ImGui::SameLine(); + ImGui::Button("Corniflower"); + + // Button + ImGui::Text("Small buttons"); ImGui::SameLine(); + ImGui::SmallButton("Like this one"); ImGui::SameLine(); + ImGui::Text("can fit within a text block."); + + // Aligned to arbitrary position. Easy/cheap column. + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)"); + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::Text("x=150"); + ImGui::SameLine(300); ImGui::Text("x=300"); + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::SmallButton("x=150"); + ImGui::SameLine(300); ImGui::SmallButton("x=300"); + + // Checkbox + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)"); + static bool c1 = false, c2 = false, c3 = false, c4 = false; + ImGui::Checkbox("My", &c1); ImGui::SameLine(); + ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); + ImGui::Checkbox("Is", &c3); ImGui::SameLine(); + ImGui::Checkbox("Rich", &c4); + + // Various + static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; + ImGui::PushItemWidth(80); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; + static int item = -1; + ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); + ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); + ImGui::PopItemWidth(); + + ImGui::PushItemWidth(80); + ImGui::Text("Lists:"); + static int selection[4] = { 0, 1, 2, 3 }; + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); + ImGui::PopID(); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + } + ImGui::PopItemWidth(); + + // Dummy + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy"); + ImVec2 button_sz(40, 40); + ImGui::Button("A", button_sz); ImGui::SameLine(); + ImGui::Dummy(button_sz); ImGui::SameLine(); + ImGui::Button("B", button_sz); + + // Manually wrapping + // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping"); + ImGui::Text("Manual wrapping:"); + ImGuiStyle& style = ImGui::GetStyle(); + int buttons_count = 20; + float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; + for (int n = 0; n < buttons_count; n++) + { + ImGui::PushID(n); + ImGui::Button("Box", button_sz); + float last_button_x2 = ImGui::GetItemRectMax().x; + float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line + if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) + ImGui::SameLine(); + ImGui::PopID(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Groups"); + if (ImGui::TreeNode("Groups")) + { + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); + ImGui::BeginGroup(); + { + ImGui::BeginGroup(); + ImGui::Button("AAA"); + ImGui::SameLine(); + ImGui::Button("BBB"); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Button("CCC"); + ImGui::Button("DDD"); + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::Button("EEE"); + ImGui::EndGroup(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("First group hovered"); + } + // Capture the group size and create widgets using the same size + ImVec2 size = ImGui::GetItemRectSize(); + const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); + + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); + ImGui::SameLine(); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::Button("LEVERAGE\nBUZZWORD", size); + ImGui::SameLine(); + + if (ImGui::BeginListBox("List", size)) + { + ImGui::Selectable("Selected", true); + ImGui::Selectable("Not Selected", false); + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment"); + if (ImGui::TreeNode("Text Baseline Alignment")) + { + { + ImGui::BulletText("Text baseline:"); + ImGui::SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); + ImGui::Indent(); + + ImGui::Text("KO Blahblah"); ImGui::SameLine(); + ImGui::Button("Some framed item"); ImGui::SameLine(); + HelpMarker("Baseline of button will look misaligned with text.."); + + // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + // (because we don't know what's coming after the Text() statement, we need to move the text baseline + // down by FramePadding.y ahead of time) + ImGui::AlignTextToFramePadding(); + ImGui::Text("OK Blahblah"); ImGui::SameLine(); + ImGui::Button("Some framed item"); ImGui::SameLine(); + HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); + + // SmallButton() uses the same vertical padding as Text + ImGui::Button("TEST##1"); ImGui::SameLine(); + ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::SmallButton("TEST##2"); + + // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + ImGui::AlignTextToFramePadding(); + ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); + ImGui::Button("Item##1"); ImGui::SameLine(); + ImGui::Text("Item"); ImGui::SameLine(); + ImGui::SmallButton("Item##2"); ImGui::SameLine(); + ImGui::Button("Item##3"); + + ImGui::Unindent(); + } + + ImGui::Spacing(); + + { + ImGui::BulletText("Multi-line text:"); + ImGui::Indent(); + ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("One\nTwo\nThree"); + + ImGui::Button("HOP##1"); ImGui::SameLine(); + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("HOP##2"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + ImGui::Unindent(); + } + + ImGui::Spacing(); + + { + ImGui::BulletText("Misc items:"); + ImGui::Indent(); + + // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. + ImGui::Button("80x80", ImVec2(80, 80)); + ImGui::SameLine(); + ImGui::Button("50x50", ImVec2(50, 50)); + ImGui::SameLine(); + ImGui::Button("Button()"); + ImGui::SameLine(); + ImGui::SmallButton("SmallButton()"); + + // Tree + const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::Button("Button##1"); + ImGui::SameLine(0.0f, spacing); + if (ImGui::TreeNode("Node##1")) + { + // Placeholder tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } + + // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + // Otherwise you can use SmallButton() (smaller fit). + ImGui::AlignTextToFramePadding(); + + // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + // other contents below the node. + bool node_open = ImGui::TreeNode("Node##2"); + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); + if (node_open) + { + // Placeholder tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } + + // Bullet + ImGui::Button("Button##3"); + ImGui::SameLine(0.0f, spacing); + ImGui::BulletText("Bullet text"); + + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Node"); + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); + ImGui::Unindent(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Scrolling"); + if (ImGui::TreeNode("Scrolling")) + { + // Vertical scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical"); + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); + + static int track_item = 50; + static bool enable_track = true; + static bool enable_extra_decorations = false; + static float scroll_to_off_px = 0.0f; + static float scroll_to_pos_px = 200.0f; + + ImGui::Checkbox("Decoration", &enable_extra_decorations); + + ImGui::Checkbox("Track", &enable_track); + ImGui::PushItemWidth(100); + ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); + + bool scroll_to_off = ImGui::Button("Scroll Offset"); + ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); + + bool scroll_to_pos = ImGui::Button("Scroll To Pos"); + ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); + ImGui::PopItemWidth(); + + if (scroll_to_off || scroll_to_pos) + enable_track = false; + + ImGuiStyle& style = ImGui::GetStyle(); + float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; + if (child_w < 1.0f) + child_w = 1.0f; + ImGui::PushID("##VerticalScrolling"); + for (int i = 0; i < 5; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; + ImGui::TextUnformatted(names[i]); + + const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; + const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); + if (ImGui::BeginMenuBar()) + { + ImGui::TextUnformatted("abc"); + ImGui::EndMenuBar(); + } + if (scroll_to_off) + ImGui::SetScrollY(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items + { + for (int item = 0; item < 100; item++) + { + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom + } + else + { + ImGui::Text("Item %d", item); + } + } + } + float scroll_y = ImGui::GetScrollY(); + float scroll_max_y = ImGui::GetScrollMaxY(); + ImGui::EndChild(); + ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); + ImGui::EndGroup(); + } + ImGui::PopID(); + + // Horizontal scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal"); + ImGui::Spacing(); + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " + "equivalent SetScrollFromPosY(+1) wouldn't."); + ImGui::PushID("##HorizontalScrolling"); + for (int i = 0; i < 5; i++) + { + float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; + ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); + ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); + if (scroll_to_off) + ImGui::SetScrollX(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items + { + for (int item = 0; item < 100; item++) + { + if (item > 0) + ImGui::SameLine(); + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + } + else + { + ImGui::Text("Item %d", item); + } + } + } + float scroll_x = ImGui::GetScrollX(); + float scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::SameLine(); + const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; + ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); + ImGui::Spacing(); + } + ImGui::PopID(); + + // Miscellaneous Horizontal Scrolling Demo + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)"); + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); + static int lines = 7; + ImGui::SliderInt("Lines", &lines, 1, 15); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); + ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); + ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); + for (int line = 0; line < lines; line++) + { + // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + // If you want to create your own time line for a real application you may be better off manipulating + // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + // yourself. You may also want to use the lower-level ImDrawList API. + int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + for (int n = 0; n < num_buttons; n++) + { + if (n > 0) ImGui::SameLine(); + ImGui::PushID(n + line * 1000); + char num_buf[16]; + sprintf(num_buf, "%d", n); + const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; + float hue = n * 0.05f; + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); + ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + } + float scroll_x = ImGui::GetScrollX(); + float scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::PopStyleVar(2); + float scroll_x_delta = 0.0f; + ImGui::SmallButton("<<"); + if (ImGui::IsItemActive()) + scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); + ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::SmallButton(">>"); + if (ImGui::IsItemActive()) + scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); + ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); + if (scroll_x_delta != 0.0f) + { + // Demonstrate a trick: you can use Begin to set yourself in the context of another window + // (here we are already out of your child window) + ImGui::BeginChild("scrolling"); + ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); + ImGui::EndChild(); + } + ImGui::Spacing(); + + static bool show_horizontal_contents_size_demo_window = false; + ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); + + if (show_horizontal_contents_size_demo_window) + { + static bool show_h_scrollbar = true; + static bool show_button = true; + static bool show_tree_nodes = true; + static bool show_text_wrapped = false; + static bool show_columns = true; + static bool show_tab_bar = true; + static bool show_child = false; + static bool explicit_content_size = false; + static float contents_size_x = 300.0f; + if (explicit_content_size) + ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); + ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window"); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); + HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); + ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); + ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size + ImGui::Checkbox("Columns", &show_columns); // Will use contents size + ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Child", &show_child); // Will grow and use contents size + ImGui::Checkbox("Explicit content size", &explicit_content_size); + ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); + if (explicit_content_size) + { + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + ImGui::DragFloat("##csx", &contents_size_x); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); + ImGui::Dummy(ImVec2(0, 10)); + } + ImGui::PopStyleVar(2); + ImGui::Separator(); + if (show_button) + { + ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); + } + if (show_tree_nodes) + { + bool open = true; + if (ImGui::TreeNode("this is a tree node")) + { + if (ImGui::TreeNode("another one of those tree node...")) + { + ImGui::Text("Some tree contents"); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + ImGui::CollapsingHeader("CollapsingHeader", &open); + } + if (show_text_wrapped) + { + ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); + } + if (show_columns) + { + ImGui::Text("Tables:"); + if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) + { + for (int n = 0; n < 4; n++) + { + ImGui::TableNextColumn(); + ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); + } + ImGui::EndTable(); + } + ImGui::Text("Columns:"); + ImGui::Columns(4); + for (int n = 0; n < 4; n++) + { + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::NextColumn(); + } + ImGui::Columns(1); + } + if (show_tab_bar && ImGui::BeginTabBar("Hello")) + { + if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } + ImGui::EndTabBar(); + } + if (show_child) + { + ImGui::BeginChild("child", ImVec2(0, 0), true); + ImGui::EndChild(); + } + ImGui::End(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Layout/Clipping"); + if (ImGui::TreeNode("Clipping")) + { + static ImVec2 size(100.0f, 100.0f); + static ImVec2 offset(30.0f, 30.0f); + ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); + ImGui::TextWrapped("(Click and drag to scroll)"); + + for (int n = 0; n < 3; n++) + { + if (n > 0) + ImGui::SameLine(); + ImGui::PushID(n); + ImGui::BeginGroup(); // Lock X position + + ImGui::InvisibleButton("##empty", size); + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + { + offset.x += ImGui::GetIO().MouseDelta.x; + offset.y += ImGui::GetIO().MouseDelta.y; + } + const ImVec2 p0 = ImGui::GetItemRectMin(); + const ImVec2 p1 = ImGui::GetItemRectMax(); + const char* text_str = "Line 1 hello\nLine 2 clip me!"; + const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + switch (n) + { + case 0: + HelpMarker( + "Using ImGui::PushClipRect():\n" + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" + "(use this if you want your clipping rectangle to affect interactions)"); + ImGui::PushClipRect(p0, p1, true); + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); + ImGui::PopClipRect(); + break; + case 1: + HelpMarker( + "Using ImDrawList::PushClipRect():\n" + "Will alter ImDrawList rendering only.\n" + "(use this as a shortcut if you are only using ImDrawList calls)"); + draw_list->PushClipRect(p0, p1, true); + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); + draw_list->PopClipRect(); + break; + case 2: + HelpMarker( + "Using ImDrawList::AddText() with a fine ClipRect:\n" + "Will alter only this specific ImDrawList::AddText() rendering.\n" + "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)"); + ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. + draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); + draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); + break; + } + ImGui::EndGroup(); + ImGui::PopID(); + } + + ImGui::TreePop(); + } +} + +static void ShowDemoWindowPopups() +{ + IMGUI_DEMO_MARKER("Popups"); + if (!ImGui::CollapsingHeader("Popups & Modal windows")) + return; + + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as + // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even + // when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close + // popups at any time. + + // Typical use for regular windows: + // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); + // Typical use for popups: + // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } + + // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. + // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. + + IMGUI_DEMO_MARKER("Popups/Popups"); + if (ImGui::TreeNode("Popups")) + { + ImGui::TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " + "Clicking outside the popup closes it."); + + static int selected_fish = -1; + const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; + static bool toggles[] = { true, false, false, false, false }; + + // Simple selection popup (if you want to show the current selection inside the Button itself, + // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if (ImGui::Button("Select..")) + ImGui::OpenPopup("my_select_popup"); + ImGui::SameLine(); + ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); + if (ImGui::BeginPopup("my_select_popup")) + { + ImGui::Text("Aquarium"); + ImGui::Separator(); + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + if (ImGui::Selectable(names[i])) + selected_fish = i; + ImGui::EndPopup(); + } + + // Showing a menu with toggles + if (ImGui::Button("Toggle..")) + ImGui::OpenPopup("my_toggle_popup"); + if (ImGui::BeginPopup("my_toggle_popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + ImGui::EndMenu(); + } + + ImGui::Separator(); + ImGui::Text("Tooltip here"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip over a popup"); + + if (ImGui::Button("Stacked Popup")) + ImGui::OpenPopup("another popup"); + if (ImGui::BeginPopup("another popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + if (ImGui::Button("Stacked Popup")) + ImGui::OpenPopup("another popup"); + if (ImGui::BeginPopup("another popup")) + { + ImGui::Text("I am the last one here."); + ImGui::EndPopup(); + } + ImGui::EndMenu(); + } + ImGui::EndPopup(); + } + ImGui::EndPopup(); + } + + // Call the more complete ShowExampleMenuFile which we use in various places of this demo + if (ImGui::Button("With a menu..")) + ImGui::OpenPopup("my_file_popup"); + if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + ImGui::MenuItem("Dummy"); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from popup!"); + ImGui::Button("This is a dummy button.."); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Popups/Context menus"); + if (ImGui::TreeNode("Context menus")) + { + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); + + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + // if (id == 0) + // id = GetItemID(); // Use last item id + // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + // OpenPopup(id); + // return BeginPopup(id); + // For advanced advanced uses you may want to replicate and customize this code. + // See more details in BeginPopupContextItem(). + + // Example 1 + // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + // and BeginPopupContextItem() will use the last item ID as the popup ID. + { + const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" }; + for (int n = 0; n < 5; n++) + { + ImGui::Selectable(names[n]); + if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id + { + ImGui::Text("This a popup for \"%s\"!", names[n]); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Right-click to open popup"); + } + } + + // Example 2 + // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + // Using an explicit identifier is also convenient if you want to activate the popups from different locations. + { + HelpMarker("Text() elements don't have stable identifiers so we need to provide one."); + static float value = 0.5f; + ImGui::Text("Value = %.3f <-- (1) right-click this value", value); + if (ImGui::BeginPopupContextItem("my popup")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = 3.1415f; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::EndPopup(); + } + + // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + // Here we make it that right-clicking this other text element opens the same popup as above. + // The popup itself will be submitted by the code above. + ImGui::Text("(2) Or right-click this text"); + ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight); + + // Back to square one: manually open the same popup. + if (ImGui::Button("(3) Or click this button")) + ImGui::OpenPopup("my popup"); + } + + // Example 3 + // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID), + // we need to make sure your item identifier is stable. + // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + { + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator."); + static char name[32] = "Label1"; + char buf[64]; + sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label + ImGui::Button(buf); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("Edit name:"); + ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Popups/Modals"); + if (ImGui::TreeNode("Modals")) + { + ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); + + if (ImGui::Button("Delete..")) + ImGui::OpenPopup("Delete?"); + + // Always center this window when appearing + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); + ImGui::Separator(); + + //static int unused_i = 0; + //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); + + static bool dont_ask_me_next_time = false; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); + ImGui::PopStyleVar(); + + if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (ImGui::Button("Stacked modals..")) + ImGui::OpenPopup("Stacked 1"); + if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Some menu item")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + + // Testing behavior of widgets stacking their own regular popups over the modal. + static int item = 1; + static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::ColorEdit4("color", color); + + if (ImGui::Button("Add another modal..")) + ImGui::OpenPopup("Stacked 2"); + + // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + // of the bool actually doesn't matter here. + bool unused_open = true; + if (ImGui::BeginPopupModal("Stacked 2", &unused_open)) + { + ImGui::Text("Hello from Stacked The Second!"); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Popups/Menus inside a regular window"); + if (ImGui::TreeNode("Menus inside a regular window")) + { + ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::Separator(); + + // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the + // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block + // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would + // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, + // which is the desired behavior for regular menus. + ImGui::PushID("foo"); + ImGui::MenuItem("Menu item", "CTRL+M"); + if (ImGui::BeginMenu("Menu inside a regular window")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::PopID(); + ImGui::Separator(); + ImGui::TreePop(); + } +} + +// Dummy data structure that we use for the Table demo. +// (pre-C++11 doesn't allow us to instantiate ImVector template if this structure if defined inside the demo function) +namespace +{ +// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. +// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. +// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) +// If you don't use sorting, you will generally never care about giving column an ID! +enum MyItemColumnID +{ + MyItemColumnID_ID, + MyItemColumnID_Name, + MyItemColumnID_Action, + MyItemColumnID_Quantity, + MyItemColumnID_Description +}; + +struct MyItem +{ + int ID; + const char* Name; + int Quantity; + + // We have a problem which is affecting _only this demo_ and should not affect your code: + // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), + // however qsort doesn't allow passing user data to comparing function. + // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. + // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. + // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called + // very often by the sorting algorithm it would be a little wasteful. + static const ImGuiTableSortSpecs* s_current_sort_specs; + + // Compare function to be used by qsort() + static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) + { + const MyItem* a = (const MyItem*)lhs; + const MyItem* b = (const MyItem*)rhs; + for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) + { + // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() + // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler! + const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n]; + int delta = 0; + switch (sort_spec->ColumnUserID) + { + case MyItemColumnID_ID: delta = (a->ID - b->ID); break; + case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break; + case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break; + case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break; + default: IM_ASSERT(0); break; + } + if (delta > 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1; + if (delta < 0) + return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1; + } + + // qsort() is instable so always return a way to differenciate items. + // Your own compare function may want to avoid fallback on implicit sort specs e.g. a Name compare if it wasn't already part of the sort specs. + return (a->ID - b->ID); + } +}; +const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; +} + +// Make the UI compact because there are so many fields +static void PushStyleCompact() +{ + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); +} + +static void PopStyleCompact() +{ + ImGui::PopStyleVar(2); +} + +// Show a combo box with a choice of sizing policies +static void EditTableSizingFlags(ImGuiTableFlags* p_flags) +{ + struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; + static const EnumDesc policies[] = + { + { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, + { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, + { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, + { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." }, + { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." } + }; + int idx; + for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++) + if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_)) + break; + const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : ""; + if (ImGui::BeginCombo("Sizing Policy", preview_text)) + { + for (int n = 0; n < IM_ARRAYSIZE(policies); n++) + if (ImGui::Selectable(policies[n].Name, idx == n)) + *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value; + ImGui::EndCombo(); + } + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f); + for (int m = 0; m < IM_ARRAYSIZE(policies); m++) + { + ImGui::Separator(); + ImGui::Text("%s:", policies[m].Name); + ImGui::Separator(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f); + ImGui::TextUnformatted(policies[m].Tooltip); + } + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) +{ + ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)"); + ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide); + ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort); + if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch)) + *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch); + if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed)) + *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed); + ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize); + ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder); + ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide); + ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip); + ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort); + ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending); + ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending); + ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel); + ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth); + ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending); + ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending); + ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0"); + ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0"); +} + +static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) +{ + ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled); + ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible); + ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted); + ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered); +} + +static void ShowDemoWindowTables() +{ + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + IMGUI_DEMO_MARKER("Tables"); + if (!ImGui::CollapsingHeader("Tables & Columns")) + return; + + // Using those as a base value to create width/height that are factor of the size of our font + const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; + const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); + + ImGui::PushID("Tables"); + + int open_action = -1; + if (ImGui::Button("Open all")) + open_action = 1; + ImGui::SameLine(); + if (ImGui::Button("Close all")) + open_action = 0; + ImGui::SameLine(); + + // Options + static bool disable_indent = false; + ImGui::Checkbox("Disable tree indentation", &disable_indent); + ImGui::SameLine(); + HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width."); + ImGui::Separator(); + if (disable_indent) + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); + + // About Styling of tables + // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. + // There are however a few settings that a shared and part of the ImGuiStyle structure: + // style.CellPadding // Padding within each cell + // style.Colors[ImGuiCol_TableHeaderBg] // Table header background + // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders + // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders + // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows) + // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) + + // Demos + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Basic"); + if (ImGui::TreeNode("Basic")) + { + // Here we will showcase three different ways to output a table. + // They are very simple variations of a same thing! + + // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. + // In many situations, this is the most flexible and easy to use pattern. + HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop."); + if (ImGui::BeginTable("table1", 3)) + { + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Row %d Column %d", row, column); + } + } + ImGui::EndTable(); + } + + // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). + // This is generally more convenient when you have code manually submitting the contents of each columns. + HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually."); + if (ImGui::BeginTable("table2", 3)) + { + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Row %d", row); + ImGui::TableNextColumn(); + ImGui::Text("Some contents"); + ImGui::TableNextColumn(); + ImGui::Text("123.456"); + } + ImGui::EndTable(); + } + + // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), + // as TableNextColumn() will automatically wrap around and create new roes as needed. + // This is generally more convenient when your cells all contains the same type of data. + HelpMarker( + "Only using TableNextColumn(), which tends to be convenient for tables where every cells contains the same type of contents.\n" + "This is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition."); + if (ImGui::BeginTable("table3", 3)) + { + for (int item = 0; item < 14; item++) + { + ImGui::TableNextColumn(); + ImGui::Text("Item %d", item); + } + ImGui::EndTable(); + } + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Borders, background"); + if (ImGui::TreeNode("Borders, background")) + { + // Expose a few Borders related flags interactively + enum ContentsType { CT_Text, CT_FillButton }; + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; + static bool display_headers = false; + static int contents_type = CT_Text; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); + ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH"); + ImGui::Indent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); + ImGui::Unindent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); + ImGui::Unindent(); + + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner); + ImGui::Unindent(); + + ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); + ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); + ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); + ImGui::Checkbox("Display headers", &display_headers); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers"); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + // Display headers so we can inspect their interaction with borders. + // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them too much. See other sections for details) + if (display_headers) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + char buf[32]; + sprintf(buf, "Hello %d,%d", column, row); + if (contents_type == CT_Text) + ImGui::TextUnformatted(buf); + else if (contents_type) + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, stretch"); + if (ImGui::TreeNode("Resizable, stretch")) + { + // By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch" + // Each columns maintain a sizing weight, and they will occupy all available width. + static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this."); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, fixed"); + if (ImGui::TreeNode("Resizable, fixed")) + { + // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) + // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) + // If there is not enough available width to fit all columns, they will however be resized down. + // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings + HelpMarker( + "Using _Resizable + _SizingFixedFit flags.\n" + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" + "Double-click a column border to auto-fit the column to its contents."); + PushStyleCompact(); + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Resizable, mixed"); + if (ImGui::TreeNode("Resizable, mixed")) + { + HelpMarker( + "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch."); + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + + if (ImGui::BeginTable("table1", 3, flags)) + { + ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableHeadersRow(); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row); + } + } + ImGui::EndTable(); + } + if (ImGui::BeginTable("table2", 6, flags)) + { + ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide); + ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide); + ImGui::TableHeadersRow(); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 6; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers"); + if (ImGui::TreeNode("Reorderable, hideable, with headers")) + { + HelpMarker( + "Click and drag column headers to reorder columns.\n\n" + "Right-click on a header to open a context menu."); + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)"); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 3, flags)) + { + // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. + // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column) + if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f))) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Fixed %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Padding"); + if (ImGui::TreeNode("Padding")) + { + // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. + // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" + "e.g.:\n" + "- BorderOuterV\n" + "- any form of row selection\n" + "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n" + "Actual padding values are using style.CellPadding.\n\n" + "In this demo we don't show horizontal borders to emphasis how they don't affect default horizontal padding."); + + static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX); + ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX); + ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX); + ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)"); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV); + static bool show_headers = false; + ImGui::Checkbox("show_headers", &show_headers); + PopStyleCompact(); + + if (ImGui::BeginTable("table_padding", 3, flags1)) + { + if (show_headers) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + { + ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); + } + else + { + char buf[32]; + sprintf(buf, "Hello %d,%d", column, row); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) + // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); + } + } + ImGui::EndTable(); + } + + // Second example: set style.CellPadding to (0.0) or a custom value. + // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... + HelpMarker("Setting style.CellPadding to (0,0) or a custom value."); + static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; + static ImVec2 cell_padding(0.0f, 0.0f); + static bool show_widget_frame_bg = true; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable); + ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg); + ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f"); + PopStyleCompact(); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding); + if (ImGui::BeginTable("table_padding_2", 3, flags2)) + { + static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells + static bool init = true; + if (!show_widget_frame_bg) + ImGui::PushStyleColor(ImGuiCol_FrameBg, 0); + for (int cell = 0; cell < 3 * 5; cell++) + { + ImGui::TableNextColumn(); + if (init) + strcpy(text_bufs[cell], "edit me"); + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::PushID(cell); + ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell])); + ImGui::PopID(); + } + if (!show_widget_frame_bg) + ImGui::PopStyleColor(); + init = false; + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Explicit widths"); + if (ImGui::TreeNode("Sizing policies")) + { + static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX); + PopStyleCompact(); + + static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame }; + for (int table_n = 0; table_n < 4; table_n++) + { + ImGui::PushID(table_n); + ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30); + EditTableSizingFlags(&sizing_policy_flags[table_n]); + + // To make it easier to understand the different sizing policy, + // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width. + if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1)) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + } + ImGui::EndTable(); + } + if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1)) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::Text("AAAA"); + ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB"); + ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC"); + } + ImGui::EndTable(); + } + ImGui::PopID(); + } + + ImGui::Spacing(); + ImGui::TextUnformatted("Advanced"); + ImGui::SameLine(); + HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns."); + + enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText }; + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable; + static int contents_type = CT_ShowWidth; + static int column_count = 3; + + PushStyleCompact(); + ImGui::PushID("Advanced"); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); + EditTableSizingFlags(&flags); + ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0"); + if (contents_type == CT_FillButton) + { + ImGui::SameLine(); + HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width."); + } + ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); + ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); + ImGui::PopItemWidth(); + ImGui::PopID(); + PopStyleCompact(); + + if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7))) + { + for (int cell = 0; cell < 10 * column_count; cell++) + { + ImGui::TableNextColumn(); + int column = ImGui::TableGetColumnIndex(); + int row = ImGui::TableGetRowIndex(); + + ImGui::PushID(cell); + char label[32]; + static char text_buf[32] = ""; + sprintf(label, "Hello %d,%d", column, row); + switch (contents_type) + { + case CT_ShortText: ImGui::TextUnformatted(label); break; + case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break; + case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break; + case CT_Button: ImGui::Button(label); break; + case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break; + case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping"); + if (ImGui::TreeNode("Vertical scrolling, with clipping")) + { + HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + PopStyleCompact(); + + // When using ScrollX or ScrollY we need to specify a size for our table container! + // Otherwise by default the table will fit all available space, like a BeginChild() call. + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); + if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size)) + { + ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible + ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None); + ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None); + ImGui::TableHeadersRow(); + + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(1000); + while (clipper.Step()) + { + for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Hello %d,%d", column, row); + } + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Horizontal scrolling"); + if (ImGui::TreeNode("Horizontal scrolling")) + { + HelpMarker( + "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" + "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX," + "because the container window won't automatically extend vertically to fix contents (this may be improved in future versions)."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + static int freeze_cols = 1; + static int freeze_rows = 1; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + PopStyleCompact(); + + // When using ScrollX or ScrollY we need to specify a size for our table container! + // Otherwise by default the table will fit all available space, like a BeginChild() call. + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8); + if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size)) + { + ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); + ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableSetupColumn("Four"); + ImGui::TableSetupColumn("Five"); + ImGui::TableSetupColumn("Six"); + ImGui::TableHeadersRow(); + for (int row = 0; row < 20; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 7; column++) + { + // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. + // Because here we know that: + // - A) all our columns are contributing the same to row height + // - B) column 0 is always visible, + // We only always submit this one column and can skip others. + // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + if (!ImGui::TableSetColumnIndex(column) && column > 0) + continue; + if (column == 0) + ImGui::Text("Line %d", row); + else + ImGui::Text("Hello world %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + ImGui::Spacing(); + ImGui::TextUnformatted("Stretch + ScrollX"); + ImGui::SameLine(); + HelpMarker( + "Showcase using Stretch columns + ScrollX together: " + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense."); + static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + static float inner_width = 1000.0f; + PushStyleCompact(); + ImGui::PushID("flags3"); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX); + ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f"); + ImGui::PopItemWidth(); + ImGui::PopID(); + PopStyleCompact(); + if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width)) + { + for (int cell = 0; cell < 20 * 7; cell++) + { + ImGui::TableNextColumn(); + ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex()); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Columns flags"); + if (ImGui::TreeNode("Columns flags")) + { + // Create a first table just to show all the options/flags we want to make visible in our example! + const int column_count = 3; + const char* column_names[column_count] = { "One", "Two", "Three" }; + static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide }; + static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags() + + if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None)) + { + PushStyleCompact(); + for (int column = 0; column < column_count; column++) + { + ImGui::TableNextColumn(); + ImGui::PushID(column); + ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation + ImGui::Text("'%s'", column_names[column]); + ImGui::Spacing(); + ImGui::Text("Input flags:"); + EditTableColumnsFlags(&column_flags[column]); + ImGui::Spacing(); + ImGui::Text("Output flags:"); + ShowTableColumnsStatusFlags(column_flags_out[column]); + ImGui::PopID(); + } + PopStyleCompact(); + ImGui::EndTable(); + } + + // Create the real table we care about for the example! + // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in + // a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down) + const ImGuiTableFlags flags + = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY + | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV + | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9); + if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size)) + { + for (int column = 0; column < column_count; column++) + ImGui::TableSetupColumn(column_names[column], column_flags[column]); + ImGui::TableHeadersRow(); + for (int column = 0; column < column_count; column++) + column_flags_out[column] = ImGui::TableGetColumnFlags(column); + float indent_step = (float)((int)TEXT_BASE_WIDTH / 2); + for (int row = 0; row < 8; row++) + { + ImGui::Indent(indent_step); // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. + ImGui::TableNextRow(); + for (int column = 0; column < column_count; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column)); + } + } + ImGui::Unindent(indent_step * 8.0f); + + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Columns widths"); + if (ImGui::TreeNode("Columns widths")) + { + HelpMarker("Using TableSetupColumn() to setup default width."); + + static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize); + PopStyleCompact(); + if (ImGui::BeginTable("table1", 3, flags1)) + { + // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f + ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f + ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto + ImGui::TableHeadersRow(); + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); + else + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + HelpMarker("Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, fixed columns with set width may still be shrunk down if there's not enough space in the host."); + + static ImGuiTableFlags flags2 = ImGuiTableFlags_None; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV); + PopStyleCompact(); + if (ImGui::BeginTable("table2", 4, flags2)) + { + // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 4; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x); + else + ImGui::Text("Hello %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Nested tables"); + if (ImGui::TreeNode("Nested tables")) + { + HelpMarker("This demonstrate embedding a table into another table cell."); + + if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("A0"); + ImGui::TableSetupColumn("A1"); + ImGui::TableHeadersRow(); + + ImGui::TableNextColumn(); + ImGui::Text("A0 Row 0"); + { + float rows_height = TEXT_BASE_HEIGHT * 2; + if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("B0"); + ImGui::TableSetupColumn("B1"); + ImGui::TableHeadersRow(); + + ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); + ImGui::TableNextColumn(); + ImGui::Text("B0 Row 0"); + ImGui::TableNextColumn(); + ImGui::Text("B1 Row 0"); + ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height); + ImGui::TableNextColumn(); + ImGui::Text("B0 Row 1"); + ImGui::TableNextColumn(); + ImGui::Text("B1 Row 1"); + + ImGui::EndTable(); + } + } + ImGui::TableNextColumn(); ImGui::Text("A1 Row 0"); + ImGui::TableNextColumn(); ImGui::Text("A0 Row 1"); + ImGui::TableNextColumn(); ImGui::Text("A1 Row 1"); + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Row height"); + if (ImGui::TreeNode("Row height")) + { + HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would requires a unique clipping rectangle per row."); + if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV)) + { + for (int row = 0; row < 10; row++) + { + float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row); + ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height); + ImGui::TableNextColumn(); + ImGui::Text("min_row_height = %.2f", min_row_height); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Outer size"); + if (ImGui::TreeNode("Outer size")) + { + // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY + // Important to that note how the two flags have slightly different behaviors! + ImGui::Text("Using NoHostExtendX and NoHostExtendY:"); + PushStyleCompact(); + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); + ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); + PopStyleCompact(); + + ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f); + if (ImGui::BeginTable("table1", 3, flags, outer_size)) + { + for (int row = 0; row < 10; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::SameLine(); + ImGui::Text("Hello!"); + + ImGui::Spacing(); + + ImGui::Text("Using explicit size:"); + if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + ImGui::SameLine(); + if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + { + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f); + for (int column = 0; column < 3; column++) + { + ImGui::TableNextColumn(); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Background color"); + if (ImGui::TreeNode("Background color")) + { + static ImGuiTableFlags flags = ImGuiTableFlags_RowBg; + static int row_bg_type = 1; + static int row_bg_target = 1; + static int cell_bg_type = 1; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); + ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0"); + ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); + ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here."); + IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2); + IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1); + IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1); + PopStyleCompact(); + + if (ImGui::BeginTable("table1", 5, flags)) + { + for (int row = 0; row < 6; row++) + { + ImGui::TableNextRow(); + + // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)' + // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + if (row_bg_type != 0) + { + ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient? + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color); + } + + // Fill cells + for (int column = 0; column < 5; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("%c%c", 'A' + row, '0' + column); + + // Change background of Cells B1->C2 + // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)' + // (the CellBg color will be blended over the RowBg and ColumnBg colors) + // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1) + { + ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color); + } + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Tree view"); + if (ImGui::TreeNode("Tree view")) + { + static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + + if (ImGui::BeginTable("3ways", 3, flags)) + { + // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); + ImGui::TableHeadersRow(); + + // Simple storage to output a dummy file-system. + struct MyTreeNode + { + const char* Name; + const char* Type; + int Size; + int ChildIdx; + int ChildCount; + static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + const bool is_folder = (node->ChildCount > 0); + if (is_folder) + { + bool open = ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::TextDisabled("--"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + if (open) + { + for (int child_n = 0; child_n < node->ChildCount; child_n++) + DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes); + ImGui::TreePop(); + } + } + else + { + ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::Text("%d", node->Size); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + } + } + }; + static const MyTreeNode nodes[] = + { + { "Root", "Folder", -1, 1, 3 }, // 0 + { "Music", "Folder", -1, 4, 2 }, // 1 + { "Textures", "Folder", -1, 6, 3 }, // 2 + { "desktop.ini", "System file", 1024, -1,-1 }, // 3 + { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4 + { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5 + { "Image001.png", "Image file", 203128, -1,-1 }, // 6 + { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7 + { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8 + }; + + MyTreeNode::DisplayNode(&nodes[0], nodes); + + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Item width"); + if (ImGui::TreeNode("Item width")) + { + HelpMarker( + "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" + "Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense."); + if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders)) + { + ImGui::TableSetupColumn("small"); + ImGui::TableSetupColumn("half"); + ImGui::TableSetupColumn("right-align"); + ImGui::TableHeadersRow(); + + for (int row = 0; row < 3; row++) + { + ImGui::TableNextRow(); + if (row == 0) + { + // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + ImGui::TableSetColumnIndex(0); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small + ImGui::TableSetColumnIndex(1); + ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::TableSetColumnIndex(2); + ImGui::PushItemWidth(-FLT_MIN); // Right-aligned + } + + // Draw our contents + static float dummy_f = 0.0f; + ImGui::PushID(row); + ImGui::TableSetColumnIndex(0); + ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f); + ImGui::TableSetColumnIndex(1); + ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f); + ImGui::TableSetColumnIndex(2); + ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f); + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // Demonstrate using TableHeader() calls instead of TableHeadersRow() + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Custom headers"); + if (ImGui::TreeNode("Custom headers")) + { + const int COLUMNS_COUNT = 3; + if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + ImGui::TableSetupColumn("Apricot"); + ImGui::TableSetupColumn("Banana"); + ImGui::TableSetupColumn("Cherry"); + + // Dummy entire-column selection storage + // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. + static bool column_selected[3] = {}; + + // Instead of calling TableHeadersRow() we'll submit custom headers ourselves + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + ImGui::TableSetColumnIndex(column); + const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn() + ImGui::PushID(column); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("##checkall", &column_selected[column]); + ImGui::PopStyleVar(); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::TableHeader(column_name); + ImGui::PopID(); + } + + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + char buf[32]; + sprintf(buf, "Cell %d,%d", column, row); + ImGui::TableSetColumnIndex(column); + ImGui::Selectable(buf, column_selected[column]); + } + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // Demonstrate creating custom context menus inside columns, while playing it nice with context menus provided by TableHeadersRow()/TableHeader() + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Context menus"); + if (ImGui::TreeNode("Context menus")) + { + HelpMarker("By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\nUsing ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body."); + static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody; + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody); + PopStyleCompact(); + + // Context Menus: first example + // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. + // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + const int COLUMNS_COUNT = 3; + if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1)) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + + // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui::TableHeadersRow(); + + // Submit dummy contents + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + ImGui::TableSetColumnIndex(column); + ImGui::Text("Cell %d,%d", column, row); + } + } + ImGui::EndTable(); + } + + // Context Menus: second example + // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + // [2.2] Right-click on the ".." to open a custom popup + // [2.3] Right-click in columns to open another custom popup + HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body)."); + ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; + if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2)) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + + // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui::TableHeadersRow(); + for (int row = 0; row < 4; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < COLUMNS_COUNT; column++) + { + // Submit dummy contents + ImGui::TableSetColumnIndex(column); + ImGui::Text("Cell %d,%d", column, row); + ImGui::SameLine(); + + // [2.2] Right-click on the ".." to open a custom popup + ImGui::PushID(row * COLUMNS_COUNT + column); + ImGui::SmallButton(".."); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::PopID(); + } + } + + // [2.3] Right-click anywhere in columns to open another custom popup + // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup + // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + int hovered_column = -1; + for (int column = 0; column < COLUMNS_COUNT + 1; column++) + { + ImGui::PushID(column); + if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered) + hovered_column = column; + if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1)) + ImGui::OpenPopup("MyPopup"); + if (ImGui::BeginPopup("MyPopup")) + { + if (column == COLUMNS_COUNT) + ImGui::Text("This is a custom popup for unused space after the last column."); + else + ImGui::Text("This is a custom popup for Column %d", column); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::PopID(); + } + + ImGui::EndTable(); + ImGui::Text("Hovered column: %d", hovered_column); + } + ImGui::TreePop(); + } + + // Demonstrate creating multiple tables with the same ID + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Synced instances"); + if (ImGui::TreeNode("Synced instances")) + { + HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); + for (int n = 0; n < 3; n++) + { + char buf[32]; + sprintf(buf, "Synced Table %d", n); + bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); + if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableSetupColumn("One"); + ImGui::TableSetupColumn("Two"); + ImGui::TableSetupColumn("Three"); + ImGui::TableHeadersRow(); + for (int cell = 0; cell < 9; cell++) + { + ImGui::TableNextColumn(); + ImGui::Text("this cell %d", cell); + } + ImGui::EndTable(); + } + } + ImGui::TreePop(); + } + + // Demonstrate using Sorting facilities + // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. + // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) + static const char* template_items_names[] = + { + "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", + "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" + }; + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Sorting"); + if (ImGui::TreeNode("Sorting")) + { + // Create item list + static ImVector items; + if (items.Size == 0) + { + items.resize(50, MyItem()); + for (int n = 0; n < items.Size; n++) + { + const int template_n = n % IM_ARRAYSIZE(template_items_names); + MyItem& item = items[n]; + item.ID = n; + item.Name = template_items_names[template_n]; + item.Quantity = (n * n - n) % 20; // Assign default quantities + } + } + + // Options + static ImGuiTableFlags flags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti + | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody + | ImGuiTableFlags_ScrollY; + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + PopStyleCompact(); + + if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f)) + { + // Declare columns + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + // Demonstrate using a mixture of flags among available sort-related flags: + // - ImGuiTableColumnFlags_DefaultSort + // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible + ImGui::TableHeadersRow(); + + // Sort our data if sort specs have been changed! + if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) + if (sorts_specs->SpecsDirty) + { + MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. + if (items.Size > 1) + qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); + MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; + } + + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(items.Size); + while (clipper.Step()) + for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) + { + // Display a data item + MyItem* item = &items[row_n]; + ImGui::PushID(item->ID); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%04d", item->ID); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(item->Name); + ImGui::TableNextColumn(); + ImGui::SmallButton("None"); + ImGui::TableNextColumn(); + ImGui::Text("%d", item->Quantity); + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + // In this example we'll expose most table flags and settings. + // For specific flags and settings refer to the corresponding section for more detailed explanation. + // This section is mostly useful to experiment with combining certain flags or settings with each others. + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + IMGUI_DEMO_MARKER("Tables/Advanced"); + if (ImGui::TreeNode("Advanced")) + { + static ImGuiTableFlags flags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable + | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti + | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody + | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY + | ImGuiTableFlags_SizingFixedFit; + + enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; + static int contents_type = CT_SelectableSpanRow; + const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" }; + static int freeze_cols = 1; + static int freeze_rows = 1; + static int items_count = IM_ARRAYSIZE(template_items_names) * 2; + static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12); + static float row_min_height = 0.0f; // Auto + static float inner_width_with_scroll = 0.0f; // Auto-extend + static bool outer_size_enabled = true; + static bool show_headers = true; + static bool show_wrapped_text = false; + //static ImGuiTextFilter filter; + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affects column sizing + if (ImGui::TreeNode("Options")) + { + // Make the UI compact because there are so many fields + PushStyleCompact(); + ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f); + + if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); + ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable); + ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings); + ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)"); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen)) + { + EditTableSizingFlags(&flags); + ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); + ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); + ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled."); + ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); + ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); + ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options."); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); + ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + ImGui::TreePop(); + } + + if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Checkbox("show_headers", &show_headers); + ImGui::Checkbox("show_wrapped_text", &show_wrapped_text); + + ImGui::DragFloat2("##OuterSize", &outer_size_value.x); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Checkbox("outer_size", &outer_size_enabled); + ImGui::SameLine(); + HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" + "- The table is output directly in the parent window.\n" + "- OuterSize.x < 0.0f will right-align the table.\n" + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch column.\n" + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set)."); + + // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. + // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX); + + ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX); + ImGui::SameLine(); HelpMarker("Specify height of the Selectable item."); + + ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999); + ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names)); + //filter.Draw("filter"); + ImGui::TreePop(); + } + + ImGui::PopItemWidth(); + PopStyleCompact(); + ImGui::Spacing(); + ImGui::TreePop(); + } + + // Update item list if we changed the number of items + static ImVector items; + static ImVector selection; + static bool items_need_sort = false; + if (items.Size != items_count) + { + items.resize(items_count, MyItem()); + for (int n = 0; n < items_count; n++) + { + const int template_n = n % IM_ARRAYSIZE(template_items_names); + MyItem& item = items[n]; + item.ID = n; + item.Name = template_items_names[template_n]; + item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities + } + } + + const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList(); + const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size; + ImVec2 table_scroll_cur, table_scroll_max; // For debug display + const ImDrawList* table_draw_list = NULL; // " + + // Submit table + const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f; + if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use)) + { + // Declare columns + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupColumn("Description", (flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Description); + ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); + ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); + + // Sort our data if sort specs have been changed! + ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty) + items_need_sort = true; + if (sorts_specs && items_need_sort && items.Size > 1) + { + MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. + qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); + MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; + } + items_need_sort = false; + + // Take note of whether we are currently sorting based on the Quantity field, + // we will use this to trigger sorting when we know the data of this column has been modified. + const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0; + + // Show headers + if (show_headers) + ImGui::TableHeadersRow(); + + // Show data + // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? + ImGui::PushButtonRepeat(true); +#if 1 + // Demonstrate using clipper for large vertical lists + ImGuiListClipper clipper; + clipper.Begin(items.Size); + while (clipper.Step()) + { + for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) +#else + // Without clipper + { + for (int row_n = 0; row_n < items.Size; row_n++) +#endif + { + MyItem* item = &items[row_n]; + //if (!filter.PassFilter(item->Name)) + // continue; + + const bool item_is_selected = selection.contains(item->ID); + ImGui::PushID(item->ID); + ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height); + + // For the demo purpose we can select among different type of items submitted in the first column + ImGui::TableSetColumnIndex(0); + char label[32]; + sprintf(label, "%04d", item->ID); + if (contents_type == CT_Text) + ImGui::TextUnformatted(label); + else if (contents_type == CT_Button) + ImGui::Button(label); + else if (contents_type == CT_SmallButton) + ImGui::SmallButton(label); + else if (contents_type == CT_FillButton) + ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); + else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) + { + ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None; + if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) + { + if (ImGui::GetIO().KeyCtrl) + { + if (item_is_selected) + selection.find_erase_unsorted(item->ID); + else + selection.push_back(item->ID); + } + else + { + selection.clear(); + selection.push_back(item->ID); + } + } + } + + if (ImGui::TableSetColumnIndex(1)) + ImGui::TextUnformatted(item->Name); + + // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, + // and we are currently sorting on the column showing the Quantity. + // To avoid triggering a sort while holding the button, we only trigger it when the button has been released. + // You will probably need a more advanced system in your code if you want to automatically sort when a specific entry changes. + if (ImGui::TableSetColumnIndex(2)) + { + if (ImGui::SmallButton("Chop")) { item->Quantity += 1; } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + ImGui::SameLine(); + if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + } + + if (ImGui::TableSetColumnIndex(3)) + ImGui::Text("%d", item->Quantity); + + ImGui::TableSetColumnIndex(4); + if (show_wrapped_text) + ImGui::TextWrapped("Lorem ipsum dolor sit amet"); + else + ImGui::Text("Lorem ipsum dolor sit amet"); + + if (ImGui::TableSetColumnIndex(5)) + ImGui::Text("1234"); + + ImGui::PopID(); + } + } + ImGui::PopButtonRepeat(); + + // Store some info to display debug details below + table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY()); + table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY()); + table_draw_list = ImGui::GetWindowDrawList(); + ImGui::EndTable(); + } + static bool show_debug_details = false; + ImGui::Checkbox("Debug details", &show_debug_details); + if (show_debug_details && table_draw_list) + { + ImGui::SameLine(0.0f, 0.0f); + const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size; + if (table_draw_list == parent_draw_list) + ImGui::Text(": DrawCmd: +%d (in same window)", + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); + else + ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y); + } + ImGui::TreePop(); + } + + ImGui::PopID(); + + ShowDemoWindowColumns(); + + if (disable_indent) + ImGui::PopStyleVar(); +} + +// Demonstrate old/legacy Columns API! +// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] +static void ShowDemoWindowColumns() +{ + IMGUI_DEMO_MARKER("Columns (legacy API)"); + bool open = ImGui::TreeNode("Legacy Columns API"); + ImGui::SameLine(); + HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!"); + if (!open) + return; + + // Basic columns + IMGUI_DEMO_MARKER("Columns (legacy API)/Basic"); + if (ImGui::TreeNode("Basic")) + { + ImGui::Text("Without border:"); + ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border + ImGui::Separator(); + for (int n = 0; n < 14; n++) + { + char label[32]; + sprintf(label, "Item %d", n); + if (ImGui::Selectable(label)) {} + //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + + ImGui::Text("With border:"); + ImGui::Columns(4, "mycolumns"); // 4-ways, with border + ImGui::Separator(); + ImGui::Text("ID"); ImGui::NextColumn(); + ImGui::Text("Name"); ImGui::NextColumn(); + ImGui::Text("Path"); ImGui::NextColumn(); + ImGui::Text("Hovered"); ImGui::NextColumn(); + ImGui::Separator(); + const char* names[3] = { "One", "Two", "Three" }; + const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; + static int selected = -1; + for (int i = 0; i < 3; i++) + { + char label[32]; + sprintf(label, "%04d", i); + if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) + selected = i; + bool hovered = ImGui::IsItemHovered(); + ImGui::NextColumn(); + ImGui::Text(names[i]); ImGui::NextColumn(); + ImGui::Text(paths[i]); ImGui::NextColumn(); + ImGui::Text("%d", hovered); ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Columns (legacy API)/Borders"); + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + static int columns_count = 4; + const int lines_count = 3; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); + if (columns_count < 2) + columns_count = 2; + ImGui::SameLine(); + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(columns_count, NULL, v_borders); + for (int i = 0; i < columns_count * lines_count; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + + // Create multiple items in a same cell before switching to next column + IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items"); + if (ImGui::TreeNode("Mixed items")) + { + ImGui::Columns(3, "mixed"); + ImGui::Separator(); + + ImGui::Text("Hello"); + ImGui::Button("Banana"); + ImGui::NextColumn(); + + ImGui::Text("ImGui"); + ImGui::Button("Apple"); + static float foo = 1.0f; + ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); + ImGui::Text("An extra line here."); + ImGui::NextColumn(); + + ImGui::Text("Sailor"); + ImGui::Button("Corniflower"); + static float bar = 1.0f; + ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); + ImGui::NextColumn(); + + if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + // Word wrapping + IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping"); + if (ImGui::TreeNode("Word-wrapping")) + { + ImGui::Columns(2, "word-wrapping"); + ImGui::Separator(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Left"); + ImGui::NextColumn(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Right"); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling"); + if (ImGui::TreeNode("Horizontal Scrolling")) + { + ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); + ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); + ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::Columns(10); + + // Also demonstrate using clipper for large vertical lists + int ITEMS_COUNT = 2000; + ImGuiListClipper clipper; + clipper.Begin(ITEMS_COUNT); + while (clipper.Step()) + { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + for (int j = 0; j < 10; j++) + { + ImGui::Text("Line %d Column %d...", i, j); + ImGui::NextColumn(); + } + } + ImGui::Columns(1); + ImGui::EndChild(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Columns (legacy API)/Tree"); + if (ImGui::TreeNode("Tree")) + { + ImGui::Columns(2, "tree", true); + for (int x = 0; x < 3; x++) + { + bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); + ImGui::NextColumn(); + ImGui::Text("Node contents"); + ImGui::NextColumn(); + if (open1) + { + for (int y = 0; y < 3; y++) + { + bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); + ImGui::NextColumn(); + ImGui::Text("Node contents"); + if (open2) + { + ImGui::Text("Even more contents"); + if (ImGui::TreeNode("Tree in column")) + { + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::TreePop(); + } + } + ImGui::NextColumn(); + if (open2) + ImGui::TreePop(); + } + ImGui::TreePop(); + } + } + ImGui::Columns(1); + ImGui::TreePop(); + } + + ImGui::TreePop(); +} + +static void ShowDemoWindowMisc() +{ + IMGUI_DEMO_MARKER("Filtering"); + if (ImGui::CollapsingHeader("Filtering")) + { + // Helper class to easy setup a text filter. + // You may want to implement a more feature-full filtering scheme in your own application. + static ImGuiTextFilter filter; + ImGui::Text("Filter usage:\n" + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); + filter.Draw(); + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (int i = 0; i < IM_ARRAYSIZE(lines); i++) + if (filter.PassFilter(lines[i])) + ImGui::BulletText("%s", lines[i]); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus"); + if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) + { + ImGuiIO& io = ImGui::GetIO(); + + // Display ImGuiIO output flags + ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); + ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + ImGui::Text("WantTextInput: %d", io.WantTextInput); + ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); + ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); + + // Display Mouse state + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse State"); + if (ImGui::TreeNode("Mouse State")) + { + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse pos: "); + ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + + int count = IM_ARRAYSIZE(io.MouseDown); + ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, ImGui::GetMouseClickedCount(i)); } + ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused + ImGui::TreePop(); + } + + // Display Keyboard/Mouse state + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard & Navigation State"); + if (ImGui::TreeNode("Keyboard & Navigation State")) + { + ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyDown(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } + ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + + ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); } + ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } + + ImGui::Button("Hovering me sets the\nkeyboard capture flag"); + if (ImGui::IsItemHovered()) + ImGui::CaptureKeyboardFromApp(true); + ImGui::SameLine(); + ImGui::Button("Holding me clears the\nthe keyboard capture flag"); + if (ImGui::IsItemActive()) + ImGui::CaptureKeyboardFromApp(false); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Tabbing"); + if (ImGui::TreeNode("Tabbing")) + { + ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); + static char buf[32] = "hello"; + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); + ImGui::PushAllowKeyboardFocus(false); + ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); + ImGui::PopAllowKeyboardFocus(); + ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Focus from code"); + if (ImGui::TreeNode("Focus from code")) + { + bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); + bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); + bool focus_3 = ImGui::Button("Focus on 3"); + int has_focus = 0; + static char buf[128] = "click on a button to set focus"; + + if (focus_1) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 1; + + if (focus_2) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 2; + + ImGui::PushAllowKeyboardFocus(false); + if (focus_3) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 3; + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); + ImGui::PopAllowKeyboardFocus(); + + if (has_focus) + ImGui::Text("Item with focus: %d", has_focus); + else + ImGui::Text("Item with focus: "); + + // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + static float f3[3] = { 0.0f, 0.0f, 0.0f }; + int focus_ahead = -1; + if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } + if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); + ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); + + ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Dragging"); + if (ImGui::TreeNode("Dragging")) + { + ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); + for (int button = 0; button < 3; button++) + { + ImGui::Text("IsMouseDragging(%d):", button); + ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); + ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); + ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); + } + + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor + + // Drag operations gets "unlocked" when the mouse has moved past a certain threshold + // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). + ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); + ImVec2 mouse_delta = io.MouseDelta; + ImGui::Text("GetMouseDragDelta(0):"); + ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); + ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); + ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse cursors"); + if (ImGui::TreeNode("Mouse cursors")) + { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); + + ImGuiMouseCursor current = ImGui::GetMouseCursor(); + ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); + ImGui::Text("Hover to see mouse cursors:"); + ImGui::SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " + "otherwise your backend needs to handle it."); + for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered()) + ImGui::SetMouseCursor(i); + } + ImGui::TreePop(); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] About Window / ShowAboutWindow() +// Access from Dear ImGui Demo -> Tools -> About +//----------------------------------------------------------------------------- + +void ImGui::ShowAboutWindow(bool* p_open) +{ + if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + IMGUI_DEMO_MARKER("Tools/About Dear ImGui"); + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); + ImGui::Separator(); + ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); + ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); + + static bool show_config_info = false; + ImGui::Checkbox("Config/Build Information", &show_config_info); + if (show_config_info) + { + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + + bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); + ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); + ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); + if (copy_to_clipboard) + { + ImGui::LogToClipboard(); + ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub + } + + ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + ImGui::Separator(); + ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); + ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); +#endif +#ifdef IMGUI_USE_BGRA_PACKED_COLOR + ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); +#endif +#ifdef _WIN32 + ImGui::Text("define: _WIN32"); +#endif +#ifdef _WIN64 + ImGui::Text("define: _WIN64"); +#endif +#ifdef __linux__ + ImGui::Text("define: __linux__"); +#endif +#ifdef __APPLE__ + ImGui::Text("define: __APPLE__"); +#endif +#ifdef _MSC_VER + ImGui::Text("define: _MSC_VER=%d", _MSC_VER); +#endif +#ifdef _MSVC_LANG + ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG); +#endif +#ifdef __MINGW32__ + ImGui::Text("define: __MINGW32__"); +#endif +#ifdef __MINGW64__ + ImGui::Text("define: __MINGW64__"); +#endif +#ifdef __GNUC__ + ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); +#endif +#ifdef __clang_version__ + ImGui::Text("define: __clang_version__=%s", __clang_version__); +#endif + ImGui::Separator(); + ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); + ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); + ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); + if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); + if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); + if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); + if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); + if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); + if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); + ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); + if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); + if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); + ImGui::Separator(); + ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); + ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); + ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + ImGui::Separator(); + ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); + ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); + ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); + ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); + ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); + ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); + ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); + + if (copy_to_clipboard) + { + ImGui::LogText("\n```\n"); + ImGui::LogFinish(); + } + ImGui::EndChildFrame(); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Style Editor / ShowStyleEditor() +//----------------------------------------------------------------------------- +// - ShowFontSelector() +// - ShowStyleSelector() +// - ShowStyleEditor() +//----------------------------------------------------------------------------- + +// Forward declare ShowFontAtlas() which isn't worth putting in public API yet +namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } + +// Demo helper function to select among loaded fonts. +// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +void ImGui::ShowFontSelector(const char* label) +{ + ImGuiIO& io = ImGui::GetIO(); + ImFont* font_current = ImGui::GetFont(); + if (ImGui::BeginCombo(label, font_current->GetDebugName())) + { + for (int n = 0; n < io.Fonts->Fonts.Size; n++) + { + ImFont* font = io.Fonts->Fonts[n]; + ImGui::PushID((void*)font); + if (ImGui::Selectable(font->GetDebugName(), font == font_current)) + io.FontDefault = font; + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + HelpMarker( + "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" + "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" + "- Read FAQ and docs/FONTS.md for more details.\n" + "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); +} + +// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +// Here we use the simplified Combo() api that packs items into a single literal string. +// Useful for quick combo boxes where the choices are known locally. +bool ImGui::ShowStyleSelector(const char* label) +{ + static int style_idx = -1; + if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0")) + { + switch (style_idx) + { + case 0: ImGui::StyleColorsDark(); break; + case 1: ImGui::StyleColorsLight(); break; + case 2: ImGui::StyleColorsClassic(); break; + } + return true; + } + return false; +} + +void ImGui::ShowStyleEditor(ImGuiStyle* ref) +{ + IMGUI_DEMO_MARKER("Tools/Style Editor"); + // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + // (without a reference style pointer, we will use one compared locally as a reference) + ImGuiStyle& style = ImGui::GetStyle(); + static ImGuiStyle ref_saved_style; + + // Default to using internal storage as reference + static bool init = true; + if (init && ref == NULL) + ref_saved_style = style; + init = false; + if (ref == NULL) + ref = &ref_saved_style; + + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); + + if (ImGui::ShowStyleSelector("Colors##Selector")) + ref_saved_style = style; + ImGui::ShowFontSelector("Fonts##Selector"); + + // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) + style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding + { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } + ImGui::SameLine(); + { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } + ImGui::SameLine(); + { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + + // Save/Revert button + if (ImGui::Button("Save Ref")) + *ref = ref_saved_style = style; + ImGui::SameLine(); + if (ImGui::Button("Revert Ref")) + style = *ref; + ImGui::SameLine(); + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " + "Use \"Export\" below to save them somewhere."); + + ImGui::Separator(); + + if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Sizes")) + { + ImGui::Text("Main"); + ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); + ImGui::Text("Borders"); + ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::Text("Rounding"); + ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + int window_menu_button_position = style.WindowMenuButtonPosition + 1; + if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + style.WindowMenuButtonPosition = window_menu_button_position - 1; + ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + ImGui::Text("Safe Area Padding"); + ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Colors")) + { + static int output_dest = 0; + static bool output_only_modified = true; + if (ImGui::Button("Export")) + { + if (output_dest == 0) + ImGui::LogToClipboard(); + else + ImGui::LogToTTY(); + ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const ImVec4& col = style.Colors[i]; + const char* name = ImGui::GetStyleColorName(i); + if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, + name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + } + ImGui::LogFinish(); + } + ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); + ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); + + static ImGuiTextFilter filter; + filter.Draw("Filter colors", ImGui::GetFontSize() * 16); + + static ImGuiColorEditFlags alpha_flags = 0; + if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); + if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); + if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + HelpMarker( + "In the color list:\n" + "Left-click on color square to open color picker,\n" + "Right-click to open edit options menu."); + + ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); + ImGui::PushItemWidth(-160); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; + ImGui::PushID(i); + ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + { + // Tips: in a real user application, you may want to merge and use an icon font into the main font, + // so instead of "Save"/"Revert" you'd use icons! + // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); + ImGui::TextUnformatted(name); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::EndChild(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Fonts")) + { + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); + ImGui::ShowFontAtlas(atlas); + + // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); + static float window_scale = 1.0f; + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); + if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + ImGui::SetWindowFontScale(window_scale); + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Rendering")) + { + ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); + ImGui::SameLine(); + HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + + ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); + ImGui::SameLine(); + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); + + ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); + if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + + // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. + ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); + if (ImGui::IsItemActive()) + { + ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); + ImGui::BeginTooltip(); + ImGui::TextUnformatted("(R = radius, N = number of segments)"); + ImGui::Spacing(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x; + for (int n = 0; n < 8; n++) + { + const float RAD_MIN = 5.0f; + const float RAD_MAX = 70.0f; + const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f); + + ImGui::BeginGroup(); + + ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); + + const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f); + const float offset_x = floorf(canvas_width * 0.5f); + const float offset_y = floorf(RAD_MAX); + + const ImVec2 p1 = ImGui::GetCursorScreenPos(); + draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + + /* + const ImVec2 p2 = ImGui::GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + */ + + ImGui::EndGroup(); + ImGui::SameLine(); + } + ImGui::EndTooltip(); + } + ImGui::SameLine(); + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); + + ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::PopItemWidth(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +//----------------------------------------------------------------------------- +// - ShowExampleAppMainMenuBar() +// - ShowExampleMenuFile() +//----------------------------------------------------------------------------- + +// Demonstrate creating a "main" fullscreen menu bar and populating it. +// Note the difference between BeginMainMenuBar() and BeginMenuBar(): +// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) +// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +static void ShowExampleAppMainMenuBar() +{ + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + if (ImGui::MenuItem("Undo", "CTRL+Z")) {} + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item + ImGui::Separator(); + if (ImGui::MenuItem("Cut", "CTRL+X")) {} + if (ImGui::MenuItem("Copy", "CTRL+C")) {} + if (ImGui::MenuItem("Paste", "CTRL+V")) {} + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } +} + +// Note that shortcuts are currently provided for display only +// (future version will add explicit flags to BeginMenu() to request processing shortcuts) +static void ShowExampleMenuFile() +{ + IMGUI_DEMO_MARKER("Examples/Menu"); + ImGui::MenuItem("(demo menu)", NULL, false, false); + if (ImGui::MenuItem("New")) {} + if (ImGui::MenuItem("Open", "Ctrl+O")) {} + if (ImGui::BeginMenu("Open Recent")) + { + ImGui::MenuItem("fish_hat.c"); + ImGui::MenuItem("fish_hat.inl"); + ImGui::MenuItem("fish_hat.h"); + if (ImGui::BeginMenu("More..")) + { + ImGui::MenuItem("Hello"); + ImGui::MenuItem("Sailor"); + if (ImGui::BeginMenu("Recurse..")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Save", "Ctrl+S")) {} + if (ImGui::MenuItem("Save As..")) {} + + ImGui::Separator(); + IMGUI_DEMO_MARKER("Examples/Menu/Options"); + if (ImGui::BeginMenu("Options")) + { + static bool enabled = true; + ImGui::MenuItem("Enabled", "", &enabled); + ImGui::BeginChild("child", ImVec2(0, 60), true); + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); + static float f = 0.5f; + static int n = 0; + ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); + ImGui::InputFloat("Input", &f, 0.1f); + ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); + ImGui::EndMenu(); + } + + IMGUI_DEMO_MARKER("Examples/Menu/Colors"); + if (ImGui::BeginMenu("Colors")) + { + float sz = ImGui::GetTextLineHeight(); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName((ImGuiCol)i); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); + ImGui::Dummy(ImVec2(sz, sz)); + ImGui::SameLine(); + ImGui::MenuItem(name); + } + ImGui::EndMenu(); + } + + // Here we demonstrate appending again to the "Options" menu (which we already created above) + // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + // In a real code-base using it would make senses to use this feature from very different code locations. + if (ImGui::BeginMenu("Options")) // <-- Append! + { + IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu"); + static bool b = true; + ImGui::Checkbox("SomeOption", &b); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Disabled", false)) // Disabled + { + IM_ASSERT(0); + } + if (ImGui::MenuItem("Checked", NULL, true)) {} + if (ImGui::MenuItem("Quit", "Alt+F4")) {} +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple console window, with scrolling, filtering, completion and history. +// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. +struct ExampleAppConsole +{ + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; + + ExampleAppConsole() + { + IMGUI_DEMO_MARKER("Examples/Console"); + ClearLog(); + memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; + + // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. + Commands.push_back("HELP"); + Commands.push_back("HISTORY"); + Commands.push_back("CLEAR"); + Commands.push_back("CLASSIFY"); + AutoScroll = true; + ScrollToBottom = false; + AddLog("Welcome to Dear ImGui!"); + } + ~ExampleAppConsole() + { + ClearLog(); + for (int i = 0; i < History.Size; i++) + free(History[i]); + } + + // Portable helpers + static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } + static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } + static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } + static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + + void ClearLog() + { + for (int i = 0; i < Items.Size; i++) + free(Items[i]); + Items.clear(); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + // FIXME-OPT + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf)-1] = 0; + va_end(args); + Items.push_back(Strdup(buf)); + } + + void Draw(const char* title, bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + // So e.g. IsItemHovered() will return true when hovering the title bar. + // Here we create a context menu only available from the title bar. + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Close Console")) + *p_open = false; + ImGui::EndPopup(); + } + + ImGui::TextWrapped( + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " + "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); + ImGui::TextWrapped("Enter 'HELP' for help."); + + // TODO: display items starting from the bottom + + if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } + ImGui::SameLine(); + if (ImGui::SmallButton("Clear")) { ClearLog(); } + ImGui::SameLine(); + bool copy_to_clipboard = ImGui::SmallButton("Copy"); + //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + + ImGui::Separator(); + + // Options menu + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::EndPopup(); + } + + // Options, Filter + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); + ImGui::Separator(); + + // Reserve enough left-over height for 1 separator + 1 input text + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } + + // Display every line as a separate entry so we can change their color or add custom widgets. + // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + // to only process visible items. The clipper will automatically measure the height of your first item and then + // "seek" to display only items in the visible area. + // To use the clipper we can replace your standard loop: + // for (int i = 0; i < Items.Size; i++) + // With: + // ImGuiListClipper clipper; + // clipper.Begin(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // - That your items are evenly spaced (same height) + // - That you have cheap random access to your elements (you can access them given their index, + // without processing all the ones before) + // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + // We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage + // to improve this example code! + // If your items are of variable height: + // - Split them into same height items would be simpler and facilitate random-seeking into your list. + // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing + if (copy_to_clipboard) + ImGui::LogToClipboard(); + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; + + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(item); + if (has_color) + ImGui::PopStyleColor(); + } + if (copy_to_clipboard) + ImGui::LogFinish(); + + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + + ImGui::PopStyleVar(); + ImGui::EndChild(); + ImGui::Separator(); + + // Command-line + bool reclaim_focus = false; + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + { + char* s = InputBuf; + Strtrim(s); + if (s[0]) + ExecCommand(s); + strcpy(s, ""); + reclaim_focus = true; + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + if (reclaim_focus) + ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget + + ImGui::End(); + } + + void ExecCommand(const char* command_line) + { + AddLog("# %s\n", command_line); + + // Insert into history. First find match and delete it so it can be pushed to the back. + // This isn't trying to be smart or optimal. + HistoryPos = -1; + for (int i = History.Size - 1; i >= 0; i--) + if (Stricmp(History[i], command_line) == 0) + { + free(History[i]); + History.erase(History.begin() + i); + break; + } + History.push_back(Strdup(command_line)); + + // Process command + if (Stricmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } + else if (Stricmp(command_line, "HELP") == 0) + { + AddLog("Commands:"); + for (int i = 0; i < Commands.Size; i++) + AddLog("- %s", Commands[i]); + } + else if (Stricmp(command_line, "HISTORY") == 0) + { + int first = History.Size - 10; + for (int i = first > 0 ? first : 0; i < History.Size; i++) + AddLog("%3d: %s\n", i, History[i]); + } + else + { + AddLog("Unknown command: '%s'\n", command_line); + } + + // On command input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; + } + + // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) + { + ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; + return console->TextEditCallback(data); + } + + int TextEditCallback(ImGuiInputTextCallbackData* data) + { + //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + { + // Example of TEXT COMPLETION + + // Locate beginning of current word + const char* word_end = data->Buf + data->CursorPos; + const char* word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') + break; + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) + candidates.push_back(Commands[i]); + + if (candidates.Size == 0) + { + // No match + AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can.. + // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + int match_len = (int)(word_end - word_start); + for (;;) + { + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + if (i == 0) + c = toupper(candidates[i][match_len]); + else if (c == 0 || c != toupper(candidates[i][match_len])) + all_candidates_matches = false; + if (!all_candidates_matches) + break; + match_len++; + } + + if (match_len > 0) + { + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); + } + + // List matches + AddLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + AddLog("- %s\n", candidates[i]); + } + + break; + } + case ImGuiInputTextFlags_CallbackHistory: + { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) + HistoryPos = History.Size - 1; + else if (HistoryPos > 0) + HistoryPos--; + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= History.Size) + HistoryPos = -1; + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } + } + return 0; + } +}; + +static void ShowExampleAppConsole(bool* p_open) +{ + static ExampleAppConsole console; + console.Draw("Example: Console", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +//----------------------------------------------------------------------------- + +// Usage: +// static ExampleAppLog my_log; +// my_log.AddLog("Hello %d world\n", 123); +// my_log.Draw("title"); +struct ExampleAppLog +{ + ImGuiTextBuffer Buf; + ImGuiTextFilter Filter; + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool AutoScroll; // Keep scrolling if already at the bottom. + + ExampleAppLog() + { + AutoScroll = true; + Clear(); + } + + void Clear() + { + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + int old_size = Buf.size(); + va_list args; + va_start(args, fmt); + Buf.appendfv(fmt, args); + va_end(args); + for (int new_size = Buf.size(); old_size < new_size; old_size++) + if (Buf[old_size] == '\n') + LineOffsets.push_back(old_size + 1); + } + + void Draw(const char* title, bool* p_open = NULL) + { + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // Options menu + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::EndPopup(); + } + + // Main window + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + bool clear = ImGui::Button("Clear"); + ImGui::SameLine(); + bool copy = ImGui::Button("Copy"); + ImGui::SameLine(); + Filter.Draw("Filter", -100.0f); + + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + + if (clear) + Clear(); + if (copy) + ImGui::LogToClipboard(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + if (Filter.IsActive()) + { + // In this example we don't use the clipper when Filter is enabled. + // This is because we don't have a random access on the result on our filter. + // A real application processing logs with ten of thousands of entries may want to store the result of + // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); + } + } + else + { + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + // within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + // on your side is recommended. Using ImGuiListClipper requires + // - A) random access into your data + // - B) items all being the same height, + // both of which we can handle since we an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display + // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + // it possible (and would be recommended if you want to search through tens of thousands of entries). + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + } + ImGui::PopStyleVar(); + + if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + ImGui::SetScrollHereY(1.0f); + + ImGui::EndChild(); + ImGui::End(); + } +}; + +// Demonstrate creating a simple log window with basic filtering. +static void ShowExampleAppLog(bool* p_open) +{ + static ExampleAppLog log; + + // For the demo: add a debug button _BEFORE_ the normal log window contents + // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. + // Most of the contents of the window will be added by the log.Draw() call. + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); + ImGui::Begin("Example: Log", p_open); + IMGUI_DEMO_MARKER("Examples/Log"); + if (ImGui::SmallButton("[Debug] Add 5 entries")) + { + static int counter = 0; + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + for (int n = 0; n < 5; n++) + { + const char* category = categories[counter % IM_ARRAYSIZE(categories)]; + const char* word = words[counter % IM_ARRAYSIZE(words)]; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui::GetFrameCount(), category, ImGui::GetTime(), word); + counter++; + } + } + ImGui::End(); + + // Actually call in the regular Log helper (which will Begin() into the same window as we just did) + log.Draw("Example: Log", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +//----------------------------------------------------------------------------- + +// Demonstrate create a window with multiple child windows. +static void ShowExampleAppLayout(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + { + IMGUI_DEMO_MARKER("Examples/Simple layout"); + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // Left + static int selected = 0; + { + ImGui::BeginChild("left pane", ImVec2(150, 0), true); + for (int i = 0; i < 100; i++) + { + // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav + char label[128]; + sprintf(label, "MyObject %d", i); + if (ImGui::Selectable(label, selected == i)) + selected = i; + } + ImGui::EndChild(); + } + ImGui::SameLine(); + + // Right + { + ImGui::BeginGroup(); + ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us + ImGui::Text("MyObject: %d", selected); + ImGui::Separator(); + if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Description")) + { + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Details")) + { + ImGui::Text("ID: 0123456789"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::EndChild(); + if (ImGui::Button("Revert")) {} + ImGui::SameLine(); + if (ImGui::Button("Save")) {} + ImGui::EndGroup(); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +//----------------------------------------------------------------------------- + +static void ShowPlaceholderObject(const char* prefix, int uid) +{ + // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::PushID(uid); + + // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high. + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + ImGui::TableSetColumnIndex(1); + ImGui::Text("my sailor is rich"); + + if (node_open) + { + static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f }; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); // Use field index as identifier. + if (i < 2) + { + ShowPlaceholderObject("Child", 424242); + } + else + { + // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; + ImGui::TreeNodeEx("Field", flags, "Field_%d", i); + + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-FLT_MIN); + if (i >= 5) + ImGui::InputFloat("##value", &placeholder_members[i], 1.0f); + else + ImGui::DragFloat("##value", &placeholder_members[i], 0.01f); + ImGui::NextColumn(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + ImGui::PopID(); +} + +// Demonstrate create a simple property editor. +static void ShowExampleAppPropertyEditor(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Property editor", p_open)) + { + ImGui::End(); + return; + } + IMGUI_DEMO_MARKER("Examples/Property Editor"); + + HelpMarker( + "This example shows how you may implement a property editor using two columns.\n" + "All objects/fields data are dummies here.\n" + "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" + "your cursor horizontally instead of using the Columns() API."); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable)) + { + // Iterate placeholder objects (all the same data) + for (int obj_i = 0; obj_i < 4; obj_i++) + { + ShowPlaceholderObject("Object", obj_i); + //ImGui::Separator(); + } + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +//----------------------------------------------------------------------------- + +// Demonstrate/test rendering huge amount of text, and the incidence of clipping. +static void ShowExampleAppLongText(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Long text display", p_open)) + { + ImGui::End(); + return; + } + IMGUI_DEMO_MARKER("Examples/Long text display"); + + static int test_type = 0; + static ImGuiTextBuffer log; + static int lines = 0; + ImGui::Text("Printing unusually long amount of text."); + ImGui::Combo("Test type", &test_type, + "Single call to TextUnformatted()\0" + "Multiple calls to Text(), clipped\0" + "Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); + if (ImGui::Button("Clear")) { log.clear(); lines = 0; } + ImGui::SameLine(); + if (ImGui::Button("Add 1000 lines")) + { + for (int i = 0; i < 1000; i++) + log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); + lines += 1000; + } + ImGui::BeginChild("Log"); + switch (test_type) + { + case 0: + // Single call to TextUnformatted() with a big buffer + ImGui::TextUnformatted(log.begin(), log.end()); + break; + case 1: + { + // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGuiListClipper clipper; + clipper.Begin(lines); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + case 2: + // Multiple calls to Text(), not clipped (slow) + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + for (int i = 0; i < lines; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + ImGui::EndChild(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window which gets auto-resized according to its content. +static void ShowExampleAppAutoResize(bool* p_open) +{ + if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + IMGUI_DEMO_MARKER("Examples/Auto-resizing window"); + + static int lines = 10; + ImGui::TextUnformatted( + "Window will resize every-frame to the size of its content.\n" + "Note that you probably don't want to query the window size to\n" + "output your content because that would create a feedback loop."); + ImGui::SliderInt("Number of lines", &lines, 1, 20); + for (int i = 0; i < lines; i++) + ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window with custom resize constraints. +static void ShowExampleAppConstrainedResize(bool* p_open) +{ + struct CustomConstraints + { + // Helper functions to demonstrate programmatic constraints + static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } + static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + }; + + const char* test_desc[] = + { + "Resize vertical only", + "Resize horizontal only", + "Width > 100, Height > 100", + "Width 400-500", + "Height 400-500", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + }; + + static bool auto_resize = false; + static int type = 0; + static int display_lines = 10; + if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 + if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step + + ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; + if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) + { + IMGUI_DEMO_MARKER("Examples/Constrained Resizing window"); + if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); + if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); + if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } + ImGui::SetNextItemWidth(200); + ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); + ImGui::SetNextItemWidth(200); + ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); + ImGui::Checkbox("Auto-resize", &auto_resize); + for (int i = 0; i < display_lines; i++) + ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple static window with no decoration +// + a context-menu to choose which corner of the screen to use. +static void ShowExampleAppSimpleOverlay(bool* p_open) +{ + static int corner = 0; + ImGuiIO& io = ImGui::GetIO(); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; + if (corner != -1) + { + const float PAD = 10.0f; + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! + ImVec2 work_size = viewport->WorkSize; + ImVec2 window_pos, window_pos_pivot; + window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD); + window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD); + window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f; + window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f; + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + window_flags |= ImGuiWindowFlags_NoMove; + } + ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background + if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) + { + IMGUI_DEMO_MARKER("Examples/Simple Overlay"); + ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + ImGui::Separator(); + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse Position: "); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + if (p_open && ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndPopup(); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window covering the entire screen/viewport +static void ShowExampleAppFullscreen(bool* p_open) +{ + static bool use_work_area = true; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + + // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) + // Based on your use case you may want one of the other. + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); + ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); + + if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) + { + ImGui::Checkbox("Use work area instead of main area", &use_work_area); + ImGui::SameLine(); + HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); + + ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); + ImGui::Unindent(); + + if (p_open && ImGui::Button("Close this window")) + *p_open = false; + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +//----------------------------------------------------------------------------- + +// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. +// This apply to all regular items as well. +// Read FAQ section "How can I have multiple widgets with the same label?" for details. +static void ShowExampleAppWindowTitles(bool*) +{ + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImVec2 base_pos = viewport->Pos; + + // By default, Windows are uniquely identified by their title. + // You can use the "##" and "###" markers to manipulate the display/ID. + + // Using "##" to display same title but have unique identifier. + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##1"); + IMGUI_DEMO_MARKER("Examples/Manipulating window titles"); + ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); + ImGui::End(); + + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##2"); + ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); + ImGui::End(); + + // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" + char buf[128]; + sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); + ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); + ImGui::Begin(buf); + ImGui::Text("This window has a changing title."); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +//----------------------------------------------------------------------------- + +// Demonstrate using the low-level ImDrawList to draw custom shapes. +static void ShowExampleAppCustomRendering(bool* p_open) +{ + if (!ImGui::Begin("Example: Custom rendering", p_open)) + { + ImGui::End(); + return; + } + IMGUI_DEMO_MARKER("Examples/Custom Rendering"); + + // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! + + if (ImGui::BeginTabBar("##TabBar")) + { + if (ImGui::BeginTabItem("Primitives")) + { + ImGui::PushItemWidth(-ImGui::GetFontSize() * 15); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + // Draw gradients + // (note that those are currently exacerbating our sRGB/Linear issues) + // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + ImGui::Text("Gradients"); + ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); + ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient1", gradient_size); + } + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); + ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient2", gradient_size); + } + + // Draw a bunch of primitives + ImGui::Text("All primitives"); + static float sz = 36.0f; + static float thickness = 3.0f; + static int ngon_sides = 6; + static bool circle_segments_override = false; + static int circle_segments_override_v = 12; + static bool curve_segments_override = false; + static int curve_segments_override_v = 8; + static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); + ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); + ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); + ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); + ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40); + ImGui::ColorEdit4("Color", &colf.x); + + const ImVec2 p = ImGui::GetCursorScreenPos(); + const ImU32 col = ImColor(colf); + const float spacing = 10.0f; + const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight; + const float rounding = sz / 5.0f; + const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; + const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; + float x = p.x + 4.0f; + float y = p.y + 4.0f; + for (int n = 0; n < 2; n++) + { + // First line uses a thickness of 1.0f, second line uses the configurable thickness + float th = (n == 0) ? 1.0f : thickness; + draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon + draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle + //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line + + // Quadratic Bezier Curve (3 control points) + ImVec2 cp3[3] = { ImVec2(x, y + sz * 0.6f), ImVec2(x + sz * 0.5f, y - sz * 0.4f), ImVec2(x + sz, y + sz) }; + draw_list->AddBezierQuadratic(cp3[0], cp3[1], cp3[2], col, th, curve_segments); x += sz + spacing; + + // Cubic Bezier Curve (4 control points) + ImVec2 cp4[4] = { ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz) }; + draw_list->AddBezierCubic(cp4[0], cp4[1], cp4[2], cp4[3], col, th, curve_segments); + + x = p.x + 4; + y += sz + spacing; + } + draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon + draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle + //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) + draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); + + ImGui::Dummy(ImVec2((sz + spacing) * 10.2f, (sz + spacing) * 3.0f)); + ImGui::PopItemWidth(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Canvas")) + { + static ImVector points; + static ImVec2 scrolling(0.0f, 0.0f); + static bool opt_enable_grid = true; + static bool opt_enable_context_menu = true; + static bool adding_line = false; + + ImGui::Checkbox("Enable grid", &opt_enable_grid); + ImGui::Checkbox("Enable context menu", &opt_enable_context_menu); + ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); + + // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + // To use a child window instead we could use, e.g: + // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding + // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color + // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); + // ImGui::PopStyleColor(); + // ImGui::PopStyleVar(); + // [...] + // ImGui::EndChild(); + + // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available + if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; + if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; + ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); + + // Draw border and background color + ImGuiIO& io = ImGui::GetIO(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); + draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); + + // This will catch our interactions + ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); + const bool is_hovered = ImGui::IsItemHovered(); // Hovered + const bool is_active = ImGui::IsItemActive(); // Held + const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin + const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); + + // Add first and second point + if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + { + points.push_back(mouse_pos_in_canvas); + points.push_back(mouse_pos_in_canvas); + adding_line = true; + } + if (adding_line) + { + points.back() = mouse_pos_in_canvas; + if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) + adding_line = false; + } + + // Pan (we use a zero mouse threshold when there's no context menu) + // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; + if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) + { + scrolling.x += io.MouseDelta.x; + scrolling.y += io.MouseDelta.y; + } + + // Context menu (under default mouse threshold) + ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); + if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f) + ImGui::OpenPopupOnItemClick("context"); + if (ImGui::BeginPopup("context")) + { + if (adding_line) + points.resize(points.size() - 2); + adding_line = false; + if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } + if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } + ImGui::EndPopup(); + } + + // Draw grid + all lines in the canvas + draw_list->PushClipRect(canvas_p0, canvas_p1, true); + if (opt_enable_grid) + { + const float GRID_STEP = 64.0f; + for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) + draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); + for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) + draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); + } + for (int n = 0; n < points.Size; n += 2) + draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); + draw_list->PopClipRect(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("BG/FG draw lists")) + { + static bool draw_bg = true; + static bool draw_fg = true; + ImGui::Checkbox("Draw in Background draw list", &draw_bg); + ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); + ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); + ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); + ImVec2 window_pos = ImGui::GetWindowPos(); + ImVec2 window_size = ImGui::GetWindowSize(); + ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); + if (draw_bg) + ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); + if (draw_fg) + ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +//----------------------------------------------------------------------------- + +// Simplified structure to mimic a Document model +struct MyDocument +{ + const char* Name; // Document title + bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + bool WantClose; // Set when the document + ImVec4 Color; // An arbitrary variable associated to the document + + MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) + { + Name = name; + Open = OpenPrev = open; + Dirty = false; + WantClose = false; + Color = color; + } + void DoOpen() { Open = true; } + void DoQueueClose() { WantClose = true; } + void DoForceClose() { Open = false; Dirty = false; } + void DoSave() { Dirty = false; } + + // Display placeholder contents for the Document + static void DisplayContents(MyDocument* doc) + { + ImGui::PushID(doc); + ImGui::Text("Document \"%s\"", doc->Name); + ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + ImGui::PopStyleColor(); + if (ImGui::Button("Modify", ImVec2(100, 0))) + doc->Dirty = true; + ImGui::SameLine(); + if (ImGui::Button("Save", ImVec2(100, 0))) + doc->DoSave(); + ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui::PopID(); + } + + // Display context menu for the Document + static void DisplayContextMenu(MyDocument* doc) + { + if (!ImGui::BeginPopupContextItem()) + return; + + char buf[256]; + sprintf(buf, "Save %s", doc->Name); + if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) + doc->DoSave(); + if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) + doc->DoQueueClose(); + ImGui::EndPopup(); + } +}; + +struct ExampleAppDocuments +{ + ImVector Documents; + + ExampleAppDocuments() + { + Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); + Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); + Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("A Rather Long Title", false)); + Documents.push_back(MyDocument("Some Document", false)); + } +}; + +// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +// the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +// give the impression of a flicker for one frame. +// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. +static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) +{ + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open && doc->OpenPrev) + ImGui::SetTabItemClosed(doc->Name); + doc->OpenPrev = doc->Open; + } +} + +void ShowExampleAppDocuments(bool* p_open) +{ + static ExampleAppDocuments app; + + // Options + static bool opt_reorderable = true; + static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; + + bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); + if (!window_contents_visible) + { + ImGui::End(); + return; + } + + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + int open_count = 0; + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + open_count += app.Documents[doc_n].Open ? 1 : 0; + + if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) + { + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + if (ImGui::MenuItem(doc->Name)) + doc->DoOpen(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + app.Documents[doc_n].DoQueueClose(); + if (ImGui::MenuItem("Exit", "Alt+F4")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // [Debug] List documents with one checkbox for each + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc_n > 0) + ImGui::SameLine(); + ImGui::PushID(doc); + if (ImGui::Checkbox(doc->Name, &doc->Open)) + if (!doc->Open) + doc->DoForceClose(); + ImGui::PopID(); + } + + ImGui::Separator(); + + // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags. + // They have multiple effects: + // - Display a dot next to the title. + // - Tab is selected when clicking the X close button. + // - Closure is not assumed (will wait for user to stop submitting the tab). + // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty + // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. + // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. + + // Submit Tab Bar and Tabs + { + ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); + if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) + { + if (opt_reorderable) + NotifyOfDocumentsClosedElsewhere(app); + + // [DEBUG] Stress tests + //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. + + // Submit Tabs + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + continue; + + ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); + bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); + + // Cancel attempt to close when unsaved add to save queue so we can display a popup. + if (!doc->Open && doc->Dirty) + { + doc->Open = true; + doc->DoQueueClose(); + } + + MyDocument::DisplayContextMenu(doc); + if (visible) + { + MyDocument::DisplayContents(doc); + ImGui::EndTabItem(); + } + } + + ImGui::EndTabBar(); + } + } + + // Update closing queue + static ImVector close_queue; + if (close_queue.empty()) + { + // Close queue is locked once we started a popup + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc->WantClose) + { + doc->WantClose = false; + close_queue.push_back(doc); + } + } + } + + // Display closing confirmation UI + if (!close_queue.empty()) + { + int close_queue_unsaved_documents = 0; + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + close_queue_unsaved_documents++; + + if (close_queue_unsaved_documents == 0) + { + // Close documents when all are unsaved + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + } + else + { + if (!ImGui::IsPopupOpen("Save?")) + ImGui::OpenPopup("Save?"); + if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("Save change to the following items?"); + float item_height = ImGui::GetTextLineHeightWithSpacing(); + if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) + { + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + ImGui::Text("%s", close_queue[n]->Name); + ImGui::EndChildFrame(); + } + + ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); + if (ImGui::Button("Yes", button_size)) + { + for (int n = 0; n < close_queue.Size; n++) + { + if (close_queue[n]->Dirty) + close_queue[n]->DoSave(); + close_queue[n]->DoForceClose(); + } + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No", button_size)) + { + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", button_size)) + { + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + } + + ImGui::End(); +} + +// End of Demo code +#else + +void ImGui::ShowAboutWindow(bool*) {} +void ImGui::ShowDemoWindow(bool*) {} +void ImGui::ShowUserGuide() {} +void ImGui::ShowStyleEditor(ImGuiStyle*) {} + +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui_draw.cpp b/thirdparty/imgui/imgui_draw.cpp new file mode 100644 index 0000000..bf1da15 --- /dev/null +++ b/thirdparty/imgui/imgui_draw.cpp @@ -0,0 +1,4184 @@ +// dear imgui, v1.86 +// (drawing and font code) + +/* + +Index of this file: + +// [SECTION] STB libraries implementation +// [SECTION] Style functions +// [SECTION] ImDrawList +// [SECTION] ImDrawListSplitter +// [SECTION] ImDrawData +// [SECTION] Helpers ShadeVertsXXX functions +// [SECTION] ImFontConfig +// [SECTION] ImFontAtlas +// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontGlyphRangesBuilder +// [SECTION] ImFont +// [SECTION] ImGui Internal Render Helpers +// [SECTION] Decompression code +// [SECTION] Default font data (ProggyClean.ttf) + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui_internal.h" +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif + +#include // vsnprintf, sscanf, printf +#if !defined(alloca) +#if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__) +#include // alloca (glibc uses . Note that Cygwin may have _WIN32 defined, so the order matters here) +#elif defined(_WIN32) +#include // alloca +#if !defined(alloca) +#define alloca _alloca // for clang with MS Codegen +#endif +#else +#include // alloca +#endif +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 6255) // [Static Analyzer] _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead. +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#if __has_warning("-Walloca") +#pragma clang diagnostic ignored "-Walloca" // warning: use of function '__builtin_alloca' is discouraged +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries implementation +//------------------------------------------------------------------------- + +// Compile time options: +//#define IMGUI_STB_NAMESPACE ImStb +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE +{ +#endif + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. +#pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. +#pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#endif + +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit +#define STBRP_STATIC +#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) +#define STBRP_SORT ImQsort +#define STB_RECT_PACK_IMPLEMENTATION +#endif +#ifdef IMGUI_STB_RECT_PACK_FILENAME +#include IMGUI_STB_RECT_PACK_FILENAME +#else +#include "imstb_rectpack.h" +#endif +#endif + +#ifdef IMGUI_ENABLE_STB_TRUETYPE +#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit +#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) +#define STBTT_free(x,u) ((void)(u), IM_FREE(x)) +#define STBTT_assert(x) do { IM_ASSERT(x); } while(0) +#define STBTT_fmod(x,y) ImFmod(x,y) +#define STBTT_sqrt(x) ImSqrt(x) +#define STBTT_pow(x,y) ImPow(x,y) +#define STBTT_fabs(x) ImFabs(x) +#define STBTT_ifloor(x) ((int)ImFloorSigned(x)) +#define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#else +#define STBTT_DEF extern +#endif +#ifdef IMGUI_STB_TRUETYPE_FILENAME +#include IMGUI_STB_TRUETYPE_FILENAME +#else +#include "imstb_truetype.h" +#endif +#endif +#endif // IMGUI_ENABLE_STB_TRUETYPE + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif + +#ifdef IMGUI_STB_NAMESPACE +} // namespace ImStb +using namespace IMGUI_STB_NAMESPACE; +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Style functions +//----------------------------------------------------------------------------- + +void ImGui::StyleColorsDark(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); +} + +void ImGui::StyleColorsClassic(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +// Those light colors are better suited with a thicker font than the default one + FrameBorder +void ImGui::StyleColorsLight(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawList +//----------------------------------------------------------------------------- + +ImDrawListSharedData::ImDrawListSharedData() +{ + memset(this, 0, sizeof(*this)); + for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); + ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); + } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); +} + +void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) +{ + if (CircleSegmentMaxError == max_error) + return; + + IM_ASSERT(max_error > 0.0f); + CircleSegmentMaxError = max_error; + for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) + { + const float radius = (float)i; + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0); + } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); +} + +// Initialize before use in a new frame. We always have a command ready in the buffer. +void ImDrawList::_ResetForNewFrame() +{ + // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. + // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC) + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + + CmdBuffer.resize(0); + IdxBuffer.resize(0); + VtxBuffer.resize(0); + Flags = _Data->InitialFlags; + memset(&_CmdHeader, 0, sizeof(_CmdHeader)); + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.resize(0); + _TextureIdStack.resize(0); + _Path.resize(0); + _Splitter.Clear(); + CmdBuffer.push_back(ImDrawCmd()); + _FringeScale = 1.0f; +} + +void ImDrawList::_ClearFreeMemory() +{ + CmdBuffer.clear(); + IdxBuffer.clear(); + VtxBuffer.clear(); + Flags = ImDrawListFlags_None; + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.clear(); + _TextureIdStack.clear(); + _Path.clear(); + _Splitter.ClearFreeMemory(); +} + +ImDrawList* ImDrawList::CloneOutput() const +{ + ImDrawList* dst = IM_NEW(ImDrawList(_Data)); + dst->CmdBuffer = CmdBuffer; + dst->IdxBuffer = IdxBuffer; + dst->VtxBuffer = VtxBuffer; + dst->Flags = Flags; + return dst; +} + +void ImDrawList::AddDrawCmd() +{ + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() + draw_cmd.TextureId = _CmdHeader.TextureId; + draw_cmd.VtxOffset = _CmdHeader.VtxOffset; + draw_cmd.IdxOffset = IdxBuffer.Size; + + IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); + CmdBuffer.push_back(draw_cmd); +} + +// Pop trailing draw command (used before merging or presenting to user) +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +void ImDrawList::_PopUnusedDrawCmd() +{ + if (CmdBuffer.Size == 0) + return; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); +} + +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) +{ + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + IM_ASSERT(curr_cmd->UserCallback == NULL); + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + } + curr_cmd->UserCallback = callback; + curr_cmd->UserCallbackData = callback_data; + + AddDrawCmd(); // Force a new command after us (see comment below) +} + +// Compare ClipRect, TextureId and VtxOffset with a single memcmp() +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset + +// Try to merge two last draw commands +void ImDrawList::_TryMergeDrawCmds() +{ + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + { + prev_cmd->ElemCount += curr_cmd->ElemCount; + CmdBuffer.pop_back(); + } +} + +// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. +// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. +void ImDrawList::_OnChangedClipRect() +{ + // If current command is used with different settings we need to add a new command + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->ClipRect = _CmdHeader.ClipRect; +} + +void ImDrawList::_OnChangedTextureID() +{ + // If current command is used with different settings we need to add a new command + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->TextureId = _CmdHeader.TextureId; +} + +void ImDrawList::_OnChangedVtxOffset() +{ + // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. + _VtxCurrentIdx = 0; + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + curr_cmd->VtxOffset = _CmdHeader.VtxOffset; +} + +int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const +{ + // Automatic segment count + const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + return _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); +} + +// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) +void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) +{ + ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); + if (intersect_with_current_clip_rect) + { + ImVec4 current = _CmdHeader.ClipRect; + if (cr.x < current.x) cr.x = current.x; + if (cr.y < current.y) cr.y = current.y; + if (cr.z > current.z) cr.z = current.z; + if (cr.w > current.w) cr.w = current.w; + } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + + _ClipRectStack.push_back(cr); + _CmdHeader.ClipRect = cr; + _OnChangedClipRect(); +} + +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); +} + +void ImDrawList::PopClipRect() +{ + _ClipRectStack.pop_back(); + _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; + _OnChangedClipRect(); +} + +void ImDrawList::PushTextureID(ImTextureID texture_id) +{ + _TextureIdStack.push_back(texture_id); + _CmdHeader.TextureId = texture_id; + _OnChangedTextureID(); +} + +void ImDrawList::PopTextureID() +{ + _TextureIdStack.pop_back(); + _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; + _OnChangedTextureID(); +} + +// Reserve space for a number of vertices and indices. +// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or +// submit the intermediate results. PrimUnreserve() can be used to release unused allocations. +void ImDrawList::PrimReserve(int idx_count, int vtx_count) +{ + // Large mesh support (when enabled) + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) + { + // FIXME: In theory we should be testing that vtx_count <64k here. + // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us + // to not make that check until we rework the text functions to handle clipping and large horizontal lines better. + _CmdHeader.VtxOffset = VtxBuffer.Size; + _OnChangedVtxOffset(); + } + + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount += idx_count; + + int vtx_buffer_old_size = VtxBuffer.Size; + VtxBuffer.resize(vtx_buffer_old_size + vtx_count); + _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; + + int idx_buffer_old_size = IdxBuffer.Size; + IdxBuffer.resize(idx_buffer_old_size + idx_count); + _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; +} + +// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve(). +void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) +{ + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount -= idx_count; + VtxBuffer.shrink(VtxBuffer.Size - vtx_count); + IdxBuffer.shrink(IdxBuffer.Size - idx_count); +} + +// Fully unrolled with inline call to keep our debug builds decently fast. +void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +{ + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. +// - Those macros expects l-values and need to be used as their own statement. +// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0 +#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) +#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0 + +// TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness) +{ + if (points_count < 2) + return; + + const bool closed = (flags & ImDrawFlags_Closed) != 0; + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw + const bool thick_line = (thickness > _FringeScale); + + if (Flags & ImDrawListFlags_AntiAliasedLines) + { + // Anti-aliased stroke + const float AA_SIZE = _FringeScale; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + // Thicknesses <1.0 should behave like thickness 1.0 + thickness = ImMax(thickness, 1.0f); + const int integer_thickness = (int)thickness; + const float fractional_thickness = thickness - integer_thickness; + + // Do we want to draw this line using a texture? + // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. + // - If AA_SIZE is not 1.0f we cannot use the texture path. + const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + + // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off + IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); + + const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); + const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3); + PrimReserve(idx_count, vtx_count); + + // Temporary buffer + // The first items are normals at each line point, then after that there are either 2 or 4 temp points for each line point + ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((use_texture || !thick_line) ? 3 : 5) * sizeof(ImVec2)); //-V630 + ImVec2* temp_points = temp_normals + points_count; + + // Calculate normals (tangents) for each line segment + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; + } + if (!closed) + temp_normals[points_count - 1] = temp_normals[points_count - 2]; + + // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point + if (use_texture || !thick_line) + { + // [PATH 1] Texture-based lines (thick or non-thick) + // [PATH 2] Non texture-based lines (non-thick) + + // The width of the geometry we need to draw - this is essentially pixels for the line itself, plus "one pixel" for AA. + // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture + // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. + // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to + // allow scaling geometry while preserving one-screen-pixel AA fringe). + const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * half_draw_size; + temp_points[1] = points[0] - temp_normals[0] * half_draw_size; + temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; + temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; + } + + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment + const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area + dm_y *= half_draw_size; + + // Add temporary vertexes for the outer edges + ImVec2* out_vtx = &temp_points[i2 * 2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; + + if (use_texture) + { + // Add indices for two triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri + _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri + _IdxWritePtr += 6; + } + else + { + // Add indexes for four triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 + _IdxWritePtr += 12; + } + + idx1 = idx2; + } + + // Add vertexes for each point on the line + if (use_texture) + { + // If we're using textures we only need to emit the left/right edge vertices + ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness]; + /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false! + { + const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1]; + tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp() + tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness; + tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness; + tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness; + }*/ + ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y); + ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge + _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge + _VtxWritePtr += 2; + } + } + else + { + // If we're not using a texture, we need the center vertex as well + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line + _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge + _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge + _VtxWritePtr += 3; + } + } + } + else + { + // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + if (!closed) + { + const int points_last = points_count - 1; + temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); + temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); + temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + } + + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + { + const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment + const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertices + ImVec2* out_vtx = &temp_points[i2 * 4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr += 18; + + idx1 = idx2; + } + + // Add vertices + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr += 4; + } + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // [PATH 4] Non texture-based, Non anti-aliased lines + const int idx_count = count * 6; + const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges + PrimReserve(idx_count, vtx_count); + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; + const ImVec2& p1 = points[i1]; + const ImVec2& p2 = points[i2]; + + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); + _IdxWritePtr += 6; + _VtxCurrentIdx += 4; + } + } +} + +// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +{ + if (points_count < 3) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + if (Flags & ImDrawListFlags_AntiAliasedFill) + { + // Anti-aliased Fill + const float AA_SIZE = _FringeScale; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + const int idx_count = (points_count - 2)*3 + points_count * 6; + const int vtx_count = (points_count * 2); + PrimReserve(idx_count, vtx_count); + + // Add indexes for fill + unsigned int vtx_inner_idx = _VtxCurrentIdx; + unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); + _IdxWritePtr += 3; + } + + // Compute normals + ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2& p0 = points[i0]; + const ImVec2& p1 = points[i1]; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; + } + + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + // Average normals + const ImVec2& n0 = temp_normals[i0]; + const ImVec2& n1 = temp_normals[i1]; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; + + // Add vertices + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr += 2; + + // Add indexes for fringes + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr += 6; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Fill + const int idx_count = (points_count - 2)*3; + const int vtx_count = points_count; + PrimReserve(idx_count, vtx_count); + for (int i = 0; i < vtx_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr++; + } + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); + _IdxWritePtr += 3; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } +} + +void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + + // Calculate arc auto segment step size + if (a_step <= 0) + a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius); + + // Make sure we never do steps larger than one quarter of the circle + a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + + const int sample_range = ImAbs(a_max_sample - a_min_sample); + const int a_next_step = a_step; + + int samples = sample_range + 1; + bool extra_max_sample = false; + if (a_step > 1) + { + samples = sample_range / a_step + 1; + const int overstep = sample_range % a_step; + + if (overstep > 0) + { + extra_max_sample = true; + samples++; + + // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end, + // distribute first step range evenly between them by reducing first step size. + if (sample_range > 0) + a_step -= (a_step - overstep) / 2; + } + } + + _Path.resize(_Path.Size + samples); + ImVec2* out_ptr = _Path.Data + (_Path.Size - samples); + + int sample_index = a_min_sample; + if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + { + sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + } + + if (a_max_sample >= a_min_sample) + { + for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + else + { + for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + + if (extra_max_sample) + { + int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (normalized_max_sample < 0) + normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + + IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr); +} + +void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + + // Note that we are adding a point at both a_min and a_max. + // If you are trying to draw a full closed circle you don't want the overlapping points! + _Path.reserve(_Path.Size + (num_segments + 1)); + for (int i = 0; i <= num_segments; i++) + { + const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); + _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius)); + } +} + +// 0: East, 3: South, 6: West, 9: North, 12: East +void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0); +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + + if (num_segments > 0) + { + _PathArcToN(center, radius, a_min, a_max, num_segments); + return; + } + + // Automatic segment count + if (radius <= _Data->ArcFastRadiusCutoff) + { + const bool a_is_reverse = a_max < a_min; + + // We are going to use precomputed values for mid samples. + // Determine first and last sample in lookup table that belong to the arc. + const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f); + const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f); + + const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f); + const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f); + const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0); + + const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const bool a_emit_start = (a_min_segment_angle - a_min) != 0.0f; + const bool a_emit_end = (a_max - a_max_segment_angle) != 0.0f; + + _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0))); + if (a_emit_start) + _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)); + if (a_mid_samples > 0) + _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0); + if (a_emit_end) + _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)); + } + else + { + const float arc_length = ImAbs(a_max - a_min); + const int circle_segment_count = _CalcCircleAutoSegmentCount(radius); + const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length)); + _PathArcToN(center, radius, a_min, a_max, arc_segment_count); + } +} + +ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) +{ + float u = 1.0f - t; + float w1 = u * u * u; + float w2 = 3 * u * u * t; + float w3 = 3 * u * t * t; + float w4 = t * t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y); +} + +ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t) +{ + float u = 1.0f - t; + float w1 = u * u; + float w2 = 2 * u * t; + float w3 = t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y); +} + +// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp +static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = (x2 - x4) * dy - (y2 - y4) * dx; + float d3 = (x3 - x4) * dy - (y3 - y4) * dx; + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + path->push_back(ImVec2(x4, y4)); + } + else if (level < 10) + { + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f; + float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f; + PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level) +{ + float dx = x3 - x1, dy = y3 - y1; + float det = (x2 - x3) * dy - (y2 - y3) * dx; + if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy)) + { + path->push_back(ImVec2(x3, y3)); + } + else if (level < 10) + { + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1); + PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1); + } +} + +void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step)); + } +} + +void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step)); + } +} + +IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4)); +static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) +{ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All) + // ~0 --> ImDrawFlags_RoundCornersAll or 0 + if (flags == ~0) + return ImDrawFlags_RoundCornersAll; + + // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations) + // 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!) + // 0x02 --> ImDrawFlags_RoundCornersTopRight + // 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight + // 0x04 --> ImDrawFlags_RoundCornersBotLeft + // 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft + // ... + // 0x0F --> ImDrawFlags_RoundCornersAll or 0 + // (See all values in ImDrawCornerFlags_) + if (flags >= 0x01 && flags <= 0x0F) + return (flags << 4); + + // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f' +#endif + + // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values. + // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc... + IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); + + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags |= ImDrawFlags_RoundCornersAll; + + return flags; +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) +{ + flags = FixRectCornerFlags(flags); + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + PathLineTo(a); + PathLineTo(ImVec2(b.x, a.y)); + PathLineTo(b); + PathLineTo(ImVec2(a.x, b.y)); + } + else + { + const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f; + PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); + PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); + PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); + PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); + } +} + +void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + PathLineTo(p1 + ImVec2(0.5f, 0.5f)); + PathLineTo(p2 + ImVec2(0.5f, 0.5f)); + PathStroke(col, 0, thickness); +} + +// p_min = upper-left, p_max = lower-right +// Note we don't render 1 pixels sized rectangles properly. +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (Flags & ImDrawListFlags_AntiAliasedLines) + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags); + else + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + } + else + { + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); + } +} + +// p_min = upper-left, p_max = lower-right +void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) +{ + if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + PrimReserve(6, 4); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); + PrimWriteVtx(p_min, uv, col_upr_left); + PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); + PrimWriteVtx(p_max, uv, col_bot_right); + PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); +} + +void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathFillConvex(col); +} + +void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathFillConvex(col); +} + +void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + } + + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + } + + PathFillConvex(col); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +// Cubic Bezier takes 4 controls points +void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierCubicCurveTo(p2, p3, p4, num_segments); + PathStroke(col, 0, thickness); +} + +// Quadratic Bezier takes 3 controls points +void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierQuadraticCurveTo(p2, p3, num_segments); + PathStroke(col, 0, thickness); +} + +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (text_end == NULL) + text_end = text_begin + strlen(text_begin); + if (text_begin == text_end) + return; + + // Pull default font/size from the shared ImDrawListSharedData instance + if (font == NULL) + font = _Data->Font; + if (font_size == 0.0f) + font_size = _Data->FontSize; + + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + + ImVec4 clip_rect = _CmdHeader.ClipRect; + if (cpu_fine_clip_rect) + { + clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); + clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); + clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); + clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); + } + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); +} + +void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) +{ + AddText(NULL, 0.0f, pos, col, text_begin, text_end); +} + +void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimRectUV(p_min, p_max, uv_min, uv_max, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + flags = FixRectCornerFlags(flags); + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); + return; + } + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + int vert_start_idx = VtxBuffer.Size; + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); + int vert_end_idx = VtxBuffer.Size; + ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); + + if (push_texture_id) + PopTextureID(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawListSplitter +//----------------------------------------------------------------------------- +// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. +//----------------------------------------------------------------------------- + +void ImDrawListSplitter::ClearFreeMemory() +{ + for (int i = 0; i < _Channels.Size; i++) + { + if (i == _Current) + memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again + _Channels[i]._CmdBuffer.clear(); + _Channels[i]._IdxBuffer.clear(); + } + _Current = 0; + _Count = 1; + _Channels.clear(); +} + +void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) +{ + IM_UNUSED(draw_list); + IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); + int old_channels_count = _Channels.Size; + if (old_channels_count < channels_count) + { + _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable + _Channels.resize(channels_count); + } + _Count = channels_count; + + // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer + // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. + // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer + memset(&_Channels[0], 0, sizeof(ImDrawChannel)); + for (int i = 1; i < channels_count; i++) + { + if (i >= old_channels_count) + { + IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); + } + else + { + _Channels[i]._CmdBuffer.resize(0); + _Channels[i]._IdxBuffer.resize(0); + } + } +} + +void ImDrawListSplitter::Merge(ImDrawList* draw_list) +{ + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + if (_Count <= 1) + return; + + SetCurrentChannel(draw_list, 0); + draw_list->_PopUnusedDrawCmd(); + + // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. + int new_cmd_buffer_count = 0; + int new_idx_buffer_count = 0; + ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; + int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + + // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback. + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) + ch._CmdBuffer.pop_back(); + + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) + { + ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + { + // Merge previous channel last draw command with current channel first draw command if matching. + last_cmd->ElemCount += next_cmd->ElemCount; + idx_offset += next_cmd->ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + } + } + if (ch._CmdBuffer.Size > 0) + last_cmd = &ch._CmdBuffer.back(); + new_cmd_buffer_count += ch._CmdBuffer.Size; + new_idx_buffer_count += ch._IdxBuffer.Size; + for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) + { + ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; + idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; + } + } + draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); + draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); + + // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) + ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; + ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } + if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } + } + draw_list->_IdxWritePtr = idx_write; + + // Ensure there's always a non-callback draw command trailing the command-buffer + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); + + _Count = 1; +} + +void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) +{ + IM_ASSERT(idx >= 0 && idx < _Count); + if (_Current == idx) + return; + + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() + memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); + _Current = idx; + memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); + draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd == NULL) + draw_list->AddDrawCmd(); + else if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawData +//----------------------------------------------------------------------------- + +// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! +void ImDrawData::DeIndexAllBuffers() +{ + ImVector new_vtx_buffer; + TotalVtxCount = TotalIdxCount = 0; + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + if (cmd_list->IdxBuffer.empty()) + continue; + new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); + for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; + cmd_list->VtxBuffer.swap(new_vtx_buffer); + cmd_list->IdxBuffer.resize(0); + TotalVtxCount += cmd_list->VtxBuffer.Size; + } +} + +// Helper to scale the ClipRect field of each ImDrawCmd. +// Use if your final output buffer is at a different scale than draw_data->DisplaySize, +// or if there is a difference between your window resolution and framebuffer resolution. +void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) +{ + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; + cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Helpers ShadeVertsXXX functions +//----------------------------------------------------------------------------- + +// Generic linear color gradient, write to RGB fields, leave A untouched. +void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) +{ + ImVec2 gradient_extent = gradient_p1 - gradient_p0; + float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF; + const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF; + const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF; + const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r; + const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g; + const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b; + for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) + { + float d = ImDot(vert->pos - gradient_p0, gradient_extent); + float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); + int r = (int)(col0_r + col_delta_r * t); + int g = (int)(col0_g + col_delta_g * t); + int b = (int)(col0_b + col_delta_b * t); + vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); + } +} + +// Distribute UV over (a, b) rectangle +void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +{ + const ImVec2 size = b - a; + const ImVec2 uv_size = uv_b - uv_a; + const ImVec2 scale = ImVec2( + size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, + size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); + + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + if (clamp) + { + const ImVec2 min = ImMin(uv_a, uv_b); + const ImVec2 max = ImMax(uv_a, uv_b); + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); + } + else + { + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontConfig +//----------------------------------------------------------------------------- + +ImFontConfig::ImFontConfig() +{ + memset(this, 0, sizeof(*this)); + FontDataOwnedByAtlas = true; + OversampleH = 3; // FIXME: 2 may be a better default? + OversampleV = 1; + GlyphMaxAdvanceX = FLT_MAX; + RasterizerMultiply = 1.0f; + EllipsisChar = (ImWchar)-1; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas +//----------------------------------------------------------------------------- + +// A work of art lies ahead! (. = white layer, X = black layer, others are blank) +// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. +// (This is used when io.MouseDrawCursor = true) +const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing. +const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" + "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " + " X..X - - X...X - X...X - X..X X..X - - X........X - " + " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " + "------------- - X - X -X.....................X- ------------------- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " +}; + +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = +{ + // Pos ........ Size ......... Offset ...... + { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE + { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand + { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed +}; + +ImFontAtlas::ImFontAtlas() +{ + memset(this, 0, sizeof(*this)); + TexGlyphPadding = 1; + PackIdMouseCursors = PackIdLines = -1; +} + +ImFontAtlas::~ImFontAtlas() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Clear(); +} + +void ImFontAtlas::ClearInputData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < ConfigData.Size; i++) + if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) + { + IM_FREE(ConfigData[i].FontData); + ConfigData[i].FontData = NULL; + } + + // When clearing this we lose access to the font name and other information used to build the font. + for (int i = 0; i < Fonts.Size; i++) + if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) + { + Fonts[i]->ConfigData = NULL; + Fonts[i]->ConfigDataCount = 0; + } + ConfigData.clear(); + CustomRects.clear(); + PackIdMouseCursors = PackIdLines = -1; + // Important: we leave TexReady untouched +} + +void ImFontAtlas::ClearTexData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + if (TexPixelsAlpha8) + IM_FREE(TexPixelsAlpha8); + if (TexPixelsRGBA32) + IM_FREE(TexPixelsRGBA32); + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; + TexPixelsUseColors = false; + // Important: we leave TexReady untouched +} + +void ImFontAtlas::ClearFonts() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Fonts.clear_delete(); + TexReady = false; +} + +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Build atlas on demand + if (TexPixelsAlpha8 == NULL) + Build(); + + *out_pixels = TexPixelsAlpha8; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; +} + +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Convert to RGBA32 format on demand + // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp + if (!TexPixelsRGBA32) + { + unsigned char* pixels = NULL; + GetTexDataAsAlpha8(&pixels, NULL, NULL); + if (pixels) + { + TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); + const unsigned char* src = pixels; + unsigned int* dst = TexPixelsRGBA32; + for (int n = TexWidth * TexHeight; n > 0; n--) + *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); + } + } + + *out_pixels = (unsigned char*)TexPixelsRGBA32; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; +} + +ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); + IM_ASSERT(font_cfg->SizePixels > 0.0f); + + // Create new font + if (!font_cfg->MergeMode) + Fonts.push_back(IM_NEW(ImFont)); + else + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + + ConfigData.push_back(*font_cfg); + ImFontConfig& new_font_cfg = ConfigData.back(); + if (new_font_cfg.DstFont == NULL) + new_font_cfg.DstFont = Fonts.back(); + if (!new_font_cfg.FontDataOwnedByAtlas) + { + new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); + new_font_cfg.FontDataOwnedByAtlas = true; + memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + } + + if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) + new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; + + // Invalidate texture + TexReady = false; + ClearTexData(); + return new_font_cfg.DstFont; +} + +// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) +static unsigned int stb_decompress_length(const unsigned char* input); +static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); +static const char* GetDefaultCompressedFontDataTTFBase85(); +static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } +static void Decode85(const unsigned char* src, unsigned char* dst) +{ + while (*src) + { + unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); + dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. + src += 5; + dst += 4; + } +} + +// Load embedded ProggyClean.ttf at size 13, disable oversampling +ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) +{ + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (!font_cfg_template) + { + font_cfg.OversampleH = font_cfg.OversampleV = 1; + font_cfg.PixelSnapH = true; + } + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); + font_cfg.EllipsisChar = (ImWchar)0x0085; + font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units + + const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); + const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); + ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); + return font; +} + +ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + size_t data_size = 0; + void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); + if (!data) + { + IM_ASSERT_USER_ERROR(0, "Could not load font file!"); + return NULL; + } + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (font_cfg.Name[0] == '\0') + { + // Store a short copy of filename into into the font name for convenience + const char* p; + for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); + } + return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); +} + +// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontData = ttf_data; + font_cfg.FontDataSize = ttf_size; + font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels; + if (glyph_ranges) + font_cfg.GlyphRanges = glyph_ranges; + return AddFont(&font_cfg); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); + unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size); + stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); + + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontDataOwnedByAtlas = true; + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) +{ + int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; + void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); + Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); + ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); + IM_FREE(compressed_ttf); + return font; +} + +int ImFontAtlas::AddCustomRectRegular(int width, int height) +{ + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +{ +#ifdef IMGUI_USE_WCHAR32 + IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); +#endif + IM_ASSERT(font != NULL); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + r.GlyphID = id; + r.GlyphAdvanceX = advance_x; + r.GlyphOffset = offset; + r.Font = font; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +{ + IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed + *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); +} + +bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +{ + if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) + return false; + if (Flags & ImFontAtlasFlags_NoMouseCursors) + return false; + + IM_ASSERT(PackIdMouseCursors != -1); + ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); + ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; + *out_size = size; + *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; + out_uv_border[0] = (pos) * TexUvScale; + out_uv_border[1] = (pos + size) * TexUvScale; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + out_uv_fill[0] = (pos) * TexUvScale; + out_uv_fill[1] = (pos + size) * TexUvScale; + return true; +} + +bool ImFontAtlas::Build() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + + // Default font is none are specified + if (ConfigData.Size == 0) + AddFontDefault(); + + // Select builder + // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which + // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere + // and point to it instead of pointing directly to return value of the GetBuilderXXX functions. + const ImFontBuilderIO* builder_io = FontBuilderIO; + if (builder_io == NULL) + { +#ifdef IMGUI_ENABLE_FREETYPE + builder_io = ImGuiFreeType::GetBuilderForFreeType(); +#elif defined(IMGUI_ENABLE_STB_TRUETYPE) + builder_io = ImFontAtlasGetBuilderForStbTruetype(); +#else + IM_ASSERT(0); // Invalid Build function +#endif + } + + // Build + return builder_io->FontBuilder_Build(this); +} + +void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) +{ + for (unsigned int i = 0; i < 256; i++) + { + unsigned int value = (unsigned int)(i * in_brighten_factor); + out_table[i] = value > 255 ? 255 : (value & 0xFF); + } +} + +void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) +{ + unsigned char* data = pixels + x + y * stride; + for (int j = h; j > 0; j--, data += stride) + for (int i = 0; i < w; i++) + data[i] = table[data[i]]; +} + +#ifdef IMGUI_ENABLE_STB_TRUETYPE +// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) +// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) +struct ImFontBuildSrcData +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + stbtt_packedchar* PackedChars; // Output glyphs + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstData +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out) +{ + IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); + const ImU32* it_begin = in->Storage.begin(); + const ImU32* it_end = in->Storage.end(); + for (const ImU32* it = it_begin; it < it_end; it++) + if (ImU32 entries_32 = *it) + for (ImU32 bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & ((ImU32)1 << bit_n)) + out->push_back((int)(((it - it_begin) << 5) + bit_n)); +} + +static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->ConfigData.Size > 0); + + ImFontAtlasBuildInit(atlas); + + // Clear atlas + atlas->TexID = (ImTextureID)NULL; + atlas->TexWidth = atlas->TexHeight = 0; + atlas->TexUvScale = ImVec2(0.0f, 0.0f); + atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); + atlas->ClearTexData(); + + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); + + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + if (src_tmp.DstIndex == -1) + { + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + return false; + } + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + return false; + + // Measure highest codepoints + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); + if (dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint); + dst_tmp.GlyphsSet.SetBit(codepoint); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + ImVector buf_packedchars; + buf_rects.resize(total_glyphs_count); + buf_packedchars.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + int total_surface = 0; + int buf_rects_out_n = 0; + int buf_packedchars_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + buf_packedchars_out_n += src_tmp.GlyphsCount; + + // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.PackRange.font_size = cfg.SizePixels; + src_tmp.PackRange.first_unicode_codepoint_in_range = 0; + src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; + src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; + src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + + // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) + const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) + { + int x0, y0, x1, y1; + const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); + IM_ASSERT(glyph_index_in_font != 0); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; + } + } + + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + stbtt_pack_context spc = {}; + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture + atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); + atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); + memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + spc.pixels = atlas->TexPixelsAlpha8; + spc.height = atlas->TexHeight; + + // 8. Render/rasterize font characters into the texture + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); + + // Apply multiply operator + if (cfg.RasterizerMultiply != 1.0f) + { + unsigned char multiply_table[256]; + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + stbrp_rect* r = &src_tmp.Rects[0]; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) + if (r->was_packed) + ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); + } + src_tmp.Rects = NULL; + } + + // End packing + stbtt_PackEnd(&spc); + buf_rects.clear(); + + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + // When merging fonts with MergeMode=true: + // - We can have multiple input fonts writing into a same destination font. + // - dst_font->ConfigData is != from cfg which is our source configuration. + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFont* dst_font = cfg.DstFont; + + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + + const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); + const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); + ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + const float font_off_x = cfg.GlyphOffset.x; + const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); + + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + { + // Register glyph + const int codepoint = src_tmp.GlyphsList[glyph_i]; + const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; + stbtt_aligned_quad q; + float unused_x = 0.0f, unused_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0); + dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); + } + } + + // Cleanup + src_tmp_array.clear_destruct(); + + ImFontAtlasBuildFinish(atlas); + return true; +} + +const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() +{ + static ImFontBuilderIO io; + io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; + return &io; +} + +#endif // IMGUI_ENABLE_STB_TRUETYPE + +void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) +{ + if (!font_config->MergeMode) + { + font->ClearOutputData(); + font->FontSize = font_config->SizePixels; + font->ConfigData = font_config; + font->ConfigDataCount = 0; + font->ContainerAtlas = atlas; + font->Ascent = ascent; + font->Descent = descent; + } + font->ConfigDataCount++; +} + +void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) +{ + stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; + IM_ASSERT(pack_context != NULL); + + ImVector& user_rects = atlas->CustomRects; + IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. + + ImVector pack_rects; + pack_rects.resize(user_rects.Size); + memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); + for (int i = 0; i < user_rects.Size; i++) + { + pack_rects[i].w = user_rects[i].Width; + pack_rects[i].h = user_rects[i].Height; + } + stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); + for (int i = 0; i < pack_rects.Size; i++) + if (pack_rects[i].was_packed) + { + user_rects[i].X = pack_rects[i].x; + user_rects[i].Y = pack_rects[i].y; + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); + } +} + +void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; +} + +void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; +} + +static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +{ + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); + IM_ASSERT(r->IsPacked()); + + const int w = atlas->TexWidth; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + { + // Render/copy pixels + IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + const int x_for_white = r->X; + const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + if (atlas->TexPixelsAlpha8 != NULL) + { + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + } + else + { + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + } + } + else + { + // Render 4 white pixels + IM_ASSERT(r->Width == 2 && r->Height == 2); + const int offset = (int)r->X + (int)r->Y * w; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } + } + atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); +} + +static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) +{ + if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) + return; + + // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); + IM_ASSERT(r->IsPacked()); + for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row + { + // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle + unsigned int y = n; + unsigned int line_width = n; + unsigned int pad_left = (r->Width - line_width) / 2; + unsigned int pad_right = r->Width - (pad_left + line_width); + + // Write each slice + IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else + { + unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32_BLACK_TRANS; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32_BLACK_TRANS; + } + + // Calculate UVs for this line + ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale; + float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); + } +} + +// Note: this is called / shared by both the stb_truetype and the FreeType builder +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + // Register texture region for mouse cursors or standard white pixels + if (atlas->PackIdMouseCursors < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + else + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2); + } + + // Register texture region for thick lines + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row + if (atlas->PackIdLines < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines)) + atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + } +} + +// This is called/shared by both the stb_truetype and the FreeType builder. +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + // Render into our custom data blocks + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); + ImFontAtlasBuildRenderDefaultTexData(atlas); + ImFontAtlasBuildRenderLinesTexData(atlas); + + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; + if (r->Font == NULL || r->GlyphID == 0) + continue; + + // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH + IM_ASSERT(r->Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(r, &uv0, &uv1); + r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); + } + + // Build all fonts lookup tables + for (int i = 0; i < atlas->Fonts.Size; i++) + if (atlas->Fonts[i]->DirtyLookupTables) + atlas->Fonts[i]->BuildLookupTable(); + + atlas->TexReady = true; +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3131, 0x3163, // Korean alphabets + 0xAC00, 0xD7A3, // Korean characters + 0xFFFD, 0xFFFD, // Invalid + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD, // Invalid + 0x4e00, 0x9FAF, // CJK Ideograms + 0, + }; + return &ranges[0]; +} + +static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) +{ + for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) + { + out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]); + base_codepoint += accumulative_offsets[n]; + } + out_ranges[0] = 0; +} + +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas glyph ranges helpers +//------------------------------------------------------------------------- + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +{ + // Store 2500 regularly used characters for Simplified Chinese. + // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 + // This table covers 97.97% of all characters used during the month in July, 1987. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, + 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, + 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, + 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, + 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, + 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, + 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, + 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, + 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, + 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, + 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, + 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, + 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, + 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, + 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, + 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, + 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, + 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, + 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, + 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, + 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, + 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, + 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, + 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, + 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, + 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, + 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, + 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, + 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, + 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, + 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, + 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, + 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, + 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, + 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, + 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, + 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, + 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, + 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, + 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() +{ + // 2999 ideograms code points for Japanese + // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points + // - 863 Jinmeiyo (meaning "for personal name") Kanji code points + // - Sourced from the character information database of the Information-technology Promotion Agency, Japan + // - https://mojikiban.ipa.go.jp/mji/ + // - Available under the terms of the Creative Commons Attribution-ShareAlike 2.1 Japan (CC BY-SA 2.1 JP). + // - https://creativecommons.org/licenses/by-sa/2.1/jp/deed.en + // - https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode + // - You can generate this code by the script at: + // - https://github.com/vaiorabbit/everyday_use_kanji + // - References: + // - List of Joyo Kanji + // - (Official list by the Agency for Cultural Affairs) https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kakuki/14/tosin02/index.html + // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji + // - List of Jinmeiyo Kanji + // - (Official list by the Ministry of Justice) http://www.moj.go.jp/MINJI/minji86.html + // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji + // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1, + 1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3, + 2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8, + 2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5, + 2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1, + 1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30, + 2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3, + 13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4, + 5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14, + 2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1, + 1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1, + 7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1, + 1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1, + 6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2, + 10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7, + 2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5, + 3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1, + 6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7, + 4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2, + 4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5, + 1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6, + 12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2, + 1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16, + 22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11, + 2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18, + 18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9, + 14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3, + 1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6, + 40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1, + 12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8, + 2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1, + 1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10, + 1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5, + 3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2, + 14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5, + 12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1, + 2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5, + 1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4, + 3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7, + 2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5, + 13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13, + 18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21, + 37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1, + 5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38, + 32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4, + 1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4, + 4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1, + 3,2,1,1,1,1,2,1,1, + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement + 0x2DE0, 0x2DFF, // Cyrillic Extended-A + 0xA640, 0xA69F, // Cyrillic Extended-B + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x2010, 0x205E, // Punctuations + 0x0E00, 0x0E7F, // Thai + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x0102, 0x0103, + 0x0110, 0x0111, + 0x0128, 0x0129, + 0x0168, 0x0169, + 0x01A0, 0x01A1, + 0x01AF, 0x01B0, + 0x1EA0, 0x1EF9, + 0, + }; + return &ranges[0]; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontGlyphRangesBuilder +//----------------------------------------------------------------------------- + +void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) +{ + while (text_end ? (text < text_end) : *text) + { + unsigned int c = 0; + int c_len = ImTextCharFromUtf8(&c, text, text_end); + text += c_len; + if (c_len == 0) + break; + AddChar((ImWchar)c); + } +} + +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) +{ + for (; ranges[0]; ranges += 2) + for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 + AddChar((ImWchar)c); +} + +void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +{ + const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; + for (int n = 0; n <= max_codepoint; n++) + if (GetBit(n)) + { + out_ranges->push_back((ImWchar)n); + while (n < max_codepoint && GetBit(n + 1)) + n++; + out_ranges->push_back((ImWchar)n); + } + out_ranges->push_back(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFont +//----------------------------------------------------------------------------- + +ImFont::ImFont() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + FallbackChar = (ImWchar)-1; + EllipsisChar = (ImWchar)-1; + DotChar = (ImWchar)-1; + FallbackGlyph = NULL; + ContainerAtlas = NULL; + ConfigData = NULL; + ConfigDataCount = 0; + DirtyLookupTables = false; + Scale = 1.0f; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); +} + +ImFont::~ImFont() +{ + ClearOutputData(); +} + +void ImFont::ClearOutputData() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + Glyphs.clear(); + IndexAdvanceX.clear(); + IndexLookup.clear(); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + DirtyLookupTables = true; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) +{ + for (int n = 0; n < candidate_chars_count; n++) + if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) + return candidate_chars[n]; + return (ImWchar)-1; +} + +void ImFont::BuildLookupTable() +{ + int max_codepoint = 0; + for (int i = 0; i != Glyphs.Size; i++) + max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + + // Build lookup table + IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved + IndexAdvanceX.clear(); + IndexLookup.clear(); + DirtyLookupTables = false; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + GrowIndex(max_codepoint + 1); + for (int i = 0; i < Glyphs.Size; i++) + { + int codepoint = (int)Glyphs[i].Codepoint; + IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; + IndexLookup[codepoint] = (ImWchar)i; + + // Mark 4K page as used + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + } + + // Create a glyph to handle TAB + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + if (FindGlyph((ImWchar)' ')) + { + if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& tab_glyph = Glyphs.back(); + tab_glyph = *FindGlyph((ImWchar)' '); + tab_glyph.Codepoint = '\t'; + tab_glyph.AdvanceX *= IM_TABSIZE; + IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); + } + + // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) + SetGlyphVisible((ImWchar)' ', false); + SetGlyphVisible((ImWchar)'\t', false); + + // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. + const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + if (EllipsisChar == (ImWchar)-1) + EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); + if (DotChar == (ImWchar)-1) + DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + + // Setup fallback character + const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + if (FallbackGlyph == NULL) + { + FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars)); + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + if (FallbackGlyph == NULL) + { + FallbackGlyph = &Glyphs.back(); + FallbackChar = (ImWchar)FallbackGlyph->Codepoint; + } + } + + FallbackAdvanceX = FallbackGlyph->AdvanceX; + for (int i = 0; i < max_codepoint + 1; i++) + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; +} + +// API is designed this way to avoid exposing the 4K page size +// e.g. use with IsGlyphRangeUnused(0, 255) +bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) +{ + unsigned int page_begin = (c_begin / 4096); + unsigned int page_last = (c_last / 4096); + for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) + if ((page_n >> 3) < sizeof(Used4kPagesMap)) + if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + return false; + return true; +} + +void ImFont::SetGlyphVisible(ImWchar c, bool visible) +{ + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) + glyph->Visible = visible ? 1 : 0; +} + +void ImFont::GrowIndex(int new_size) +{ + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); + if (new_size <= IndexLookup.Size) + return; + IndexAdvanceX.resize(new_size, -1.0f); + IndexLookup.resize(new_size, (ImWchar)-1); +} + +// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. +// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). +// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. +void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +{ + if (cfg != NULL) + { + // Clamp & recenter if needed + const float advance_x_original = advance_x; + advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX); + if (advance_x != advance_x_original) + { + float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; + x0 += char_off_x; + x1 += char_off_x; + } + + // Snap to pixel + if (cfg->PixelSnapH) + advance_x = IM_ROUND(advance_x); + + // Bake spacing + advance_x += cfg->GlyphExtraSpacing.x; + } + + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& glyph = Glyphs.back(); + glyph.Codepoint = (unsigned int)codepoint; + glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.Colored = false; + glyph.X0 = x0; + glyph.Y0 = y0; + glyph.X1 = x1; + glyph.Y1 = y1; + glyph.U0 = u0; + glyph.V0 = v0; + glyph.U1 = u1; + glyph.V1 = v1; + glyph.AdvanceX = advance_x; + + // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. + float pad = ContainerAtlas->TexGlyphPadding + 0.99f; + DirtyLookupTables = true; + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); +} + +void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +{ + IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. + unsigned int index_size = (unsigned int)IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists + return; + if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + return; + + GrowIndex(dst + 1); + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; + IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; +} + +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return FallbackGlyph; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return FallbackGlyph; + return &Glyphs.Data[i]; +} + +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return NULL; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return NULL; + return &Glyphs.Data[i]; +} + +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ + // Simple word-wrapping for English, not full-featured. Please submit failing cases! + // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) + + // For references, possible wrap point marked with ^ + // "aaa bbb, ccc,ddd. eee fff. ggg!" + // ^ ^ ^ ^ ^__ ^ ^ + + // List of hardcoded separators: .,;!?'" + + // Skip extra blanks after a line returns (that includes not counting them in width computation) + // e.g. "Hello world" --> "Hello" "World" + + // Cut words that cannot possibly fit within one line. + // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" + + float line_width = 0.0f; + float word_width = 0.0f; + float blank_width = 0.0f; + wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters + + const char* word_end = text; + const char* prev_word_end = NULL; + bool inside_word = true; + + const char* s = text; + while (s < text_end) + { + unsigned int c = (unsigned int)*s; + const char* next_s; + if (c < 0x80) + next_s = s + 1; + else + next_s = s + ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + + if (c < 32) + { + if (c == '\n') + { + line_width = word_width = blank_width = 0.0f; + inside_word = true; + s = next_s; + continue; + } + if (c == '\r') + { + s = next_s; + continue; + } + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + if (ImCharIsBlankW(c)) + { + if (inside_word) + { + line_width += blank_width; + blank_width = 0.0f; + word_end = s; + } + blank_width += char_width; + inside_word = false; + } + else + { + word_width += char_width; + if (inside_word) + { + word_end = next_s; + } + else + { + prev_word_end = word_end; + line_width += word_width + blank_width; + word_width = blank_width = 0.0f; + } + + // Allow wrapping after punctuation. + inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); + } + + // We ignore blank width at the end of the line (they can be skipped) + if (line_width + word_width > wrap_width) + { + // Words that cannot possibly fit within an entire line will be cut anywhere. + if (word_width < wrap_width) + s = prev_word_end ? prev_word_end : word_end; + break; + } + + s = next_s; + } + + return s; +} + +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. + + const float line_height = size; + const float scale = size / FontSize; + + ImVec2 text_size = ImVec2(0, 0); + float line_width = 0.0f; + + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + const char* s = text_begin; + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + if (text_size.x < line_width) + text_size.x = line_width; + text_size.y += line_height; + line_width = 0.0f; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + const char* prev_s = s; + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + continue; + } + if (c == '\r') + continue; + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; + if (line_width + char_width >= max_width) + { + s = prev_s; + break; + } + + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const +{ + const ImFontGlyph* glyph = FindGlyph(c); + if (!glyph || !glyph->Visible) + return; + if (glyph->Colored) + col |= ~IM_COL32_A_MASK; + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + pos.x = IM_FLOOR(pos.x); + pos.y = IM_FLOOR(pos.y); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); +} + +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + + // Align to be pixel perfect + pos.x = IM_FLOOR(pos.x); + pos.y = IM_FLOOR(pos.y); + float x = pos.x; + float y = pos.y; + if (y > clip_rect.w) + return; + + const float scale = size / FontSize; + const float line_height = FontSize * scale; + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + // Fast-forward to first visible line + const char* s = text_begin; + if (y + line_height < clip_rect.y && !word_wrap_enabled) + while (y + line_height < clip_rect.y && s < text_end) + { + s = (const char*)memchr(s, '\n', text_end - s); + s = s ? s + 1 : text_end; + y += line_height; + } + + // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() + // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) + if (text_end - s > 10000 && !word_wrap_enabled) + { + const char* s_end = s; + float y_end = y; + while (y_end < clip_rect.w && s_end < text_end) + { + s_end = (const char*)memchr(s_end, '\n', text_end - s_end); + s_end = s_end ? s_end + 1 : text_end; + y_end += line_height; + } + text_end = s_end; + } + if (s == text_end) + return; + + // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int vtx_count_max = (int)(text_end - s) * 4; + const int idx_count_max = (int)(text_end - s) * 6; + const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; + draw_list->PrimReserve(idx_count_max, vtx_count_max); + + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + x = pos.x; + y += line_height; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + x = pos.x; + y += line_height; + if (y > clip_rect.w) + break; // break out of main loop + continue; + } + if (c == '\r') + continue; + } + + const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + if (glyph == NULL) + continue; + + float char_width = glyph->AdvanceX * scale; + if (glyph->Visible) + { + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + if (x1 <= clip_rect.z && x2 >= clip_rect.x) + { + // Render a character + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip) + { + if (x1 < clip_rect.x) + { + u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); + x1 = clip_rect.x; + } + if (y1 < clip_rect.y) + { + v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); + y1 = clip_rect.y; + } + if (x2 > clip_rect.z) + { + u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); + x2 = clip_rect.z; + } + if (y2 > clip_rect.w) + { + v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); + y2 = clip_rect.w; + } + if (y1 >= y2) + { + x += char_width; + continue; + } + } + + // Support for untinted glyphs + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + { + idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); + idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + vtx_write += 4; + vtx_current_idx += 4; + idx_write += 6; + } + } + } + x += char_width; + } + + // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. + draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() + draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); + draw_list->_VtxWritePtr = vtx_write; + draw_list->_IdxWritePtr = idx_write; + draw_list->_VtxCurrentIdx = vtx_current_idx; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGui Internal Render Helpers +//----------------------------------------------------------------------------- +// Vaguely redesigned to stop accessing ImGui global state: +// - RenderArrow() +// - RenderBullet() +// - RenderCheckMark() +// - RenderMouseCursor() +// - RenderArrowPointingAt() +// - RenderRectFilledRangeH() +// - RenderRectFilledWithHole() +//----------------------------------------------------------------------------- +// Function in need of a redesign (legacy mess) +// - RenderColorRectWithAlphaCheckerboard() +//----------------------------------------------------------------------------- + +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) +{ + const float h = draw_list->_Data->FontSize * 1.00f; + float r = h * 0.40f * scale; + ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); + + ImVec2 a, b, c; + switch (dir) + { + case ImGuiDir_Up: + case ImGuiDir_Down: + if (dir == ImGuiDir_Up) r = -r; + a = ImVec2(+0.000f, +0.750f) * r; + b = ImVec2(-0.866f, -0.750f) * r; + c = ImVec2(+0.866f, -0.750f) * r; + break; + case ImGuiDir_Left: + case ImGuiDir_Right: + if (dir == ImGuiDir_Left) r = -r; + a = ImVec2(+0.750f, +0.000f) * r; + b = ImVec2(-0.750f, +0.866f) * r; + c = ImVec2(-0.750f, -0.866f) * r; + break; + case ImGuiDir_None: + case ImGuiDir_COUNT: + IM_ASSERT(0); + break; + } + draw_list->AddTriangleFilled(center + a, center + b, center + c, col); +} + +void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +{ + draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); +} + +void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) +{ + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + float third = sz / 3.0f; + float bx = pos.x + third; + float by = pos.y + sz - third * 0.5f; + draw_list->PathLineTo(ImVec2(bx - third, by - third)); + draw_list->PathLineTo(ImVec2(bx, by)); + draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); + draw_list->PathStroke(col, 0, thickness); +} + +void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) +{ + if (mouse_cursor == ImGuiMouseCursor_None) + return; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + + ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; + ImVec2 offset, size, uv[4]; + if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + { + pos -= offset; + ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } +} + +// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. +void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) +{ + switch (direction) + { + case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings + } +} + +static inline float ImAcos01(float x) +{ + if (x <= 0.0f) return IM_PI * 0.5f; + if (x >= 1.0f) return 0.0f; + return ImAcos(x); + //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. +} + +// FIXME: Cleanup and move code to ImDrawList. +void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) +{ + if (x_end_norm == x_start_norm) + return; + if (x_start_norm > x_end_norm) + ImSwap(x_start_norm, x_end_norm); + + ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); + ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); + if (rounding == 0.0f) + { + draw_list->AddRectFilled(p0, p1, col, 0.0f); + return; + } + + rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); + const float inv_rounding = 1.0f / rounding; + const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); + const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. + const float x0 = ImMax(p0.x, rect.Min.x + rounding); + if (arc0_b == arc0_e) + { + draw_list->PathLineTo(ImVec2(x0, p1.y)); + draw_list->PathLineTo(ImVec2(x0, p0.y)); + } + else if (arc0_b == 0.0f && arc0_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL + draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR + } + else + { + draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL + draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR + } + if (p1.x > rect.Min.x + rounding) + { + const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); + const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); + const float x1 = ImMin(p1.x, rect.Max.x - rounding); + if (arc1_b == arc1_e) + { + draw_list->PathLineTo(ImVec2(x1, p0.y)); + draw_list->PathLineTo(ImVec2(x1, p1.y)); + } + else if (arc1_b == 0.0f && arc1_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR + draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR + } + else + { + draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR + draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR + } + } + draw_list->PathFillConvex(col); +} + +void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding) +{ + const bool fill_L = (inner.Min.x > outer.Min.x); + const bool fill_R = (inner.Max.x < outer.Max.x); + const bool fill_U = (inner.Min.y > outer.Min.y); + const bool fill_D = (inner.Max.y < outer.Max.y); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); +} + +// Helper for ColorPicker4() +// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. +// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. +// FIXME: uses ImGui::GetColorU32 +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) +{ + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags = ImDrawFlags_RoundCornersDefault_; + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); + + int yi = 0; + for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) + { + float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + if (y2 <= y1) + continue; + for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + { + float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + if (x2 <= x1) + continue; + ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; + if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } + + // Combine flags + cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags); + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags); + } + } + } + else + { + draw_list->AddRectFilled(p_min, p_max, col, rounding, flags); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Decompression code +//----------------------------------------------------------------------------- +// Compressed with stb_compress() then converted to a C array and encoded as base85. +// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file. +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h +//----------------------------------------------------------------------------- + +static unsigned int stb_decompress_length(const unsigned char *input) +{ + return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; +} + +static unsigned char *stb__barrier_out_e, *stb__barrier_out_b; +static const unsigned char *stb__barrier_in_b; +static unsigned char *stb__dout; +static void stb__match(const unsigned char *data, unsigned int length) +{ + // INVERSE of memmove... write each byte before copying the next... + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } + while (length--) *stb__dout++ = *data++; +} + +static void stb__lit(const unsigned char *data, unsigned int length) +{ + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } + memcpy(stb__dout, data, length); + stb__dout += length; +} + +#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) +#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) +#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) + +static const unsigned char *stb_decompress_token(const unsigned char *i) +{ + if (*i >= 0x20) { // use fewer if's for cases that expand small + if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; + else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { // more ifs for cases that expand large, since overhead is amortized + if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; + else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; + else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); + else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); + else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; + else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; + } + return i; +} + +static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) +{ + const unsigned long ADLER_MOD = 65521; + unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; + unsigned long blocklen = buflen % 5552; + + unsigned long i; + while (buflen) { + for (i=0; i + 7 < blocklen; i += 8) { + s1 += buffer[0], s2 += s1; + s1 += buffer[1], s2 += s1; + s1 += buffer[2], s2 += s1; + s1 += buffer[3], s2 += s1; + s1 += buffer[4], s2 += s1; + s1 += buffer[5], s2 += s1; + s1 += buffer[6], s2 += s1; + s1 += buffer[7], s2 += s1; + + buffer += 8; + } + + for (; i < blocklen; ++i) + s1 += *buffer++, s2 += s1; + + s1 %= ADLER_MOD, s2 %= ADLER_MOD; + buflen -= blocklen; + blocklen = 5552; + } + return (unsigned int)(s2 << 16) + (unsigned int)s1; +} + +static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) +{ + if (stb__in4(0) != 0x57bC0000) return 0; + if (stb__in4(4) != 0) return 0; // error! stream is > 4GB + const unsigned int olen = stb_decompress_length(i); + stb__barrier_in_b = i; + stb__barrier_out_e = output + olen; + stb__barrier_out_b = output; + i += 16; + + stb__dout = output; + for (;;) { + const unsigned char *old_i = i; + i = stb_decompress_token(i); + if (i == old_i) { + if (*i == 0x05 && i[1] == 0xfa) { + IM_ASSERT(stb__dout == output + olen); + if (stb__dout != output + olen) return 0; + if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) + return 0; + return olen; + } else { + IM_ASSERT(0); /* NOTREACHED */ + return 0; + } + } + IM_ASSERT(stb__dout <= output + olen); + if (stb__dout > output + olen) + return 0; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Default font data (ProggyClean.ttf) +//----------------------------------------------------------------------------- +// ProggyClean.ttf +// Copyright (c) 2004, 2005 Tristan Grimmer +// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) +// Download and more information at http://upperbounds.net +//----------------------------------------------------------------------------- +// File: 'ProggyClean.ttf' (41208 bytes) +// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +//----------------------------------------------------------------------------- +static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; + +static const char* GetDefaultCompressedFontDataTTFBase85() +{ + return proggy_clean_ttf_compressed_data_base85; +} + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui_internal.h b/thirdparty/imgui/imgui_internal.h new file mode 100644 index 0000000..73d58f6 --- /dev/null +++ b/thirdparty/imgui/imgui_internal.h @@ -0,0 +1,2857 @@ +// dear imgui, v1.86 +// (internal structures/api) + +// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! +// Set: +// #define IMGUI_DEFINE_MATH_OPERATORS +// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) + +/* + +Index of this file: + +// [SECTION] Header mess +// [SECTION] Forward declarations +// [SECTION] Context pointer +// [SECTION] STB libraries includes +// [SECTION] Macros +// [SECTION] Generic helpers +// [SECTION] ImDrawList support +// [SECTION] Widgets support: flags, enums, data structures +// [SECTION] Clipper support +// [SECTION] Navigation support +// [SECTION] Columns support +// [SECTION] Multi-select support +// [SECTION] Docking support +// [SECTION] Viewport support +// [SECTION] Settings support +// [SECTION] Metrics, Debug tools +// [SECTION] Generic context hooks +// [SECTION] ImGuiContext (main imgui context) +// [SECTION] ImGuiWindowTempData, ImGuiWindow +// [SECTION] Tab bar, Tab item support +// [SECTION] Table support +// [SECTION] ImGui internal API +// [SECTION] ImFontAtlas internal API +// [SECTION] Test Engine specific hooks (imgui_test_engine) + +*/ + +#pragma once +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#ifndef IMGUI_VERSION +#include "imgui.h" +#endif + +#include // FILE*, sscanf +#include // NULL, malloc, free, qsort, atoi, atof +#include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf +#include // INT_MIN, INT_MAX + +// Enable SSE intrinsics if available +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE) +#define IMGUI_ENABLE_SSE +#include +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 26812) // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned() +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// Legacy defines +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#endif + +// Enable stb_truetype by default unless FreeType is enabled. +// You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together. +#ifndef IMGUI_ENABLE_FREETYPE +#define IMGUI_ENABLE_STB_TRUETYPE +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward declarations +//----------------------------------------------------------------------------- + +struct ImBitVector; // Store 1-bit per value +struct ImRect; // An axis-aligned rectangle (2 points) +struct ImDrawDataBuilder; // Helper to build a ImDrawData instance +struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it +struct ImGuiContext; // Main Dear ImGui context +struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine +struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum +struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box +struct ImGuiLastItemData; // Status storage for last submitted items +struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only +struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions +struct ImGuiNextWindowData; // Storage for SetNextWindow** functions +struct ImGuiNextItemData; // Storage for SetNextItem** functions +struct ImGuiOldColumnData; // Storage data for a single column for legacy Columns() api +struct ImGuiOldColumns; // Storage data for a columns set for legacy Columns() api +struct ImGuiPopupData; // Storage for current popup stack +struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting +struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiTabBar; // Storage for a tab bar +struct ImGuiTabItem; // Storage for a tab item (within a tab bar) +struct ImGuiTable; // Storage for a table +struct ImGuiTableColumn; // Storage for one column of a table +struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables. +struct ImGuiTableSettings; // Storage for a table .ini settings +struct ImGuiTableColumnsSettings; // Storage for a column .ini settings +struct ImGuiWindow; // Storage for one window +struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) +struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) + +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical +typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags +typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() +typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions +typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions +typedef int ImGuiScrollFlags; // -> enum ImGuiScrollFlags_ // Flags: for ScrollToItem() and navigation requests +typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() +typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() +typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() + +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); + +//----------------------------------------------------------------------------- +// [SECTION] Context pointer +// See implementation of this variable in imgui.cpp for comments and details. +//----------------------------------------------------------------------------- + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries includes +//------------------------------------------------------------------------- + +namespace ImStb +{ + +#undef STB_TEXTEDIT_STRING +#undef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_STRING ImGuiInputTextState +#define STB_TEXTEDIT_CHARTYPE ImWchar +#define STB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#include "imstb_textedit.h" + +} // namespace ImStb + +//----------------------------------------------------------------------------- +// [SECTION] Macros +//----------------------------------------------------------------------------- + +// Debug Logging +#ifndef IMGUI_DEBUG_LOG +#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) +#endif + +// Debug Logging for selected systems. Remove the '((void)0) //' to enable. +//#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log +//#define IMGUI_DEBUG_LOG_NAV IMGUI_DEBUG_LOG // Enable log +#define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log +#define IMGUI_DEBUG_LOG_NAV(...) ((void)0) // Disable log + +// Static Asserts +#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") +#else +#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#endif + +// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. +// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. +//#define IMGUI_DEBUG_PARANOID +#ifdef IMGUI_DEBUG_PARANOID +#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) +#else +#define IM_ASSERT_PARANOID(_EXPR) +#endif + +// Error handling +// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error +#endif + +// Misc Macros +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) +#else +#define IM_NEWLINE "\n" +#endif +#define IM_TABSIZE (4) +#define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + (_ALIGN - 1)) & ~(_ALIGN - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8 +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 +#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif + +// Warnings +#if defined(_MSC_VER) && !defined(__clang__) +#define IM_MSVC_WARNING_SUPPRESS(XXXX) __pragma(warning(suppress: XXXX)) +#else +#define IM_MSVC_WARNING_SUPPRESS(XXXX) +#endif + +// Debug Tools +// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item. +// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference. +#ifndef IM_DEBUG_BREAK +#if defined (_MSC_VER) +#define IM_DEBUG_BREAK() __debugbreak() +#elif defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define IM_DEBUG_BREAK() __asm__ volatile("int $0x03") +#elif defined(__GNUC__) && defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0"); +#else +#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! +#endif +#endif // #ifndef IM_DEBUG_BREAK + +//----------------------------------------------------------------------------- +// [SECTION] Generic helpers +// Note that the ImXXX helpers functions are lower-level than ImGui functions. +// ImGui functions or the ImGui context are never called/used from other ImXXX functions. +//----------------------------------------------------------------------------- +// - Helpers: Hashing +// - Helpers: Sorting +// - Helpers: Bit manipulation +// - Helpers: String, Formatting +// - Helpers: UTF-8 <> wchar conversions +// - Helpers: ImVec2/ImVec4 operators +// - Helpers: Maths +// - Helpers: Geometry +// - Helper: ImVec1 +// - Helper: ImVec2ih +// - Helper: ImRect +// - Helper: ImBitArray +// - Helper: ImBitVector +// - Helper: ImSpan<>, ImSpanAllocator<> +// - Helper: ImPool<> +// - Helper: ImChunkStream<> +//----------------------------------------------------------------------------- + +// Helpers: Hashing +IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static inline ImGuiID ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] +#endif + +// Helpers: Sorting +#ifndef ImQsort +static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } +#endif + +// Helpers: Color Blending +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); + +// Helpers: Bit manipulation +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } + +// Helpers: String, Formatting +IMGUI_API int ImStricmp(const char* str1, const char* str2); +IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); +IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); +IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); +IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); +IMGUI_API int ImStrlenW(const ImWchar* str); +IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line +IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); +IMGUI_API void ImStrTrimBlanks(char* str); +IMGUI_API const char* ImStrSkipBlank(const char* str); +IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API const char* ImParseFormatFindStart(const char* format); +IMGUI_API const char* ImParseFormatFindEnd(const char* format); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); +IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } + +// Helpers: UTF-8 <> wchar conversions +IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf +IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 + +// Helpers: ImVec2/ImVec4 operators +// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) +// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +IM_MSVC_RUNTIME_CHECKS_OFF +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + +// Helpers: File System +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS +#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef void* ImFileHandle; +static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +static inline bool ImFileClose(ImFileHandle) { return false; } +static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } +static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } +static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } +#endif +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef FILE* ImFileHandle; +IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); +IMGUI_API bool ImFileClose(ImFileHandle file); +IMGUI_API ImU64 ImFileGetSize(ImFileHandle file); +IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); +IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); +#else +#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + +// Helpers: Maths +IM_MSVC_RUNTIME_CHECKS_OFF +// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) +#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#define ImFabs(X) fabsf(X) +#define ImSqrt(X) sqrtf(X) +#define ImFmod(X, Y) fmodf((X), (Y)) +#define ImCos(X) cosf(X) +#define ImSin(X) sinf(X) +#define ImAcos(X) acosf(X) +#define ImAtan2(Y, X) atan2f((Y), (X)) +#define ImAtof(STR) atof(STR) +//#define ImFloorStd(X) floorf(X) // We use our own, see ImFloor() and ImFloorSigned() +#define ImCeil(X) ceilf(X) +static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision +static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision +static inline double ImLog(double x) { return log(x); } +static inline int ImAbs(int x) { return x < 0 ? -x : x; } +static inline float ImAbs(float x) { return fabsf(x); } +static inline double ImAbs(double x) { return fabs(x); } +static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument +static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } +#ifdef IMGUI_ENABLE_SSE +static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +#else +static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +#endif +static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } +#endif +// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double +// (Exceptionally using templates here but we could also redefine them for those types) +template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } +template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } +template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } +// - Misc maths helpers +static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } +static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } +static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } +static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } +static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)(f); } +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +static inline int ImModPositive(int a, int b) { return (a + b) % b; } +static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } +static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } +static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helpers: Geometry +IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); +IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments +IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol +IMGUI_API ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t); +IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); +IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); +inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); + +// Helper: ImVec1 (1D vector) +// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImVec1 +{ + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } +}; + +// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) +struct ImVec2ih +{ + short x, y; + ImVec2ih() { x = y = 0; } + ImVec2ih(short _x, short _y) { x = _x; y = _y; } + explicit ImVec2ih(const ImVec2& rhs) { x = (short)rhs.x; y = (short)rhs.y; } +}; + +// Helper: ImRect (2D axis aligned bounding-box) +// NB: we can't rely on ImVec2 math operators being available here! +struct IMGUI_API ImRect +{ + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right + + ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + + ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } + float GetWidth() const { return Max.x - Min.x; } + float GetHeight() const { return Max.y - Min.y; } + float GetArea() const { return (Max.x - Min.x) * (Max.y - Min.y); } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } + void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } + void TranslateX(float dx) { Min.x += dx; Max.x += dx; } + void TranslateY(float dy) { Min.y += dy; Max.y += dy; } + void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. + void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } + bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } + ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helper: ImBitArray +inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } +inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } +inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } +inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on range [n..n2) +{ + n2--; + while (n <= n2) + { + int a_mod = (n & 31); + int b_mod = (n2 > (n | 31) ? 31 : (n2 & 31)) + 1; + ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); + arr[n >> 5] |= mask; + n = (n + 32) & ~31; + } +} + +// Helper: ImBitArray class (wrapper over ImBitArray functions) +// Store 1-bit per value. +template +struct IMGUI_API ImBitArray +{ + ImU32 Storage[(BITCOUNT + 31) >> 5]; + ImBitArray() { ClearAllBits(); } + void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } + void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } + bool TestBit(int n) const { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + void SetBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArraySetBit(Storage, n); } + void ClearBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArrayClearBit(Storage, n); } + void SetBitRange(int n, int n2) { ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) +}; + +// Helper: ImBitVector +// Store 1-bit per value. +struct IMGUI_API ImBitVector +{ + ImVector Storage; + void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } + void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } + void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } +}; + +// Helper: ImSpan<> +// Pointing to a span of data we don't own. +template +struct ImSpan +{ + T* Data; + T* DataEnd; + + // Constructors, destructor + inline ImSpan() { Data = DataEnd = NULL; } + inline ImSpan(T* data, int size) { Data = data; DataEnd = data + size; } + inline ImSpan(T* data, T* data_end) { Data = data; DataEnd = data_end; } + + inline void set(T* data, int size) { Data = data; DataEnd = data + size; } + inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; } + inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } + inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } + inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + inline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return DataEnd; } + inline const T* end() const { return DataEnd; } + + // Utilities + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; } +}; + +// Helper: ImSpanAllocator<> +// Facilitate storing multiple chunks into a single large block (the "arena") +// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges. +template +struct ImSpanAllocator +{ + char* BasePtr; + int CurrOff; + int CurrIdx; + int Offsets[CHUNKS]; + int Sizes[CHUNKS]; + + ImSpanAllocator() { memset(this, 0, sizeof(*this)); } + inline void Reserve(int n, size_t sz, int a=4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; } + inline int GetArenaSizeInBytes() { return CurrOff; } + inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } + inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); } + inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); } + template + inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } +}; + +// Helper: ImPool<> +// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, +// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. +typedef int ImPoolIdx; +template +struct IMGUI_API ImPool +{ + ImVector Buf; // Contiguous data + ImGuiStorage Map; // ID->Index + ImPoolIdx FreeIdx; // Next free idx to use + ImPoolIdx AliveCount; // Number of active/alive items (for display purpose) + + ImPool() { FreeIdx = AliveCount = 0; } + ~ImPool() { Clear(); } + T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } + T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } + ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } + T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } + bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = AliveCount = 0; } + T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); AliveCount++; return &Buf[idx]; } + void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } + void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); AliveCount--; } + void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } + + // To iterate a ImPool: for (int n = 0; n < pool.GetMapSize(); n++) if (T* t = pool.TryGetMapData(n)) { ... } + // Can be avoided if you know .Remove() has never been called on the pool, or AliveCount == GetMapSize() + int GetAliveCount() const { return AliveCount; } // Number of active/alive items in the pool (for display purpose) + int GetBufSize() const { return Buf.Size; } + int GetMapSize() const { return Map.Data.Size; } // It is the map we need iterate to find valid items, since we don't have "alive" storage anywhere + T* TryGetMapData(ImPoolIdx n) { int idx = Map.Data[n].val_i; if (idx == -1) return NULL; return GetByIndex(idx); } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + int GetSize() { return GetMapSize(); } // For ImPlot: should use GetMapSize() from (IMGUI_VERSION_NUM >= 18304) +#endif +}; + +// Helper: ImChunkStream<> +// Build and iterate a contiguous stream of variable-sized structures. +// This is used by Settings to store persistent data while reducing allocation count. +// We store the chunk size first, and align the final size on 4 bytes boundaries. +// The tedious/zealous amount of casting is to avoid -Wcast-align warnings. +template +struct IMGUI_API ImChunkStream +{ + ImVector Buf; + + void clear() { Buf.clear(); } + bool empty() const { return Buf.Size == 0; } + int size() const { return Buf.Size; } + T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } + T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } + T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } + int chunk_size(const T* p) { return ((const int*)p)[-1]; } + T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } + int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } + T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } + void swap(ImChunkStream& rhs) { rhs.Buf.swap(Buf); } + +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawList support +//----------------------------------------------------------------------------- + +// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. +// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693 +// Number of segments (N) is calculated using equation: +// N = ceil ( pi / acos(1 - error / r) ) where r > 0, error <= r +// Our equation is significantly simpler that one in the post thanks for choosing segment that is +// perpendicular to X axis. Follow steps in the article from this starting condition and you will +// will get this result. +// +// Rendering circles with an odd number of segments, while mathematically correct will produce +// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.) +// +#define IM_ROUNDUP_TO_EVEN(_V) ((((_V) + 1) / 2) * 2) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +// Raw equation from IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC rewritten for 'r' and 'error'. +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR) ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI)))) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD) ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD)) + +// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle. +#ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE +#define IM_DRAWLIST_ARCFAST_TABLE_SIZE 48 // Number of samples in lookup table. +#endif +#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. + +// Data shared between all ImDrawList instances +// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +struct IMGUI_API ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() + float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + + // [Internal] Lookup tables + ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. + float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() + ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas + + ImDrawListSharedData(); + void SetCircleTessellationMaxError(float max_error); +}; + +struct ImDrawDataBuilder +{ + ImVector Layers[2]; // Global layers for: regular, tooltip + + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + int GetDrawListCount() const { int count = 0; for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) count += Layers[n].Size; return count; } + IMGUI_API void FlattenIntoSingleLayer(); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Widgets support: flags, enums, data structures +//----------------------------------------------------------------------------- + +// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +// This is going to be exposed in imgui.h when stabilized enough. +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing (FIXME: should merge with _NoNav) + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false // Disable keyboard/gamepad directional navigation (FIXME: should merge with _NoTabStop) + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items) + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window + ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) + ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. + ImGuiItemFlags_Inputable = 1 << 8 // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. +}; + +// Storage for LastItem data +enum ImGuiItemStatusFlags_ +{ + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test) + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // g.LastItemData.DisplayRect is valid + ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues. + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. + ImGuiItemStatusFlags_Deactivated = 1 << 6, // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_HoveredWindow = 1 << 7, // Override the HoveredWindow test to allow cross-window hover testing. + ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8 // Set when the Focusable item just got focused by Tabbing (FIXME: to be removed soon) + +#ifdef IMGUI_ENABLE_TEST_ENGINE + , // [imgui_tests only] + ImGuiItemStatusFlags_Openable = 1 << 20, // + ImGuiItemStatusFlags_Opened = 1 << 21, // + ImGuiItemStatusFlags_Checkable = 1 << 22, // + ImGuiItemStatusFlags_Checked = 1 << 23 // +#endif +}; + +// Extend ImGuiInputTextFlags_ +enum ImGuiInputTextFlagsPrivate_ +{ + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_MergedItem = 1 << 28 // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. +}; + +// Extend ImGuiButtonFlags_ +enum ImGuiButtonFlagsPrivate_ +{ + ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event) + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item + ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) + ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat + ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] + //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease +}; + +// Extend ImGuiComboFlags_ +enum ImGuiComboFlagsPrivate_ +{ + ImGuiComboFlags_CustomPreview = 1 << 20 // enable BeginComboPreview() +}; + +// Extend ImGuiSliderFlags_ +enum ImGuiSliderFlagsPrivate_ +{ + ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically? + ImGuiSliderFlags_ReadOnly = 1 << 21 +}; + +// Extend ImGuiSelectableFlags_ +enum ImGuiSelectableFlagsPrivate_ +{ + // NB: need to be in sync with last value of ImGuiSelectableFlags_ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnNav = 1 << 21, // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API. + ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release) + ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release) + ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 25, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26, // Set Nav/Focus ID on mouse hover (used by MenuItem) + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 27 // Disable padding each side with ItemSpacing * 0.5f +}; + +// Extend ImGuiTreeNodeFlags_ +enum ImGuiTreeNodeFlagsPrivate_ +{ + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 +}; + +enum ImGuiSeparatorFlags_ +{ + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 +}; + +enum ImGuiTextFlags_ +{ + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}; + +enum ImGuiTooltipFlags_ +{ + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 // Override will clear/ignore previously submitted tooltip (defaults to append) +}; + +// FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}; + +enum ImGuiLogType +{ + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}; + +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}; + +enum ImGuiPlotType +{ + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only + ImGuiInputSource_Clipboard, // Currently only used by InputText() + ImGuiInputSource_COUNT +}; + +// FIXME-NAV: Clarify/expose various repeat delay/rate +enum ImGuiInputReadMode +{ + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}; + +enum ImGuiPopupPositionPolicy +{ + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip +}; + +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT +}; + +// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo(). +struct ImGuiDataTypeInfo +{ + size_t Size; // Size in bytes + const char* Name; // Short descriptive name for the type, for debugging + const char* PrintFmt; // Default printf format for the type + const char* ScanFmt; // Default scanf format for the type +}; + +// Extend ImGuiDataType_ +enum ImGuiDataTypePrivate_ +{ + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID +}; + +// Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } +}; + +// Storage data for BeginComboPreview()/EndComboPreview() +struct IMGUI_API ImGuiComboPreviewData +{ + ImRect PreviewRect; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; + float BackupPrevLineTextBaseOffset; + ImGuiLayoutType BackupLayout; + + ImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); } +}; + +// Stacked storage data for BeginGroup()/EndGroup() +struct IMGUI_API ImGuiGroupData +{ + ImGuiID WindowID; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; + bool EmitItem; +}; + +// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. +struct IMGUI_API ImGuiMenuColumns +{ + ImU32 TotalWidth; + ImU32 NextTotalWidth; + ImU16 Spacing; + ImU16 OffsetIcon; // Always zero for now + ImU16 OffsetLabel; // Offsets are locked in Update() + ImU16 OffsetShortcut; + ImU16 OffsetMark; + ImU16 Widths[4]; // Width of: Icon, Label, Shortcut, Mark (accumulators for current frame) + + ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } + void Update(float spacing, bool window_reappearing); + float DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark); + void CalcNextTotalWidth(bool update_offsets); +}; + +// Internal state of the currently focused/edited text input box +// For a given item ID, access with ImGui::GetInputTextState() +struct IMGUI_API ImGuiInputTextState +{ + ImGuiID ID; // widget id owning the text state + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. + ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. + ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. + ImVector InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) + int BufCapacityA; // end-user buffer capacity + float ScrollX; // horizontal scrolling/offset + ImStb::STB_TexteditState Stb; // state for stb_textedit.h + float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately + bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) + bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection + bool Edited; // edited this frame + ImGuiInputTextFlags Flags; // copy of InputText() flags + + ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } + void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } + int GetUndoAvailCount() const { return Stb.undostate.undo_point; } + int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } + void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation + + // Cursor & Selection + void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking + void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } + bool HasSelection() const { return Stb.select_start != Stb.select_end; } + void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + int GetCursorPos() const { return Stb.cursor; } + int GetSelectionStart() const { return Stb.select_start; } + int GetSelectionEnd() const { return Stb.select_end; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } +}; + +// Storage for current popup stack +struct ImGuiPopupData +{ + ImGuiID PopupId; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* SourceWindow; // Set on OpenPopup() copy of NavWindow at the time of opening the popup + int OpenFrameCount; // Set on OpenPopup() + ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) + ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) + ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup + + ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; } +}; + +enum ImGuiNextWindowDataFlags_ +{ + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7 +}; + +// Storage for SetNexWindow** functions +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; // Override background alpha + ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) + + ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } +}; + +enum ImGuiNextItemDataFlags_ +{ + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1 +}; + +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; // Set by SetNextItemWidth() + ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) + ImGuiCond OpenCond; + bool OpenVal; // Set by SetNextItemOpen() + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! +}; + +// Status storage for the last submitted item +struct ImGuiLastItemData +{ + ImGuiID ID; + ImGuiItemFlags InFlags; // See ImGuiItemFlags_ + ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ + ImRect Rect; // Full rectangle + ImRect NavRect; // Navigation scoring rectangle (not displayed) + ImRect DisplayRect; // Display rectangle (only if ImGuiItemStatusFlags_HasDisplayRect is set) + + ImGuiLastItemData() { memset(this, 0, sizeof(*this)); } +}; + +struct IMGUI_API ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfItemFlagsStack; + short SizeOfBeginPopupStack; + short SizeOfDisabledStack; + + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + void SetToCurrentState(); + void CompareWithCurrentState(); +}; + +// Data saved for each window pushed into the stack +struct ImGuiWindowStackData +{ + ImGuiWindow* Window; + ImGuiLastItemData ParentLastItemDataBackup; + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting +}; + +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; +}; + +struct ImGuiPtrOrIndex +{ + void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. + int Index; // Usually index in a main pool. + + ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } + ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Clipper support +//----------------------------------------------------------------------------- + +struct ImGuiListClipperRange +{ + int Min; + int Max; + bool PosToIndexConvert; // Begin/End are absolute position (will be converted to indices later) + ImS8 PosToIndexOffsetMin; // Add to Min after converting to indices + ImS8 PosToIndexOffsetMax; // Add to Min after converting to indices + + static ImGuiListClipperRange FromIndices(int min, int max) { ImGuiListClipperRange r = { min, max, false, 0, 0 }; return r; } + static ImGuiListClipperRange FromPositions(float y1, float y2, int off_min, int off_max) { ImGuiListClipperRange r = { (int)y1, (int)y2, true, (ImS8)off_min, (ImS8)off_max }; return r; } +}; + +// Temporary clipper data, buffers shared/reused between instances +struct ImGuiListClipperData +{ + ImGuiListClipper* ListClipper; + float LossynessOffset; + int StepNo; + int ItemsFrozen; + ImVector Ranges; + + ImGuiListClipperData() { memset(this, 0, sizeof(*this)); } + void Reset(ImGuiListClipper* clipper) { ListClipper = clipper; StepNo = ItemsFrozen = 0; Ranges.resize(0); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Navigation support +//----------------------------------------------------------------------------- + +enum ImGuiActivateFlags_ +{ + ImGuiActivateFlags_None = 0, + ImGuiActivateFlags_PreferInput = 1 << 0, // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default if keyboard is available. + ImGuiActivateFlags_PreferTweak = 1 << 1, // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default if keyboard is not available. + ImGuiActivateFlags_TryToPreserveState = 1 << 2 // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection) +}; + +// Early work-in-progress API for ScrollToItem() +enum ImGuiScrollFlags_ +{ + ImGuiScrollFlags_None = 0, + ImGuiScrollFlags_KeepVisibleEdgeX = 1 << 0, // If item is not visible: scroll as little as possible on X axis to bring item back into view [default for X axis] + ImGuiScrollFlags_KeepVisibleEdgeY = 1 << 1, // If item is not visible: scroll as little as possible on Y axis to bring item back into view [default for Y axis for windows that are already visible] + ImGuiScrollFlags_KeepVisibleCenterX = 1 << 2, // If item is not visible: scroll to make the item centered on X axis [rarely used] + ImGuiScrollFlags_KeepVisibleCenterY = 1 << 3, // If item is not visible: scroll to make the item centered on Y axis + ImGuiScrollFlags_AlwaysCenterX = 1 << 4, // Always center the result item on X axis [rarely used] + ImGuiScrollFlags_AlwaysCenterY = 1 << 5, // Always center the result item on Y axis [default for Y axis for appearing window) + ImGuiScrollFlags_NoScrollParent = 1 << 6, // Disable forwarding scrolling to parent window if required to keep item/rect visible (only scroll window the function was applied to). + ImGuiScrollFlags_MaskX_ = ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleCenterX | ImGuiScrollFlags_AlwaysCenterX, + ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}; + +enum ImGuiNavDirSourceFlags_ +{ + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_RawKeyboard = 1 << 0, // Raw keyboard (not pulled from nav), faciliate use of some functions before we can unify nav and keys + ImGuiNavDirSourceFlags_Keyboard = 1 << 1, + ImGuiNavDirSourceFlags_PadDPad = 1 << 2, + ImGuiNavDirSourceFlags_PadLStick = 1 << 3 +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) + ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown) + ImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6, // Force scrolling to min/max (used by Home/End) // FIXME-NAV: Aim to remove or reword, probably unnecessary + ImGuiNavMoveFlags_Forwarded = 1 << 7, + ImGuiNavMoveFlags_DebugNoResult = 1 << 8, // Dummy scoring for debug purpose, don't apply result + ImGuiNavMoveFlags_FocusApi = 1 << 9, + ImGuiNavMoveFlags_Tabbing = 1 << 10, // == Focus + Activate if item is Inputable + DontChangeNavHighlight + ImGuiNavMoveFlags_Activate = 1 << 11, + ImGuiNavMoveFlags_DontSetNavHighlight = 1 << 12 // Do not alter the visible state of keyboard vs mouse nav highlight +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) + ImGuiNavLayer_COUNT +}; + +struct ImGuiNavItemData +{ + ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window) + ImGuiID ID; // Init,Move // Best candidate item ID + ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID + ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space + ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags + float DistBox; // Move // Best candidate box distance to current NavId + float DistCenter; // Move // Best candidate center distance to current NavId + float DistAxial; // Move // Best candidate axial distance to current NavId + + ImGuiNavItemData() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; DistBox = DistCenter = DistAxial = FLT_MAX; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Columns support +//----------------------------------------------------------------------------- + +// Flags for internal's BeginColumns(). Prefix using BeginTable() nowadays! +enum ImGuiOldColumnFlags_ +{ + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, // Disable column dividers + ImGuiOldColumnFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiColumnsFlags_None = ImGuiOldColumnFlags_None, + ImGuiColumnsFlags_NoBorder = ImGuiOldColumnFlags_NoBorder, + ImGuiColumnsFlags_NoResize = ImGuiOldColumnFlags_NoResize, + ImGuiColumnsFlags_NoPreserveWidths = ImGuiOldColumnFlags_NoPreserveWidths, + ImGuiColumnsFlags_NoForceWithinWindow = ImGuiOldColumnFlags_NoForceWithinWindow, + ImGuiColumnsFlags_GrowParentContentsSize = ImGuiOldColumnFlags_GrowParentContentsSize +#endif +}; + +struct ImGuiOldColumnData +{ + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + float OffsetNormBeforeResize; + ImGuiOldColumnFlags Flags; // Not exposed + ImRect ClipRect; + + ImGuiOldColumnData() { memset(this, 0, sizeof(*this)); } +}; + +struct ImGuiOldColumns +{ + ImGuiID ID; + ImGuiOldColumnFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x + float LineMinY, LineMaxY; + float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect HostInitialClipRect; // Backup of ClipRect at the time of BeginColumns() + ImRect HostBackupClipRect; // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground() + ImRect HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns() + ImVector Columns; + ImDrawListSplitter Splitter; + + ImGuiOldColumns() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Multi-select support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_MULTI_SELECT +// +#endif // #ifdef IMGUI_HAS_MULTI_SELECT + +//----------------------------------------------------------------------------- +// [SECTION] Docking support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_DOCK +// +#endif // #ifdef IMGUI_HAS_DOCK + +//----------------------------------------------------------------------------- +// [SECTION] Viewport support +//----------------------------------------------------------------------------- + +// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Every instance of ImGuiViewport is in fact a ImGuiViewportP. +struct ImGuiViewportP : public ImGuiViewport +{ + int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used + ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. + ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. + + ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + + // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) + ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields + + // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Settings support +//----------------------------------------------------------------------------- + +// Windows data saved in imgui.ini file +// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. +// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + + ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } + char* GetName() { return (char*)(this + 1); } +}; + +struct ImGuiSettingsHandler +{ + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHashStr(TypeName) + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' + void* UserData; + + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Metrics, Debug Tools +//----------------------------------------------------------------------------- + +struct ImGuiMetricsConfig +{ + bool ShowStackTool; + bool ShowWindowsRects; + bool ShowWindowsBeginOrder; + bool ShowTablesRects; + bool ShowDrawCmdMesh; + bool ShowDrawCmdBoundingBoxes; + int ShowWindowsRectsType; + int ShowTablesRectsType; + + ImGuiMetricsConfig() + { + ShowStackTool = false; + ShowWindowsRects = false; + ShowWindowsBeginOrder = false; + ShowTablesRects = false; + ShowDrawCmdMesh = true; + ShowDrawCmdBoundingBoxes = true; + ShowWindowsRectsType = -1; + ShowTablesRectsType = -1; + } +}; + +struct ImGuiStackLevelInfo +{ + ImGuiID ID; + ImS8 QueryFrameCount; // >= 1: Query in progress + bool QuerySuccess; // Obtained result from DebugHookIdInfo() + char Desc[58]; // Arbitrarily sized buffer to hold a result (FIXME: could replace Results[] with a chunk stream?) + + ImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); } +}; + +// State for Stack tool queries +struct ImGuiStackTool +{ + int LastActiveFrame; + int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level + ImGuiID QueryId; // ID to query details for + ImVector Results; + + ImGuiStackTool() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Generic context hooks +//----------------------------------------------------------------------------- + +typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); +enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }; + +struct ImGuiContextHook +{ + ImGuiID HookId; // A unique ID assigned by AddContextHook() + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; + + ImGuiContextHook() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiContext (main imgui context) +//----------------------------------------------------------------------------- + +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() + float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. + float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() + bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() + bool GcCompactAll; // Request full GC + bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() + void* TestEngine; // Test engine user data + + // Windows state + ImVector Windows; // Windows, sorted in display order, back to front + ImVector WindowsFocusOrder; // Root windows, sorted in focus order, back to front. + ImVector WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child + ImVector CurrentWindowStack; + ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* + int WindowsActiveCount; // Number of unique windows submitted by frame + ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) + ImGuiWindow* CurrentWindow; // Window being drawn into + ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. + ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. + ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. + ImVec2 WheelingWindowRefMousePos; + float WheelingWindowTimer; + + // Item/widgets state and tracking information + ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] + ImGuiID HoveredId; // Hovered widget, filled during the frame + ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdUsingMouseWheel; // Hovered widget will use mouse wheel. Blocks scrolling the underlying window. + bool HoveredIdPreviousFrameUsingMouseWheel; + bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. + float HoveredIdTimer; // Measure contiguous hovering time + float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active + ImGuiID ActiveId; // Active widget + ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) + float ActiveIdTimer; + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdNoClearOnFocusLoss; // Disable losing active id if the active id window gets unfocused. + bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. + bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdHasBeenEditedThisFrame; + bool ActiveIdUsingMouseWheel; // Active widget will want to read mouse wheel. Blocks scrolling the underlying window. + ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) + ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs. + ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. + ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. + float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + + // Next window/item data + ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back() + ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions + ImGuiLastItemData LastItemData; // Storage for last submitted item (setup by ItemAdd) + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + + // Shared stacks + ImVector ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() + ImVector StyleVarStack; // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin() + ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() + ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - not inherited by Begin(), unless child window + ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin() + ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() + ImVectorOpenPopupStack; // Which popups are open (persistent) + ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + int BeginMenuCount; + + // Viewports + ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. + + // Gamepad/keyboard Navigation + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' + ImGuiID NavId; // Focused item for navigation + ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavActivateInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0; ImGuiActivateFlags_PreferInput will be set and NavActivateId will be 0. + ImGuiActivateFlags NavActivateFlags; + ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). + ImGuiKeyModFlags NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. + ImGuiActivateFlags NavNextActivateFlags; + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. + ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid + bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) + bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. + + // Navigation: Init & Move Requests + bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() + bool NavInitRequest; // Init request for appearing window to select first item + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window) + bool NavMoveSubmitted; // Move request submitted, will process result on next NewFrame() + bool NavMoveScoringItems; // Move request submitted, still scoring incoming items + bool NavMoveForwardToNextFrame; + ImGuiNavMoveFlags NavMoveFlags; + ImGuiScrollFlags NavMoveScrollFlags; + ImGuiKeyModFlags NavMoveKeyMods; + ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down) + ImGuiDir NavMoveDirForDebug; + ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? + ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. + ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted + int NavScoringDebugCount; // Metrics for debugging + int NavTabbingDir; // Generally -1 or +1, 0 when tabbing without a nav id + int NavTabbingCounter; // >0 when counting items for tabbing + ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavItemData NavMoveResultLocalVisible; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy + + // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) + ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! + ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it. + ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + + // Render + float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) + ImGuiMouseCursor MouseCursor; + + // Drag and Drop + bool DragDropActive; + bool DragDropWithinSource; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source. + bool DragDropWithinTarget; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target. + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; // Store rectangle of current target candidate (we favor small targets when overlapping) + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) + ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) + ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) + int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source + ImGuiID DragDropHoldJustPressedId; // Set when holding a payload just made ButtonBehavior() return a press. + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size + unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads + + // Clipper + int ClipperTempDataStacked; + ImVector ClipperTempData; + + // Table + ImGuiTable* CurrentTable; + int TablesTempDataStacked; // Temporary table data size (because we leave previous instances undestructed, we generally don't use TablesTempData.Size) + ImVector TablesTempData; // Temporary table data (buffers reused/shared across instances, support nesting) + ImPool Tables; // Persistent table data + ImVector TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC) + ImVector DrawChannelsTempMergeBuffer; + + // Tab bars + ImGuiTabBar* CurrentTabBar; + ImPool TabBars; + ImVector CurrentTabBarStack; + ImVector ShrinkWidthBuffer; + + // Widget state + ImVec2 MouseLastValidPos; + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets + float ColorEditLastHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips + float ColorEditLastSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips + ImU32 ColorEditLastColor; // RGB value with alpha set to 0. + ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. + ImGuiComboPreviewData ComboPreviewData; + float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. + bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? + bool DragCurrentAccumDirty; + float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings + float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio + float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() + short DisabledStackSize; + short TooltipOverrideCount; + float TooltipSlowDelay; // Time before slow tooltips appears (FIXME: This is temporary until we merge in tooltip timer+priority work) + ImVector ClipboardHandlerData; // If no custom clipboard handler is defined + ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once + + // Platform support + ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor + ImVec2 PlatformImeLastPos; + char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point + + // Settings + bool SettingsLoaded; + float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero + ImGuiTextBuffer SettingsIniData; // In memory .ini settings + ImVector SettingsHandlers; // List of .ini settings handlers + ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries + ImChunkStream SettingsTables; // ImGuiTable .ini settings entries + ImVector Hooks; // Hooks for extensions (e.g. test engine) + ImGuiID HookIdNext; // Next available HookId + + // Capture/Logging + bool LogEnabled; // Currently capturing + ImGuiLogType LogType; // Capture target + ImFileHandle LogFile; // If != NULL log to stdout/ file + ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + const char* LogNextPrefix; + const char* LogNextSuffix; + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. + + // Debug Tools + bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) + ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID + ImGuiMetricsConfig DebugMetricsConfig; + ImGuiStackTool DebugStackTool; + + // Misc + float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. + int FramerateSecPerFrameIdx; + int FramerateSecPerFrameCount; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024 * 3 + 1]; // Temporary text buffer + + ImGuiContext(ImFontAtlas* shared_font_atlas) + { + Initialized = false; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; + Font = NULL; + FontSize = FontBaseSize = 0.0f; + IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + Time = 0.0f; + FrameCount = 0; + FrameCountEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + GcCompactAll = false; + TestEngineHookItems = false; + TestEngine = NULL; + + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; + MovingWindow = NULL; + WheelingWindow = NULL; + WheelingWindowTimer = 0.0f; + + DebugHookIdInfo = 0; + HoveredId = HoveredIdPreviousFrame = 0; + HoveredIdAllowOverlap = false; + HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false; + HoveredIdDisabled = false; + HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ActiveId = 0; + ActiveIdIsAlive = 0; + ActiveIdTimer = 0.0f; + ActiveIdIsJustActivated = false; + ActiveIdAllowOverlap = false; + ActiveIdNoClearOnFocusLoss = false; + ActiveIdHasBeenPressedBefore = false; + ActiveIdHasBeenEditedBefore = false; + ActiveIdHasBeenEditedThisFrame = false; + ActiveIdUsingMouseWheel = false; + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingNavInputMask = 0x00; + ActiveIdUsingKeyInputMask = 0x00; + ActiveIdClickOffset = ImVec2(-1, -1); + ActiveIdWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = -1; + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + + CurrentItemFlags = ImGuiItemFlags_None; + BeginMenuCount = 0; + + NavWindow = NULL; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavActivateInputId = 0; + NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; + NavJustMovedToKeyMods = ImGuiKeyModFlags_None; + NavInputSource = ImGuiInputSource_None; + NavLayer = ImGuiNavLayer_Main; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavInitResultId = 0; + NavMoveSubmitted = false; + NavMoveScoringItems = false; + NavMoveForwardToNextFrame = false; + NavMoveFlags = ImGuiNavMoveFlags_None; + NavMoveScrollFlags = ImGuiScrollFlags_None; + NavMoveKeyMods = ImGuiKeyModFlags_None; + NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; + NavScoringDebugCount = 0; + NavTabbingDir = 0; + NavTabbingCounter = 0; + + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + + DimBgRatio = 0.0f; + MouseCursor = ImGuiMouseCursor_Arrow; + + DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; + DragDropSourceFlags = ImGuiDragDropFlags_None; + DragDropSourceFrameCount = -1; + DragDropMouseButton = -1; + DragDropTargetId = 0; + DragDropAcceptFlags = ImGuiDragDropFlags_None; + DragDropAcceptIdCurrRectSurface = 0.0f; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; + DragDropHoldJustPressedId = 0; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + + ClipperTempDataStacked = 0; + + CurrentTable = NULL; + TablesTempDataStacked = 0; + CurrentTabBar = NULL; + + TempInputId = 0; + ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; + ColorEditLastHue = ColorEditLastSat = 0.0f; + ColorEditLastColor = 0; + SliderCurrentAccum = 0.0f; + SliderCurrentAccumDirty = false; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + DisabledAlphaBackup = 0.0f; + DisabledStackSize = 0; + ScrollbarClickDeltaToGrabCenter = 0.0f; + TooltipOverrideCount = 0; + TooltipSlowDelay = 0.50f; + + PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformLocaleDecimalPoint = '.'; + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + HookIdNext = 0; + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + DebugItemPickerActive = false; + DebugItemPickerBreakId = 0; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + memset(TempBuffer, 0, sizeof(TempBuffer)); + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiWindowTempData, ImGuiWindow +//----------------------------------------------------------------------------- + +// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. +// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..) +// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin) +struct IMGUI_API ImGuiWindowTempData +{ + // Layout + ImVec2 CursorPos; // Current emitting position, in absolute coordinates. + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding. + ImVec2 CursorMaxPos; // Used to implicitly calculate ContentSize at the beginning of next frame, for scrolling range and auto-resize. Always growing during the frame. + ImVec2 IdealMaxPos; // Used to implicitly calculate ContentSizeIdeal at the beginning of next frame, for auto-resize only. Always growing during the frame. + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added). + float PrevLineTextBaseOffset; + ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. + ImVec1 GroupOffset; + ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensentate and fix the most common use case of large scroll area. + + // Keyboard/Gamepad navigation + ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) + short NavLayersActiveMask; // Which layers have been written to (result from previous frame) + short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) + ImGuiID NavFocusScopeIdCurrent; // Current focus scope ID while appending + bool NavHideHighlightOneFrame; + bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) + + // Miscellaneous + bool MenuBarAppending; // FIXME: Remove this + ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. + ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement + int TreeDepth; // Current tree depth. + ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. + ImVector ChildWindows; + ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) + ImGuiOldColumns* CurrentColumns; // Current columns set + int CurrentTableIdx; // Current table index (into g.Tables) + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() + + // Local parameters stacks + // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). + float TextWrapPos; // Current text wrap pos. + ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) + ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) +}; + +// Storage for one window +struct IMGUI_API ImGuiWindow +{ + char* Name; // Window name, owned by the window. + ImGuiID ID; // == ImHashStr(Name) + ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ + ImVec2 Pos; // Position (always rounded-up to nearest pixel) + ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) + ImVec2 SizeFull; // Size when non collapsed + ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 ContentSizeIdeal; + ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). + ImVec2 WindowPadding; // Window padding at the time of Begin(). + float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. + float WindowBorderSize; // Window border size at the time of Begin(). + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! + ImGuiID MoveId; // == window->GetID("#MOVE") + ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) + ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered + ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold + ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. + bool ScrollbarX, ScrollbarY; // Are scrollbars visible? + bool Active; // Set to true on Begin(), unless Collapsed + bool WasActive; + bool WriteAccessed; // Set to true when any widget access the current window + bool Collapsed; // Set when collapsing window to become only title-bar + bool WantCollapseToggle; + bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) + bool Appearing; // Set during the frame where the window is appearing (or re-appearing) + bool Hidden; // Do not display (== HiddenFrames*** > 0) + bool IsFallbackWindow; // Set on the "Debug##Default" window. + bool IsExplicitChild; // Set when passed _ChildWindow, left to false by BeginDocked() + bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) + short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. + short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames + ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only + ImS8 DisableInputsFrames; // Disable window interactions for N frames + ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. + + ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) + ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. + + // The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer. + // The main 'OuterRect', omitted as a field, is window->Rect(). + ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. + ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) + ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. + ImRect WorkRect; // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). + ImRect ParentWorkRect; // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack? + ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). + ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + ImVec2ih HitTestHoleSize; // Define an optional rectangular hole where mouse will pass-through the window. + ImVec2ih HitTestHoleOffset; + + int LastFrameActive; // Last frame number the window was Active. + float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector ColumnsStorage; + float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() + int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) + + ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* ParentWindowInBeginStack; + ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes. + ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child. + ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. + ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. + + ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) + ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space + + int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy + int MemoryDrawListVtxCapacity; + bool MemoryCompacted; // Set when window extraneous data have been garbage collected + +public: + ImGuiWindow(ImGuiContext* context, const char* name); + ~ImGuiWindow(); + + ImGuiID GetID(const char* str, const char* str_end = NULL); + ImGuiID GetID(const void* ptr); + ImGuiID GetID(int n); + ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + ImGuiID GetIDNoKeepAlive(const void* ptr); + ImGuiID GetIDNoKeepAlive(int n); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); + + // We don't use g.FontSize because the window may be != g.CurrentWidow. + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } + float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Tab bar, Tab item support +//----------------------------------------------------------------------------- + +// Extend ImGuiTabBarFlags_ +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs +}; + +// Extend ImGuiTabItemFlags_ +enum ImGuiTabItemFlagsPrivate_ +{ + ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) + ImGuiTabItemFlags_Button = 1 << 21 // Used by TabItemButton, change the tab item behavior to mimic a button +}; + +// Storage for one active tab item (sizeof() 40 bytes) +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float ContentWidth; // Width of label, stored during BeginTabItem() call + ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames + ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable + ImS16 IndexDuringLayout; // Index only used during TabBarLayout() + bool WantClose; // Marked as closed by SetTabItemClosed() + + ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } +}; + +// Storage for a tab bar (sizeof() 152 bytes) +struct IMGUI_API ImGuiTabBar +{ + ImVector Tabs; + ImGuiTabBarFlags Flags; + ImGuiID ID; // Zero for tab-bars used by docking + ImGuiID SelectedTabId; // Selected tab/window + ImGuiID NextSelectedTabId; // Next selected tab/window. Will also trigger a scrolling animation + ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; // Record the height of contents submitted below the tab bar + float WidthAllTabs; // Actual width of all tabs (locked during layout) + float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + float ScrollingRectMinX; + float ScrollingRectMaxX; + ImGuiID ReorderRequestTabId; + ImS16 ReorderRequestOffset; + ImS8 BeginCount; + bool WantLayout; + bool VisibleTabWasSubmitted; + bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame + ImS16 TabsActiveCount; // Number of tabs submitted this frame. + ImS16 LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem() + float ItemSpacingY; + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + ImVec2 BackupCursorPos; + ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. + + ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Table support +//----------------------------------------------------------------------------- + +#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. +#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. +#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels() + +// Our current column maximum is 64 but we may raise that in the future. +typedef ImS8 ImGuiTableColumnIdx; +typedef ImU8 ImGuiTableDrawChannelIdx; + +// [Internal] sizeof() ~ 104 +// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. +// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping. +// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped". +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_ + float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space. + float MinX; // Absolute positions + float MaxX; + float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() + float WidthAuto; // Automatic width + float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. + float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). + ImRect ClipRect; // Clipping rectangle for the column + ImGuiID UserID; // Optional, value passed to TableSetupColumn() + float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column + float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2) + float ItemWidth; // Current item width for the column, preserved across rows + float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width. + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; // Offset into parent ColumnsNames[] + ImGuiTableColumnIdx DisplayOrder; // Index within Table's IndexToDisplayOrder[] (column may be reordered by users) + ImGuiTableColumnIdx IndexWithinEnabledSet; // Index within enabled/visible set (<= IndexToDisplayOrder) + ImGuiTableColumnIdx PrevEnabledColumn; // Index of prev enabled/visible column within Columns[], -1 if first enabled/visible column + ImGuiTableColumnIdx NextEnabledColumn; // Index of next enabled/visible column within Columns[], -1 if last enabled/visible column + ImGuiTableColumnIdx SortOrder; // Index of this column within sort specs, -1 if not sorting on this column, 0 for single-sort, may be >0 on multi-sort + ImGuiTableDrawChannelIdx DrawChannelCurrent; // Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx DrawChannelFrozen; // Draw channels for frozen rows (often headers) + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; // Draw channels for unfrozen rows + bool IsEnabled; // IsUserEnabled && (Flags & ImGuiTableColumnFlags_Disabled) == 0 + bool IsUserEnabled; // Is the column not marked Hidden by the user? (unrelated to being off view, e.g. clipped by scrolling). + bool IsUserEnabledNextFrame; + bool IsVisibleX; // Is actually in view (e.g. overlapping the host window clipping rectangle, not scrolled). + bool IsVisibleY; + bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not. + bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte + ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit + ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem + ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) + ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) + ImU8 SortDirectionsAvailList; // Ordered of available sort directions (2-bits each) + + ImGuiTableColumn() + { + memset(this, 0, sizeof(*this)); + StretchWeight = WidthRequest = -1.0f; + NameOffset = -1; + DisplayOrder = IndexWithinEnabledSet = -1; + PrevEnabledColumn = NextEnabledColumn = -1; + SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1; + } +}; + +// Transient cell data stored per row. +// sizeof() ~ 6 +struct ImGuiTableCellData +{ + ImU32 BgColor; // Actual color + ImGuiTableColumnIdx Column; // Column number +}; + +// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData +struct IMGUI_API ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[] + ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[] + ImSpan Columns; // Point within RawData[] + ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) + ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. + ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map + ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data + ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items) + ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) + int SettingsOffset; // Offset in g.SettingsTables + int LastFrameActive; + int ColumnsCount; // Number of columns declared in BeginTable() + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. + ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with + float RowPosY1; + float RowPosY2; + float RowMinHeight; // Height submitted to TableNextRow() + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; // Current row flags, see ImGuiTableRowFlags_ + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; // Counter for alternating background colors (can be fast-forwarded by e.g clipper), not same as CurrentRow because header rows typically don't increase this. + ImU32 RowBgColor[2]; // Background color override for current row. + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; // Padding from each borders + float CellPaddingY; + float CellSpacingX1; // Spacing between non-bordered cells + float CellSpacingX2; + float LastOuterHeight; // Outer height from last frame + float LastFirstRowHeight; // Height of first row from last frame + float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details. + float ColumnsGivenWidth; // Sum of current column width + float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; // Lock minimum contents width while resizing down in order to not create feedback loops. But we allow growing the table. + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable(). + ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; // We use this to cpu-clip cell background color fill + ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped + ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. + ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. + ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground() + ImGuiWindow* OuterWindow; // Parent window for the table + ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) + ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names + ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn() + ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column! + ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing). + ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit. + ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0. + ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. + ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. + ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) + ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1 + ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. + ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. + ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column. + ImGuiTableColumnIdx RightMostStretchedColumn; // Index of right-most stretched column. + ImGuiTableColumnIdx ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot + ImGuiTableColumnIdx FreezeRowsRequest; // Requested frozen rows count + ImGuiTableColumnIdx FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx FreezeColumnsRequest; // Requested frozen columns count + ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row + ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. + bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. + bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). + bool IsSettingsRequestLoad; + bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data. + bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; // Set when we got past the frozen row. + bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() + bool MemoryCompacted; + bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis + + ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; } + ~ImGuiTable() { IM_FREE(RawData); } +}; + +// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). +// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. +// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. +struct IMGUI_API ImGuiTableTempData +{ + int TableIndex; // Index in g.Tables.Buf[] pool + float LastTimeActive; // Last timestamp this structure was used + + ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() + ImDrawListSplitter DrawSplitter; + + ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() + ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() + ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable() + ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable() + ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() + ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable() + float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable() + int HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable() + + ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; } +}; + +// sizeof() ~ 12 +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; // "Visible" in ini file + ImU8 IsStretch : 1; + + ImGuiTableColumnSettings() + { + WidthOrWeight = 0.0f; + UserID = 0; + Index = -1; + DisplayOrder = SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + IsEnabled = 1; + IsStretch = 0; + } +}; + +// This is designed to be stored in a single ImChunkStream (1 header followed by N ImGuiTableColumnSettings, etc.) +struct ImGuiTableSettings +{ + ImGuiID ID; // Set to 0 to invalidate/delete the setting + ImGuiTableFlags SaveFlags; // Indicate data we want to save using the Resizable/Reorderable/Sortable/Hideable flags (could be using its own flags..) + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + + ImGuiTableSettings() { memset(this, 0, sizeof(*this)); } + ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGui internal API +// No guarantee of forward compatibility here! +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Windows + // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) + // If this ever crash because g.CurrentWindow is NULL it means that either + // - ImGui::NewFrame() has never been called, which is illegal. + // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } + IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); + IMGUI_API ImGuiWindow* FindWindowByName(const char* name); + IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); + IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window); + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); + IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); + IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); + IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); + IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); + inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } + inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } + + // Windows: Display Order and Focus Order + IMGUI_API void FocusWindow(ImGuiWindow* window); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* above_window); + IMGUI_API int FindWindowDisplayIndex(ImGuiWindow* window); + IMGUI_API ImGuiWindow* FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); + + // Fonts, drawing + IMGUI_API void SetCurrentFont(ImFont* font); + inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + + // Init + IMGUI_API void Initialize(ImGuiContext* context); + IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). + + // NewFrame + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); + + // Generic context hooks + IMGUI_API ImGuiID AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook); + IMGUI_API void RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove); + IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); + + // Settings + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); + IMGUI_API void ClearIniSettings(); + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + + // Scrolling + IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is + IMGUI_API void SetScrollX(ImGuiWindow* window, float scroll_x); + IMGUI_API void SetScrollY(ImGuiWindow* window, float scroll_y); + IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio); + IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio); + + // Early work-in-progress API (ScrollToItem() will become public) + IMGUI_API void ScrollToItem(ImGuiScrollFlags flags = 0); + IMGUI_API void ScrollToRect(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); + IMGUI_API ImVec2 ScrollToRectEx(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); +//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& rect) { ScrollToRect(window, rect, ImGuiScrollFlags_KeepVisibleEdgeY); } +//#endif + + // Basic Accessors + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.LastItemData.ID; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand) + inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void ClearActiveID(); + IMGUI_API ImGuiID GetHoveredID(); + IMGUI_API void SetHoveredID(ImGuiID id); + IMGUI_API void KeepAliveID(ImGuiID id); + IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. + IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) + IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); + + // Basic Helpers for widget code + IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); + IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); + IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); + IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void PushMultiItemsWidths(int components, float width_full); + IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API ImVec2 GetContentRegionMaxAbs(); + IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); + + // Parameter stacks + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Currently refactoring focus/nav/tabbing system + // If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): + // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' + // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' + // (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || g.NavActivateInputId == id' (WIP) + // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() + inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd() + inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem +#endif + + // Logging/Capture + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); + + // Popups, Modals, Tooltips + IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); + IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); + IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); + IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); + IMGUI_API void ClosePopupsExceptModals(); + IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); + IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); + IMGUI_API void BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); + IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); + IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); + IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); + IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); + + // Menus + IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); + IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true); + IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); + + // Combos + IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); + IMGUI_API bool BeginComboPreview(); + IMGUI_API void EndComboPreview(); + + // Gamepad/Keyboard Navigation + IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API void NavInitRequestApplyResult(); + IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); + IMGUI_API void NavMoveRequestCancel(); + IMGUI_API void NavMoveRequestApplyResult(); + IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); + IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); + IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. + IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); + + // Focus Scope (WIP) + // This is generally used to identify a selection set (multiple of which may be in the same window), as selection + // patterns generally need to react (e.g. clear selection) when landing on an item of the set. + IMGUI_API void PushFocusScope(ImGuiID id); + IMGUI_API void PopFocusScope(); + inline ImGuiID GetFocusedFocusScope() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } // Focus scope which is actually active + inline ImGuiID GetFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.NavFocusScopeIdCurrent; } // Focus scope we are outputting into, set by PushFocusScope() + + // Inputs + // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. + IMGUI_API void SetItemUsingMouseWheel(); + IMGUI_API void SetActiveIdUsingNavAndKeys(); + inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } + inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } + inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } + IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } + inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } + inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } + IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags(); + + // Drag and Drop + IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + IMGUI_API void ClearDragDrop(); + IMGUI_API bool IsDragDropPayloadBeingAccepted(); + + // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns + IMGUI_API void PushColumnClipRect(int column_index); + IMGUI_API void PushColumnsBackground(); + IMGUI_API void PopColumnsBackground(); + IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); + IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); + IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); + + // Tables: Candidates for public API + IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnWidth(int column_n, float width); + IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); + IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. + IMGUI_API float TableGetHeaderRowHeight(); + IMGUI_API void TablePushBackgroundChannel(); + IMGUI_API void TablePopBackgroundChannel(); + + // Tables: Internals + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } + IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); + IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); + IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); + IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); + IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); + IMGUI_API void TableUpdateLayout(ImGuiTable* table); + IMGUI_API void TableUpdateBorders(ImGuiTable* table); + IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); + IMGUI_API void TableDrawBorders(ImGuiTable* table); + IMGUI_API void TableDrawContextMenu(ImGuiTable* table); + IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); + IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); + IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); + IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API void TableBeginRow(ImGuiTable* table); + IMGUI_API void TableEndRow(ImGuiTable* table); + IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); + IMGUI_API void TableEndCell(ImGuiTable* table); + IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); + IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); + IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableRemove(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); + IMGUI_API void TableGcCompactSettings(); + + // Tables: Settings + IMGUI_API void TableLoadSettings(ImGuiTable* table); + IMGUI_API void TableSaveSettings(ImGuiTable* table); + IMGUI_API void TableResetSettings(ImGuiTable* table); + IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); + IMGUI_API void TableSettingsInstallHandler(ImGuiContext* context); + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); + + // Tab Bars + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset); + IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos); + IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); + IMGUI_API void TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped); + + // Render helpers + // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. + // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) + IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); + IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. + + // Render helpers (those functions don't access any ImGui state!) + IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); + IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); + IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); + IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); + IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); + IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); + IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while] + inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); } + inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); } +#endif + + // Widgets + IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); + IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); + IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); + IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col); + IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners + IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); + IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); + + // Widgets low-level behaviors + IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging + IMGUI_API void TreePushOverrideID(ImGuiID id); + + // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. + // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). + // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " + template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + template IMGUI_API bool CheckboxFlagsT(const char* label, T* flags, T flags_value); + + // Data type helpers + IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); + IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); + IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); + + // InputText + IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); + IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); + inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } + inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active + + // Color + IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); + + // Plot + IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); + + // Shade functions (write over already created vertices) + IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); + IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); + + // Garbage collection + IMGUI_API void GcCompactTransientMiscBuffers(); + IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + + // Debug Tools + IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); } + inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } + + IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); + IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); + IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); + IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); + IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); + IMGUI_API void DebugNodeFont(ImFont* font); + IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); + IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); + IMGUI_API void DebugNodeTable(ImGuiTable* table); + IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings); + IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label); + IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); + IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); + IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); + IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); + +} // namespace ImGui + + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas internal API +//----------------------------------------------------------------------------- + +// This structure is likely to evolve as we add support for incremental atlas updates +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; + +// Helper for font builder +IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +//----------------------------------------------------------------------------- +// [SECTION] Test Engine specific hooks (imgui_test_engine) +//----------------------------------------------------------------------------- + +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id); + +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +#else +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0) +#endif + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui_tables.cpp b/thirdparty/imgui/imgui_tables.cpp new file mode 100644 index 0000000..8a3fe93 --- /dev/null +++ b/thirdparty/imgui/imgui_tables.cpp @@ -0,0 +1,4049 @@ +// dear imgui, v1.86 +// (tables and columns code) + +/* + +Index of this file: + +// [SECTION] Commentary +// [SECTION] Header mess +// [SECTION] Tables: Main code +// [SECTION] Tables: Simple accessors +// [SECTION] Tables: Row changes +// [SECTION] Tables: Columns changes +// [SECTION] Tables: Columns width management +// [SECTION] Tables: Drawing +// [SECTION] Tables: Sorting +// [SECTION] Tables: Headers +// [SECTION] Tables: Context Menu +// [SECTION] Tables: Settings (.ini data) +// [SECTION] Tables: Garbage Collection +// [SECTION] Tables: Debugging +// [SECTION] Columns, BeginColumns, EndColumns, etc. + +*/ + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + +//----------------------------------------------------------------------------- +// [SECTION] Commentary +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typical tables call flow: (root level is generally public API): +//----------------------------------------------------------------------------- +// - BeginTable() user begin into a table +// | BeginChild() - (if ScrollX/ScrollY is set) +// | TableBeginInitMemory() - first time table is used +// | TableResetSettings() - on settings reset +// | TableLoadSettings() - on settings load +// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests +// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) +// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width +// - TableSetupColumn() user submit columns details (optional) +// - TableSetupScrollFreeze() user submit scroll freeze information (optional) +//----------------------------------------------------------------------------- +// - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). +// | TableSetupDrawChannels() - setup ImDrawList channels +// | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission +// | TableDrawContextMenu() - draw right-click context menu +//----------------------------------------------------------------------------- +// - TableHeadersRow() or TableHeader() user submit a headers row (optional) +// | TableSortSpecsClickColumn() - when left-clicked: alter sort order and sort direction +// | TableOpenContextMenu() - when right-clicked: trigger opening of the default context menu +// - TableGetSortSpecs() user queries updated sort specs (optional, generally after submitting headers) +// - TableNextRow() user begin into a new row (also automatically called by TableHeadersRow()) +// | TableEndRow() - finish existing row +// | TableBeginRow() - add a new row +// - TableSetColumnIndex() / TableNextColumn() user begin into a cell +// | TableEndCell() - close existing column/cell +// | TableBeginCell() - enter into current column/cell +// - [...] user emit contents +//----------------------------------------------------------------------------- +// - EndTable() user ends the table +// | TableDrawBorders() - draw outer borders, inner vertical borders +// | TableMergeDrawChannels() - merge draw channels if clipping isn't required +// | EndChild() - (if ScrollX/ScrollY is set) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// TABLE SIZING +//----------------------------------------------------------------------------- +// (Read carefully because this is subtle but it does make sense!) +//----------------------------------------------------------------------------- +// About 'outer_size': +// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags. +// Default value is ImVec2(0.0f, 0.0f). +// X +// - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge. +// - outer_size.x > 0.0f -> Set Fixed width. +// Y with ScrollX/ScrollY disabled: we output table directly in current window +// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful is parent window can vertically scroll. +// - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) +// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) +// Y with ScrollX/ScrollY enabled: using a child window for scrolling +// - outer_size.y < 0.0f -> Bottom-align. Not meaningful is parent window can vertically scroll. +// - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. +// - outer_size.y > 0.0f -> Set Exact height. Recommended when using Scrolling on any axis. +//----------------------------------------------------------------------------- +// Outer size is also affected by the NoHostExtendX/NoHostExtendY flags. +// Important to that note how the two flags have slightly different behaviors! +// - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. +// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible. +// In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height. +// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not easily noticeable) +//----------------------------------------------------------------------------- +// About 'inner_width': +// With ScrollX disabled: +// - inner_width -> *ignored* +// With ScrollX enabled: +// - inner_width < 0.0f -> *illegal* fit in known width (right align from outer_size.x) <-- weird +// - inner_width = 0.0f -> fit in outer_width: Fixed size columns will take space they need (if avail, otherwise shrink down), Stretch columns becomes Fixed columns. +// - inner_width > 0.0f -> override scrolling width, generally to be larger than outer_size.x. Fixed column take space they need (if avail, otherwise shrink down), Stretch columns share remaining space! +//----------------------------------------------------------------------------- +// Details: +// - If you want to use Stretch columns with ScrollX, you generally need to specify 'inner_width' otherwise the concept +// of "available space" doesn't make sense. +// - Even if not really useful, we allow 'inner_width < outer_size.x' for consistency and to facilitate understanding +// of what the value does. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// COLUMNS SIZING POLICIES +//----------------------------------------------------------------------------- +// About overriding column sizing policy and width/weight with TableSetupColumn(): +// We use a default parameter of 'init_width_or_weight == -1'. +// - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic +// - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom +// - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f +// - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom +// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f) +// and you can fit a 100.0f wide item in it without clipping and with full padding. +//----------------------------------------------------------------------------- +// About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag) +// - with Table policy ImGuiTableFlags_SizingFixedFit --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width +// - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width +// - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f +// - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents +// Default Width and default Weight can be overridden when calling TableSetupColumn(). +//----------------------------------------------------------------------------- +// About mixing Fixed/Auto and Stretch columns together: +// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! +// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. +// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents. +// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths. +//----------------------------------------------------------------------------- +// About using column width: +// If a column is manual resizable or has a width specified with TableSetupColumn(): +// - you may use GetContentRegionAvail().x to query the width available in a given column. +// - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width. +// If the column is not resizable and has no width specified with TableSetupColumn(): +// - its width will be automatic and be set to the max of items submitted. +// - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN). +// - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN). +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// TABLES CLIPPING/CULLING +//----------------------------------------------------------------------------- +// About clipping/culling of Rows in Tables: +// - For large numbers of rows, it is recommended you use ImGuiListClipper to only submit visible rows. +// ImGuiListClipper is reliant on the fact that rows are of equal height. +// See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper. +// - Note that auto-resizing columns don't play well with using the clipper. +// By default a table with _ScrollX but without _Resizable will have column auto-resize. +// So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns width explicitly with _WidthFixed. +//----------------------------------------------------------------------------- +// About clipping/culling of Columns in Tables: +// - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing +// width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know +// it is not going to contribute to row height. +// In many situations, you may skip submitting contents for every column but one (e.g. the first one). +// - Case A: column is not hidden by user, and at least partially in sight (most common case). +// - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output. +// - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.). +// +// [A] [B] [C] +// TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() return false, user can skip submitting items but only if the column doesn't contribute to row height. +// SkipItems: false false true -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output. +// ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way. +// ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway). +// +// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row. +// However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer. +//----------------------------------------------------------------------------- +// About clipping/culling of whole Tables: +// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// System includes +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Main code +//----------------------------------------------------------------------------- +// - TableFixFlags() [Internal] +// - TableFindByID() [Internal] +// - BeginTable() +// - BeginTableEx() [Internal] +// - TableBeginInitMemory() [Internal] +// - TableBeginApplyRequests() [Internal] +// - TableSetupColumnFlags() [Internal] +// - TableUpdateLayout() [Internal] +// - TableUpdateBorders() [Internal] +// - EndTable() +// - TableSetupColumn() +// - TableSetupScrollFreeze() +//----------------------------------------------------------------------------- + +// Configuration +static const int TABLE_DRAW_CHANNEL_BG0 = 0; +static const int TABLE_DRAW_CHANNEL_BG2_FROZEN = 1; +static const int TABLE_DRAW_CHANNEL_NOCLIP = 2; // When using ImGuiTableFlags_NoClip (this becomes the last visible channel) +static const float TABLE_BORDER_SIZE = 1.0f; // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering. +static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; // Extend outside inner borders. +static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped. + +// Helper +inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window) +{ + // Adjust flags: set default sizing policy + if ((flags & ImGuiTableFlags_SizingMask_) == 0) + flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame; + + // Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame + if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableFlags_NoKeepColumnsVisible; + + // Adjust flags: enforce borders when resizable + if (flags & ImGuiTableFlags_Resizable) + flags |= ImGuiTableFlags_BordersInnerV; + + // Adjust flags: disable NoHostExtendX/NoHostExtendY if we have any scrolling going on + if (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) + flags &= ~(ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY); + + // Adjust flags: NoBordersInBodyUntilResize takes priority over NoBordersInBody + if (flags & ImGuiTableFlags_NoBordersInBodyUntilResize) + flags &= ~ImGuiTableFlags_NoBordersInBody; + + // Adjust flags: disable saved settings if there's nothing to save + if ((flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable)) == 0) + flags |= ImGuiTableFlags_NoSavedSettings; + + // Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set) + if (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings) + flags |= ImGuiTableFlags_NoSavedSettings; + + return flags; +} + +ImGuiTable* ImGui::TableFindByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.Tables.GetByKey(id); +} + +// Read about "TABLE SIZING" at the top of this file. +bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiID id = GetID(str_id); + return BeginTableEx(str_id, id, columns_count, flags, outer_size, inner_width); +} + +bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* outer_window = GetCurrentWindow(); + if (outer_window->SkipItems) // Consistent with other tables + beneficial side effect that assert on miscalling EndTable() will be more visible. + return false; + + // Sanity checks + IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!"); + if (flags & ImGuiTableFlags_ScrollX) + IM_ASSERT(inner_width >= 0.0f); + + // If an outer size is specified ahead we will be able to early out when not visible. Exact clipping rules may evolve. + const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; + const ImVec2 avail_size = GetContentRegionAvail(); + ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); + ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); + if (use_child_window && IsClippedEx(outer_rect, 0)) + { + ItemSize(outer_rect); + return false; + } + + // Acquire storage for the table + ImGuiTable* table = g.Tables.GetOrAddByKey(id); + const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; + const ImGuiID instance_id = id + instance_no; + const ImGuiTableFlags table_last_flags = table->Flags; + if (instance_no > 0) + IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); + + // Acquire temporary buffers + const int table_idx = g.Tables.GetIndex(table); + if (++g.TablesTempDataStacked > g.TablesTempData.Size) + g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData()); + ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1]; + temp_data->TableIndex = table_idx; + table->DrawSplitter = &table->TempData->DrawSplitter; + table->DrawSplitter->Clear(); + + // Fix flags + table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0; + flags = TableFixFlags(flags, outer_window); + + // Initialize + table->ID = id; + table->Flags = flags; + table->InstanceCurrent = (ImS16)instance_no; + table->LastFrameActive = g.FrameCount; + table->OuterWindow = table->InnerWindow = outer_window; + table->ColumnsCount = columns_count; + table->IsLayoutLocked = false; + table->InnerWidth = inner_width; + temp_data->UserOuterSize = outer_size; + + // When not using a child window, WorkRect.Max will grow as we append contents. + if (use_child_window) + { + // Ensure no vertical scrollbar appears if we only want horizontal one, to make flag consistent + // (we have no other way to disable vertical scrollbar of a window while keeping the horizontal one showing) + ImVec2 override_content_size(FLT_MAX, FLT_MAX); + if ((flags & ImGuiTableFlags_ScrollX) && !(flags & ImGuiTableFlags_ScrollY)) + override_content_size.y = FLT_MIN; + + // Ensure specified width (when not specified, Stretched columns will act as if the width == OuterWidth and + // never lead to any scrolling). We don't handle inner_width < 0.0f, we could potentially use it to right-align + // based on the right side of the child window work rect, which would require knowing ahead if we are going to + // have decoration taking horizontal spaces (typically a vertical scrollbar). + if ((flags & ImGuiTableFlags_ScrollX) && inner_width > 0.0f) + override_content_size.x = inner_width; + + if (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX) + SetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f)); + + // Reset scroll if we are reactivating it + if ((table_last_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + + // Create scrolling region (without border and zero window padding) + ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; + BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags); + table->InnerWindow = g.CurrentWindow; + table->WorkRect = table->InnerWindow->WorkRect; + table->OuterRect = table->InnerWindow->Rect(); + table->InnerRect = table->InnerWindow->InnerRect; + IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f); + } + else + { + // For non-scrolling tables, WorkRect == OuterRect == InnerRect. + // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable(). + table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; + } + + // Push a standardized ID for both child-using and not-child-using tables + PushOverrideID(instance_id); + + // Backup a copy of host window members we will modify + ImGuiWindow* inner_window = table->InnerWindow; + table->HostIndentX = inner_window->DC.Indent.x; + table->HostClipRect = inner_window->ClipRect; + table->HostSkipItems = inner_window->SkipItems; + temp_data->HostBackupWorkRect = inner_window->WorkRect; + temp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect; + temp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; + temp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; + temp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; + temp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; + temp_data->HostBackupItemWidth = outer_window->DC.ItemWidth; + temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; + inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + + // Padding and Spacing + // - None ........Content..... Pad .....Content........ + // - PadOuter | Pad ..Content..... Pad .....Content.. Pad | + // - PadInner ........Content.. Pad | Pad ..Content........ + // - PadOuter+PadInner | Pad ..Content.. Pad | Pad ..Content.. Pad | + const bool pad_outer_x = (flags & ImGuiTableFlags_NoPadOuterX) ? false : (flags & ImGuiTableFlags_PadOuterX) ? true : (flags & ImGuiTableFlags_BordersOuterV) != 0; + const bool pad_inner_x = (flags & ImGuiTableFlags_NoPadInnerX) ? false : true; + const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f; + const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f; + const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f; + table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border; + table->CellSpacingX2 = inner_spacing_explicit; + table->CellPaddingX = inner_padding_explicit; + table->CellPaddingY = g.Style.CellPadding.y; + + const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f; + table->OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table->CellPaddingX; + + table->CurrentColumn = -1; + table->CurrentRow = -1; + table->RowBgColorCounter = 0; + table->LastRowFlags = ImGuiTableRowFlags_None; + table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect; + table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width + table->InnerClipRect.ClipWithFull(table->HostClipRect); + table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; + + table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow + table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() + table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any + table->FreezeColumnsRequest = table->FreezeColumnsCount = 0; + table->IsUnfrozenRows = true; + table->DeclColumnsCount = 0; + + // Using opaque colors facilitate overlapping elements of the grid + table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); + table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); + + // Make table current + g.CurrentTable = table; + outer_window->DC.CurrentTableIdx = table_idx; + if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. + inner_window->DC.CurrentTableIdx = table_idx; + + if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) + table->IsResetDisplayOrderRequest = true; + + // Mark as used + if (table_idx >= g.TablesLastTimeActive.Size) + g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); + g.TablesLastTimeActive[table_idx] = (float)g.Time; + temp_data->LastTimeActive = (float)g.Time; + table->MemoryCompacted = false; + + // Setup memory buffer (clear data if columns count changed) + ImGuiTableColumn* old_columns_to_preserve = NULL; + void* old_columns_raw_data = NULL; + const int old_columns_count = table->Columns.size(); + if (old_columns_count != 0 && old_columns_count != columns_count) + { + // Attempt to preserve width on column count change (#4046) + old_columns_to_preserve = table->Columns.Data; + old_columns_raw_data = table->RawData; + table->RawData = NULL; + } + if (table->RawData == NULL) + { + TableBeginInitMemory(table, columns_count); + table->IsInitializing = table->IsSettingsRequestLoad = true; + } + if (table->IsResetAllRequest) + TableResetSettings(table); + if (table->IsInitializing) + { + // Initialize + table->SettingsOffset = -1; + table->IsSortSpecsDirty = true; + table->InstanceInteracted = -1; + table->ContextPopupColumn = -1; + table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; + table->AutoFitSingleColumn = -1; + table->HoveredColumnBody = table->HoveredColumnBorder = -1; + for (int n = 0; n < columns_count; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + if (old_columns_to_preserve && n < old_columns_count) + { + // FIXME: We don't attempt to preserve column order in this path. + *column = old_columns_to_preserve[n]; + } + else + { + float width_auto = column->WidthAuto; + *column = ImGuiTableColumn(); + column->WidthAuto = width_auto; + column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker + column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true; + } + column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; + } + } + if (old_columns_raw_data) + IM_FREE(old_columns_raw_data); + + // Load settings + if (table->IsSettingsRequestLoad) + TableLoadSettings(table); + + // Handle DPI/font resize + // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. + // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. + // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. + // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. + const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) + { + const float scale_factor = new_ref_scale_unit / table->RefScale; + //IMGUI_DEBUG_LOG("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor); + for (int n = 0; n < columns_count; n++) + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; + } + table->RefScale = new_ref_scale_unit; + + // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. + // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user. + // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. + inner_window->SkipItems = true; + + // Clear names + // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() + if (table->ColumnsNames.Buf.Size > 0) + table->ColumnsNames.Buf.resize(0); + + // Apply queued resizing/reordering/hiding requests + TableBeginApplyRequests(table); + + return true; +} + +// For reference, the average total _allocation count_ for a table is: +// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables) +// + 1 (for table->RawData allocated below) +// + 1 (for table->ColumnsNames, if names are used) +// Shared allocations per number of nested tables +// + 1 (for table->Splitter._Channels) +// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels) +// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details. +// Unused channels don't perform their +2 allocations. +void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) +{ + // Allocate single buffer for our arrays + ImSpanAllocator<3> span_allocator; + span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); + span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); + span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); + table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); + memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); + span_allocator.SetArenaBasePtr(table->RawData); + span_allocator.GetSpan(0, &table->Columns); + span_allocator.GetSpan(1, &table->DisplayOrderToIndex); + span_allocator.GetSpan(2, &table->RowCellData); +} + +// Apply queued resizing/reordering/hiding requests +void ImGui::TableBeginApplyRequests(ImGuiTable* table) +{ + // Handle resizing request + // (We process this at the first TableBegin of the frame) + // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling? + if (table->InstanceCurrent == 0) + { + if (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX) + TableSetColumnWidth(table->ResizedColumn, table->ResizedColumnNextWidth); + table->LastResizedColumn = table->ResizedColumn; + table->ResizedColumnNextWidth = FLT_MAX; + table->ResizedColumn = -1; + + // Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy. + // FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings. + if (table->AutoFitSingleColumn != -1) + { + TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto); + table->AutoFitSingleColumn = -1; + } + } + + // Handle reordering request + // Note: we don't clear ReorderColumn after handling the request. + if (table->InstanceCurrent == 0) + { + if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) + table->ReorderColumn = -1; + table->HeldHeaderColumn = -1; + if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0) + { + // We need to handle reordering across hidden columns. + // In the configuration below, moving C to the right of E will lead to: + // ... C [D] E ---> ... [D] E C (Column name/index) + // ... 2 3 4 ... 2 3 4 (Display order) + const int reorder_dir = table->ReorderColumnDir; + IM_ASSERT(reorder_dir == -1 || reorder_dir == +1); + IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable); + ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn]; + ImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; + IM_UNUSED(dst_column); + const int src_order = src_column->DisplayOrder; + const int dst_order = dst_column->DisplayOrder; + src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; + for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) + table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; + IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); + + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[], + // rebuild the later from the former. + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; + table->ReorderColumnDir = 0; + table->IsSettingsDirty = true; + } + } + + // Handle display order reset request + if (table->IsResetDisplayOrderRequest) + { + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[n] = table->Columns[n].DisplayOrder = (ImGuiTableColumnIdx)n; + table->IsResetDisplayOrderRequest = false; + table->IsSettingsDirty = true; + } +} + +// Adjust flags: default width mode + stretch columns are not allowed when auto extending +static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) +{ + ImGuiTableColumnFlags flags = flags_in; + + // Sizing Policy + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) + { + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + if (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + else + flags |= ImGuiTableColumnFlags_WidthStretch; + } + else + { + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. + } + + // Resize + if ((table->Flags & ImGuiTableFlags_Resizable) == 0) + flags |= ImGuiTableColumnFlags_NoResize; + + // Sorting + if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending)) + flags |= ImGuiTableColumnFlags_NoSort; + + // Indentation + if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0) + flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + + // Alignment + //if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0) + // flags |= ImGuiTableColumnFlags_AlignCenter; + //IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used. + + // Preserve status flags + column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); + + // Build an ordered list of available sort directions + column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0; + if (table->Flags & ImGuiTableFlags_Sortable) + { + int count = 0, mask = 0, list = 0; + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; } + column->SortDirectionsAvailList = (ImU8)list; + column->SortDirectionsAvailMask = (ImU8)mask; + column->SortDirectionsAvailCount = (ImU8)count; + ImGui::TableFixColumnSortDirection(table, column); + } +} + +// Layout columns for the frame. This is in essence the followup to BeginTable(). +// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first. +// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns. +// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns? +void ImGui::TableUpdateLayout(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->IsLayoutLocked == false); + + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + table->IsDefaultDisplayOrder = true; + table->ColumnsEnabledCount = 0; + table->EnabledMaskByIndex = 0x00; + table->EnabledMaskByDisplayOrder = 0x00; + table->LeftMostEnabledColumn = -1; + table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE + + // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns. + // Process columns in their visible orders as we are building the Prev/Next indices. + int count_fixed = 0; // Number of columns that have fixed sizing policies + int count_stretch = 0; // Number of columns that have stretch sizing policies + int prev_visible_column_idx = -1; + bool has_auto_fit_request = false; + bool has_resizable = false; + float stretch_sum_width_auto = 0.0f; + float fixed_max_width_auto = 0.0f; + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + if (column_n != order_n) + table->IsDefaultDisplayOrder = false; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame. + // It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway. + // We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect. + if (table->DeclColumnsCount <= column_n) + { + TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); + column->NameOffset = -1; + column->UserID = 0; + column->InitStretchWeightOrWidth = -1.0f; + } + + // Update Enabled state, mark settings and sort specs dirty + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) + column->IsUserEnabledNextFrame = true; + if (column->IsUserEnabled != column->IsUserEnabledNextFrame) + { + column->IsUserEnabled = column->IsUserEnabledNextFrame; + table->IsSettingsDirty = true; + } + column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0; + + if (column->SortOrder != -1 && !column->IsEnabled) + table->IsSortSpecsDirty = true; + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) + table->IsSortSpecsDirty = true; + + // Auto-fit unsized columns + const bool start_auto_fit = (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f); + if (start_auto_fit) + column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames + + if (!column->IsEnabled) + { + column->IndexWithinEnabledSet = -1; + continue; + } + + // Mark as enabled and link to previous/next enabled column + column->PrevEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + column->NextEnabledColumn = -1; + if (prev_visible_column_idx != -1) + table->Columns[prev_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + else + table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; + column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; + table->EnabledMaskByIndex |= (ImU64)1 << column_n; + table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; + prev_visible_column_idx = column_n; + IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); + + // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) + // Combine width from regular rows + width from headers unless requested not to. + if (!column->IsPreserveWidthAuto) + column->WidthAuto = TableGetColumnWidthAuto(table, column); + + // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column_is_resizable) + has_resizable = true; + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable) + column->WidthAuto = column->InitStretchWeightOrWidth; + + if (column->AutoFitQueue != 0x00) + has_auto_fit_request = true; + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + stretch_sum_width_auto += column->WidthAuto; + count_stretch++; + } + else + { + fixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto); + count_fixed++; + } + } + if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + table->IsSortSpecsDirty = true; + table->RightMostEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + IM_ASSERT(table->LeftMostEnabledColumn >= 0 && table->RightMostEnabledColumn >= 0); + + // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible + // to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing). + // FIXME-TABLE: for always auto-resizing columns may not want to do that all the time. + if (has_auto_fit_request && table->OuterWindow != table->InnerWindow) + table->InnerWindow->SkipItems = false; + if (has_auto_fit_request) + table->IsSettingsDirty = true; + + // [Part 3] Fix column flags and record a few extra information. + float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. + float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. + table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + { + // Apply same widths policy + float width_auto = column->WidthAuto; + if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable)) + width_auto = fixed_max_width_auto; + + // Apply automatic width + // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) + if (column->AutoFitQueue != 0x00) + column->WidthRequest = width_auto; + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n))) + column->WidthRequest = width_auto; + + // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets + // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very + // large height (= first frame scrollbar display very off + clipper would skip lots of items). + // This is merely making the side-effect less extreme, but doesn't properly fixes it. + // FIXME: Move this to ->WidthGiven to avoid temporary lossyless? + // FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller. + if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto) + column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale? + sum_width_requests += column->WidthRequest; + } + else + { + // Initialize stretch weight + if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable) + { + if (column->InitStretchWeightOrWidth > 0.0f) + column->StretchWeight = column->InitStretchWeightOrWidth; + else if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp) + column->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch; + else + column->StretchWeight = 1.0f; + } + + stretch_sum_weights += column->StretchWeight; + if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder) + table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder) + table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + } + column->IsPreserveWidthAuto = false; + sum_width_requests += table->CellPaddingX * 2.0f; + } + table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed; + + // [Part 4] Apply final widths based on requested widths + const ImRect work_rect = table->WorkRect; + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth(); + const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; + float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; + table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest) + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + float weight_ratio = column->StretchWeight / stretch_sum_weights; + column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f); + width_remaining_for_stretched_columns -= column->WidthRequest; + } + + // [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column + // See additional comments in TableSetColumnWidth(). + if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1) + column->Flags |= ImGuiTableColumnFlags_NoDirectResize_; + + // Assign final width, record width in case we will need to shrink + column->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth)); + table->ColumnsGivenWidth += column->WidthGiven; + } + + // [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). + // Using right-to-left distribution (more likely to match resizing cursor). + if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) + for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) + { + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + continue; + ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; + if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->WidthRequest += 1.0f; + column->WidthGiven += 1.0f; + width_remaining_for_stretched_columns -= 1.0f; + } + + table->HoveredColumnBody = -1; + table->HoveredColumnBorder = -1; + const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table->LastOuterHeight)); + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); + + // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column + // Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping. + int visible_n = 0; + bool offset_x_frozen = (table->FreezeColumnsCount > 0); + float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; + ImRect host_clip_rect = table->InnerClipRect; + //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; + table->VisibleMaskByIndex = 0x00; + table->RequestOutputMaskByIndex = 0x00; + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + + column->NavLayerCurrent = (ImS8)((table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); + + if (offset_x_frozen && table->FreezeColumnsCount == visible_n) + { + offset_x += work_rect.Min.x - table->OuterRect.Min.x; + offset_x_frozen = false; + } + + // Clear status flags + column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; + + if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0) + { + // Hidden column: clear a few fields and we are done with it for the remainder of the function. + // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. + column->MinX = column->MaxX = column->WorkMinX = column->ClipRect.Min.x = column->ClipRect.Max.x = offset_x; + column->WidthGiven = 0.0f; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + column->IsVisibleX = column->IsVisibleY = column->IsRequestOutput = false; + column->IsSkipItems = true; + column->ItemWidth = 1.0f; + continue; + } + + // Detect hovered column + if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x) + table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; + + // Lock start position + column->MinX = offset_x; + + // Lock width based on start position and minimum/maximum width for this position + float max_width = TableGetMaxColumnWidth(table, column_n); + column->WidthGiven = ImMin(column->WidthGiven, max_width); + column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth)); + column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + + // Lock other positions + // - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging. + // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column. + // - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow. + // - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter. + column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1; + column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max + column->ItemWidth = ImFloor(column->WidthGiven * 0.65f); + column->ClipRect.Min.x = column->MinX; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + + // Mark column as Clipped (not in sight) + // Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables. + // FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY. + // Taking advantage of LastOuterHeight would yield good results there... + // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x, + // and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else). + // Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small. + column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); + column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); + const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; + if (is_visible) + table->VisibleMaskByIndex |= ((ImU64)1 << column_n); + + // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. + column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; + if (column->IsRequestOutput) + table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n); + + // Mark column as SkipItems (ignoring all items/layout) + column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; + if (column->IsSkipItems) + IM_ASSERT(!is_visible); + + // Update status flags + column->Flags |= ImGuiTableColumnFlags_IsEnabled; + if (is_visible) + column->Flags |= ImGuiTableColumnFlags_IsVisible; + if (column->SortOrder != -1) + column->Flags |= ImGuiTableColumnFlags_IsSorted; + if (table->HoveredColumnBody == column_n) + column->Flags |= ImGuiTableColumnFlags_IsHovered; + + // Alignment + // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in + // many cases (to be able to honor this we might be able to store a log of cells width, per row, for + // visible rows, but nav/programmatic scroll would have visible artifacts.) + //if (column->Flags & ImGuiTableColumnFlags_AlignRight) + // column->WorkMinX = ImMax(column->WorkMinX, column->MaxX - column->ContentWidthRowsUnfrozen); + //else if (column->Flags & ImGuiTableColumnFlags_AlignCenter) + // column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f); + + // Reset content width variables + column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX; + column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX; + + // Don't decrement auto-fit counters until container window got a chance to submit its items + if (table->HostSkipItems == false) + { + column->AutoFitQueue >>= 1; + column->CannotSkipItemsQueue >>= 1; + } + + if (visible_n < table->FreezeColumnsCount) + host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x); + + offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + visible_n++; + } + + // [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it) + // Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either + // because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu. + const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); + if (is_hovering_table && table->HoveredColumnBody == -1) + { + if (g.IO.MousePos.x >= unused_x1) + table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount; + } + if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable)) + table->Flags &= ~ImGuiTableFlags_Resizable; + + // [Part 8] Lock actual OuterRect/WorkRect right-most position. + // This is done late to handle the case of fixed-columns tables not claiming more widths that they need. + // Because of this we are careful with uses of WorkRect and InnerClipRect before this point. + if (table->RightMostStretchedColumn != -1) + table->Flags &= ~ImGuiTableFlags_NoHostExtendX; + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + table->OuterRect.Max.x = table->WorkRect.Max.x = unused_x1; + table->InnerClipRect.Max.x = ImMin(table->InnerClipRect.Max.x, unused_x1); + } + table->InnerWindow->ParentWorkRect = table->WorkRect; + table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f); + table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f); + + // [Part 9] Allocate draw channels and setup background cliprect + TableSetupDrawChannels(table); + + // [Part 10] Hit testing on borders + if (table->Flags & ImGuiTableFlags_Resizable) + TableUpdateBorders(table); + table->LastFirstRowHeight = 0.0f; + table->IsLayoutLocked = true; + table->IsUsingHeaders = false; + + // [Part 11] Context menu + if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted) + { + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) + { + TableDrawContextMenu(table); + EndPopup(); + } + else + { + table->IsContextPopupOpen = false; + } + } + + // [Part 13] Sanitize and build sort specs before we have a change to use them for display. + // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) + if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) + TableSortSpecsBuild(table); + + // Initial state + ImGuiWindow* inner_window = table->InnerWindow; + if (table->Flags & ImGuiTableFlags_NoClip) + table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + else + inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); +} + +// Process hit-testing on resizing borders. Actual size change will be applied in EndTable() +// - Set table->HoveredColumnBorder with a short delay/timer to reduce feedback noise +// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize widgets +// overlapping the same area. +void ImGui::TableUpdateBorders(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->Flags & ImGuiTableFlags_Resizable); + + // At this point OuterRect height may be zero or under actual final height, so we rely on temporal coherency and + // use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not + // really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height). + // Actual columns highlight/render will be performed in EndTable() and not be affected. + const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS; + const float hit_y1 = table->OuterRect.Min.y; + const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table->LastOuterHeight); + const float hit_y2_head = hit_y1 + table->LastFirstRowHeight; + + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) + continue; + + // ImGuiTableFlags_NoBordersInBodyUntilResize will be honored in TableDrawBorders() + const float border_y2_hit = (table->Flags & ImGuiTableFlags_NoBordersInBody) ? hit_y2_head : hit_y2_body; + if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false) + continue; + + if (!column->IsVisibleX && table->LastResizedColumn != column_n) + continue; + + ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent); + ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit); + //GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100)); + KeepAliveID(column_id); + + bool hovered = false, held = false; + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); + if (pressed && IsMouseDoubleClicked(0)) + { + TableSetColumnWidthAutoSingle(table, column_n); + ClearActiveID(); + held = hovered = false; + } + if (held) + { + if (table->LastResizedColumn == -1) + table->ResizeLockMinContentsX2 = table->RightMostEnabledColumn != -1 ? table->Columns[table->RightMostEnabledColumn].MaxX : -FLT_MAX; + table->ResizedColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + } + if ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held) + { + table->HoveredColumnBorder = (ImGuiTableColumnIdx)column_n; + SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + } +} + +void ImGui::EndTable() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!"); + + // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some + // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) + //IM_ASSERT(table->IsLayoutLocked && "Table unused: never called TableNextRow(), is that the intent?"); + + // If the user never got to call TableNextRow() or TableNextColumn(), we call layout ourselves to ensure all our + // code paths are consistent (instead of just hoping that TableBegin/TableEnd will work), get borders drawn, etc. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + const ImGuiTableFlags flags = table->Flags; + ImGuiWindow* inner_window = table->InnerWindow; + ImGuiWindow* outer_window = table->OuterWindow; + ImGuiTableTempData* temp_data = table->TempData; + IM_ASSERT(inner_window == g.CurrentWindow); + IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow); + + if (table->IsInsideRow) + TableEndRow(table); + + // Context menu in columns body + if (flags & ImGuiTableFlags_ContextMenuInBody) + if (table->HoveredColumnBody != -1 && !IsAnyItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + TableOpenContextMenu((int)table->HoveredColumnBody); + + // Finalize table height + inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize; + inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize; + inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos; + const float inner_content_max_y = table->RowPosY2; + IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y); + if (inner_window != outer_window) + inner_window->DC.CursorMaxPos.y = inner_content_max_y; + else if (!(flags & ImGuiTableFlags_NoHostExtendY)) + table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height + table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y); + table->LastOuterHeight = table->OuterRect.GetHeight(); + + // Setup inner scrolling range + // FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y, + // but since the later is likely to be impossible to do we'd rather update both axises together. + if (table->Flags & ImGuiTableFlags_ScrollX) + { + const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + float max_pos_x = table->InnerWindow->DC.CursorMaxPos.x; + if (table->RightMostEnabledColumn != -1) + max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border); + if (table->ResizedColumn != -1) + max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2); + table->InnerWindow->DC.CursorMaxPos.x = max_pos_x; + } + + // Pop clipping rect + if (!(flags & ImGuiTableFlags_NoClip)) + inner_window->DrawList->PopClipRect(); + inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back(); + + // Draw borders + if ((flags & ImGuiTableFlags_Borders) != 0) + TableDrawBorders(table); + +#if 0 + // Strip out dummy channel draw calls + // We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out) + // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway. + // Cons: making it harder for users watching metrics/debugger to spot the wasted vertices. + if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) + { + ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; + dummy_channel->_CmdBuffer.resize(0); + dummy_channel->_IdxBuffer.resize(0); + } +#endif + + // Flatten channels and merge draw calls + ImDrawListSplitter* splitter = table->DrawSplitter; + splitter->SetCurrentChannel(inner_window->DrawList, 0); + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + TableMergeDrawChannels(table); + splitter->Merge(inner_window->DrawList); + + // Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable() + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (table->EnabledMaskByIndex & ((ImU64)1 << column_n)) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) + table->ColumnsAutoFitWidth += column->WidthRequest; + else + table->ColumnsAutoFitWidth += TableGetColumnWidthAuto(table, column); + } + + // Update scroll + if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window) + { + inner_window->Scroll.x = 0.0f; + } + else if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent) + { + // When releasing a column being resized, scroll to keep the resulting column in sight + const float neighbor_width_to_keep_visible = table->MinColumnWidth + table->CellPaddingX * 2.0f; + ImGuiTableColumn* column = &table->Columns[table->LastResizedColumn]; + if (column->MaxX < table->InnerClipRect.Min.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - neighbor_width_to_keep_visible, 1.0f); + else if (column->MaxX > table->InnerClipRect.Max.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + neighbor_width_to_keep_visible, 1.0f); + } + + // Apply resizing/dragging at the end of the frame + if (table->ResizedColumn != -1 && table->InstanceCurrent == table->InstanceInteracted) + { + ImGuiTableColumn* column = &table->Columns[table->ResizedColumn]; + const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS); + const float new_width = ImFloor(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f); + table->ResizedColumnNextWidth = new_width; + } + + // Pop from id stack + IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); + IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); + PopID(); + + // Restore window data that we modified + const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos; + inner_window->WorkRect = temp_data->HostBackupWorkRect; + inner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect; + inner_window->SkipItems = table->HostSkipItems; + outer_window->DC.CursorPos = table->OuterRect.Min; + outer_window->DC.ItemWidth = temp_data->HostBackupItemWidth; + outer_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize; + outer_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset; + + // Layout in outer window + // (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding + // CursorPosPrevLine and CursorMaxPos manually. That should be a more general layout feature, see same problem e.g. #3414) + if (inner_window != outer_window) + { + EndChild(); + } + else + { + ItemSize(table->OuterRect.GetSize()); + ItemAdd(table->OuterRect, 0); + } + + // Override declared contents width/height to enable auto-resize while not needlessly adding a scrollbar + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + // FIXME-TABLE: Could we remove this section? + // ColumnsAutoFitWidth may be one frame ahead here since for Fixed+NoResize is calculated from latest contents + IM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth); + } + else if (temp_data->UserOuterSize.x <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f; + outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); + } + else + { + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x); + } + if (temp_data->UserOuterSize.y <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f; + outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); + } + else + { + // OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags_NoHostExtendY is set) + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table->OuterRect.Max.y); + } + + // Save settings + if (table->IsSettingsDirty) + TableSaveSettings(table); + table->IsInitializing = false; + + // Clear or restore current table, if any + IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); + IM_ASSERT(g.TablesTempDataStacked > 0); + temp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL; + g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL; + if (g.CurrentTable) + { + g.CurrentTable->TempData = temp_data; + g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; + } + outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; +} + +// See "COLUMN SIZING POLICIES" comments at the top of this file +// If (init_width_or_weight <= 0.0f) it is ignored +void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!"); + IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); + if (table->DeclColumnsCount >= table->ColumnsCount) + { + IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "Called TableSetupColumn() too many times!"); + return; + } + + ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; + table->DeclColumnsCount++; + + // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. + // Give a grace to users of ImGuiTableFlags_ScrollX. + if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) + IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); + + // When passing a width automatically enforce WidthFixed policy + // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f) + if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + + TableSetupColumnFlags(table, column, flags); + column->UserID = user_id; + flags = column->Flags; + + // Initialize defaults + column->InitStretchWeightOrWidth = init_width_or_weight; + if (table->IsInitializing) + { + // Init width or weight + if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) + { + if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) + column->WidthRequest = init_width_or_weight; + if (flags & ImGuiTableColumnFlags_WidthStretch) + column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f; + + // Disable auto-fit if an explicit width/weight has been specified + if (init_width_or_weight > 0.0f) + column->AutoFitQueue = 0x00; + } + + // Init default visibility/sort state + if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) + column->IsUserEnabled = column->IsUserEnabledNextFrame = false; + if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) + { + column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + } + } + + // Store name (append with zero-terminator in contiguous buffer) + column->NameOffset = -1; + if (label != NULL && label[0] != 0) + { + column->NameOffset = (ImS16)table->ColumnsNames.size(); + table->ColumnsNames.append(label, label + strlen(label) + 1); + } +} + +// [Public] +void ImGui::TableSetupScrollFreeze(int columns, int rows) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); + IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit + + table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0; + table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0; + table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0; + table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0; + table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b + + // Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered. + // FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section) + for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++) + { + int order_n = table->DisplayOrderToIndex[column_n]; + if (order_n != column_n && order_n >= table->FreezeColumnsRequest) + { + ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder); + ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Simple accessors +//----------------------------------------------------------------------------- +// - TableGetColumnCount() +// - TableGetColumnName() +// - TableGetColumnName() [Internal] +// - TableSetColumnEnabled() +// - TableGetColumnFlags() +// - TableGetCellBgRect() [Internal] +// - TableGetColumnResizeID() [Internal] +// - TableGetHoveredColumn() [Internal] +// - TableSetBgColor() +//----------------------------------------------------------------------------- + +int ImGui::TableGetColumnCount() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + return table ? table->ColumnsCount : 0; +} + +const char* ImGui::TableGetColumnName(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return NULL; + if (column_n < 0) + column_n = table->CurrentColumn; + return TableGetColumnName(table, column_n); +} + +const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) +{ + if (table->IsLayoutLocked == false && column_n >= table->DeclColumnsCount) + return ""; // NameOffset is invalid at this point + const ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->NameOffset == -1) + return ""; + return &table->ColumnsNames.Buf[column->NameOffset]; +} + +// Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view) +// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) +// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state. +// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable(). +// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0. +// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu. +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsUserEnabledNextFrame = enabled; +} + +// We allow querying for an extra column in order to poll the IsHovered state of the right-most section +ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return ImGuiTableColumnFlags_None; + if (column_n < 0) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) + return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None; + return table->Columns[column_n].Flags; +} + +// Return the cell rectangle based on currently known height. +// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. +// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right +// columns report a small offset so their CellBgRect can extend up to the outer border. +ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float x1 = column->MinX; + float x2 = column->MaxX; + if (column->PrevEnabledColumn == -1) + x1 -= table->CellSpacingX1; + if (column->NextEnabledColumn == -1) + x2 += table->CellSpacingX2; + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); +} + +// Return the resizing ID for the right-side of the given column. +ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; + return id; +} + +// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. +int ImGui::TableGetHoveredColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + return (int)table->HoveredColumnBody; +} + +void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(target != ImGuiTableBgTarget_None); + + if (color == IM_COL32_DISABLE) + color = 0; + + // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. + switch (target) + { + case ImGuiTableBgTarget_CellBg: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + if (column_n == -1) + column_n = table->CurrentColumn; + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + return; + if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) + table->RowCellDataCurrent++; + ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent]; + cell_data->BgColor = color; + cell_data->Column = (ImGuiTableColumnIdx)column_n; + break; + } + case ImGuiTableBgTarget_RowBg0: + case ImGuiTableBgTarget_RowBg1: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + IM_ASSERT(column_n == -1); + int bg_idx = (target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; + table->RowBgColor[bg_idx] = color; + break; + } + default: + IM_ASSERT(0); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Row changes +//------------------------------------------------------------------------- +// - TableGetRowIndex() +// - TableNextRow() +// - TableBeginRow() [Internal] +// - TableEndRow() [Internal] +//------------------------------------------------------------------------- + +// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows +int ImGui::TableGetRowIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentRow; +} + +// [Public] Starts into the first cell of a new row +void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + if (table->IsInsideRow) + TableEndRow(table); + + table->LastRowFlags = table->RowFlags; + table->RowFlags = row_flags; + table->RowMinHeight = row_min_height; + TableBeginRow(table); + + // We honor min_row_height requested by user, but cannot guarantee per-row maximum height, + // because that would essentially require a unique clipping rectangle per-cell. + table->RowPosY2 += table->CellPaddingY * 2.0f; + table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height); + + // Disable output until user calls TableNextColumn() + table->InnerWindow->SkipItems = true; +} + +// [Internal] Called by TableNextRow() +void ImGui::TableBeginRow(ImGuiTable* table) +{ + ImGuiWindow* window = table->InnerWindow; + IM_ASSERT(!table->IsInsideRow); + + // New row + table->CurrentRow++; + table->CurrentColumn = -1; + table->RowBgColor[0] = table->RowBgColor[1] = IM_COL32_DISABLE; + table->RowCellDataCurrent = -1; + table->IsInsideRow = true; + + // Begin frozen rows + float next_y1 = table->RowPosY2; + if (table->CurrentRow == 0 && table->FreezeRowsCount > 0) + next_y1 = window->DC.CursorPos.y = table->OuterRect.Min.y; + + table->RowPosY1 = table->RowPosY2 = next_y1; + table->RowTextBaseline = 0.0f; + table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent + window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.CursorMaxPos.y = next_y1; + + // Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging. + if (table->RowFlags & ImGuiTableRowFlags_Headers) + { + TableSetBgColor(ImGuiTableBgTarget_RowBg0, GetColorU32(ImGuiCol_TableHeaderBg)); + if (table->CurrentRow == 0) + table->IsUsingHeaders = true; + } +} + +// [Internal] Called by TableNextRow() +void ImGui::TableEndRow(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window == table->InnerWindow); + IM_ASSERT(table->IsInsideRow); + + if (table->CurrentColumn != -1) + TableEndCell(table); + + // Logging + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + + // Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is + // likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding. + window->DC.CursorPos.y = table->RowPosY2; + + // Row background fill + const float bg_y1 = table->RowPosY1; + const float bg_y2 = table->RowPosY2; + const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount); + const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest); + if (table->CurrentRow == 0) + table->LastFirstRowHeight = bg_y2 - bg_y1; + + const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y); + if (is_visible) + { + // Decide of background color for the row + ImU32 bg_col0 = 0; + ImU32 bg_col1 = 0; + if (table->RowBgColor[0] != IM_COL32_DISABLE) + bg_col0 = table->RowBgColor[0]; + else if (table->Flags & ImGuiTableFlags_RowBg) + bg_col0 = GetColorU32((table->RowBgColorCounter & 1) ? ImGuiCol_TableRowBgAlt : ImGuiCol_TableRowBg); + if (table->RowBgColor[1] != IM_COL32_DISABLE) + bg_col1 = table->RowBgColor[1]; + + // Decide of top border color + ImU32 border_col = 0; + const float border_size = TABLE_BORDER_SIZE; + if (table->CurrentRow > 0 || table->InnerWindow == table->OuterWindow) + if (table->Flags & ImGuiTableFlags_BordersInnerH) + border_col = (table->LastRowFlags & ImGuiTableRowFlags_Headers) ? table->BorderColorStrong : table->BorderColorLight; + + const bool draw_cell_bg_color = table->RowCellDataCurrent >= 0; + const bool draw_strong_bottom_border = unfreeze_rows_actual; + if ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color) + { + // In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is + // always followed by a change of clipping rectangle we perform the smallest overwrite possible here. + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4(); + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); + } + + // Draw row background + // We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle + if (bg_col0 || bg_col1) + { + ImRect row_rect(table->WorkRect.Min.x, bg_y1, table->WorkRect.Max.x, bg_y2); + row_rect.ClipWith(table->BgClipRect); + if (bg_col0 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col0); + if (bg_col1 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col1); + } + + // Draw cell background color + if (draw_cell_bg_color) + { + ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; + for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) + { + const ImGuiTableColumn* column = &table->Columns[cell_data->Column]; + ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); + cell_bg_rect.ClipWith(table->BgClipRect); + cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped + cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); + window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); + } + } + + // Draw top border + if (border_col && bg_y1 >= table->BgClipRect.Min.y && bg_y1 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), border_col, border_size); + + // Draw bottom border at the row unfreezing mark (always strong) + if (draw_strong_bottom_border && bg_y2 >= table->BgClipRect.Min.y && bg_y2 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong, border_size); + } + + // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle) + // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and + // get the new cursor position. + if (unfreeze_rows_request) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->NavLayerCurrent = (ImS8)((column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); + } + if (unfreeze_rows_actual) + { + IM_ASSERT(table->IsUnfrozenRows == false); + table->IsUnfrozenRows = true; + + // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); + table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); + table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; + table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; + IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); + + float row_height = table->RowPosY2 - table->RowPosY1; + table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; + table->RowPosY1 = table->RowPosY2 - row_height; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->DrawChannelCurrent = column->DrawChannelUnfrozen; + column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; + } + + // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y + SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + } + + if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) + table->RowBgColorCounter++; + table->IsInsideRow = false; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns changes +//------------------------------------------------------------------------- +// - TableGetColumnIndex() +// - TableSetColumnIndex() +// - TableNextColumn() +// - TableBeginCell() [Internal] +// - TableEndCell() [Internal] +//------------------------------------------------------------------------- + +int ImGui::TableGetColumnIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentColumn; +} + +// [Public] Append into a specific column +bool ImGui::TableSetColumnIndex(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->CurrentColumn != column_n) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + IM_ASSERT(column_n >= 0 && table->ColumnsCount); + TableBeginCell(table, column_n); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + +// [Public] Append into the next column, wrap and create a new row when already on last column +bool ImGui::TableNextColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + TableBeginCell(table, table->CurrentColumn + 1); + } + else + { + TableNextRow(); + TableBeginCell(table, 0); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + int column_n = table->CurrentColumn; + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + + +// [Internal] Called by TableSetColumnIndex()/TableNextColumn() +// This is called very frequently, so we need to be mindful of unnecessary overhead. +// FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns. +void ImGui::TableBeginCell(ImGuiTable* table, int column_n) +{ + ImGuiTableColumn* column = &table->Columns[column_n]; + ImGuiWindow* window = table->InnerWindow; + table->CurrentColumn = column_n; + + // Start position is roughly ~~ CellRect.Min + CellPadding + Indent + float start_x = column->WorkMinX; + if (column->Flags & ImGuiTableColumnFlags_IndentEnable) + start_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row. + + window->DC.CursorPos.x = start_x; + window->DC.CursorPos.y = table->RowPosY1 + table->CellPaddingY; + window->DC.CursorMaxPos.x = window->DC.CursorPos.x; + window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT + window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; + window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; + + window->WorkRect.Min.y = window->DC.CursorPos.y; + window->WorkRect.Min.x = column->WorkMinX; + window->WorkRect.Max.x = column->WorkMaxX; + window->DC.ItemWidth = column->ItemWidth; + + // To allow ImGuiListClipper to function we propagate our row height + if (!column->IsEnabled) + window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2); + + window->SkipItems = column->IsSkipItems; + if (column->IsSkipItems) + { + ImGuiContext& g = *GImGui; + g.LastItemData.ID = 0; + g.LastItemData.StatusFlags = 0; + } + + if (table->Flags & ImGuiTableFlags_NoClip) + { + // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP); + } + else + { + // FIXME-TABLE: Could avoid this if draw channel is dummy channel? + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + } + + // Logging + ImGuiContext& g = *GImGui; + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } +} + +// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() +void ImGui::TableEndCell(ImGuiTable* table) +{ + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + ImGuiWindow* window = table->InnerWindow; + + // Report maximum position so we can infer content size per column. + float* p_max_pos_x; + if (table->RowFlags & ImGuiTableRowFlags_Headers) + p_max_pos_x = &column->ContentMaxXHeadersUsed; // Useful in case user submit contents in header row that is not a TableHeader() call + else + p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; + *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); + table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); + column->ItemWidth = window->DC.ItemWidth; + + // Propagate text baseline for the entire row + // FIXME-TABLE: Here we propagate text baseline from the last line of the cell.. instead of the first one. + table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns width management +//------------------------------------------------------------------------- +// - TableGetMaxColumnWidth() [Internal] +// - TableGetColumnWidthAuto() [Internal] +// - TableSetColumnWidth() +// - TableSetColumnWidthAutoSingle() [Internal] +// - TableSetColumnWidthAutoAll() [Internal] +// - TableUpdateColumnsWeightFromWidth() [Internal] +//------------------------------------------------------------------------- + +// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. +float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float max_width = FLT_MAX; + const float min_column_distance = table->MinColumnWidth + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2; + if (table->Flags & ImGuiTableFlags_ScrollX) + { + // Frozen columns can't reach beyond visible width else scrolling will naturally break. + // (we use DisplayOrder as within a set of multiple frozen column reordering is possible) + if (column->DisplayOrder < table->FreezeColumnsRequest) + { + max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX; + max_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2; + } + } + else if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0) + { + // If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make + // sure they are all visible. Because of this we also know that all of the columns will always fit in + // table->WorkRect and therefore in table->InnerRect (because ScrollX is off) + // FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match. + // See "table_width_distrib" and "table_width_keep_visible" tests + max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX; + //max_width -= table->CellSpacingX1; + max_width -= table->CellSpacingX2; + max_width -= table->CellPaddingX * 2.0f; + max_width -= table->OuterPaddingX; + } + return max_width; +} + +// Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field +float ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column) +{ + const float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; + const float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX; + float width_auto = content_width_body; + if (!(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth)) + width_auto = ImMax(width_auto, content_width_headers); + + // Non-resizable fixed columns preserve their requested width + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) + if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize)) + width_auto = column->InitStretchWeightOrWidth; + + return ImMax(width_auto, table->MinColumnWidth); +} + +// 'width' = inner column width, without padding +void ImGui::TableSetColumnWidth(int column_n, float width) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && table->IsLayoutLocked == false); + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column_0 = &table->Columns[column_n]; + float column_0_width = width; + + // Apply constraints early + // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) + IM_ASSERT(table->MinColumnWidth > 0.0f); + const float min_width = table->MinColumnWidth; + const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); + column_0_width = ImClamp(column_0_width, min_width, max_width); + if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) + return; + + //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width); + ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; + + // In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns. + // - All fixed: easy. + // - All stretch: easy. + // - One or more fixed + one stretch: easy. + // - One or more fixed + more than one stretch: tricky. + // Qt when manual resize is enabled only support a single _trailing_ stretch column. + + // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. + // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. + // Scenarios: + // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset. + // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered. + // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size. + // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 W3 resize from W1| or W2| --> ok + // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 F3 resize from W1| or W2| --> ok + // - W1 F2 W3 resize from W1| or F2| --> ok + // - F1 W2 F3 resize from W2| --> ok + // - F1 W3 F2 resize from W3| --> ok + // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. + // - W1 F2 F3 resize from F2| --> ok + // All resizes from a Wx columns are locking other columns. + + // Possible improvements: + // - W1 W2 W3 resize W1| --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns. + // - W3 F1 F2 resize W3| --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix. + + // [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout(). + + // If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize. + // This is the preferred resize path + if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed) + if (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder) + { + column_0->WidthRequest = column_0_width; + table->IsSettingsDirty = true; + return; + } + + // We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column) + if (column_1 == NULL) + column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; + if (column_1 == NULL) + return; + + // Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column. + // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) + float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); + column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + IM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f); + column_0->WidthRequest = column_0_width; + column_1->WidthRequest = column_1_width; + if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch) + TableUpdateColumnsWeightFromWidth(table); + table->IsSettingsDirty = true; +} + +// Disable clipping then auto-fit, will take 2 frames +// (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns) +void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n) +{ + // Single auto width uses auto-fit + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled) + return; + column->CannotSkipItemsQueue = (1 << 0); + table->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n; +} + +void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table) +{ + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column + continue; + column->CannotSkipItemsQueue = (1 << 0); + column->AutoFitQueue = (1 << 1); + } +} + +void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) +{ + IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1); + + // Measure existing quantity + float visible_weight = 0.0f; + float visible_width = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + IM_ASSERT(column->StretchWeight > 0.0f); + visible_weight += column->StretchWeight; + visible_width += column->WidthRequest; + } + IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); + + // Apply new weights + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->StretchWeight = (column->WidthRequest / visible_width) * visible_weight; + IM_ASSERT(column->StretchWeight > 0.0f); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Drawing +//------------------------------------------------------------------------- +// - TablePushBackgroundChannel() [Internal] +// - TablePopBackgroundChannel() [Internal] +// - TableSetupDrawChannels() [Internal] +// - TableMergeDrawChannels() [Internal] +// - TableDrawBorders() [Internal] +//------------------------------------------------------------------------- + +// Bg2 is used by Selectable (and possibly other widgets) to render to the background. +// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect. +void ImGui::TablePushBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + table->HostBackupInnerClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent); +} + +void ImGui::TablePopBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); +} + +// Allocate draw channels. Called by TableUpdateLayout() +// - We allocate them following storage order instead of display order so reordering columns won't needlessly +// increase overall dormant memory cost. +// - We isolate headers draw commands in their own channels instead of just altering clip rects. +// This is in order to facilitate merging of draw commands. +// - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels. +// - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other +// channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged. +// - We allocate 1 or 2 background draw channels. This is because we know TablePushBackgroundChannel() is only used for +// horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4). +// Draw channel allocation (before merging): +// - NoClip --> 2+D+1 channels: bg0/1 + bg2 + foreground (same clip rect == always 1 draw call) +// - Clip --> 2+D+N channels +// - FreezeRows --> 2+D+N*2 (unless scrolling value is zero) +// - FreezeRows || FreezeColunns --> 3+D+N*2 (unless scrolling value is zero) +// Where D is 1 if any column is clipped or hidden (dummy channel) otherwise 0. +void ImGui::TableSetupDrawChannels(ImGuiTable* table) +{ + const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; + const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount; + const int channels_for_bg = 1 + 1 * freeze_row_multiplier; + const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0; + const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; + table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); + table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); + table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN; + table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN); + + int draw_channel_current = 2; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsVisibleX && column->IsVisibleY) + { + column->DrawChannelFrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current); + column->DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row + 1 : 0)); + if (!(table->Flags & ImGuiTableFlags_NoClip)) + draw_channel_current++; + } + else + { + column->DrawChannelFrozen = column->DrawChannelUnfrozen = table->DummyDrawChannel; + } + column->DrawChannelCurrent = column->DrawChannelFrozen; + } + + // Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default. + // All our cell highlight are manually clipped with BgClipRect. When unfreezing it will be made smaller to fit scrolling rect. + // (This technically isn't part of setting up draw channels, but is reasonably related to be done here) + table->BgClipRect = table->InnerClipRect; + table->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect; + table->Bg2ClipRectForDrawCmd = table->HostClipRect; + IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y); +} + +// This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable(). +// For simplicity we call it TableMergeDrawChannels() but in fact it only reorder channels + overwrite ClipRect, +// actual merging is done by table->DrawSplitter.Merge() which is called right after TableMergeDrawChannels(). +// +// Columns where the contents didn't stray off their local clip rectangle can be merged. To achieve +// this we merge their clip rect and make them contiguous in the channel list, so they can be merged +// by the call to DrawSplitter.Merge() following to the call to this function. +// We reorder draw commands by arranging them into a maximum of 4 distinct groups: +// +// 1 group: 2 groups: 2 groups: 4 groups: +// [ 0. ] no freeze [ 0. ] row freeze [ 01 ] col freeze [ 01 ] row+col freeze +// [ .. ] or no scroll [ 2. ] and v-scroll [ .. ] and h-scroll [ 23 ] and v+h-scroll +// +// Each column itself can use 1 channel (row freeze disabled) or 2 channels (row freeze enabled). +// When the contents of a column didn't stray off its limit, we move its channels into the corresponding group +// based on its position (within frozen rows/columns groups or not). +// At the end of the operation our 1-4 groups will each have a ImDrawCmd using the same ClipRect. +// This function assume that each column are pointing to a distinct draw channel, +// otherwise merge_group->ChannelsCount will not match set bit count of merge_group->ChannelsMask. +// +// Column channels will not be merged into one of the 1-4 groups in the following cases: +// - The contents stray off its clipping rectangle (we only compare the MaxX value, not the MinX value). +// Direct ImDrawList calls won't be taken into account by default, if you use them make sure the ImGui:: bounds +// matches, by e.g. calling SetCursorScreenPos(). +// - The channel uses more than one draw command itself. We drop all our attempt at merging stuff here.. +// we could do better but it's going to be rare and probably not worth the hassle. +// Columns for which the draw channel(s) haven't been merged with other will use their own ImDrawCmd. +// +// This function is particularly tricky to understand.. take a breath. +void ImGui::TableMergeDrawChannels(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImDrawListSplitter* splitter = table->DrawSplitter; + const bool has_freeze_v = (table->FreezeRowsCount > 0); + const bool has_freeze_h = (table->FreezeColumnsCount > 0); + IM_ASSERT(splitter->_Current == 0); + + // Track which groups we are going to attempt to merge, and which channels goes into each group. + struct MergeGroup + { + ImRect ClipRect; + int ChannelsCount; + ImBitArray ChannelsMask; + + MergeGroup() { ChannelsCount = 0; } + }; + int merge_group_mask = 0x00; + MergeGroup merge_groups[4]; + + // 1. Scan channels and take note of those which can be merged + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const int merge_group_sub_count = has_freeze_v ? 2 : 1; + for (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++) + { + const int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen; + + // Don't attempt to merge if there are multiple draw calls within the column + ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; + if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0) + src_channel->_CmdBuffer.pop_back(); + if (src_channel->_CmdBuffer.Size != 1) + continue; + + // Find out the width of this merge group and check if it will fit in our column + // (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it) + if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) + { + float content_max_x; + if (!has_freeze_v) + content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze + else if (merge_group_sub_n == 0) + content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); // Row freeze: use width before freeze + else + content_max_x = column->ContentMaxXUnfrozen; // Row freeze: use width after freeze + if (content_max_x > column->ClipRect.Max.x) + continue; + } + + const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); + IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS); + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + merge_group->ChannelsMask.SetBit(channel_no); + merge_group->ChannelsCount++; + merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); + merge_group_mask |= (1 << merge_group_n); + } + + // Invalidate current draw channel + // (we don't clear DrawChannelFrozen/DrawChannelUnfrozen solely to facilitate debugging/later inspection of data) + column->DrawChannelCurrent = (ImGuiTableDrawChannelIdx)-1; + } + + // [DEBUG] Display merge groups +#if 0 + if (g.IO.KeyShift) + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + continue; + char buf[32]; + ImFormatString(buf, 32, "MG%d:%d", merge_group_n, merge_group->ChannelsCount); + ImVec2 text_pos = merge_group->ClipRect.Min + ImVec2(4, 4); + ImVec2 text_size = CalcTextSize(buf, NULL); + GetForegroundDrawList()->AddRectFilled(text_pos, text_pos + text_size, IM_COL32(0, 0, 0, 255)); + GetForegroundDrawList()->AddText(text_pos, IM_COL32(255, 255, 0, 255), buf, NULL); + GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 255, 0, 255)); + } +#endif + + // 2. Rewrite channel list in our preferred order + if (merge_group_mask != 0) + { + // We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels(). + const int LEADING_DRAW_CHANNELS = 2; + g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized + ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; + ImBitArray remaining_mask; // We need 132-bit of storage + remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); + remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen); + IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); + int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS); + //ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect; + ImRect host_rect = table->HostClipRect; + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + if (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + ImRect merge_clip_rect = merge_group->ClipRect; + + // Extend outer-most clip limits to match those of host, so draw calls can be merged even if + // outer-most columns have some outer padding offsetting them from their parent ClipRect. + // The principal cases this is dealing with are: + // - On a same-window table (not scrolling = single group), all fitting columns ClipRect -> will extend and match host ClipRect -> will merge + // - Columns can use padding and have left-most ClipRect.Min.x and right-most ClipRect.Max.x != from host ClipRect -> will extend and match host ClipRect -> will merge + // FIXME-TABLE FIXME-WORKRECT: We are wasting a merge opportunity on tables without scrolling if column doesn't fit + // within host clip rect, solely because of the half-padding difference between window->WorkRect and window->InnerClipRect. + if ((merge_group_n & 1) == 0 || !has_freeze_h) + merge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x); + if ((merge_group_n & 2) == 0 || !has_freeze_v) + merge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y); + if ((merge_group_n & 1) != 0) + merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x); + if ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0) + merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y); +#if 0 + GetOverlayDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); + GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); +#endif + remaining_count -= merge_group->ChannelsCount; + for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++) + remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n]; + for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) + { + // Copy + overwrite new clip rect + if (!merge_group->ChannelsMask.TestBit(n)) + continue; + merge_group->ChannelsMask.ClearBit(n); + merge_channels_count--; + + ImDrawChannel* channel = &splitter->_Channels[n]; + IM_ASSERT(channel->_CmdBuffer.Size == 1 && merge_clip_rect.Contains(ImRect(channel->_CmdBuffer[0].ClipRect))); + channel->_CmdBuffer[0].ClipRect = merge_clip_rect.ToVec4(); + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + } + } + + // Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1) + if (merge_group_n == 1 && has_freeze_v) + memcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel)); + } + + // Append unmergeable channels that we didn't reorder at the end of the list + for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) + { + if (!remaining_mask.TestBit(n)) + continue; + ImDrawChannel* channel = &splitter->_Channels[n]; + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + remaining_count--; + } + IM_ASSERT(dst_tmp == g.DrawChannelsTempMergeBuffer.Data + g.DrawChannelsTempMergeBuffer.Size); + memcpy(splitter->_Channels.Data + LEADING_DRAW_CHANNELS, g.DrawChannelsTempMergeBuffer.Data, (splitter->_Count - LEADING_DRAW_CHANNELS) * sizeof(ImDrawChannel)); + } +} + +// FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow) +void ImGui::TableDrawBorders(ImGuiTable* table) +{ + ImGuiWindow* inner_window = table->InnerWindow; + if (!table->OuterWindow->ClipRect.Overlaps(table->OuterRect)) + return; + + ImDrawList* inner_drawlist = inner_window->DrawList; + table->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0); + inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false); + + // Draw inner border and resizing feedback + const float border_size = TABLE_BORDER_SIZE; + const float draw_y1 = table->InnerRect.Min.y; + const float draw_y2_body = table->InnerRect.Max.y; + const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table->LastFirstRowHeight) : draw_y1; + if (table->Flags & ImGuiTableFlags_BordersInnerV) + { + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + const bool is_hovered = (table->HoveredColumnBorder == column_n); + const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent); + const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0; + const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1); + if (column->MaxX > table->InnerClipRect.Max.x && !is_resized) + continue; + + // Decide whether right-most column is visible + if (column->NextEnabledColumn == -1 && !is_resizable) + if ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || (table->Flags & ImGuiTableFlags_NoHostExtendX)) + continue; + if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. + continue; + + // Draw in outer window so right-most column won't be clipped + // Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling. + ImU32 col; + float draw_y2; + if (is_hovered || is_resized || is_frozen_separator) + { + draw_y2 = draw_y2_body; + col = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong; + } + else + { + draw_y2 = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? draw_y2_head : draw_y2_body; + col = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? table->BorderColorStrong : table->BorderColorLight; + } + + if (draw_y2 > draw_y1) + inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), col, border_size); + } + } + + // Draw outer border + // FIXME: could use AddRect or explicit VLine/HLine helper? + if (table->Flags & ImGuiTableFlags_BordersOuter) + { + // Display outer border offset by 1 which is a simple way to display it without adding an extra draw call + // (Without the offset, in outer_window it would be rendered behind cells, because child windows are above their + // parent. In inner_window, it won't reach out over scrollbars. Another weird solution would be to display part + // of it in inner window, and the part that's over scrollbars in the outer window..) + // Either solution currently won't allow us to use a larger border size: the border would clipped. + const ImRect outer_border = table->OuterRect; + const ImU32 outer_col = table->BorderColorStrong; + if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) + { + inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterV) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterH) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size); + } + } + if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y) + { + // Draw bottom-most row border + const float border_y = table->RowPosY2; + if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y) + inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size); + } + + inner_drawlist->PopClipRect(); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Sorting +//------------------------------------------------------------------------- +// - TableGetSortSpecs() +// - TableFixColumnSortDirection() [Internal] +// - TableGetColumnNextSortDirection() [Internal] +// - TableSetColumnSortDirection() [Internal] +// - TableSortSpecsSanitize() [Internal] +// - TableSortSpecsBuild() [Internal] +//------------------------------------------------------------------------- + +// Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set) +// You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since +// last call, or the first time. +// Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! +ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + + if (!(table->Flags & ImGuiTableFlags_Sortable)) + return NULL; + + // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + TableSortSpecsBuild(table); + + return &table->SortSpecs; +} + +static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) +{ + IM_ASSERT(n < column->SortDirectionsAvailCount); + return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; +} + +// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) +void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column) +{ + if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0) + return; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + table->IsSortSpecsDirty = true; +} + +// Calculate next sort direction that would be set after clicking the column +// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click. +// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op. +IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2); +ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column) +{ + IM_ASSERT(column->SortDirectionsAvailCount > 0); + if (column->SortOrder == -1) + return TableGetColumnAvailSortDirection(column, 0); + for (int n = 0; n < 3; n++) + if (column->SortDirection == TableGetColumnAvailSortDirection(column, n)) + return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount); + IM_ASSERT(0); + return ImGuiSortDirection_None; +} + +// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert +// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. +void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!(table->Flags & ImGuiTableFlags_SortMulti)) + append_to_sort_specs = false; + if (!(table->Flags & ImGuiTableFlags_SortTristate)) + IM_ASSERT(sort_direction != ImGuiSortDirection_None); + + ImGuiTableColumnIdx sort_order_max = 0; + if (append_to_sort_specs) + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder); + + ImGuiTableColumn* column = &table->Columns[column_n]; + column->SortDirection = (ImU8)sort_direction; + if (column->SortDirection == ImGuiSortDirection_None) + column->SortOrder = -1; + else if (column->SortOrder == -1 || !append_to_sort_specs) + column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0; + + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column != column && !append_to_sort_specs) + other_column->SortOrder = -1; + TableFixColumnSortDirection(table, other_column); + } + table->IsSettingsDirty = true; + table->IsSortSpecsDirty = true; +} + +void ImGui::TableSortSpecsSanitize(ImGuiTable* table) +{ + IM_ASSERT(table->Flags & ImGuiTableFlags_Sortable); + + // Clear SortOrder from hidden column and verify that there's no gap or duplicate. + int sort_order_count = 0; + ImU64 sort_order_mask = 0x00; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder != -1 && !column->IsEnabled) + column->SortOrder = -1; + if (column->SortOrder == -1) + continue; + sort_order_count++; + sort_order_mask |= ((ImU64)1 << column->SortOrder); + IM_ASSERT(sort_order_count < (int)sizeof(sort_order_mask) * 8); + } + + const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1); + const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti); + if (need_fix_linearize || need_fix_single_sort_order) + { + ImU64 fixed_mask = 0x00; + for (int sort_n = 0; sort_n < sort_order_count; sort_n++) + { + // Fix: Rewrite sort order fields if needed so they have no gap or duplicate. + // (e.g. SortOrder 0 disappeared, SortOrder 1..2 exists --> rewrite then as SortOrder 0..1) + int column_with_smallest_sort_order = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if ((fixed_mask & ((ImU64)1 << (ImU64)column_n)) == 0 && table->Columns[column_n].SortOrder != -1) + if (column_with_smallest_sort_order == -1 || table->Columns[column_n].SortOrder < table->Columns[column_with_smallest_sort_order].SortOrder) + column_with_smallest_sort_order = column_n; + IM_ASSERT(column_with_smallest_sort_order != -1); + fixed_mask |= ((ImU64)1 << column_with_smallest_sort_order); + table->Columns[column_with_smallest_sort_order].SortOrder = (ImGuiTableColumnIdx)sort_n; + + // Fix: Make sure only one column has a SortOrder if ImGuiTableFlags_MultiSortable is not set. + if (need_fix_single_sort_order) + { + sort_order_count = 1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (column_n != column_with_smallest_sort_order) + table->Columns[column_n].SortOrder = -1; + break; + } + } + } + + // Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag) + if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + sort_order_count = 1; + column->SortOrder = 0; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + break; + } + } + + table->SortSpecsCount = (ImGuiTableColumnIdx)sort_order_count; +} + +void ImGui::TableSortSpecsBuild(ImGuiTable* table) +{ + bool dirty = table->IsSortSpecsDirty; + if (dirty) + { + TableSortSpecsSanitize(table); + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + table->SortSpecs.SpecsDirty = true; // Mark as dirty for user + table->IsSortSpecsDirty = false; // Mark as not dirty for us + } + + // Write output + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + if (dirty && sort_specs != NULL) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder == -1) + continue; + IM_ASSERT(column->SortOrder < table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; + sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; + sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; + sort_spec->SortDirection = column->SortDirection; + } + + table->SortSpecs.Specs = sort_specs; + table->SortSpecs.SpecsCount = table->SortSpecsCount; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Headers +//------------------------------------------------------------------------- +// - TableGetHeaderRowHeight() [Internal] +// - TableHeadersRow() +// - TableHeader() +//------------------------------------------------------------------------- + +float ImGui::TableGetHeaderRowHeight() +{ + // Caring for a minor edge case: + // Calculate row height, for the unlikely case that some labels may be taller than others. + // If we didn't do that, uneven header height would highlight but smaller one before the tallest wouldn't catch input for all height. + // In your custom header row you may omit this all together and just call TableNextRow() without a height... + float row_height = GetTextLineHeight(); + int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + ImGuiTableColumnFlags flags = TableGetColumnFlags(column_n); + if ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel)) + row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y); + } + row_height += GetStyle().CellPadding.y * 2.0f; + return row_height; +} + +// [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn(). +// The intent is that advanced users willing to create customized headers would not need to use this helper +// and can create their own! For example: TableHeader() may be preceeded by Checkbox() or other custom widgets. +// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this. +// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy. +// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public. +void ImGui::TableHeadersRow() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + + // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout) + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + // Open row + const float row_y1 = GetCursorScreenPos().y; + const float row_height = TableGetHeaderRowHeight(); + TableNextRow(ImGuiTableRowFlags_Headers, row_height); + if (table->HostSkipItems) // Merely an optimization, you may skip in your own code. + return; + + const int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + if (!TableSetColumnIndex(column_n)) + continue; + + // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) + // - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide + // - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier. + const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); + PushID(table->InstanceCurrent * table->ColumnsCount + column_n); + TableHeader(name); + PopID(); + } + + // Allow opening popup from the right-most section after the last column. + ImVec2 mouse_pos = ImGui::GetMousePos(); + if (IsMouseReleased(1) && TableGetHoveredColumn() == columns_count) + if (mouse_pos.y >= row_y1 && mouse_pos.y < row_y1 + row_height) + TableOpenContextMenu(-1); // Will open a non-column-specific popup. +} + +// Emit a column header (text + optional sort order) +// We cpu-clip text here so that all columns headers can be merged into a same draw call. +// Note that because of how we cpu-clip and display sorting indicators, you _cannot_ use SameLine() after a TableHeader() +void ImGui::TableHeader(const char* label) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!"); + IM_ASSERT(table->CurrentColumn != -1); + const int column_n = table->CurrentColumn; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Label + if (label == NULL) + label = ""; + const char* label_end = FindRenderedTextEnd(label); + ImVec2 label_size = CalcTextSize(label, label_end, true); + ImVec2 label_pos = window->DC.CursorPos; + + // If we already got a row height, there's use that. + // FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect? + ImRect cell_r = TableGetCellBgRect(table, column_n); + float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f); + + // Calculate ideal size for sort order arrow + float w_arrow = 0.0f; + float w_sort_text = 0.0f; + char sort_order_suf[4] = ""; + const float ARROW_SCALE = 0.65f; + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x); + if (column->SortOrder > 0) + { + ImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), "%d", column->SortOrder + 1); + w_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x; + } + } + + // We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging. + float max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow; + column->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX); + column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x); + + // Keep header highlighted when context menu is open. + const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent); + ImGuiID id = window->GetID(label); + ImRect bb(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0f)); + ItemSize(ImVec2(0.0f, label_height)); // Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal + if (!ItemAdd(bb, id)) + return; + + //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + + // Using AllowItemOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + if (held || hovered || selected) + { + const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + //RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); + } + else + { + // Submit single cell bg color in the case we didn't submit a full header row + if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + if (held) + table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; + window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; + + // Drag and drop to re-order columns. + // FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone. + if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive) + { + // While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x + table->ReorderColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + + // We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder. + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x) + if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL) + if (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = -1; + if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x) + if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL) + if (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = +1; + } + + // Sort order arrow + const float ellipsis_max = cell_r.Max.x - w_arrow - w_sort_text; + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + if (column->SortOrder != -1) + { + float x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text); + float y = label_pos.y; + if (column->SortOrder > 0) + { + PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text, 0.70f)); + RenderText(ImVec2(x + g.Style.ItemInnerSpacing.x, y), sort_order_suf); + PopStyleColor(); + x += w_sort_text; + } + RenderArrow(window->DrawList, ImVec2(x, y), GetColorU32(ImGuiCol_Text), column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE); + } + + // Handle clicking on column header to adjust Sort Order + if (pressed && table->ReorderColumn != column_n) + { + ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column); + TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); + } + } + + // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will + // be merged into a single draw call. + //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); + + const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); + if (text_clipped && hovered && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay) + SetTooltip("%.*s", (int)(label_end - label), label); + + // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden + if (IsMouseReleased(1) && IsItemHovered()) + TableOpenContextMenu(column_n); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Context Menu +//------------------------------------------------------------------------- +// - TableOpenContextMenu() [Internal] +// - TableDrawContextMenu() [Internal] +//------------------------------------------------------------------------- + +// Use -1 to open menu not specific to a given column. +void ImGui::TableOpenContextMenu(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (column_n == -1 && table->CurrentColumn != -1) // When called within a column automatically use this one (for consistency) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) // To facilitate using with TableGetHoveredColumn() + column_n = -1; + IM_ASSERT(column_n >= -1 && column_n < table->ColumnsCount); + if (table->Flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + table->IsContextPopupOpen = true; + table->ContextPopupColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + OpenPopupEx(context_menu_id, ImGuiPopupFlags_None); + } +} + +// Output context menu into current window (generally a popup) +// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data? +void ImGui::TableDrawContextMenu(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + bool want_separator = false; + const int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1; + ImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL; + + // Sizing + if (table->Flags & ImGuiTableFlags_Resizable) + { + if (column != NULL) + { + const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled; + if (MenuItem("Size column to fit###SizeOne", NULL, false, can_resize)) + TableSetColumnWidthAutoSingle(table, column_n); + } + + const char* size_all_desc; + if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame) + size_all_desc = "Size all columns to fit###SizeAll"; // All fixed + else + size_all_desc = "Size all columns to default###SizeAll"; // All stretch or mixed + if (MenuItem(size_all_desc, NULL)) + TableSetColumnWidthAutoAll(table); + want_separator = true; + } + + // Ordering + if (table->Flags & ImGuiTableFlags_Reorderable) + { + if (MenuItem("Reset order", NULL, false, !table->IsDefaultDisplayOrder)) + table->IsResetDisplayOrderRequest = true; + want_separator = true; + } + + // Reset all (should work but seems unnecessary/noisy to expose?) + //if (MenuItem("Reset all")) + // table->IsResetAllRequest = true; + + // Sorting + // (modify TableOpenContextMenu() to add _Sortable flag if enabling this) +#if 0 + if ((table->Flags & ImGuiTableFlags_Sortable) && column != NULL && (column->Flags & ImGuiTableColumnFlags_NoSort) == 0) + { + if (want_separator) + Separator(); + want_separator = true; + + bool append_to_sort_specs = g.IO.KeyShift; + if (MenuItem("Sort in Ascending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Ascending, (column->Flags & ImGuiTableColumnFlags_NoSortAscending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Ascending, append_to_sort_specs); + if (MenuItem("Sort in Descending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Descending, (column->Flags & ImGuiTableColumnFlags_NoSortDescending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Descending, append_to_sort_specs); + } +#endif + + // Hiding / Visibility + if (table->Flags & ImGuiTableFlags_Hideable) + { + if (want_separator) + Separator(); + want_separator = true; + + PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true); + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column->Flags & ImGuiTableColumnFlags_Disabled) + continue; + + const char* name = TableGetColumnName(table, other_column_n); + if (name == NULL || name[0] == 0) + name = ""; + + // Make sure we can't hide the last active column + bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true; + if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1) + menu_item_active = false; + if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active)) + other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled; + } + PopItemFlag(); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Settings (.ini data) +//------------------------------------------------------------------------- +// FIXME: The binding/finding/creating flow are too confusing. +//------------------------------------------------------------------------- +// - TableSettingsInit() [Internal] +// - TableSettingsCalcChunkSize() [Internal] +// - TableSettingsCreate() [Internal] +// - TableSettingsFindByID() [Internal] +// - TableGetBoundSettings() [Internal] +// - TableResetSettings() +// - TableSaveSettings() [Internal] +// - TableLoadSettings() [Internal] +// - TableSettingsHandler_ClearAll() [Internal] +// - TableSettingsHandler_ApplyAll() [Internal] +// - TableSettingsHandler_ReadOpen() [Internal] +// - TableSettingsHandler_ReadLine() [Internal] +// - TableSettingsHandler_WriteAll() [Internal] +// - TableSettingsInstallHandler() [Internal] +//------------------------------------------------------------------------- +// [Init] 1: TableSettingsHandler_ReadXXXX() Load and parse .ini file into TableSettings. +// [Main] 2: TableLoadSettings() When table is created, bind Table to TableSettings, serialize TableSettings data into Table. +// [Main] 3: TableSaveSettings() When table properties are modified, serialize Table data into bound or new TableSettings, mark .ini as dirty. +// [Main] 4: TableSettingsHandler_WriteAll() When .ini file is dirty (which can come from other source), save TableSettings into .ini file. +//------------------------------------------------------------------------- + +// Clear and initialize empty settings instance +static void TableSettingsInit(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max) +{ + IM_PLACEMENT_NEW(settings) ImGuiTableSettings(); + ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings(); + for (int n = 0; n < columns_count_max; n++, settings_column++) + IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings(); + settings->ID = id; + settings->ColumnsCount = (ImGuiTableColumnIdx)columns_count; + settings->ColumnsCountMax = (ImGuiTableColumnIdx)columns_count_max; + settings->WantApply = true; +} + +static size_t TableSettingsCalcChunkSize(int columns_count) +{ + return sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings); +} + +ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count) +{ + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count)); + TableSettingsInit(settings, id, columns_count, columns_count); + return settings; +} + +// Find existing settings +ImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id) +{ + // FIXME-OPT: Might want to store a lookup map for this? + ImGuiContext& g = *GImGui; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +// Get settings for a given table, NULL if none +ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table) +{ + if (table->SettingsOffset != -1) + { + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); + IM_ASSERT(settings->ID == table->ID); + if (settings->ColumnsCountMax >= table->ColumnsCount) + return settings; // OK + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return NULL; +} + +// Restore initial state of table (with or without saved settings) +void ImGui::TableResetSettings(ImGuiTable* table) +{ + table->IsInitializing = table->IsSettingsDirty = true; + table->IsResetAllRequest = false; + table->IsSettingsRequestLoad = false; // Don't reload from ini + table->SettingsLoadedFlags = ImGuiTableFlags_None; // Mark as nothing loaded so our initialized data becomes authoritative +} + +void ImGui::TableSaveSettings(ImGuiTable* table) +{ + table->IsSettingsDirty = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind or create settings data + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = TableGetBoundSettings(table); + if (settings == NULL) + { + settings = TableSettingsCreate(table->ID, table->ColumnsCount); + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + settings->ColumnsCount = (ImGuiTableColumnIdx)table->ColumnsCount; + + // Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings + IM_ASSERT(settings->ID == table->ID); + IM_ASSERT(settings->ColumnsCount == table->ColumnsCount && settings->ColumnsCountMax >= settings->ColumnsCount); + ImGuiTableColumn* column = table->Columns.Data; + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + + bool save_ref_scale = false; + settings->SaveFlags = ImGuiTableFlags_None; + for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) + { + const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; + column_settings->WidthOrWeight = width_or_weight; + column_settings->Index = (ImGuiTableColumnIdx)n; + column_settings->DisplayOrder = column->DisplayOrder; + column_settings->SortOrder = column->SortOrder; + column_settings->SortDirection = column->SortDirection; + column_settings->IsEnabled = column->IsUserEnabled; + column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0) + save_ref_scale = true; + + // We skip saving some data in the .ini file when they are unnecessary to restore our state. + // Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f. + // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present. + if (width_or_weight != column->InitStretchWeightOrWidth) + settings->SaveFlags |= ImGuiTableFlags_Resizable; + if (column->DisplayOrder != n) + settings->SaveFlags |= ImGuiTableFlags_Reorderable; + if (column->SortOrder != -1) + settings->SaveFlags |= ImGuiTableFlags_Sortable; + if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) + settings->SaveFlags |= ImGuiTableFlags_Hideable; + } + settings->SaveFlags &= table->Flags; + settings->RefScale = save_ref_scale ? table->RefScale : 0.0f; + + MarkIniSettingsDirty(); +} + +void ImGui::TableLoadSettings(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + table->IsSettingsRequestLoad = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind settings + ImGuiTableSettings* settings; + if (table->SettingsOffset == -1) + { + settings = TableSettingsFindByID(table->ID); + if (settings == NULL) + return; + if (settings->ColumnsCount != table->ColumnsCount) // Allow settings if columns count changed. We could otherwise decide to return... + table->IsSettingsDirty = true; + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + else + { + settings = TableGetBoundSettings(table); + } + + table->SettingsLoadedFlags = settings->SaveFlags; + table->RefScale = settings->RefScale; + + // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + ImU64 display_order_mask = 0; + for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++) + { + int column_n = column_settings->Index; + if (column_n < 0 || column_n >= table->ColumnsCount) + continue; + + ImGuiTableColumn* column = &table->Columns[column_n]; + if (settings->SaveFlags & ImGuiTableFlags_Resizable) + { + if (column_settings->IsStretch) + column->StretchWeight = column_settings->WidthOrWeight; + else + column->WidthRequest = column_settings->WidthOrWeight; + column->AutoFitQueue = 0x00; + } + if (settings->SaveFlags & ImGuiTableFlags_Reorderable) + column->DisplayOrder = column_settings->DisplayOrder; + else + column->DisplayOrder = (ImGuiTableColumnIdx)column_n; + display_order_mask |= (ImU64)1 << column->DisplayOrder; + column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled; + column->SortOrder = column_settings->SortOrder; + column->SortDirection = column_settings->SortDirection; + } + + // Validate and fix invalid display order data + const ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1; + if (display_order_mask != expected_display_order_mask) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n; + + // Rebuild index + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; +} + +static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + table->SettingsOffset = -1; + g.SettingsTables.clear(); +} + +// Apply to existing windows (if any) +static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + { + table->IsSettingsRequestLoad = true; + table->SettingsOffset = -1; + } +} + +static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiID id = 0; + int columns_count = 0; + if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2) + return NULL; + + if (ImGuiTableSettings* settings = ImGui::TableSettingsFindByID(id)) + { + if (settings->ColumnsCountMax >= columns_count) + { + TableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle + return settings; + } + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return ImGui::TableSettingsCreate(id, columns_count); +} + +static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + ImGuiTableSettings* settings = (ImGuiTableSettings*)entry; + float f = 0.0f; + int column_n = 0, r = 0, n = 0; + + if (sscanf(line, "RefScale=%f", &f) == 1) { settings->RefScale = f; return; } + + if (sscanf(line, "Column %d%n", &column_n, &r) == 1) + { + if (column_n < 0 || column_n >= settings->ColumnsCount) + return; + line = ImStrSkipBlank(line + r); + char c = 0; + ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n; + column->Index = (ImGuiTableColumnIdx)column_n; + if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; } + if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; } + if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; } + if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; } + } +} + +static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + ImGuiContext& g = *ctx; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + { + if (settings->ID == 0) // Skip ditched settings + continue; + + // TableSaveSettings() may clear some of those flags when we establish that the data can be stripped + // (e.g. Order was unchanged) + const bool save_size = (settings->SaveFlags & ImGuiTableFlags_Resizable) != 0; + const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0; + const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0; + const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0; + if (!save_size && !save_visible && !save_order && !save_sort) + continue; + + buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve + buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount); + if (settings->RefScale != 0.0f) + buf->appendf("RefScale=%g\n", settings->RefScale); + ImGuiTableColumnSettings* column = settings->GetColumnSettings(); + for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) + { + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); + if (!save_column) + continue; + buf->appendf("Column %-2d", column_n); + if (column->UserID != 0) buf->appendf(" UserID=%08X", column->UserID); + if (save_size && column->IsStretch) buf->appendf(" Weight=%.4f", column->WidthOrWeight); + if (save_size && !column->IsStretch) buf->appendf(" Width=%d", (int)column->WidthOrWeight); + if (save_visible) buf->appendf(" Visible=%d", column->IsEnabled); + if (save_order) buf->appendf(" Order=%d", column->DisplayOrder); + if (save_sort && column->SortOrder != -1) buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); + buf->append("\n"); + } + buf->append("\n"); + } +} + +void ImGui::TableSettingsInstallHandler(ImGuiContext* context) +{ + ImGuiContext& g = *context; + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Table"; + ini_handler.TypeHash = ImHashStr("Table"); + ini_handler.ClearAllFn = TableSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = TableSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = TableSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Garbage Collection +//------------------------------------------------------------------------- +// - TableRemove() [Internal] +// - TableGcCompactTransientBuffers() [Internal] +// - TableGcCompactSettings() [Internal] +//------------------------------------------------------------------------- + +// Remove Table (currently only used by TestEngine) +void ImGui::TableRemove(ImGuiTable* table) +{ + //IMGUI_DEBUG_LOG("TableRemove() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + int table_idx = g.Tables.GetIndex(table); + //memset(table->RawData.Data, 0, table->RawData.size_in_bytes()); + //memset(table, 0, sizeof(ImGuiTable)); + g.Tables.Remove(table->ID, table); + g.TablesLastTimeActive[table_idx] = -1.0f; +} + +// Free up/compact internal Table buffers for when it gets unused +void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) +{ + //IMGUI_DEBUG_LOG("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + IM_ASSERT(table->MemoryCompacted == false); + table->SortSpecs.Specs = NULL; + table->SortSpecsMulti.clear(); + table->IsSortSpecsDirty = true; // FIXME: shouldn't have to leak into user performing a sort + table->ColumnsNames.clear(); + table->MemoryCompacted = true; + for (int n = 0; n < table->ColumnsCount; n++) + table->Columns[n].NameOffset = -1; + g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f; +} + +void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) +{ + temp_data->DrawSplitter.ClearFreeMemory(); + temp_data->LastTimeActive = -1.0f; +} + +// Compact and remove unused settings data (currently only used by TestEngine) +void ImGui::TableGcCompactSettings() +{ + ImGuiContext& g = *GImGui; + int required_memory = 0; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + required_memory += (int)TableSettingsCalcChunkSize(settings->ColumnsCount); + if (required_memory == g.SettingsTables.Buf.Size) + return; + ImChunkStream new_chunk_stream; + new_chunk_stream.Buf.reserve(required_memory); + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount)); + g.SettingsTables.swap(new_chunk_stream); +} + + +//------------------------------------------------------------------------- +// [SECTION] Tables: Debugging +//------------------------------------------------------------------------- +// - DebugNodeTable() [Internal] +//------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_METRICS_WINDOW + +static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy) +{ + sizing_policy &= ImGuiTableFlags_SizingMask_; + if (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return "FixedFit"; } + if (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return "FixedSame"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return "StretchProp"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return "StretchSame"; } + return "N/A"; +} + +void ImGui::DebugNodeTable(ImGuiTable* table) +{ + char buf[512]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + ImFormatString(p, buf_end - p, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(table, "%s", buf); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); + if (IsItemVisible() && table->HoveredColumnBody != -1) + GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + if (!open) + return; + bool clear_settings = SmallButton("Clear settings"); + BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags)); + BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); + BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); + BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); + BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); + //BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen); + float sum_weights = 0.0f; + for (int n = 0; n < table->ColumnsCount; n++) + if (table->Columns[n].Flags & ImGuiTableColumnFlags_WidthStretch) + sum_weights += table->Columns[n].StretchWeight; + for (int n = 0; n < table->ColumnsCount; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + const char* name = TableGetColumnName(table, n); + ImFormatString(buf, IM_ARRAYSIZE(buf), + "Column %d order %d '%s': offset %+.2f to %+.2f%s\n" + "Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n" + "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n" + "MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n" + "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n" + "Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..", + n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "", + column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen, + column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f, + column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x, + column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX, + column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags, + (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", + (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", + (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); + Bullet(); + Selectable(buf); + if (IsItemHovered()) + { + ImRect r(column->MinX, table->OuterRect.Min.y, column->MaxX, table->OuterRect.Max.y); + GetForegroundDrawList()->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255)); + } + } + if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) + DebugNodeTableSettings(settings); + if (clear_settings) + table->IsResetAllRequest = true; + TreePop(); +} + +void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings) +{ + if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount)) + return; + BulletText("SaveFlags: 0x%08X", settings->SaveFlags); + BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); + for (int n = 0; n < settings->ColumnsCount; n++) + { + ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; + ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; + BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X", + n, column_settings->DisplayOrder, column_settings->SortOrder, + (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", + column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID); + } + TreePop(); +} + +#else // #ifndef IMGUI_DISABLE_METRICS_WINDOW + +void ImGui::DebugNodeTable(ImGuiTable*) {} +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} + +#endif + + +//------------------------------------------------------------------------- +// [SECTION] Columns, BeginColumns, EndColumns, etc. +// (This is a legacy API, prefer using BeginTable/EndTable!) +//------------------------------------------------------------------------- +// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.) +//------------------------------------------------------------------------- +// - SetWindowClipRectBeforeSetChannel() [Internal] +// - GetColumnIndex() +// - GetColumnsCount() +// - GetColumnOffset() +// - GetColumnWidth() +// - SetColumnOffset() +// - SetColumnWidth() +// - PushColumnClipRect() [Internal] +// - PushColumnsBackground() [Internal] +// - PopColumnsBackground() [Internal] +// - FindOrCreateColumns() [Internal] +// - GetColumnsID() [Internal] +// - BeginColumns() +// - NextColumn() +// - EndColumns() +// - Columns() +//------------------------------------------------------------------------- + +// [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences, +// they would meddle many times with the underlying ImDrawCmd. +// Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let +// the subsequent single call to SetCurrentChannel() does it things once. +void ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect) +{ + ImVec4 clip_rect_vec4 = clip_rect.ToVec4(); + window->ClipRect = clip_rect; + window->DrawList->_CmdHeader.ClipRect = clip_rect_vec4; + window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4; +} + +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; +} + +float ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm) +{ + return offset_norm * (columns->OffMaxX - columns->OffMinX); +} + +float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset) +{ + return offset / (columns->OffMaxX - columns->OffMinX); +} + +static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; + +static float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index) +{ + // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing + // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. + IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); + + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; + x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); + if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) + x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); + + return x; +} + +float ImGui::GetColumnOffset(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return 0.0f; + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const float t = columns->Columns[column_index].OffsetNorm; + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); + return x_offset; +} + +static float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false) +{ + if (column_index < 0) + column_index = columns->Current; + + float offset_norm; + if (before_resize) + offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; + else + offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; + return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); +} + +float ImGui::GetColumnWidth(int column_index) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return GetContentRegionAvail().x; + + if (column_index < 0) + column_index = columns->Current; + return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); +} + +void ImGui::SetColumnOffset(int column_index, float offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1); + const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; + + if (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow)) + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); + + if (preserve_width) + SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); +} + +void ImGui::SetColumnWidth(int column_index, float width) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); +} + +void ImGui::PushColumnClipRect(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (column_index < 0) + column_index = columns->Current; + + ImGuiOldColumnData* column = &columns->Columns[column_index]; + PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); +} + +// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + columns->HostBackupClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, 0); +} + +void ImGui::PopColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); +} + +ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) +{ + // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. + for (int n = 0; n < window->ColumnsStorage.Size; n++) + if (window->ColumnsStorage[n].ID == id) + return &window->ColumnsStorage[n]; + + window->ColumnsStorage.push_back(ImGuiOldColumns()); + ImGuiOldColumns* columns = &window->ColumnsStorage.back(); + columns->ID = id; + return columns; +} + +ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) +{ + ImGuiWindow* window = GetCurrentWindow(); + + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. + PushID(0x11223347 + (str_id ? 0 : columns_count)); + ImGuiID id = window->GetID(str_id ? str_id : "columns"); + PopID(); + + return id; +} + +void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT(columns_count >= 1); + IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported + + // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); + ImGuiOldColumns* columns = FindOrCreateColumns(window, id); + IM_ASSERT(columns->ID == id); + columns->Current = 0; + columns->Count = columns_count; + columns->Flags = flags; + window->DC.CurrentColumns = columns; + + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostInitialClipRect = window->ClipRect; + columns->HostBackupParentWorkRect = window->ParentWorkRect; + window->ParentWorkRect = window->WorkRect; + + // Set state for first column + // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect + const float column_padding = g.Style.ItemSpacing.x; + const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); + const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); + const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; + columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); + columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; + + // Clear data if columns count changed + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + // Initialize default widths + columns->IsFirstFrame = (columns->Columns.Size == 0); + if (columns->Columns.Size == 0) + { + columns->Columns.reserve(columns_count + 1); + for (int n = 0; n < columns_count + 1; n++) + { + ImGuiOldColumnData column; + column.OffsetNorm = n / (float)columns_count; + columns->Columns.push_back(column); + } + } + + for (int n = 0; n < columns_count; n++) + { + // Compute clipping rectangle + ImGuiOldColumnData* column = &columns->Columns[n]; + float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); + float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); + column->ClipRect.ClipWithFull(window->ClipRect); + } + + if (columns->Count > 1) + { + columns->Splitter.Split(window->DrawList, 1 + columns->Count); + columns->Splitter.SetCurrentChannel(window->DrawList, 1); + PushColumnClipRect(0); + } + + // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::NextColumn() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems || window->DC.CurrentColumns == NULL) + return; + + ImGuiContext& g = *GImGui; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + + if (columns->Count == 1) + { + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + IM_ASSERT(columns->Current == 0); + return; + } + + // Next column + if (++columns->Current == columns->Count) + columns->Current = 0; + + PopItemWidth(); + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() + // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), + ImGuiOldColumnData* column = &columns->Columns[columns->Current]; + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); + + const float column_padding = g.Style.ItemSpacing.x; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + if (columns->Current > 0) + { + // Columns 1+ ignore IndentX (by canceling it out) + // FIXME-COLUMNS: Unnecessary, could be locked? + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; + } + else + { + // New row/line: column 0 honor IndentX. + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->LineMinY = columns->LineMaxY; + } + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = columns->LineMinY; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = 0.0f; + + // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::EndColumns() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + PopItemWidth(); + if (columns->Count > 1) + { + PopClipRect(); + columns->Splitter.Merge(window->DrawList); + } + + const ImGuiOldColumnFlags flags = columns->Flags; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + window->DC.CursorPos.y = columns->LineMaxY; + if (!(flags & ImGuiOldColumnFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + + // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy + bool is_being_resized = false; + if (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) + { + // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); + const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); + int dragging_column = -1; + for (int n = 1; n < columns->Count; n++) + { + ImGuiOldColumnData* column = &columns->Columns[n]; + float x = window->Pos.x + GetColumnOffset(n); + const ImGuiID column_id = columns->ID + ImGuiID(n); + const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); + KeepAliveID(column_id); + if (IsClippedEx(column_hit_rect, column_id)) // FIXME: Can be removed or replaced with a lower-level test + continue; + + bool hovered = false, held = false; + if (!(flags & ImGuiOldColumnFlags_NoResize)) + { + ButtonBehavior(column_hit_rect, column_id, &hovered, &held); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; + if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) + dragging_column = n; + } + + // Draw column + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const float xi = IM_FLOOR(x); + window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); + } + + // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. + if (dragging_column != -1) + { + if (!columns->IsBeingResized) + for (int n = 0; n < columns->Count + 1; n++) + columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; + columns->IsBeingResized = is_being_resized = true; + float x = GetDraggedColumnOffset(columns, dragging_column); + SetColumnOffset(dragging_column, x); + } + } + columns->IsBeingResized = is_being_resized; + + window->WorkRect = window->ParentWorkRect; + window->ParentWorkRect = columns->HostBackupParentWorkRect; + window->DC.CurrentColumns = NULL; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); +} + +void ImGui::Columns(int columns_count, const char* id, bool border) +{ + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(columns_count >= 1); + + ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); + //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) + return; + + if (columns != NULL) + EndColumns(); + + if (columns_count != 1) + BeginColumns(id, columns_count, flags); +} + +//------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imgui_widgets.cpp b/thirdparty/imgui/imgui_widgets.cpp new file mode 100644 index 0000000..f199ad4 --- /dev/null +++ b/thirdparty/imgui/imgui_widgets.cpp @@ -0,0 +1,8305 @@ +// dear imgui, v1.86 +// (widgets code) + +/* + +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Widgets: Text, etc. +// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, Bullet, etc.) +// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separator, etc.) +// [SECTION] Widgets: ComboBox +// [SECTION] Data Type and Data Formatting Helpers +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +// [SECTION] Widgets: InputText, InputTextMultiline +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +// [SECTION] Widgets: Selectable +// [SECTION] Widgets: ListBox +// [SECTION] Widgets: PlotLines, PlotHistogram +// [SECTION] Widgets: Value helpers +// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// System includes +#include // toupper +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +//------------------------------------------------------------------------- +// Warnings +//------------------------------------------------------------------------- + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------- + +// Widgets +static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f; // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior. +static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; // Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags. + +// Those MIN/MAX values are not define because we need to point to them +static const signed char IM_S8_MIN = -128; +static const signed char IM_S8_MAX = 127; +static const unsigned char IM_U8_MIN = 0; +static const unsigned char IM_U8_MAX = 0xFF; +static const signed short IM_S16_MIN = -32768; +static const signed short IM_S16_MAX = 32767; +static const unsigned short IM_U16_MIN = 0; +static const unsigned short IM_U16_MAX = 0xFFFF; +static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); +static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) +#ifdef LLONG_MIN +static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); +static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); +#else +static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; +static const ImS64 IM_S64_MAX = 9223372036854775807LL; +#endif +static const ImU64 IM_U64_MIN = 0; +#ifdef ULLONG_MAX +static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); +#else +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +#endif + +//------------------------------------------------------------------------- +// [SECTION] Forward Declarations +//------------------------------------------------------------------------- + +// For InputTextEx() +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Text, etc. +//------------------------------------------------------------------------- +// - TextEx() [Internal] +// - TextUnformatted() +// - Text() +// - TextV() +// - TextColored() +// - TextColoredV() +// - TextDisabled() +// - TextDisabledV() +// - TextWrapped() +// - TextWrappedV() +// - LabelText() +// - LabelTextV() +// - BulletText() +// - BulletTextV() +//------------------------------------------------------------------------- + +void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Accept null ranges + if (text == text_end) + text = text_end = ""; + + // Calculate length + const char* text_begin = text; + if (text_end == NULL) + text_end = text + strlen(text); // FIXME-OPT + + const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + const float wrap_pos_x = window->DC.TextWrapPos; + const bool wrap_enabled = (wrap_pos_x >= 0.0f); + if (text_end - text > 2000 && !wrap_enabled) + { + // Long text! + // Perform manual coarse clipping to optimize for long multi-line text + // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. + const char* line = text; + const float line_height = GetTextLineHeight(); + ImVec2 text_size(0, 0); + + // Lines to skip (can't skip when logging text) + ImVec2 pos = text_pos; + if (!g.LogEnabled) + { + int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height); + if (lines_skippable > 0) + { + int lines_skipped = 0; + while (line < text_end && lines_skipped < lines_skippable) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + } + + // Lines to render + if (line < text_end) + { + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); + while (line < text_end) + { + if (IsClippedEx(line_rect, 0)) + break; + + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + RenderText(pos, line, line_end, false); + line = line_end + 1; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; + pos.y += line_height; + } + + // Count remaining lines + int lines_skipped = 0; + while (line < text_end) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + text_size.y = (pos - text_pos).y; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + ItemAdd(bb, 0); + } + else + { + const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; + const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + if (!ItemAdd(bb, 0)) + return; + + // Render (we don't hide text after ## in this end-user function) + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } +} + +void ImGui::TextUnformatted(const char* text, const char* text_end) +{ + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::Text(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} + +void ImGui::TextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + // FIXME-OPT: Handle the %s shortcut? + ImGuiContext& g = *GImGui; + const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextColoredV(col, fmt, args); + va_end(args); +} + +void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, col); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextDisabled(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextDisabledV(fmt, args); + va_end(args); +} + +void ImGui::TextDisabledV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextWrapped(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextWrappedV(fmt, args); + va_end(args); +} + +void ImGui::TextWrappedV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting + else + TextV(fmt, args); + if (need_backup) + PopTextWrapPos(); +} + +void ImGui::LabelText(const char* label, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LabelTextV(label, fmt, args); + va_end(args); +} + +// Add a label+text combo aligned to other label+value widgets +void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float w = CalcItemWidth(); + + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const ImVec2 pos = window->DC.CursorPos; + const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2)); + const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0)) + return; + + // Render + RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); +} + +void ImGui::BulletText(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + BulletTextV(fmt, args); + va_end(args); +} + +// Text with a little bullet aligned to the typical tree node. +void ImGui::BulletTextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const char* text_begin = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); + const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(total_size, 0.0f); + const ImRect bb(pos, pos + total_size); + if (!ItemAdd(bb, 0)) + return; + + // Render + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col); + RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Main +//------------------------------------------------------------------------- +// - ButtonBehavior() [Internal] +// - Button() +// - SmallButton() +// - InvisibleButton() +// - ArrowButton() +// - CloseButton() [Internal] +// - CollapseButton() [Internal] +// - GetWindowScrollbarID() [Internal] +// - GetWindowScrollbarRect() [Internal] +// - Scrollbar() [Internal] +// - ScrollbarEx() [Internal] +// - Image() +// - ImageButton() +// - Checkbox() +// - CheckboxFlagsT() [Internal] +// - CheckboxFlags() +// - RadioButton() +// - ProgressBar() +// - Bullet() +//------------------------------------------------------------------------- + +// The ButtonBehavior() function is key to many interactions and used by many/most widgets. +// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via ImGuiButtonFlags_), +// this code is a little complex. +// By far the most common path is interacting with the Mouse using the default ImGuiButtonFlags_PressedOnClickRelease button behavior. +// See the series of events below and the corresponding state reported by dear imgui: +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse is outside bb) - - - - - - +// Frame N+1 (mouse moves inside bb) - true - - - - +// Frame N+2 (mouse button is down) - true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+4 (mouse moves outside bb) - - true - - - +// Frame N+5 (mouse moves inside bb) - true true - - - +// Frame N+6 (mouse button is released) true true - - true - +// Frame N+7 (mouse button is released) - true - - - - +// Frame N+8 (mouse moves outside bb) - - - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) true true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) - true - - - true +// Frame N+3 (mouse button is down) - true - - - - +// Frame N+6 (mouse button is released) true true - - - - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse button is down) - true - - - true +// Frame N+1 (mouse button is down) - true - - - - +// Frame N+2 (mouse button is released) - true - - - - +// Frame N+3 (mouse button is released) - true - - - - +// Frame N+4 (mouse button is down) true true true true - true +// Frame N+5 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// Note that some combinations are supported, +// - PressedOnDragDropHold can generally be associated with any flag. +// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. +//------------------------------------------------------------------------------------------------------------------------------------------------ +// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set: +// Repeat+ Repeat+ Repeat+ Repeat+ +// PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick +//------------------------------------------------------------------------------------------------------------------------------------------------- +// Frame N+0 (mouse button is down) - true - true +// ... - - - - +// Frame N + RepeatDelay true true - true +// ... - - - - +// Frame N + RepeatDelay + RepeatRate*N true true - true +//------------------------------------------------------------------------------------------------------------------------------------------------- + +bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + // Default only reacts to left mouse button + if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) + flags |= ImGuiButtonFlags_MouseButtonDefault_; + + // Default behavior requires click + release inside bounding box + if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) + flags |= ImGuiButtonFlags_PressedOnDefault_; + + ImGuiWindow* backup_hovered_window = g.HoveredWindow; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; + if (flatten_hovered_children) + g.HoveredWindow = window; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0 && g.LastItemData.ID != id) + IMGUI_TEST_ENGINE_ITEM_ADD(bb, id); +#endif + + bool pressed = false; + bool hovered = ItemHoverable(bb, id); + + // Drag source doesn't report as hovered + if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + hovered = false; + + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + hovered = true; + SetHoveredID(id); + if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) + { + pressed = true; + g.DragDropHoldJustPressedId = id; + FocusWindow(window); + } + } + + if (flatten_hovered_children) + g.HoveredWindow = backup_hovered_window; + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = false; + + // Mouse handling + if (hovered) + { + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + { + // Poll buttons + int mouse_button_clicked = -1; + int mouse_button_released = -1; + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseClicked[0]) { mouse_button_clicked = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseClicked[1]) { mouse_button_clicked = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseClicked[2]) { mouse_button_clicked = 2; } + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseReleased[0]) { mouse_button_released = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseReleased[1]) { mouse_button_released = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseReleased[2]) { mouse_button_released = 2; } + + if (mouse_button_clicked != -1 && g.ActiveId != id) + { + if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere)) + { + SetActiveID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveId) + ClearActiveID(); + else + SetActiveID(id, window); // Hold on ID + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); + } + } + if ((flags & ImGuiButtonFlags_PressedOnRelease) && mouse_button_released != -1) + { + // Repeat mode trumps on release behavior + const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; + if (!has_repeated_at_least_once) + pressed = true; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + ClearActiveID(); + } + + // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, true)) + pressed = true; + } + + if (pressed) + g.NavDisableHighlight = true; + } + + // Gamepad/Keyboard navigation + // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. + if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) + if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) + hovered = true; + if (g.NavActivateDownId == id) + { + bool nav_activated_by_code = (g.NavActivateId == id); + bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + if (nav_activated_by_code || nav_activated_by_inputs) + { + // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. + pressed = true; + SetActiveID(id, window); + g.ActiveIdSource = ImGuiInputSource_Nav; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + } + } + + // Process while held + bool held = false; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (g.ActiveIdIsJustActivated) + g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; + + const int mouse_button = g.ActiveIdMouseButton; + IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); + if (g.IO.MouseDown[mouse_button]) + { + held = true; + } + else + { + bool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0; + bool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0; + if ((release_in || release_anywhere) && !g.DragDropActive) + { + // Report as pressed when releasing the mouse (this is the most common path) + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; + bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + if (!is_double_click_release && !is_repeating_already) + pressed = true; + } + ClearActiveID(); + } + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + // When activated using Nav, we hold on the ActiveID until activation button is released + if (g.NavActivateDownId != id) + ClearActiveID(); + } + if (pressed) + g.ActiveIdHasBeenPressedBefore = true; + } + + if (out_hovered) *out_hovered = hovered; + if (out_held) *out_held = held; + + return pressed; +} + +bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + ImVec2 pos = window->DC.CursorPos; + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; + ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); + + const ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, id)) + return false; + + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + + if (g.LogEnabled) + LogSetNextTextDecoration("[", "]"); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + + // Automatically close popups + //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; +} + +bool ImGui::Button(const char* label, const ImVec2& size_arg) +{ + return ButtonEx(label, size_arg, ImGuiButtonFlags_None); +} + +// Small buttons fits within text without additional vertical spacing. +bool ImGui::SmallButton(const char* label) +{ + ImGuiContext& g = *GImGui; + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); + g.Style.FramePadding.y = backup_padding_y; + return pressed; +} + +// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. +// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. + IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); + + const ImGuiID id = window->GetID(str_id); + ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + return pressed; +} + +bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(str_id); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const float default_size = GetFrameHeight(); + ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); + if (!ItemAdd(bb, id)) + return false; + + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); + RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + + return pressed; +} + +bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +{ + float sz = GetFrameHeight(); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); +} + +// Button to close a window +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) + // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? + const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ImRect bb_interact = bb; + const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); + if (area_to_visible_ratio < 1.5f) + bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); + + // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + bool is_clipped = !ItemAdd(bb_interact, id); + + bool hovered, held; + bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held); + if (is_clipped) + return pressed; + + // Render + // FIXME: Clarify this mess + ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); + ImVec2 center = bb.GetCenter(); + if (hovered) + window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12); + + float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; + ImU32 cross_col = GetColorU32(ImGuiCol_Text); + center -= ImVec2(0.5f, 0.5f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f); + + return pressed; +} + +bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ItemAdd(bb, id); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); + + // Render + ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImVec2 center = bb.GetCenter(); + if (hovered || held) + window->DrawList->AddCircleFilled(center/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12); + RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + + // Switch to moving the window after mouse is moved beyond the initial drag threshold + if (IsItemActive() && IsMouseDragging(0)) + StartMouseMovingWindow(window); + + return pressed; +} + +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +{ + return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. +ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) +{ + const ImRect outer_rect = window->Rect(); + const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) + IM_ASSERT(scrollbar_size > 0.0f); + if (axis == ImGuiAxis_X) + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x, outer_rect.Max.y); + else + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y); +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiID id = GetWindowScrollbarID(window, axis); + KeepAliveID(id); + + // Calculate scrollbar bounding box + ImRect bb = GetWindowScrollbarRect(window, axis); + ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone; + if (axis == ImGuiAxis_X) + { + rounding_corners |= ImDrawFlags_RoundCornersBottomLeft; + if (!window->ScrollbarY) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + else + { + if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) + rounding_corners |= ImDrawFlags_RoundCornersTopRight; + if (!window->ScrollbarX) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; + float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; + ImS64 scroll = (ImS64)window->Scroll[axis]; + ScrollbarEx(bb, id, axis, &scroll, (ImS64)size_avail, (ImS64)size_contents, rounding_corners); + window->Scroll[axis] = (float)scroll; +} + +// Vertical/Horizontal scrollbar +// The entire piece of code below is rather confusing because: +// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) +// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar +// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. +// Still, the code should probably be made simpler.. +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_avail_v, ImS64 size_contents_v, ImDrawFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const float bb_frame_width = bb_frame.GetWidth(); + const float bb_frame_height = bb_frame.GetHeight(); + if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) + return false; + + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) + float alpha = 1.0f; + if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return false; + + const ImGuiStyle& style = g.Style; + const bool allow_interaction = (alpha >= 1.0f); + + ImRect bb = bb_frame; + bb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); + + // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) + const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); + + // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) + // But we maintain a minimum size in pixel to allow for the user to still aim inside. + IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), (ImS64)1); + const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_avail_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). + bool held = false; + bool hovered = false; + ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + + const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space + if (held && allow_interaction && grab_h_norm < 1.0f) + { + const float scrollbar_pos_v = bb.Min[axis]; + const float mouse_pos_v = g.IO.MousePos[axis]; + + // Click position in scrollbar normalized space (0.0f->1.0f) + const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); + SetHoveredID(id); + + bool seek_absolute = false; + if (g.ActiveIdIsJustActivated) + { + // On initial click calculate the distance between mouse and the center of the grab + seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm); + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = 0.0f; + else + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position + const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + *p_scroll_v = (ImS64)(scroll_v_norm * scroll_max); + + // Update values for rendering + scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); + grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Render + const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); + const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); + ImRect grab_rect; + if (axis == ImGuiAxis_X) + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); + else + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); + window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); + + return held; +} + +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + if (border_col.w > 0.0f) + bb.Max += ImVec2(2, 2); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + return; + + if (border_col.w > 0.0f) + { + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f); + window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col)); + } + else + { + window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col)); + } +} + +// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) +// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); + ItemSize(bb); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); + window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + + return pressed; +} + +// frame_padding < 0: uses FramePadding from style (default) +// frame_padding = 0: no framing +// frame_padding > 0: set framing size +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : g.Style.FramePadding; + return ImageButtonEx(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col); +} + +bool ImGui::Checkbox(const char* label, bool* v) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return false; + } + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + { + *v = !(*v); + MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + RenderNavHighlight(total_bb, id); + RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); + bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) + { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) + ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } + else if (*v) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) + RenderText(label_pos, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +template +bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) +{ + bool all_on = (*flags & flags_value) == flags_value; + bool any_on = (*flags & flags_value) != 0; + bool pressed; + if (!all_on && any_on) + { + ImGuiContext& g = *GImGui; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_MixedValue; + pressed = Checkbox(label, &all_on); + g.CurrentItemFlags = backup_item_flags; + } + else + { + pressed = Checkbox(label, &all_on); + + } + if (pressed) + { + if (all_on) + *flags |= flags_value; + else + *flags &= ~flags_value; + } + return pressed; +} + +bool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::RadioButton(const char* label, bool active) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + ImVec2 center = check_bb.GetCenter(); + center.x = IM_ROUND(center.x); + center.y = IM_ROUND(center.y); + const float radius = (square_sz - 1.0f) * 0.5f; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + MarkItemEdited(id); + + RenderNavHighlight(total_bb, id); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); + if (active) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); + } + + if (style.FrameBorderSize > 0.0f) + { + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) + LogRenderedText(&label_pos, active ? "(x)" : "( )"); + if (label_size.x > 0.0f) + RenderText(label_pos, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; +} + +// FIXME: This would work nicely if it was a public template, e.g. 'template RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it.. +bool ImGui::RadioButton(const char* label, int* v, int v_button) +{ + const bool pressed = RadioButton(label, *v == v_button); + if (pressed) + *v = v_button; + return pressed; +} + +// size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size +void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + ImVec2 pos = window->DC.CursorPos; + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f); + ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, 0)) + return; + + // Render + fraction = ImSaturate(fraction); + RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); + const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y); + RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding); + + // Default displaying the fraction as percentage string, but user can override it + char overlay_buf[32]; + if (!overlay) + { + ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f); + overlay = overlay_buf; + } + + ImVec2 overlay_size = CalcTextSize(overlay, NULL); + if (overlay_size.x > 0.0f) + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); +} + +void ImGui::Bullet() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + { + SameLine(0, style.FramePadding.x * 2); + return; + } + + // Render and stay on same line + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), text_col); + SameLine(0, style.FramePadding.x * 2.0f); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Low-level Layout helpers +//------------------------------------------------------------------------- +// - Spacing() +// - Dummy() +// - NewLine() +// - AlignTextToFramePadding() +// - SeparatorEx() [Internal] +// - Separator() +// - SplitterBehavior() [Internal] +// - ShrinkWidths() [Internal] +//------------------------------------------------------------------------- + +void ImGui::Spacing() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ItemSize(ImVec2(0, 0)); +} + +void ImGui::Dummy(const ImVec2& size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + ItemAdd(bb, 0); +} + +void ImGui::NewLine() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + ItemSize(ImVec2(0, 0)); + else + ItemSize(ImVec2(0.0f, g.FontSize)); + window->DC.LayoutType = backup_layout_type; +} + +void ImGui::AlignTextToFramePadding() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); +} + +// Horizontal/vertical separating line +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + + float thickness_draw = 1.0f; + float thickness_layout = 0.0f; + if (flags & ImGuiSeparatorFlags_Vertical) + { + // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + float y1 = window->DC.CursorPos.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); + ItemSize(ImVec2(thickness_layout, 0.0f)); + if (!ItemAdd(bb, 0)) + return; + + // Draw + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); + } + else if (flags & ImGuiSeparatorFlags_Horizontal) + { + // Horizontal Separator + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + + // FIXME-WORKRECT: old hack (#205) until we decide of consistent behavior with WorkRect/Indent and Separator + if (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID) + x1 += window->DC.Indent.x; + + // FIXME-WORKRECT: In theory we should simply be using WorkRect.Min.x/Max.x everywhere but it isn't aesthetically what we want, + // need to introduce a variant of WorkRect for that purpose. (#4787) + if (ImGuiTable* table = g.CurrentTable) + { + x1 = table->Columns[table->CurrentColumn].MinX; + x2 = table->Columns[table->CurrentColumn].MaxX; + } + + ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + if (columns) + PushColumnsBackground(); + + // We don't provide our width to the layout so that it doesn't get feed back into AutoFit + // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); + ItemSize(ImVec2(0.0f, thickness_layout)); + const bool item_visible = ItemAdd(bb, 0); + if (item_visible) + { + // Draw + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------\n"); + + } + if (columns) + { + PopColumnsBackground(); + columns->LineMinY = window->DC.CursorPos.y; + } + } +} + +void ImGui::Separator() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // Those flags should eventually be overridable by the user + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + flags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot. + SeparatorEx(flags); +} + +// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; + bool item_add = ItemAdd(bb, id); + g.CurrentItemFlags = item_flags_backup; + if (!item_add) + return false; + + bool hovered, held; + ImRect bb_interact = bb; + bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (hovered) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) + SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); + + ImRect bb_render = bb; + if (held) + { + ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; + float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; + + // Minimum pane size + float size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1); + float size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2); + if (mouse_delta < -size_1_maximum_delta) + mouse_delta = -size_1_maximum_delta; + if (mouse_delta > size_2_maximum_delta) + mouse_delta = size_2_maximum_delta; + + // Apply resize + if (mouse_delta != 0.0f) + { + if (mouse_delta < 0.0f) + IM_ASSERT(*size1 + mouse_delta >= min_size1); + if (mouse_delta > 0.0f) + IM_ASSERT(*size2 - mouse_delta >= min_size2); + *size1 += mouse_delta; + *size2 -= mouse_delta; + bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + MarkItemEdited(id); + } + } + + // Render + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); + + return held; +} + +static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) +{ + const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs; + const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs; + if (int d = (int)(b->Width - a->Width)) + return d; + return (b->Index - a->Index); +} + +// Shrink excess width from a set of item, by removing width from the larger items first. +// Set items Width to -1.0f to disable shrinking this item. +void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess) +{ + if (count == 1) + { + if (items[0].Width >= 0.0f) + items[0].Width = ImMax(items[0].Width - width_excess, 1.0f); + return; + } + ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); + int count_same_width = 1; + while (width_excess > 0.0f && count_same_width < count) + { + while (count_same_width < count && items[0].Width <= items[count_same_width].Width) + count_same_width++; + float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + if (max_width_to_remove_per_item <= 0.0f) + break; + float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item); + for (int item_n = 0; item_n < count_same_width; item_n++) + items[item_n].Width -= width_to_remove_per_item; + width_excess -= width_to_remove_per_item * count_same_width; + } + + // Round width and redistribute remainder left-to-right (could make it an option of the function?) + // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator. + width_excess = 0.0f; + for (int n = 0; n < count; n++) + { + float width_rounded = ImFloor(items[n].Width); + width_excess += items[n].Width - width_rounded; + items[n].Width = width_rounded; + } + if (width_excess > 0.0f) + for (int n = 0; n < count; n++) + if (items[n].Index < (int)(width_excess + 0.01f)) + items[n].Width += 1.0f; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ComboBox +//------------------------------------------------------------------------- +// - CalcMaxPopupHeightFromItemCount() [Internal] +// - BeginCombo() +// - BeginComboPopup() [Internal] +// - EndCombo() +// - BeginComboPreview() [Internal] +// - EndComboPreview() [Internal] +// - Combo() +//------------------------------------------------------------------------- + +static float CalcMaxPopupHeightFromItemCount(int items_count) +{ + ImGuiContext& g = *GImGui; + if (items_count <= 0) + return FLT_MAX; + return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); +} + +bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags; + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together + + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &bb)) + return false; + + // Open on click + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id); + bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None); + if (pressed && !popup_open) + { + OpenPopupEx(popup_id, ImGuiPopupFlags_None); + popup_open = true; + } + + // Render shape + const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); + RenderNavHighlight(bb, id); + if (!(flags & ImGuiComboFlags_NoPreview)) + window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); + if (!(flags & ImGuiComboFlags_NoArrowButton)) + { + ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); + if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + } + RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); + + // Custom preview + if (flags & ImGuiComboFlags_CustomPreview) + { + g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); + IM_ASSERT(preview_value == NULL || preview_value[0] == 0); + preview_value = NULL; + } + + // Render preview and label + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + { + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL); + } + if (label_size.x > 0) + RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label); + + if (!popup_open) + return false; + + g.NextWindowData.Flags = backup_next_window_data_flags; + return BeginComboPopup(popup_id, bb, flags); +} + +bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); + return false; + } + + // Set popup size + float w = bb.GetWidth(); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); + } + else + { + if ((flags & ImGuiComboFlags_HeightMask_) == 0) + flags |= ImGuiComboFlags_HeightRegular; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one + int popup_max_height_in_items = -1; + if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; + else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; + else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; + SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + } + + // This is essentially a specialized version of BeginPopupEx() + char name[16]; + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + + // Set position given a custom constraint (peak into expected window size so we can position it) + // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? + // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()? + if (ImGuiWindow* popup_window = FindWindowByName(name)) + if (popup_window->WasActive) + { + // Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us. + ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window); + popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)" + ImRect r_outer = GetPopupAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox); + SetNextWindowPos(pos); + } + + // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text + bool ret = Begin(name, NULL, window_flags); + PopStyleVar(); + if (!ret) + { + EndPopup(); + IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above + return false; + } + return true; +} + +void ImGui::EndCombo() +{ + EndPopup(); +} + +// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements +// (Experimental, see GitHub issues: #1658, #4168) +bool ImGui::BeginComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + if (window->SkipItems || !window->ClipRect.Overlaps(g.LastItemData.Rect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result + return false; + IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? + if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional) + return false; + + // FIXME: This could be contained in a PushWorkRect() api + preview_data->BackupCursorPos = window->DC.CursorPos; + preview_data->BackupCursorMaxPos = window->DC.CursorMaxPos; + preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; + preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + preview_data->BackupLayout = window->DC.LayoutType; + window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + PushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max, true); + + return true; +} + +void ImGui::EndComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + // FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future + ImDrawList* draw_list = window->DrawList; + if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) + if (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command + { + draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; + draw_list->_TryMergeDrawCmds(); + } + PopClipRect(); + window->DC.CursorPos = preview_data->BackupCursorPos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); + window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine; + window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset; + window->DC.LayoutType = preview_data->BackupLayout; + preview_data->PreviewRect = ImRect(); +} + +// Getter for the old Combo() API: const char*[] +static bool Items_ArrayGetter(void* data, int idx, const char** out_text) +{ + const char* const* items = (const char* const*)data; + if (out_text) + *out_text = items[idx]; + return true; +} + +// Getter for the old Combo() API: "item1\0item2\0item3\0" +static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) +{ + // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited. + const char* items_separated_by_zeros = (const char*)data; + int items_count = 0; + const char* p = items_separated_by_zeros; + while (*p) + { + if (idx == items_count) + break; + p += strlen(p) + 1; + items_count++; + } + if (!*p) + return false; + if (out_text) + *out_text = p; + return true; +} + +// Old API, prefer using BeginCombo() nowadays if you can. +bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Call the getter to obtain the preview string which is a parameter to BeginCombo() + const char* preview_value = NULL; + if (*current_item >= 0 && *current_item < items_count) + items_getter(data, *current_item, &preview_value); + + // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. + if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) + SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + + if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) + return false; + + // Display items + // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) + bool value_changed = false; + for (int i = 0; i < items_count; i++) + { + PushID(i); + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + if (Selectable(item_text, item_selected)) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + + EndCombo(); + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +// Combo box helper allowing to pass an array of strings. +bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) +{ + const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); + return value_changed; +} + +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" +bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) +{ + int items_count = 0; + const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open + while (*p) + { + p += strlen(p) + 1; + items_count++; + } + bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Data Type and Data Formatting Helpers [Internal] +//------------------------------------------------------------------------- +// - PatchFormatStringFloatToInt() +// - DataTypeGetInfo() +// - DataTypeFormatString() +// - DataTypeApplyOp() +// - DataTypeApplyOpFromText() +// - DataTypeClamp() +// - GetMinimumStepAtDecimalPrecision +// - RoundScalarWithFormat<>() +//------------------------------------------------------------------------- + +static const ImGuiDataTypeInfo GDataTypeInfo[] = +{ + { sizeof(char), "S8", "%d", "%d" }, // ImGuiDataType_S8 + { sizeof(unsigned char), "U8", "%u", "%u" }, + { sizeof(short), "S16", "%d", "%d" }, // ImGuiDataType_S16 + { sizeof(unsigned short), "U16", "%u", "%u" }, + { sizeof(int), "S32", "%d", "%d" }, // ImGuiDataType_S32 + { sizeof(unsigned int), "U32", "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "S64", "%I64d","%I64d" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%I64u","%I64u" }, +#else + { sizeof(ImS64), "S64", "%lld", "%lld" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%llu", "%llu" }, +#endif + { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double +}; +IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); + +// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) + const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" +#endif + } + return fmt; +} + +const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type) +{ + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + return &GDataTypeInfo[data_type]; +} + +int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format) +{ + // Signedness doesn't matter when pushing integer arguments + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) + return ImFormatString(buf, buf_size, format, *(const ImU32*)p_data); + if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + return ImFormatString(buf, buf_size, format, *(const ImU64*)p_data); + if (data_type == ImGuiDataType_Float) + return ImFormatString(buf, buf_size, format, *(const float*)p_data); + if (data_type == ImGuiDataType_Double) + return ImFormatString(buf, buf_size, format, *(const double*)p_data); + if (data_type == ImGuiDataType_S8) + return ImFormatString(buf, buf_size, format, *(const ImS8*)p_data); + if (data_type == ImGuiDataType_U8) + return ImFormatString(buf, buf_size, format, *(const ImU8*)p_data); + if (data_type == ImGuiDataType_S16) + return ImFormatString(buf, buf_size, format, *(const ImS16*)p_data); + if (data_type == ImGuiDataType_U16) + return ImFormatString(buf, buf_size, format, *(const ImU16*)p_data); + IM_ASSERT(0); + return 0; +} + +void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg1, const void* arg2) +{ + IM_ASSERT(op == '+' || op == '-'); + switch (data_type) + { + case ImGuiDataType_S8: + if (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + if (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + return; + case ImGuiDataType_U8: + if (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + if (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + return; + case ImGuiDataType_S16: + if (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + if (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + return; + case ImGuiDataType_U16: + if (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + if (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + return; + case ImGuiDataType_S32: + if (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + if (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + return; + case ImGuiDataType_U32: + if (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + if (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + return; + case ImGuiDataType_S64: + if (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + if (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + return; + case ImGuiDataType_U64: + if (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + if (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + return; + case ImGuiDataType_Float: + if (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; } + if (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; } + return; + case ImGuiDataType_Double: + if (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; } + if (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; } + return; + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); +} + +// User can input math operators (e.g. +100) to edit a numerical values. +// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. +bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) +{ + while (ImCharIsBlankA(*buf)) + buf++; + + // We don't support '-' op because it would conflict with inputing negative value. + // Instead you can use +-100 to subtract from an existing value + char op = buf[0]; + if (op == '+' || op == '*' || op == '/') + { + buf++; + while (ImCharIsBlankA(*buf)) + buf++; + } + else + { + op = 0; + } + if (!buf[0]) + return false; + + // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, type_info->Size); + + if (format == NULL) + format = type_info->ScanFmt; + + // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. + int arg1i = 0; + if (data_type == ImGuiDataType_S32) + { + int* v = (int*)p_data; + int arg0i = *v; + float arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0i) < 1) + return false; + // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision + if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) + else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply + else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide + else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant + } + else if (data_type == ImGuiDataType_Float) + { + // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in + format = "%f"; + float* v = (float*)p_data; + float arg0f = *v, arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_Double) + { + format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis + double* v = (double*)p_data; + double arg0f = *v, arg1f = 0.0; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + { + // All other types assign constant + // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. + if (sscanf(buf, format, p_data) < 1) + return false; + } + else + { + // Small types need a 32-bit buffer to receive the result from scanf() + int v32; + if (sscanf(buf, format, &v32) < 1) + return false; + if (data_type == ImGuiDataType_S8) + *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); + else if (data_type == ImGuiDataType_U8) + *(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); + else if (data_type == ImGuiDataType_S16) + *(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); + else if (data_type == ImGuiDataType_U16) + *(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); + else + IM_ASSERT(0); + } + + return memcmp(&data_backup, p_data, type_info->Size) != 0; +} + +template +static int DataTypeCompareT(const T* lhs, const T* rhs) +{ + if (*lhs < *rhs) return -1; + if (*lhs > *rhs) return +1; + return 0; +} + +int ImGui::DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeCompareT((const ImS8* )arg_1, (const ImS8* )arg_2); + case ImGuiDataType_U8: return DataTypeCompareT((const ImU8* )arg_1, (const ImU8* )arg_2); + case ImGuiDataType_S16: return DataTypeCompareT((const ImS16* )arg_1, (const ImS16* )arg_2); + case ImGuiDataType_U16: return DataTypeCompareT((const ImU16* )arg_1, (const ImU16* )arg_2); + case ImGuiDataType_S32: return DataTypeCompareT((const ImS32* )arg_1, (const ImS32* )arg_2); + case ImGuiDataType_U32: return DataTypeCompareT((const ImU32* )arg_1, (const ImU32* )arg_2); + case ImGuiDataType_S64: return DataTypeCompareT((const ImS64* )arg_1, (const ImS64* )arg_2); + case ImGuiDataType_U64: return DataTypeCompareT((const ImU64* )arg_1, (const ImU64* )arg_2); + case ImGuiDataType_Float: return DataTypeCompareT((const float* )arg_1, (const float* )arg_2); + case ImGuiDataType_Double: return DataTypeCompareT((const double*)arg_1, (const double*)arg_2); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return 0; +} + +template +static bool DataTypeClampT(T* v, const T* v_min, const T* v_max) +{ + // Clamp, both sides are optional, return true if modified + if (v_min && *v < *v_min) { *v = *v_min; return true; } + if (v_max && *v > *v_max) { *v = *v_max; return true; } + return false; +} + +bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeClampT((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max); + case ImGuiDataType_U8: return DataTypeClampT((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max); + case ImGuiDataType_S16: return DataTypeClampT((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max); + case ImGuiDataType_U16: return DataTypeClampT((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max); + case ImGuiDataType_S32: return DataTypeClampT((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max); + case ImGuiDataType_U32: return DataTypeClampT((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max); + case ImGuiDataType_S64: return DataTypeClampT((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max); + case ImGuiDataType_U64: return DataTypeClampT((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max); + case ImGuiDataType_Float: return DataTypeClampT((float* )p_data, (const float* )p_min, (const float* )p_max); + case ImGuiDataType_Double: return DataTypeClampT((double*)p_data, (const double*)p_min, (const double*)p_max); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +static float GetMinimumStepAtDecimalPrecision(int decimal_precision) +{ + static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + if (decimal_precision < 0) + return FLT_MIN; + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); +} + +template +static const char* ImAtoi(const char* src, TYPE* output) +{ + int negative = 0; + if (*src == '-') { negative = 1; src++; } + if (*src == '+') { src++; } + TYPE v = 0; + while (*src >= '0' && *src <= '9') + v = (v * 10) + (*src++ - '0'); + *output = negative ? -v : v; + return src; +} + +// Sanitize format +// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi +// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi. +static void SanitizeFormatString(const char* fmt, char* fmt_out, size_t fmt_out_size) +{ + IM_UNUSED(fmt_out_size); + const char* fmt_end = ImParseFormatFindEnd(fmt); + IM_ASSERT((size_t)(fmt_end - fmt + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + while (fmt < fmt_end) + { + char c = *(fmt++); + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; + } + *fmt_out = 0; // Zero-terminate +} + +template +TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +{ + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string + return v; + + // Sanitize format + char fmt_sanitized[32]; + SanitizeFormatString(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized)); + fmt_start = fmt_sanitized; + + // Format value with our rounding, and read back + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v = (TYPE)ImAtof(p); + else + ImAtoi(p, (SIGNEDTYPE*)&v); + return v; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +//------------------------------------------------------------------------- +// - DragBehaviorT<>() [Internal] +// - DragBehavior() [Internal] +// - DragScalar() +// - DragScalarN() +// - DragFloat() +// - DragFloat2() +// - DragFloat3() +// - DragFloat4() +// - DragFloatRange2() +// - DragInt() +// - DragInt2() +// - DragInt3() +// - DragInt4() +// - DragIntRange2() +//------------------------------------------------------------------------- + +// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) +template +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_clamped = (v_min < v_max); + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + + // Default tweak speed + if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); + + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + float adjust_delta = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + { + adjust_delta = g.IO.MouseDelta[axis]; + if (g.IO.KeyAlt) + adjust_delta *= 1.0f / 100.0f; + if (g.IO.KeyShift) + adjust_delta *= 10.0f; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; + v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); + } + adjust_delta *= v_speed; + + // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter. + if (axis == ImGuiAxis_Y) + adjust_delta = -adjust_delta; + + // For logarithmic use our range is effectively 0..1 so scale the delta into that range + if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) // Epsilon to avoid /0 + adjust_delta /= (float)(v_max - v_min); + + // Clear current value on activation + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + bool is_just_activated = g.ActiveIdIsJustActivated; + bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + if (is_just_activated || is_already_past_limits_and_pushing_outward) + { + g.DragCurrentAccum = 0.0f; + g.DragCurrentAccumDirty = false; + } + else if (adjust_delta != 0.0f) + { + g.DragCurrentAccum += adjust_delta; + g.DragCurrentAccumDirty = true; + } + + if (!g.DragCurrentAccumDirty) + return false; + + TYPE v_cur = *v; + FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; + + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + const float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense) + if (is_logarithmic) + { + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + + // Convert to parametric space, apply delta, convert back + float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = v_old_parametric + g.DragCurrentAccum; + v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_old_ref_for_accum_remainder = v_old_parametric; + } + else + { + v_cur += (SIGNEDTYPE)g.DragCurrentAccum; + } + + // Round to user desired precision based on format string + if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + + // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. + g.DragCurrentAccumDirty = false; + if (is_logarithmic) + { + // Convert to parametric space, apply delta, convert back + float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); + } + else + { + g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); + } + + // Lose zero sign for float/double + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + // Clamp values (+ handle overflow/wrap-around for integer types) + if (*v != v_cur && is_clamped) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) + v_cur = v_max; + } + + // Apply result + if (*v == v_cur) + return false; + *v = v_cur; + return true; +} + +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. +// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Drag turns it into an InputText + const bool hovered = ItemHoverable(frame_bb, id); + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2); + if (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (temp_input_allowed) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavActivateInputId == id) + temp_input_is_active = true; + } + + // Experimental: simple click (without moving) turns Drag into an InputText + if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) + if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + { + g.NavActivateId = g.NavActivateInputId = id; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + temp_input_is_active = true; + } + } + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + // Drag behavior + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags); + if (value_changed) + MarkItemEdited(id); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return value_changed; +} + +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); +} + +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + float min_min = (v_min >= v_max) ? -FLT_MAX : v_min; + float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + float max_max = (v_min >= v_max) ? FLT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +// NB: v_speed is float to allow adjusting the drag speed with more precision +bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags); +} + +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + int min_min = (v_min >= v_max) ? INT_MIN : v_min; + int min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragInt("##min", v_current_min, v_speed, min_min, min_max, format, min_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + int max_max = (v_min >= v_max) ? INT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds + drag_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return DragScalar(label, data_type, p_data, v_speed, p_min, p_max, format, drag_flags); +} + +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds + drag_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return DragScalarN(label, data_type, p_data, components, v_speed, p_min, p_max, format, drag_flags); +} + +#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//------------------------------------------------------------------------- +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +//------------------------------------------------------------------------- +// - ScaleRatioFromValueT<> [Internal] +// - ScaleValueFromRatioT<> [Internal] +// - SliderBehaviorT<>() [Internal] +// - SliderBehavior() [Internal] +// - SliderScalar() +// - SliderScalarN() +// - SliderFloat() +// - SliderFloat2() +// - SliderFloat3() +// - SliderFloat4() +// - SliderAngle() +// - SliderInt() +// - SliderInt2() +// - SliderInt3() +// - SliderInt4() +// - VSliderScalar() +// - VSliderFloat() +// - VSliderInt() +//------------------------------------------------------------------------- + +// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) +template +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +{ + if (v_min == v_max) + return 0.0f; + IM_UNUSED(data_type); + + const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + if (is_logarithmic) + { + bool flipped = v_max < v_min; + + if (flipped) // Handle the case where the range is backwards + ImSwap(v_min, v_max); + + // Fudge min/max to avoid getting close to log(0) + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_min == 0.0f) && (v_max < 0.0f)) + v_min_fudged = -logarithmic_zero_epsilon; + else if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float result; + + if (v_clamped <= v_min_fudged) + result = 0.0f; // Workaround for values that are in-range but below our fudge + else if (v_clamped >= v_max_fudged) + result = 1.0f; // Workaround for values that are in-range but above our fudge + else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions + { + float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (v == 0.0f) + result = zero_point_center; // Special case for exactly zero + else if (v < 0.0f) + result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L; + else + result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R)); + } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)); + else + result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged)); + + return flipped ? (1.0f - result) : result; + } + + // Linear slider + return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); +} + +// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) +template +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +{ + if (v_min == v_max) + return v_min; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + + TYPE result; + if (is_logarithmic) + { + // We special-case the extents because otherwise our fudging can lead to "mathematically correct" but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value + if (t <= 0.0f) + result = v_min; + else if (t >= 1.0f) + result = v_max; + else + { + bool flipped = v_max < v_min; // Check if range is "backwards" + + // Fudge min/max to avoid getting silly results close to zero + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + if (flipped) + ImSwap(v_min_fudged, v_max_fudged); + + // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range + + if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts + { + float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R) + result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise) + else if (t_with_flip < zero_point_center) + result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); + else + result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); + } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); + else + result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); + } + } + else + { + // Linear slider + if (is_floating_point) + { + result = ImLerp(v_min, v_max, t); + } + else + { + // - For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 + // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. + if (t < 1.0) + { + FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; + result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); + } + else + { + result = v_max; + } + } + } + + return result; +} + +// FIXME: Move more of the code into SliderBehavior() +template +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + + const float grab_padding = 2.0f; + const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; + float grab_sz = style.GrabMinSize; + SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + grab_sz = ImMin(grab_sz, slider_sz); + const float slider_usable_sz = slider_sz - grab_sz; + const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; + const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; + + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true + if (is_logarithmic) + { + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f); + } + + // Process interacting with the slider + bool value_changed = false; + if (g.ActiveId == id) + { + bool set_new_value = false; + float clicked_t = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (!g.IO.MouseDown[0]) + { + ClearActiveID(); + } + else + { + const float mouse_abs_pos = g.IO.MousePos[axis]; + clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; + } + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + if (g.ActiveIdIsJustActivated) + { + g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation + g.SliderCurrentAccumDirty = false; + } + + const ImVec2 input_delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); + float input_delta = (axis == ImGuiAxis_X) ? input_delta2.x : -input_delta2.y; + if (input_delta != 0.0f) + { + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + if (decimal_precision > 0) + { + input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (IsNavInputDown(ImGuiNavInput_TweakSlow)) + input_delta /= 10.0f; + } + else + { + if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow)) + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + else + input_delta /= 100.0f; + } + if (IsNavInputDown(ImGuiNavInput_TweakFast)) + input_delta *= 10.0f; + + g.SliderCurrentAccum += input_delta; + g.SliderCurrentAccumDirty = true; + } + + float delta = g.SliderCurrentAccum; + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + { + ClearActiveID(); + } + else if (g.SliderCurrentAccumDirty) + { + clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits + { + set_new_value = false; + g.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate + } + else + { + set_new_value = true; + float old_clicked_t = clicked_t; + clicked_t = ImSaturate(clicked_t + delta); + + // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if (delta > 0) + g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); + else + g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta); + } + + g.SliderCurrentAccumDirty = false; + } + } + + if (set_new_value) + { + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + // Round to user desired precision based on format string + if (!(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + + // Apply result + if (*v != v_new) + { + *v = v_new; + value_changed = true; + } + } + } + + if (slider_sz < 1.0f) + { + *out_grab_bb = ImRect(bb.Min, bb.Min); + } + else + { + // Output grab position so it can be displayed by the caller + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + } + + return value_changed; +} + +// For 32-bit and larger types, slider bounds are limited to half the natural type range. +// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. +// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + + ImGuiContext& g = *GImGui; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: + IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_U32: + IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_S64: + IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_U64: + IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_Float: + IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_Double: + IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. +// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Slider turns it into an input box + const bool hovered = ItemHoverable(frame_bb, id); + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = (hovered && g.IO.MouseClicked[0]); + if (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (temp_input_allowed && (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id)) + temp_input_is_active = true; + } + } + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0; + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return value_changed; +} + +// Add multiple sliders on 1 line for compact edition of multiple components +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags) +{ + if (format == NULL) + format = "%.0f deg"; + float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags); + *v_rad = v_deg * (2 * IM_PI) / 360.0f; + return value_changed; +} + +bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags); +} + +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(frame_bb, id)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.y > grab_bb.Min.y) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + // For the vertical slider we allow centered text to overlap the frame padding + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + return value_changed; +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); +} + +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details. +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return SliderScalar(label, data_type, p_data, p_min, p_max, format, slider_flags); +} + +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None; + if (power != 1.0f) + { + IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!"); + slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths + } + return SliderScalarN(label, data_type, v, components, v_min, v_max, format, slider_flags); +} + +#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +//------------------------------------------------------------------------- +// - ImParseFormatFindStart() [Internal] +// - ImParseFormatFindEnd() [Internal] +// - ImParseFormatTrimDecorations() [Internal] +// - ImParseFormatPrecision() [Internal] +// - TempInputTextScalar() [Internal] +// - InputScalar() +// - InputScalarN() +// - InputFloat() +// - InputFloat2() +// - InputFloat3() +// - InputFloat4() +// - InputInt() +// - InputInt2() +// - InputInt3() +// - InputInt4() +// - InputDouble() +//------------------------------------------------------------------------- + +// We don't use strchr() because our strings are usually very short and often start with '%' +const char* ImParseFormatFindStart(const char* fmt) +{ + while (char c = fmt[0]) + { + if (c == '%' && fmt[1] != '%') + return fmt; + else if (c == '%') + fmt++; + fmt++; + } + return fmt; +} + +const char* ImParseFormatFindEnd(const char* fmt) +{ + // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. + if (fmt[0] != '%') + return fmt; + const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + for (char c; (c = *fmt) != 0; fmt++) + { + if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) + return fmt + 1; + if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0) + return fmt + 1; + } + return fmt; +} + +// Extract the format out of a format string with leading or trailing decorations +// fmt = "blah blah" -> return fmt +// fmt = "%.3f" -> return fmt +// fmt = "hello %.3f" -> return fmt + 6 +// fmt = "%.3f hello" -> return buf written with "%.3f" +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + if (fmt_start[0] != '%') + return fmt; + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); + return buf; +} + +// Parse display precision back from the display format string +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. +int ImParseFormatPrecision(const char* fmt, int default_precision) +{ + fmt = ImParseFormatFindStart(fmt); + if (fmt[0] != '%') + return default_precision; + fmt++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + int precision = INT_MAX; + if (*fmt == '.') + { + fmt = ImAtoi(fmt + 1, &precision); + if (precision < 0 || precision > 99) + precision = default_precision; + } + if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} + +// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) +// FIXME: Facilitate using this in variety of other situations. +bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +{ + // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. + // We clear ActiveID on the first frame to allow the InputText() taking it back. + ImGuiContext& g = *GImGui; + const bool init = (g.TempInputId != id); + if (init) + ClearActiveID(); + + g.CurrentWindow->DC.CursorPos = bb.Min; + bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); + if (init) + { + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); + g.TempInputId = g.ActiveId; + } + return value_changed; +} + +// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the ImGuiSliderFlags_AlwaysClamp flag is set! +// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility. +// However this may not be ideal for all uses, as some user code may break on out of bound values. +bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) +{ + ImGuiContext& g = *GImGui; + + char fmt_buf[32]; + char data_buf[32]; + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); + ImStrTrimBlanks(data_buf); + + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); + bool value_changed = false; + if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) + { + // Backup old value + size_t data_type_size = DataTypeGetInfo(data_type)->Size; + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); + if (p_clamp_min || p_clamp_max) + { + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + ImSwap(p_clamp_min, p_clamp_max); + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); + } + + // Only mark as edited if new value is different + value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); + } + return value_changed; +} + +// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional. +// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + char buf[64]; + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); + + bool value_changed = false; + if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= ImGuiInputTextFlags_CharsDecimal; + flags |= ImGuiInputTextFlags_AutoSelectAll; + flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. + + if (p_step != NULL) + { + const float button_size = GetFrameHeight(); + + BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() + PushID(label); + SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + + // Step buttons + const ImVec2 backup_frame_padding = style.FramePadding; + style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (flags & ImGuiInputTextFlags_ReadOnly) + BeginDisabled(); + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + if (flags & ImGuiInputTextFlags_ReadOnly) + EndDisabled(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + style.FramePadding = backup_frame_padding; + + PopID(); + EndGroup(); + } + else + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + } + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= InputScalar("", data_type, p_data, p_step, p_step_fast, format, flags); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0.0f, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} + +bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) +{ + // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. + const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); +} + +bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint +//------------------------------------------------------------------------- +// - InputText() +// - InputTextWithHint() +// - InputTextMultiline() +// - InputTextEx() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) +{ + int line_count = 0; + const char* s = text_begin; + while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding + if (c == '\n') + line_count++; + s--; + if (s[0] != '\n' && s[0] != '\r') + line_count++; + *out_text_end = s; + return line_count; +} + +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +{ + ImGuiContext& g = *GImGui; + ImFont* font = g.Font; + const float line_height = g.FontSize; + const float scale = line_height / font->FontSize; + + ImVec2 text_size = ImVec2(0, 0); + float line_width = 0.0f; + + const ImWchar* s = text_begin; + while (s < text_end) + { + unsigned int c = (unsigned int)(*s++); + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + if (stop_on_new_line) + break; + continue; + } + if (c == '\r') + continue; + + const float char_width = font->GetCharAdvance((ImWchar)c) * scale; + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (out_offset) + *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n + + if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) +namespace ImStb +{ + +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } +static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) +{ + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + r->x0 = 0.0f; + r->x1 = size.x; + r->baseline_y_delta = size.y; + r->ymin = 0.0f; + r->ymax = size.y; + r->num_chars = (int)(text_remaining - (text + line_start_idx)); +} + +// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. +static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r'; } +static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; } +static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#ifdef __APPLE__ // FIXME: Move setting to IO structure +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_MAC +#else +static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_WIN +#endif + +static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) +{ + ImWchar* dst = obj->TextW.Data + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats + obj->Edited = true; + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text (FIXME-OPT: Use memmove) + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len) +{ + const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int text_len = obj->CurLenW; + IM_ASSERT(pos <= text_len); + + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) + return false; + + // Grow internal buffer if needed + if (new_text_len + text_len + 1 > obj->TextW.Size) + { + if (!is_resizable) + return false; + IM_ASSERT(text_len < obj->TextW.Size); + obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1); + } + + ImWchar* text = obj->TextW.Data; + if (pos != text_len) + memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); + memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); + + obj->Edited = true; + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->TextW[obj->CurLenW] = '\0'; + + return true; +} + +// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) +#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page +#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page +#define STB_TEXTEDIT_K_SHIFT 0x400000 + +#define STB_TEXTEDIT_IMPLEMENTATION +#include "imstb_textedit.h" + +// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling +// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) +static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) +{ + stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); + if (text_len <= 0) + return; + if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len)) + { + state->cursor = text_len; + state->has_preferred_x = 0; + return; + } + IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() +} + +} // namespace ImStb + +void ImGuiInputTextState::OnKeyPressed(int key) +{ + stb_textedit_key(this, &Stb, key); + CursorFollow = true; + CursorAnimReset(); +} + +ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() +{ + memset(this, 0, sizeof(*this)); +} + +// Public API to manipulate UTF-8 text +// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// FIXME: The existence of this rarely exercised code path is a bit of a nuisance. +void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) +{ + IM_ASSERT(pos + bytes_count <= BufTextLen); + char* dst = Buf + pos; + const char* src = Buf + pos + bytes_count; + while (char c = *src++) + *dst++ = c; + *dst = '\0'; + + if (CursorPos >= pos + bytes_count) + CursorPos -= bytes_count; + else if (CursorPos >= pos) + CursorPos = pos; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen -= bytes_count; +} + +void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) +{ + const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + if (new_text_len + BufTextLen >= BufSize) + { + if (!is_resizable) + return; + + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) + ImGuiContext& g = *GImGui; + ImGuiInputTextState* edit_state = &g.InputTextState; + IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); + IM_ASSERT(Buf == edit_state->TextA.Data); + int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; + edit_state->TextA.reserve(new_buf_size + 1); + Buf = edit_state->TextA.Data; + BufSize = edit_state->BufCapacityA = new_buf_size; + } + + if (BufTextLen != pos) + memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); + memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); + Buf[BufTextLen + new_text_len] = '\0'; + + if (CursorPos >= pos) + CursorPos += new_text_len; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen += new_text_len; +} + +// Return false to discard a character. +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) +{ + IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); + unsigned int c = *p_char; + + // Filter non-printable (NB: isprint is unreliable! see #2467) + bool apply_named_filters = true; + if (c < 0x20) + { + bool pass = false; + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); + pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); + if (!pass) + return false; + apply_named_filters = false; // Override named filters below so newline and tabs can still be inserted. + } + + if (input_source != ImGuiInputSource_Clipboard) + { + // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) + if (c == 127) + return false; + + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) + return false; + } + + // Filter Unicode ranges we are not handling in this build + if (c > IM_UNICODE_CODEPOINT_MAX) + return false; + + // Generic named filters + if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific))) + { + // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'. + // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. + // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. + // Change the default decimal_point with: + // ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; + // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. + ImGuiContext& g = *GImGui; + const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + + // Allow 0-9 . - + * / + if (flags & ImGuiInputTextFlags_CharsDecimal) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + return false; + + // Allow 0-9 . - + * / e E + if (flags & ImGuiInputTextFlags_CharsScientific) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + return false; + + // Allow 0-9 a-F A-F + if (flags & ImGuiInputTextFlags_CharsHexadecimal) + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) + return false; + + // Turn a-z into A-Z + if (flags & ImGuiInputTextFlags_CharsUppercase) + if (c >= 'a' && c <= 'z') + *p_char = (c += (unsigned int)('A' - 'a')); + + if (flags & ImGuiInputTextFlags_CharsNoBlank) + if (ImCharIsBlankW(c)) + return false; + } + + // Custom callback filter + if (flags & ImGuiInputTextFlags_CallbackCharFilter) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; + callback_data.EventChar = (ImWchar)c; + callback_data.Flags = flags; + callback_data.UserData = user_data; + if (callback(&callback_data) != 0) + return false; + *p_char = callback_data.EventChar; + if (!callback_data.EventChar) + return false; + } + + return true; +} + +// Edit a string of text +// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". +// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match +// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. +// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. +// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h +// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are +// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) +bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT(buf != NULL && buf_size >= 0); + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + const ImGuiStyle& style = g.Style; + + const bool RENDER_SELECTION_WHEN_INACTIVE = false; + const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; + const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; + if (is_resizable) + IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) + BeginGroup(); + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size); + + ImGuiWindow* draw_window = window; + ImVec2 inner_size = frame_size; + ImGuiItemStatusFlags item_status_flags = 0; + ImGuiLastItemData item_data_backup; + if (is_multiline) + { + ImVec2 backup_pos = window->DC.CursorPos; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) + { + EndGroup(); + return false; + } + item_status_flags = g.LastItemData.StatusFlags; + item_data_backup = g.LastItemData; + window->DC.CursorPos = backup_pos; + + // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. + // FIXME-NAV: Pressing NavActivate will trigger general child activation right before triggering our own below. Harmless but bizarre. + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(3); + PopStyleColor(); + if (!child_visible) + { + EndChild(); + EndGroup(); + return false; + } + draw_window = g.CurrentWindow; // Child window + draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.CursorPos += style.FramePadding; + inner_size.x -= draw_window->ScrollbarSizes.x; + } + else + { + // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) + ItemSize(total_bb, style.FramePadding.y); + if (!(flags & ImGuiInputTextFlags_MergedItem)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) + return false; + item_status_flags = g.LastItemData.StatusFlags; + } + const bool hovered = ItemHoverable(frame_bb, id); + if (hovered) + g.MouseCursor = ImGuiMouseCursor_TextInput; + + // We are only allowed to access the state if we are already the active widget. + ImGuiInputTextState* state = GetInputTextState(id); + + const bool input_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); + + const bool user_clicked = hovered && io.MouseClicked[0]; + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + bool clear_active_id = false; + bool select_all = false; + + float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; + + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); + const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing); + const bool init_state = (init_make_active || user_scroll_active); + if ((init_state && g.ActiveId != id) || init_changed_specs) + { + // Access state even if we don't own it yet. + state = &g.InputTextState; + state->CursorAnimReset(); + + // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) + // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) + const int buf_len = (int)strlen(buf); + state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + + // Start edition + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(0); + state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + + // Preserve cursor position and undo/redo stack if we come back to same widget + // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed. + const bool recycle_state = (state->ID == id && !init_changed_specs); + if (recycle_state) + { + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + state->CursorClamp(); + } + else + { + state->ID = id; + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); + } + + if (!is_multiline) + { + if (flags & ImGuiInputTextFlags_AutoSelectAll) + select_all = true; + if (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) + select_all = true; + if (input_requested_by_tabbing || (user_clicked && io.KeyCtrl)) + select_all = true; + } + + if (flags & ImGuiInputTextFlags_AlwaysOverwrite) + state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) + } + + if (g.ActiveId != id && init_make_active) + { + IM_ASSERT(state && state->ID == id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + + // Declare our inputs + IM_ASSERT(ImGuiNavInput_COUNT < 32); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End); + if (is_multiline) + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); + } + + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) + if (g.ActiveId == id && state == NULL) + ClearActiveID(); + + // Release focus when we click outside + if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560 + clear_active_id = true; + + // Lock the decision of whether we are going to take the path displaying the cursor or selection + const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool value_changed = false; + bool enter_pressed = false; + + // When read-only we always use the live data passed to the function + // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( + if (is_readonly && state != NULL && (render_cursor || render_selection)) + { + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + state->CursorClamp(); + render_selection &= state->HasSelection(); + } + + // Select the buffer to render. + const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid; + const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + + // Password pushes a temporary font with only a fallback glyph + if (is_password && !is_displaying_hint) + { + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); + PushFont(password_font); + } + + // Process mouse inputs and character inputs + int backup_current_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + backup_current_text_length = state->CurLenA; + state->Edited = false; + state->BufCapacityA = buf_size; + state->Flags = flags; + + // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. + // Down the line we should have a cleaner library-wide concept of Selected vs Active. + g.ActiveIdAllowOverlap = !io.MouseDown[0]; + g.WantTextInputNextFrame = 1; + + // Edit in progress + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); + + const bool is_osx = io.ConfigMacOSXBehaviors; + if (select_all) + { + state->SelectAll(); + state->SelectedAllMouseLock = true; + } + else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift) + { + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + const int multiclick_count = (io.MouseClickedCount[0] - 2); + if ((multiclick_count % 2) == 0) + { + // Double-click: Select word + // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: + // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) + const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\n'; + if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + if (!STB_TEXT_HAS_SELECTION(&state->Stb)) + ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb); + state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor); + state->Stb.select_end = state->Stb.cursor; + ImStb::stb_textedit_clamp(state, &state->Stb); + } + else + { + // Triple-click: Select line + const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\n'; + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART); + state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT); + state->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT); + if (!is_eol && is_multiline) + { + ImSwap(state->Stb.select_start, state->Stb.select_end); + state->Stb.cursor = state->Stb.select_end; + } + state->CursorFollow = false; + } + state->CursorAnimReset(); + } + else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) + { + // FIXME: unselect on late click could be done release? + if (hovered) + { + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + } + } + else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) + { + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + state->CursorFollow = true; + } + if (state->SelectedAllMouseLock && !io.MouseDown[0]) + state->SelectedAllMouseLock = false; + + // It is ill-defined whether the backend needs to send a \t character when pressing the TAB keys. + // Win32 and GLFW naturally do it but not SDL. + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) + if (!io.InputQueueCharacters.contains('\t')) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + + // Process regular text input (before we check for Return because using some IME will effectively send a Return?) + // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + if (io.InputQueueCharacters.Size > 0) + { + if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) + { + // Insert character if they pass filtering + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (c == '\t' && io.KeyShift) + continue; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + + // Consume characters + io.InputQueueCharacters.resize(0); + } + } + + // Process other shortcuts/key-presses + bool cancel_edit = false; + if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) + { + IM_ASSERT(state != NULL); + IM_ASSERT(io.KeyMods == GetMergedKeyModFlags() && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); // We rarely do this check, but if anything let's do it here. + + const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); + state->Stb.row_count_per_page = row_count_per_page; + + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_osx = io.ConfigMacOSXBehaviors; + const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyModFlags_Super | ImGuiKeyModFlags_Shift)); + const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl); + const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); + const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); + + const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; + const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); + const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; + + // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. + const bool is_validate_enter = IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter); + const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed) && !IsKeyPressedMap(ImGuiKey_Space)) || IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); + const bool is_cancel = IsKeyPressedMap(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); + + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } + else if (IsKeyPressedMap(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) + { + if (!state->HasSelection()) + { + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT); + else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); + } + else if (is_validate_enter) + { + bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; + if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + { + enter_pressed = clear_active_id = true; + } + else if (!is_readonly) + { + unsigned int c = '\n'; // Insert new line + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + } + else if (is_validate_nav) + { + IM_ASSERT(!is_validate_enter); + enter_pressed = clear_active_id = true; + } + else if (is_cancel) + { + clear_active_id = cancel_edit = true; + } + else if (is_undo || is_redo) + { + state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); + state->ClearSelection(); + } + else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + { + state->SelectAll(); + state->CursorFollow = true; + } + else if (is_cut || is_copy) + { + // Cut, Copy + if (io.SetClipboardTextFn) + { + const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; + char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); + ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); + SetClipboardText(clipboard_data); + MemFree(clipboard_data); + } + if (is_cut) + { + if (!state->HasSelection()) + state->SelectAll(); + state->CursorFollow = true; + stb_textedit_cut(state, &state->Stb); + } + } + else if (is_paste) + { + if (const char* clipboard = GetClipboardText()) + { + // Filter pasted buffer + const int clipboard_len = (int)strlen(clipboard); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; + for (const char* s = clipboard; *s; ) + { + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; + } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + { + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + state->CursorFollow = true; + } + MemFree(clipboard_filtered); + } + } + + // Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame. + render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + } + + // Process callbacks and apply result back to user's buffer. + const char* apply_new_text = NULL; + int apply_new_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + if (cancel_edit) + { + // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. + if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0) + { + // Push records into the undo stack so we can CTRL+Z the revert operation itself + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; + ImVector w_text; + if (apply_new_text_length > 0) + { + w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); + ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); + } + stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); + } + } + + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). + bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + if (apply_edit_back_to_user_buffer) + { + // Apply new value immediately - copy modified buffer back + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + + // User callback + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) + { + IM_ASSERT(callback != NULL); + + // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. + ImGuiInputTextFlags event_flag = 0; + ImGuiKey event_key = ImGuiKey_COUNT; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + { + event_flag = ImGuiInputTextFlags_CallbackCompletion; + event_key = ImGuiKey_Tab; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_UpArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_DownArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited) + { + event_flag = ImGuiInputTextFlags_CallbackEdit; + } + else if (flags & ImGuiInputTextFlags_CallbackAlways) + { + event_flag = ImGuiInputTextFlags_CallbackAlways; + } + + if (event_flag) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = event_flag; + callback_data.Flags = flags; + callback_data.UserData = callback_user_data; + + char* callback_buf = is_readonly ? buf : state->TextA.Data; + callback_data.EventKey = event_key; + callback_data.Buf = callback_buf; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; + callback_data.BufDirty = false; + + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) + ImWchar* text = state->TextW.Data; + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); + + // Call user code + callback(&callback_data); + + // Read back what user may have modified + callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback + IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields + IM_ASSERT(callback_data.BufSize == state->BufCapacityA); + IM_ASSERT(callback_data.Flags == flags); + const bool buf_dirty = callback_data.BufDirty; + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (buf_dirty) + { + IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + state->CursorAnimReset(); + } + } + } + + // Will copy result string if modified + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + { + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; + } + } + + // Clear temporary user storage + state->Flags = ImGuiInputTextFlags_None; + } + + // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) + if (apply_new_text != NULL) + { + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; + } + + // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) + if (clear_active_id && g.ActiveId == id) + ClearActiveID(); + + // Render frame + if (!is_multiline) + { + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + } + + const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size + ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; + ImVec2 text_size(0.0f, 0.0f); + + // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line + // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. + // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. + const int buf_display_max_length = 2 * 1024 * 1024; + const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 + const char* buf_display_end = NULL; // We have specialized paths below for setting the length + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + + // Render text. We currently only render selection when the widget is active or while scrolling. + // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive. + if (render_cursor || render_selection) + { + IM_ASSERT(state != NULL); + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + + // Render text (with cursor and selection) + // This is going to be messy. We need to: + // - Display the text (this alone can be more easily clipped) + // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) + // - Measure text height (for scrollbar) + // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. + const ImWchar* text_begin = state->TextW.Data; + ImVec2 cursor_offset, select_start_offset; + + { + // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions. + const ImWchar* searches_input_ptr[2] = { NULL, NULL }; + int searches_result_line_no[2] = { -1000, -1000 }; + int searches_remaining = 0; + if (render_cursor) + { + searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_result_line_no[0] = -1; + searches_remaining++; + } + if (render_selection) + { + searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_result_line_no[1] = -1; + searches_remaining++; + } + + // Iterate all lines to find our line numbers + // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit + for (const ImWchar* s = text_begin; *s != 0; s++) + if (*s == '\n') + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } + line_count++; + if (searches_result_line_no[0] == -1) + searches_result_line_no[0] = line_count; + if (searches_result_line_no[1] == -1) + searches_result_line_no[1] = line_count; + + // Calculate 2d position by finding the beginning of the line and measuring distance + cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.y = searches_result_line_no[0] * g.FontSize; + if (searches_result_line_no[1] >= 0) + { + select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; + } + + // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) + if (is_multiline) + text_size = ImVec2(inner_size.x, line_count * g.FontSize); + } + + // Scroll + if (render_cursor && state->CursorFollow) + { + // Horizontal scroll in chunks of quarter width + if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) + { + const float scroll_increment_x = inner_size.x * 0.25f; + const float visible_width = inner_size.x - style.FramePadding.x; + if (cursor_offset.x < state->ScrollX) + state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x); + } + else + { + state->ScrollX = 0.0f; + } + + // Vertical scroll + if (is_multiline) + { + // Test if cursor is vertically visible + if (cursor_offset.y - g.FontSize < scroll_y) + scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); + else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y) + scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; + const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); + scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y); + draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag + draw_window->Scroll.y = scroll_y; + } + + state->CursorFollow = false; + } + + // Draw selection + const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); + if (render_selection) + { + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); + + ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. + float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. + float bg_offy_dn = is_multiline ? 0.0f : 2.0f; + ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; + for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) + { + if (rect_pos.y > clip_rect.w + g.FontSize) + break; + if (rect_pos.y < clip_rect.y) + { + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit + //p = p ? p + 1 : text_selected_end; + while (p < text_selected_end) + if (*p++ == '\n') + break; + } + else + { + ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); + rect.ClipWith(clip_rect); + if (rect.Overlaps(clip_rect)) + draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); + } + rect_pos.x = draw_pos.x - draw_scroll.x; + rect_pos.y += g.FontSize; + } + } + + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + + // Draw blinking cursor + if (render_cursor) + { + state->CursorAnim += io.DeltaTime; + bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; + ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_scroll); + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); + + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) + if (!is_readonly) + g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + } + } + else + { + // Render text only (no selection, no cursor) + if (is_multiline) + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + else if (!is_displaying_hint && g.ActiveId == id) + buf_display_end = buf_display + state->CurLenA; + else if (!is_displaying_hint) + buf_display_end = buf_display + strlen(buf_display); + + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + } + + if (is_password && !is_displaying_hint) + PopFont(); + + if (is_multiline) + { + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + EndChild(); + item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); + g.CurrentItemFlags = backup_item_flags; + + // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... + // FIXME: This quite messy/tricky, should attempt to get rid of the child window. + EndGroup(); + if (g.LastItemData.ID == 0) + { + g.LastItemData.ID = id; + g.LastItemData.InFlags = item_data_backup.InFlags; + g.LastItemData.StatusFlags = item_data_backup.StatusFlags; + } + } + + // Log as text + if (g.LogEnabled && (!is_password || is_displaying_hint)) + { + LogSetNextTextDecoration("{", "}"); + LogRenderedText(&draw_pos, buf_display, buf_display_end); + } + + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) + MarkItemEdited(id); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) + return enter_pressed; + else + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +//------------------------------------------------------------------------- +// - ColorEdit3() +// - ColorEdit4() +// - ColorPicker3() +// - RenderColorRectWithAlphaCheckerboard() [Internal] +// - ColorPicker4() +// - ColorButton() +// - SetColorEditOptions() +// - ColorTooltip() [Internal] +// - ColorEditOptionsPopup() [Internal] +// - ColorPickerOptionsPopup() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); +} + +// ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. +// Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. +static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) +{ + // This check is optional. Suppose we have two color widgets side by side, both widgets display different colors, but both colors have hue and/or saturation undefined. + // With color check: hue/saturation is preserved in one widget. Editing color in one widget would reset hue/saturation in another one. + // Without color check: common hue/saturation would be displayed in all widgets that have hue/saturation undefined. + // g.ColorEditLastColor is stored as ImU32 RGB value: this essentially gives us color equality check with reduced precision. + // Tiny external color changes would not be detected and this check would still pass. This is OK, since we only restore hue/saturation _only_ if they are undefined, + // therefore this change flipping hue/saturation from undefined to a very tiny value would still be represented in color picker. + ImGuiContext& g = *GImGui; + if (g.ColorEditLastColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + return; + + // When S == 0, H is undefined. + // When H == 1 it wraps around to 0. + if (*S == 0.0f || (*H == 0.0f && g.ColorEditLastHue == 1)) + *H = g.ColorEditLastHue; + + // When V == 0, S is undefined. + if (*V == 0.0f) + *S = g.ColorEditLastSat; +} + +// Edit colors components (each component in 0.0f..1.0f range). +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float square_sz = GetFrameHeight(); + const float w_full = CalcItemWidth(); + const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); + const float w_inputs = w_full - w_button; + const char* label_display_end = FindRenderedTextEnd(label); + g.NextItemData.ClearFlags(); + + BeginGroup(); + PushID(label); + + // If we're not showing any slider there's no point in doing any HSV conversions + const ImGuiColorEditFlags flags_untouched = flags; + if (flags & ImGuiColorEditFlags_NoInputs) + flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + + // Context menu: display and modify options (before defaults are applied) + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorEditOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags_DisplayMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_); + if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_); + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_); + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected + + const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; + const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; + const int components = alpha ? 4 : 3; + + // Convert to the formats we need + float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; + if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB)) + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) + { + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); + } + int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; + + bool value_changed = false; + bool value_changed_as_float = false; + + const ImVec2 pos = window->DC.CursorPos; + const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f; + window->DC.CursorPos.x = pos.x + inputs_offset_x; + + if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB/HSV 0..255 Sliders + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + + const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); + static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; + static const char* fmt_table_int[3][4] = + { + { "%3d", "%3d", "%3d", "%3d" }, // Short display + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA + }; + static const char* fmt_table_float[3][4] = + { + { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display + { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA + { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA + }; + const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; + + for (int n = 0; n < components; n++) + { + if (n > 0) + SameLine(0, style.ItemInnerSpacing.x); + SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last); + + // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0. + if (flags & ImGuiColorEditFlags_Float) + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } + else + { + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + } + else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB Hexadecimal Input + char buf[64]; + if (alpha) + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); + else + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); + SetNextItemWidth(w_inputs); + if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) + { + value_changed = true; + char* p = buf; + while (*p == '#' || ImCharIsBlankA(*p)) + p++; + i[0] = i[1] = i[2] = 0; + i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. inputting #FFFFFF omitting alpha) + int r; + if (alpha) + r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + else + r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + + ImGuiWindow* picker_active_window = NULL; + if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) + { + const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); + + const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); + if (ColorButton("##ColorButton", col_v4, flags)) + { + if (!(flags & ImGuiColorEditFlags_NoPicker)) + { + // Store current color and open a picker + g.ColorPickerRef = col_v4; + OpenPopup("picker"); + SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(-1, style.ItemSpacing.y)); + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + if (BeginPopup("picker")) + { + picker_active_window = g.CurrentWindow; + if (label != label_display_end) + { + TextEx(label, label_display_end); + Spacing(); + } + ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + EndPopup(); + } + } + + if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) + { + const float text_offset_x = (flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + text_offset_x, pos.y + style.FramePadding.y); + TextEx(label, label_display_end); + } + + // Convert back + if (value_changed && picker_active_window == NULL) + { + if (!value_changed_as_float) + for (int n = 0; n < 4; n++) + f[n] = i[n] / 255.0f; + if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) + { + g.ColorEditLastHue = f[0]; + g.ColorEditLastSat = f[1]; + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); + } + if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + + col[0] = f[0]; + col[1] = f[1]; + col[2] = f[2]; + if (alpha) + col[3] = f[3]; + } + + PopID(); + EndGroup(); + + // Drag and Drop Target + // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + { + bool accepted_drag_drop = false; + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 + value_changed = accepted_drag_drop = true; + } + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * components); + value_changed = accepted_drag_drop = true; + } + + // Drag-drop payloads are always RGB + if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]); + EndDragDropTarget(); + } + + // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). + if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) + g.LastItemData.ID = g.ActiveId; + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + float col4[4] = { col[0], col[1], col[2], 1.0f }; + if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) + return false; + col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; + return true; +} + +// Helper for ColorPicker4() +static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) +{ + ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8)); +} + +// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.) +// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) +// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0) +bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImDrawList* draw_list = window->DrawList; + ImGuiStyle& style = g.Style; + ImGuiIO& io = g.IO; + + const float width = CalcItemWidth(); + g.NextItemData.ClearFlags(); + + PushID(label); + BeginGroup(); + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + flags |= ImGuiColorEditFlags_NoSmallPreview; + + // Context menu: display and store options. + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorPickerOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_NoOptions)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + + // Setup + int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; + bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha); + ImVec2 picker_pos = window->DC.CursorPos; + float square_sz = GetFrameHeight(); + float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars + float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; + float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; + float bars_triangles_half_sz = IM_FLOOR(bars_width * 0.20f); + + float backup_initial_col[4]; + memcpy(backup_initial_col, col, components * sizeof(float)); + + float wheel_thickness = sv_picker_size * 0.08f; + float wheel_r_outer = sv_picker_size * 0.50f; + float wheel_r_inner = wheel_r_outer - wheel_thickness; + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); + + // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. + ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. + ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. + + float H = col[0], S = col[1], V = col[2]; + float R = col[0], G = col[1], B = col[2]; + if (flags & ImGuiColorEditFlags_InputRGB) + { + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(R, G, B, H, S, V); + ColorEditRestoreHS(col, &H, &S, &V); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + + bool value_changed = false, value_changed_h = false, value_changed_sv = false; + + PushItemFlag(ImGuiItemFlags_NoNav, true); + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Hue wheel + SV triangle logic + InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); + if (IsItemActive()) + { + ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; + ImVec2 current_off = g.IO.MousePos - wheel_center; + float initial_dist2 = ImLengthSqr(initial_off); + if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1)) + { + // Interactive with Hue wheel + H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f; + if (H < 0.0f) + H += 1.0f; + value_changed = value_changed_h = true; + } + float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); + if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) + { + // Interacting with SV triangle + ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); + if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) + current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); + float uu, vv, ww; + ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); + V = ImClamp(1.0f - vv, 0.0001f, 1.0f); + S = ImClamp(uu / V, 0.0001f, 1.0f); + value_changed = value_changed_sv = true; + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // SV rectangle logic + InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); + if (IsItemActive()) + { + S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); + V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + + // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. + if (g.ColorEditLastColor == ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + H = g.ColorEditLastHue; + value_changed = value_changed_sv = true; + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + // Hue bar logic + SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); + InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + value_changed = value_changed_h = true; + } + } + + // Alpha bar logic + if (alpha_bar) + { + SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); + InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + value_changed = true; + } + } + PopItemFlag(); // ImGuiItemFlags_NoNav + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + SameLine(0, style.ItemInnerSpacing.x); + BeginGroup(); + } + + if (!(flags & ImGuiColorEditFlags_NoLabel)) + { + const char* label_display_end = FindRenderedTextEnd(label); + if (label != label_display_end) + { + if ((flags & ImGuiColorEditFlags_NoSidePreview)) + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + } + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if ((flags & ImGuiColorEditFlags_NoLabel)) + Text("Current"); + + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); + if (ref_col != NULL) + { + Text("Original"); + ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); + if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2))) + { + memcpy(col, ref_col, components * sizeof(float)); + value_changed = true; + } + } + PopItemFlag(); + EndGroup(); + } + + // Convert back color to RGB + if (value_changed_h || value_changed_sv) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]); + g.ColorEditLastHue = H; + g.ColorEditLastSat = S; + g.ColorEditLastColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + col[0] = H; + col[1] = S; + col[2] = V; + } + } + + // R,G,B and H,S,V slider color editor + bool value_changed_fix_hue_wrap = false; + if ((flags & ImGuiColorEditFlags_NoInputs) == 0) + { + PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; + if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) + { + // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. + // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) + value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); + value_changed = true; + } + if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV); + if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex); + PopItemWidth(); + } + + // Try to cancel hue wrap (after ColorEdit4 call), if any + if (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB)) + { + float new_H, new_S, new_V; + ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); + if (new_H <= 0 && H > 0) + { + if (new_V <= 0 && V != new_V) + ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); + else if (new_S <= 0) + ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); + } + } + + if (value_changed) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + R = col[0]; + G = col[1]; + B = col[2]; + ColorConvertRGBtoHSV(R, G, B, H, S, V); + ColorEditRestoreHS(col, &H, &S, &V); // Fix local Hue as display below will use it immediately. + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + H = col[0]; + S = col[1]; + V = col[2]; + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + } + + const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha); + const ImU32 col_black = IM_COL32(0,0,0,style_alpha8); + const ImU32 col_white = IM_COL32(255,255,255,style_alpha8); + const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8); + const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) }; + + ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); + ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); + ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!! + + ImVec2 sv_cursor_pos; + + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Render Hue Wheel + const float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). + const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); + for (int n = 0; n < 6; n++) + { + const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; + const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; + const int vert_start_idx = draw_list->VtxBuffer.Size; + draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); + draw_list->PathStroke(col_white, 0, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; + + // Paint colors over existing vertices + ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); + ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]); + } + + // Render Cursor + preview on Hue Wheel + float cos_hue_angle = ImCos(H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(H * 2.0f * IM_PI); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); + float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; + int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); + draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); + + // Render SV triangle (rotated according to hue) + ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); + ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); + ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); + ImVec2 uv_white = GetFontTexUvWhitePixel(); + draw_list->PrimReserve(6, 6); + draw_list->PrimVtx(tra, uv_white, hue_color32); + draw_list->PrimVtx(trb, uv_white, hue_color32); + draw_list->PrimVtx(trc, uv_white, col_white); + draw_list->PrimVtx(tra, uv_white, 0); + draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trc, uv_white, 0); + draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); + sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // Render SV Square + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black); + RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); + sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + + // Render Hue Bar + for (int i = 0; i < 6; ++i) + draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]); + float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size); + RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) + float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12); + + // Render alpha bar + if (alpha_bar) + { + float alpha = ImSaturate(col[3]); + ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); + float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); + RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + EndGroup(); + + if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) + value_changed = false; + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + PopID(); + + return value_changed; +} + +// A little color square. Return true when clicked. +// FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. +// 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. +// Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(desc_id); + float default_size = GetFrameHeight(); + if (size.x == 0.0f) + size.x = default_size; + if (size.y == 0.0f) + size.y = default_size; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + if (flags & ImGuiColorEditFlags_NoAlpha) + flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImVec4 col_rgb = col; + if (flags & ImGuiColorEditFlags_InputHSV) + ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z); + + ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); + float grid_step = ImMin(size.x, size.y) / 2.99f; + float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); + ImRect bb_inner = bb; + float off = 0.0f; + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + bb_inner.Expand(off); + } + if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) + { + float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); + } + else + { + // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; + if (col_source.w < 1.0f) + RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + else + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); + } + RenderNavHighlight(bb, id); + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + if (g.Style.FrameBorderSize > 0.0f) + RenderFrameBorder(bb.Min, bb.Max, rounding); + else + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + } + + // Drag and Drop Source + // NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. + if (g.ActiveId == id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource()) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once); + else + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once); + ColorButton(desc_id, col, flags); + SameLine(); + TextEx("Color"); + EndDragDropSource(); + } + + // Tooltip + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + + return pressed; +} + +// Initialize/override default color options +void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; + if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; + if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; + if ((flags & ImGuiColorEditFlags_InputMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + g.ColorEditOptions = flags; +} + +// Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); + const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; + if (text_end > text) + { + TextEx(text, text_end); + Separator(); + } + + ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); + ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + SameLine(); + if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); + else + Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("H: %.3f, S: %.3f, V: %.3f", col[0], col[1], col[2]); + else + Text("H: %.3f, S: %.3f, V: %.3f, A: %.3f", col[0], col[1], col[2], col[3]); + } + EndTooltip(); +} + +void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) +{ + bool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_); + bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); + if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + ImGuiColorEditFlags opts = g.ColorEditOptions; + if (allow_opt_inputs) + { + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex; + } + if (allow_opt_datatype) + { + if (allow_opt_inputs) Separator(); + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float; + } + + if (allow_opt_inputs || allow_opt_datatype) + Separator(); + if (Button("Copy as..", ImVec2(-1, 0))) + OpenPopup("Copy"); + if (BeginPopup("Copy")) + { + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, cb); + if (Selectable(buf)) + SetClipboardText(buf); + if (!(flags & ImGuiColorEditFlags_NoAlpha)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + } + EndPopup(); + } + + g.ColorEditOptions = opts; + EndPopup(); +} + +void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) +{ + bool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_); + bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); + if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + if (allow_opt_picker) + { + ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function + PushItemWidth(picker_size.x); + for (int picker_type = 0; picker_type < 2; picker_type++) + { + // Draw small/thumbnail version of each picker type (over an invisible button for selection) + if (picker_type > 0) Separator(); + PushID(picker_type); + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha); + if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; + ImVec2 backup_pos = GetCursorScreenPos(); + if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + SetCursorScreenPos(backup_pos); + ImVec4 previewing_ref_col; + memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + ColorPicker4("##previewing_picker", &previewing_ref_col.x, picker_flags); + PopID(); + } + PopItemWidth(); + } + if (allow_opt_alpha_bar) + { + if (allow_opt_picker) Separator(); + CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + } + EndPopup(); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +//------------------------------------------------------------------------- +// - TreeNode() +// - TreeNodeV() +// - TreeNodeEx() +// - TreeNodeExV() +// - TreeNodeBehavior() [Internal] +// - TreePush() +// - TreePop() +// - GetTreeNodeToLabelSpacing() +// - SetNextItemOpen() +// - CollapsingHeader() +//------------------------------------------------------------------------- + +bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + return TreeNodeBehavior(window->GetID(label), 0, label, NULL); +} + +bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +{ + return TreeNodeExV(str_id, 0, fmt, args); +} + +bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) +{ + return TreeNodeExV(ptr_id, 0, fmt, args); +} + +bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags, label, NULL); +} + +bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +{ + if (flags & ImGuiTreeNodeFlags_Leaf) + return true; + + // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStorage* storage = window->DC.StateStorage; + + bool is_open; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) + { + if (g.NextItemData.OpenCond & ImGuiCond_Always) + { + is_open = g.NextItemData.OpenVal; + storage->SetInt(id, is_open); + } + else + { + // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. + const int stored_value = storage->GetInt(id, -1); + if (stored_value == -1) + { + is_open = g.NextItemData.OpenVal; + storage->SetInt(id, is_open); + } + else + { + is_open = stored_value != 0; + } + } + } + else + { + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + } + + // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). + // NB- If we are above max depth we still allow manually opened nodes to be logged. + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) + is_open = true; + + return is_open; +} + +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; + const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); + + if (!label_end) + label_end = FindRenderedTextEnd(label); + const ImVec2 label_size = CalcTextSize(label, label_end, false); + + // We vertically grow up to current line height up the typical widget height. + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); + ImRect frame_bb; + frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; + frame_bb.Min.y = window->DC.CursorPos.y; + frame_bb.Max.x = window->WorkRect.Max.x; + frame_bb.Max.y = window->DC.CursorPos.y + frame_height; + if (display_frame) + { + // Framed header expand a little outside the default padding, to the edge of InnerClipRect + // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f) + frame_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f); + } + + const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapser arrow width + Spacing + const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapser + ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); + ItemSize(ImVec2(text_width, frame_height), padding.y); + + // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing + ImRect interact_bb = frame_bb; + if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) + interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; + + // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. + // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). + // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. + const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + bool is_open = TreeNodeBehaviorIsOpen(id, flags); + if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); + + bool item_add = ItemAdd(interact_bb, id); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + g.LastItemData.DisplayRect = frame_bb; + + if (!item_add) + { + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; + } + + ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + button_flags |= ImGuiButtonFlags_AllowItemOverlap; + if (!is_leaf) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // allow browsing a tree while preserving selection with code implementing multi-selection patterns. + // When clicking on the rest of the tree node we always disallow keyboard modifiers. + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; + const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); + if (window != g.HoveredWindow || !is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_NoKeyModifiers; + + // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. + // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. + // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1) + // - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1) + // - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0) + // It is rather standard that arrow click react on Down rather than Up. + // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work. + if (is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_PressedOnClick; + else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + else + button_flags |= ImGuiButtonFlags_PressedOnClickRelease; + + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; + const bool was_selected = selected; + + bool hovered, held; + bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); + bool toggled = false; + if (!is_leaf) + { + if (pressed && g.DragDropHoldJustPressedId != id) + { + if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) + toggled = true; + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) + toggled = true; + } + else if (pressed && g.DragDropHoldJustPressedId == id) + { + IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); + if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. + toggled = true; + } + + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) + { + toggled = true; + NavMoveRequestCancel(); + } + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + { + toggled = true; + NavMoveRequestCancel(); + } + + if (toggled) + { + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; + } + } + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin; + if (display_frame) + { + // Framed type + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); + else // Leaf without bullet, left-adjusted text + text_pos.x -= text_offset_x; + if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) + frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + + if (g.LogEnabled) + LogSetNextTextDecoration("###", "###"); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + } + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogSetNextTextDecoration(">", NULL); + RenderText(text_pos, label, label_end, false); + } + + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; +} + +void ImGui::TreePush(const char* str_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(str_id); +} + +void ImGui::TreePush(const void* ptr_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(ptr_id); +} + +void ImGui::TreePushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Indent(); + window->DC.TreeDepth++; + PushOverrideID(id); +} + +void ImGui::TreePop() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Unindent(); + + window->DC.TreeDepth--; + ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); + + // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) + if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) + { + SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); + NavMoveRequestCancel(); + } + window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; + + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. + PopID(); +} + +// Horizontal distance preceding label when using TreeNode() or Bullet() +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); +} + +// Set next TreeNode/CollapsingHeader open state. +void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.OpenVal = is_open; + g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always; +} + +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). +// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). +bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); +} + +// p_visible == NULL : regular collapsing header +// p_visible != NULL && *p_visible == true : show a small close button on the corner of the header, clicking the button will set *p_visible = false +// p_visible != NULL && *p_visible == false : do not show the header at all +// Do not mistake this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or ImGuiTreeNodeFlags_DefaultOpen. +bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (p_visible && !*p_visible) + return false; + + ImGuiID id = window->GetID(label); + flags |= ImGuiTreeNodeFlags_CollapsingHeader; + if (p_visible) + flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool is_open = TreeNodeBehavior(id, flags, label); + if (p_visible != NULL) + { + // Create a small overlapping close button + // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. + // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. + ImGuiContext& g = *GImGui; + ImGuiLastItemData last_item_backup = g.LastItemData; + float button_size = g.FontSize; + float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); + float button_y = g.LastItemData.Rect.Min.y; + ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); + if (CloseButton(close_button_id, ImVec2(button_x, button_y))) + *p_visible = false; + g.LastItemData = last_item_backup; + } + + return is_open; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Selectable +//------------------------------------------------------------------------- +// - Selectable() +//------------------------------------------------------------------------- + +// Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. +// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags. +// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. +bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. + ImGuiID id = window->GetID(label); + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(size, 0.0f); + + // Fill horizontal space + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; + const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; + const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) + size.x = ImMax(label_size.x, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); + if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) + { + const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += (spacing_x - spacing_L); + bb.Max.y += (spacing_y - spacing_U); + } + //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) + { + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; + } + + const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; + const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None); + if (span_all_columns) + { + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; + } + + if (!item_add) + return false; + + const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (disabled_item && !disabled_global) // Only testing this as an optimization + BeginDisabled(); + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + + // Auto-select when moved into + // - This will be more fully fleshed in the range-select branch + // - This is not exposed as it won't nicely work with some user side handling of shift/control + // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons + // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) + // - (2) usage will fail with clipped items + // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == window->DC.NavFocusScopeIdCurrent) + if (g.NavJustMovedToId == id) + selected = pressed = true; + + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) + { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + { + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, WindowRectAbsToRel(window, bb)); // (bb == NavRect) + g.NavDisableHighlight = true; + } + } + if (pressed) + MarkItemEdited(id); + + if (flags & ImGuiSelectableFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + // In this branch, Selectable() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) + hovered = true; + if (hovered || selected) + { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + + if (span_all_columns && window->DC.CurrentColumns) + PopColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); + + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + if (disabled_item && !disabled_global) + EndDisabled(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; //-V1020 +} + +bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + if (Selectable(label, *p_selected, flags, size_arg)) + { + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ListBox +//------------------------------------------------------------------------- +// - BeginListBox() +// - EndListBox() +// - ListBox() +//------------------------------------------------------------------------- + +// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). +bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Size default to hold ~7.25 items. + // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); + ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + g.NextItemData.ClearFlags(); + + if (!IsRectVisible(bb.Min, bb.Max)) + { + ItemSize(bb.GetSize(), style.FramePadding.y); + ItemAdd(bb, 0, &frame_bb); + return false; + } + + // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. + BeginGroup(); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } + + BeginChildFrame(id, frame_bb.GetSize()); + return true; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// OBSOLETED in 1.81 (from February 2021) +bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +{ + // If height_in_items == -1, default height is maximum 7. + ImGuiContext& g = *GImGui; + float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f; + ImVec2 size; + size.x = 0.0f; + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; + return BeginListBox(label, size); +} +#endif + +void ImGui::EndListBox() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); + IM_UNUSED(window); + + EndChildFrame(); + EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label +} + +bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) +{ + const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); + return value_changed; +} + +// This is merely a helper around BeginListBox(), EndListBox(). +// Considering using those directly to submit custom data or store selection differently. +bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Calculate size from "height_in_items" + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + float height_in_items_f = height_in_items + 0.25f; + ImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f)); + + if (!BeginListBox(label, size)) + return false; + + // Assume all items have even height (= 1 line of text). If you need items of different height, + // you can create a custom version of ListBox() in your code without using the clipper. + bool value_changed = false; + ImGuiListClipper clipper; + clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + + PushID(i); + const bool item_selected = (i == *current_item); + if (Selectable(item_text, item_selected)) + { + *current_item = i; + value_changed = true; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + EndListBox(); + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: PlotLines, PlotHistogram +//------------------------------------------------------------------------- +// - PlotEx() [Internal] +// - PlotLines() +// - PlotHistogram() +//------------------------------------------------------------------------- +// Plot/Graph widgets are not very good. +// Consider writing your own, or using a third-party one, see: +// - ImPlot https://github.com/epezent/implot +// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions +//------------------------------------------------------------------------- + +int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return -1; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + if (frame_size.x == 0.0f) + frame_size.x = CalcItemWidth(); + if (frame_size.y == 0.0f) + frame_size.y = label_size.y + (style.FramePadding.y * 2); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0, &frame_bb)) + return -1; + const bool hovered = ItemHoverable(frame_bb, id); + + // Determine scale from values if not specified + if (scale_min == FLT_MAX || scale_max == FLT_MAX) + { + float v_min = FLT_MAX; + float v_max = -FLT_MAX; + for (int i = 0; i < values_count; i++) + { + const float v = values_getter(data, i); + if (v != v) // Ignore NaN values + continue; + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); + } + if (scale_min == FLT_MAX) + scale_min = v_min; + if (scale_max == FLT_MAX) + scale_max = v_max; + } + + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + + const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1; + int idx_hovered = -1; + if (values_count >= values_count_min) + { + int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + + // Tooltip on hover + if (hovered && inner_bb.Contains(g.IO.MousePos)) + { + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const int v_idx = (int)(t * item_count); + IM_ASSERT(v_idx >= 0 && v_idx < values_count); + + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); + const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); + if (plot_type == ImGuiPlotType_Lines) + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1); + else if (plot_type == ImGuiPlotType_Histogram) + SetTooltip("%d: %8.4g", v_idx, v0); + idx_hovered = v_idx; + } + + const float t_step = 1.0f / (float)res_w; + const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); + + float v0 = values_getter(data, (0 + values_offset) % values_count); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + + const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + + t0 = t1; + tp0 = tp1; + } + } + + // Text overlay + if (overlay_text) + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + // Return hovered index or -1 if none are hovered. + // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + return idx_hovered; +} + +struct ImGuiPlotArrayGetterData +{ + const float* Values; + int Stride; + + ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } +}; + +static float Plot_ArrayGetter(void* data, int idx) +{ + ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; + const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); + return v; +} + +void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Value helpers +// Those is not very useful, legacy API. +//------------------------------------------------------------------------- +// - Value() +//------------------------------------------------------------------------- + +void ImGui::Value(const char* prefix, bool b) +{ + Text("%s: %s", prefix, (b ? "true" : "false")); +} + +void ImGui::Value(const char* prefix, int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, unsigned int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, float v, const char* float_format) +{ + if (float_format) + { + char fmt[64]; + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); + Text(fmt, prefix, v); + } + else + { + Text("%s: %.3f", prefix, v); + } +} + +//------------------------------------------------------------------------- +// [SECTION] MenuItem, BeginMenu, EndMenu, etc. +//------------------------------------------------------------------------- +// - ImGuiMenuColumns [Internal] +// - BeginMenuBar() +// - EndMenuBar() +// - BeginMainMenuBar() +// - EndMainMenuBar() +// - BeginMenu() +// - EndMenu() +// - MenuItemEx() [Internal] +// - MenuItem() +//------------------------------------------------------------------------- + +// Helpers for internal use +void ImGuiMenuColumns::Update(float spacing, bool window_reappearing) +{ + if (window_reappearing) + memset(Widths, 0, sizeof(Widths)); + Spacing = (ImU16)spacing; + CalcNextTotalWidth(true); + memset(Widths, 0, sizeof(Widths)); + TotalWidth = NextTotalWidth; + NextTotalWidth = 0; +} + +void ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets) +{ + ImU16 offset = 0; + bool want_spacing = false; + for (int i = 0; i < IM_ARRAYSIZE(Widths); i++) + { + ImU16 width = Widths[i]; + if (want_spacing && width > 0) + offset += Spacing; + want_spacing |= (width > 0); + if (update_offsets) + { + if (i == 1) { OffsetLabel = offset; } + if (i == 2) { OffsetShortcut = offset; } + if (i == 3) { OffsetMark = offset; } + } + offset += width; + } + NextTotalWidth = offset; +} + +float ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark) +{ + Widths[0] = ImMax(Widths[0], (ImU16)w_icon); + Widths[1] = ImMax(Widths[1], (ImU16)w_label); + Widths[2] = ImMax(Widths[2], (ImU16)w_shortcut); + Widths[3] = ImMax(Widths[3], (ImU16)w_mark); + CalcNextTotalWidth(false); + return (float)ImMax(TotalWidth, NextTotalWidth); +} + +// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. +// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. +// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary. +// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars. +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; + + IM_ASSERT(!window->DC.MenuBarAppending); + BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore + PushID("##menubar"); + + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + ImRect bar_rect = window->MenuBarRect(); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y)); + clip_rect.ClipWith(window->OuterRectClipped); + PushClipRect(clip_rect.Min, clip_rect.Max, false); + + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). + window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.MenuBarAppending = true; + AlignTextToFramePadding(); + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + { + // Try to find out if the request is for one of our child menu + ImGuiWindow* nav_earliest_child = g.NavWindow; + while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) + nav_earliest_child = nav_earliest_child->ParentWindow; + if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + { + // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. + // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering) + const ImGuiNavLayer layer = ImGuiNavLayer_Menu; + IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check + FocusWindow(window); + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavDisableMouseHover = g.NavMousePosDirty = true; + NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat + } + } + + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + PopClipRect(); + PopID(); + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + g.GroupStack.back().EmitItem = false; + EndGroup(); // Restore position on layer 0 + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.MenuBarAppending = false; +} + +// Important: calling order matters! +// FIXME: Somehow overlapping with docking tech. +// FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts) +bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags) +{ + IM_ASSERT(dir != ImGuiDir_None); + + ImGuiWindow* bar_window = FindWindowByName(name); + if (bar_window == NULL || bar_window->BeginCount == 0) + { + // Calculate and set window size/position + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); + ImRect avail_rect = viewport->GetBuildWorkRect(); + ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + ImVec2 pos = avail_rect.Min; + if (dir == ImGuiDir_Right || dir == ImGuiDir_Down) + pos[axis] = avail_rect.Max[axis] - axis_size; + ImVec2 size = avail_rect.GetSize(); + size[axis] = axis_size; + SetNextWindowPos(pos); + SetNextWindowSize(size); + + // Report our size into work area (for next frame) using actual window size + if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) + viewport->BuildWorkOffsetMin[axis] += axis_size; + else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) + viewport->BuildWorkOffsetMax[axis] -= axis_size; + } + + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint + bool is_open = Begin(name, NULL, window_flags); + PopStyleVar(2); + + return is_open; +} + +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. + // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea? + // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings. + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + float height = GetFrameHeight(); + bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + + if (is_open) + BeginMenuBar(); + else + End(); + return is_open; +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + // FIXME: With this strategy we won't be able to restore a NULL focus. + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL); + + End(); +} + +static bool IsRootOfOpenMenuSet() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu)) + return false; + + // Initially we used 'OpenParentId' to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) based on parent ID. + // This would however prevent the use of e.g. PuhsID() user code submitting menus. + // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, + // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. + // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup + // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first chilld menu. + const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; + return (/*upper_popup->OpenParentId == window->IDStack.back() &&*/ upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu)); +} + +bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); + + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) + // The first menu in a hierarchy isn't so hovering doesn't get accross (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. + ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + flags |= ImGuiWindowFlags_ChildWindow; + + // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). + // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. + // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. + if (g.MenusIdSubmittedThisFrame.contains(id)) + { + if (menu_is_open) + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + else + g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values + return menu_is_open; + } + + // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu + g.MenusIdSubmittedThisFrame.push_back(id); + + ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) + const bool menuset_is_open = IsRootOfOpenMenuSet(); + ImGuiWindow* backed_nav_window = g.NavWindow; + if (menuset_is_open) + g.NavWindow = window; + + // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, + // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). + // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. + ImVec2 popup_pos, pos = window->DC.CursorPos; + PushID(label); + if (!enabled) + BeginDisabled(); + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + bool pressed; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Menu inside an horizontal menu bar + // Selectable extend their highlight by half ItemSpacing in each direction. + // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() + popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + float w = label_size.x; + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups, ImVec2(w, 0.0f)); + RenderText(text_pos, label); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu inside a regular/vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); + RenderText(text_pos, label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); + } + if (!enabled) + EndDisabled(); + + const bool hovered = (g.HoveredId == id) && enabled; + if (menuset_is_open) + g.NavWindow = backed_nav_window; + + bool want_open = false; + bool want_close = false; + if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + { + // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. + bool moving_toward_other_child_menu = false; + ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; + if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) + { + float ref_unit = g.FontSize; // FIXME-DPI + ImRect next_window_rect = child_menu_window->Rect(); + ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); + ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack. + ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues (FIXME: ??) + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f); + moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_other_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] + } + if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu) + want_close = true; + + // Open + if (!menu_is_open && pressed) // Click/activate to open + want_open = true; + else if (!menu_is_open && hovered && !moving_toward_other_child_menu) // Hover to open + want_open = true; + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + else + { + // Menu bar + if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it + { + want_close = true; + want_open = menu_is_open = false; + } + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others + { + want_open = true; + } + else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + want_close = true; + if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + PopID(); + + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + { + // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. + OpenPopup(label); + return false; + } + + menu_is_open |= want_open; + if (want_open) + OpenPopup(label); + + if (menu_is_open) + { + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: this is super misleading! The value will serve as reference for FindBestWindowPosForPopup(), not actual pos. + PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + PopStyleVar(); + } + else + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + } + + return menu_is_open; +} + +bool ImGui::BeginMenu(const char* label, bool enabled) +{ + return BeginMenuEx(label, NULL, enabled); +} + +void ImGui::EndMenu() +{ + // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). + // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. + // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) + if (g.NavWindow && (g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow == window) + { + ClosePopupToLevel(g.BeginPopupStack.Size, true); + NavMoveRequestCancel(); + } + + EndPopup(); +} + +bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 pos = window->DC.CursorPos; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + const bool menuset_is_open = IsRootOfOpenMenuSet(); + ImGuiWindow* backed_nav_window = g.NavWindow; + if (menuset_is_open) + g.NavWindow = window; + + // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), + // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. + bool pressed; + PushID(label); + if (!enabled) + BeginDisabled(); + + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover; + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful + // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark. + float w = label_size.x; + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); + PopStyleVar(); + RenderText(text_pos, label); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu item inside a vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame + float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); + RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + if (shortcut_w > 0.0f) + { + PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); + } + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + if (!enabled) + EndDisabled(); + PopID(); + if (menuset_is_open) + g.NavWindow = backed_nav_window; + + return pressed; +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +{ + return MenuItemEx(label, NULL, shortcut, selected, enabled); +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +{ + if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled)) + { + if (p_selected) + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +//------------------------------------------------------------------------- +// - BeginTabBar() +// - BeginTabBarEx() [Internal] +// - EndTabBar() +// - TabBarLayout() [Internal] +// - TabBarCalcTabID() [Internal] +// - TabBarCalcMaxTabWidth() [Internal] +// - TabBarFindTabById() [Internal] +// - TabBarRemoveTab() [Internal] +// - TabBarCloseTab() [Internal] +// - TabBarScrollClamp() [Internal] +// - TabBarScrollToTab() [Internal] +// - TabBarQueueChangeTabOrder() [Internal] +// - TabBarScrollingButtons() [Internal] +// - TabBarTabListPopupButton() [Internal] +//------------------------------------------------------------------------- + +struct ImGuiTabBarSection +{ + int TabCount; // Number of tabs in this section. + float Width; // Sum of width of tabs in this section (after shrinking down) + float Spacing; // Horizontal spacing at the end of the section. + + ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); } +}; + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); + static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); + static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); +} + +ImGuiTabBar::ImGuiTabBar() +{ + memset(this, 0, sizeof(*this)); + CurrFrameVisible = PrevFrameVisible = -1; + LastTabItemIdx = -1; +} + +static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab) +{ + return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; +} + +static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + const int a_section = TabItemGetSectionIdx(a); + const int b_section = TabItemGetSectionIdx(b); + if (a_section != b_section) + return a_section - b_section; + return (int)(a->IndexDuringLayout - b->IndexDuringLayout); +} + +static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + return (int)(a->BeginOrder - b->BeginOrder); +} + +static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) +{ + ImGuiContext& g = *GImGui; + return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index); +} + +static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + if (g.TabBars.Contains(tab_bar)) + return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar)); + return ImGuiPtrOrIndex(tab_bar); +} + +bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(str_id); + ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + tab_bar->ID = id; + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); +} + +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + if ((flags & ImGuiTabBarFlags_DockNode) == 0) + PushOverrideID(tab_bar->ID); + + // Add to stack + g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); + g.CurrentTabBar = tab_bar; + + // Append with multiple BeginTabBar()/EndTabBar() pairs. + tab_bar->BackupCursorPos = window->DC.CursorPos; + if (tab_bar->CurrFrameVisible == g.FrameCount) + { + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + tab_bar->BeginCount++; + return true; + } + + // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); + tab_bar->TabsAddedNew = false; + + // Flags + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() + tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; + tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->PrevTabsContentsHeight = tab_bar->CurrTabsContentsHeight; + tab_bar->CurrTabsContentsHeight = 0.0f; + tab_bar->ItemSpacingY = g.Style.ItemSpacing.y; + tab_bar->FramePadding = g.Style.FramePadding; + tab_bar->TabsActiveCount = 0; + tab_bar->BeginCount = 1; + + // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + + // Draw separator + const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); + const float y = tab_bar->BarRect.Max.y - 1.0f; + { + const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); + const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + return true; +} + +void ImGui::EndTabBar() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); + return; + } + + // Fallback in case no TabItem have been submitted + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) + { + tab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight); + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight; + } + else + { + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->PrevTabsContentsHeight; + } + if (tab_bar->BeginCount > 1) + window->DC.CursorPos = tab_bar->BackupCursorPos; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + + g.CurrentTabBarStack.pop_back(); + g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); +} + +// This is called only once a frame before by the first call to ItemTab() +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + // Garbage collect by compacting list + // Detect if we need to sort out tab list (e.g. in rare case where a tab changed section) + int tab_dst_n = 0; + bool need_sort_by_section = false; + ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing + for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose) + { + // Remove tab + if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; } + continue; + } + if (tab_dst_n != tab_src_n) + tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + + tab = &tab_bar->Tabs[tab_dst_n]; + tab->IndexDuringLayout = (ImS16)tab_dst_n; + + // We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another) + int curr_tab_section_n = TabItemGetSectionIdx(tab); + if (tab_dst_n > 0) + { + ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; + int prev_tab_section_n = TabItemGetSectionIdx(prev_tab); + if (curr_tab_section_n == 0 && prev_tab_section_n != 0) + need_sort_by_section = true; + if (prev_tab_section_n == 2 && curr_tab_section_n != 2) + need_sort_by_section = true; + } + + sections[curr_tab_section_n].TabCount++; + tab_dst_n++; + } + if (tab_bar->Tabs.Size != tab_dst_n) + tab_bar->Tabs.resize(tab_dst_n); + + if (need_sort_by_section) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection); + + // Calculate spacing between sections + sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + + // Setup next selected tab + ImGuiID scroll_to_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_to_tab_id = tab_bar->SelectedTabId; + } + + // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). + if (tab_bar->ReorderRequestTabId != 0) + { + if (TabBarProcessReorder(tab_bar)) + if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId) + scroll_to_tab_id = tab_bar->ReorderRequestTabId; + tab_bar->ReorderRequestTabId = 0; + } + + // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) + const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; + if (tab_list_popup_button) + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! + scroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central + // (whereas our tabs are stored as: leading, central, trailing) + int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount }; + g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); + + // Compute ideal tabs widths + store them into shrink buffer + ImGuiTabItem* most_recently_selected_tab = NULL; + int curr_section_n = -1; + bool found_selected_tab_id = false; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); + + if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button)) + most_recently_selected_tab = tab; + if (tab->ID == tab_bar->SelectedTabId) + found_selected_tab_id = true; + if (scroll_to_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_to_tab_id = tab->ID; + + // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. + const char* tab_name = tab_bar->GetTabName(tab); + const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true; + tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; + + int section_n = TabItemGetSectionIdx(tab); + ImGuiTabBarSection* section = §ions[section_n]; + section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f); + curr_section_n = section_n; + + // Store data so we can build an array sorted by width if we need to shrink tabs down + IM_MSVC_WARNING_SUPPRESS(6385); + int shrink_buffer_index = shrink_buffer_indexes[section_n]++; + g.ShrinkWidthBuffer[shrink_buffer_index].Index = tab_n; + g.ShrinkWidthBuffer[shrink_buffer_index].Width = tab->ContentWidth; + + IM_ASSERT(tab->ContentWidth > 0.0f); + tab->Width = tab->ContentWidth; + } + + // Compute total ideal width (used for e.g. auto-resizing a window) + tab_bar->WidthAllTabsIdeal = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) + tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing; + + // Horizontal scrolling buttons + // (note that TabBarScrollButtons() will alter BarRect.Max.x) + if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) + { + scroll_to_tab_id = scroll_and_select_tab->ID; + if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) + tab_bar->SelectedTabId = scroll_to_tab_id; + } + + // Shrink widths if full tabs don't fit in their allocated space + float section_0_w = sections[0].Width + sections[0].Spacing; + float section_1_w = sections[1].Width + sections[1].Spacing; + float section_2_w = sections[2].Width + sections[2].Spacing; + bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth(); + float width_excess; + if (central_section_is_visible) + width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section + else + width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section + + // With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore + if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible)) + { + int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount); + int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0); + ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess); + + // Apply shrunk values into tabs and sections + for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index]; + float shrinked_width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); + if (shrinked_width < 0.0f) + continue; + + int section_n = TabItemGetSectionIdx(tab); + sections[section_n].Width -= (tab->Width - shrinked_width); + tab->Width = shrinked_width; + } + } + + // Layout all active tabs + int section_tab_index = 0; + float tab_offset = 0.0f; + tab_bar->WidthAllTabs = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) + { + ImGuiTabBarSection* section = §ions[section_n]; + if (section_n == 2) + tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset); + + for (int tab_n = 0; tab_n < section->TabCount; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n]; + tab->Offset = tab_offset; + tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f); + } + tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f); + tab_offset += section->Spacing; + section_tab_index += section->TabCount; + } + + // If we have lost the selected tab, select the next most recently active one + if (found_selected_tab_id == false) + tab_bar->SelectedTabId = 0; + if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) + scroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + // Lock in visible tab + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + // Update scrolling + if (scroll_to_tab_id != 0) + TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); + tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); + if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) + { + // Scrolling speed adjust itself so we can always reach our target in 1/3 seconds. + // Teleport if we are aiming far off the visible line + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize); + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); + const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); + tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed); + } + else + { + tab_bar->ScrollingSpeed = 0.0f; + } + tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing; + tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing; + + // Clear name buffers + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); + + // Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame) + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos = tab_bar->BarRect.Min; + ItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); + window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal); +} + +// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +{ + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + ImGuiID id = ImHashStr(label); + KeepAliveID(id); + return id; + } + else + { + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(label); + } +} + +static float ImGui::TabBarCalcMaxTabWidth() +{ + ImGuiContext& g = *GImGui; + return g.FontSize * 20.0f; +} + +ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (tab_id != 0) + for (int n = 0; n < tab_bar->Tabs.Size; n++) + if (tab_bar->Tabs[n].ID == tab_id) + return &tab_bar->Tabs[n]; + return NULL; +} + +// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab_bar->Tabs.erase(tab); + if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } +} + +// Called on manual closure attempt +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + IM_ASSERT(!(tab->Flags & ImGuiTabItemFlags_Button)); + if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // This will remove a frame of lag for selecting another tab on closure. + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + tab->WantClose = true; + if (tab_bar->VisibleTabId == tab->ID) + { + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + } + else + { + // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) + if (tab_bar->VisibleTabId != tab->ID) + tab_bar->NextSelectedTabId = tab->ID; + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +// Note: we may scroll to tab that are not selected! e.g. using keyboard arrow keys +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections) +{ + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); + if (tab == NULL) + return; + if (tab->Flags & ImGuiTabItemFlags_SectionMask_) + return; + + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + int order = tab_bar->GetTabOrder(tab); + + // Scrolling happens only in the central section (leading/trailing sections are not scrolling) + // FIXME: This is all confusing. + float scrollable_width = tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; + + // We make all tabs positions all relative Sections[0].Width to make code simpler + float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f); + float tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f); + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width)) + { + // Scroll to the left + tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); + tab_bar->ScrollingTarget = tab_x1; + } + else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width) + { + // Scroll to the right + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - scrollable_width; + } +} + +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset) +{ + IM_ASSERT(offset != 0); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestOffset = (ImS16)offset; +} + +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0) + return; + + const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0); + + // Count number of contiguous tabs we are crossing over + const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1; + const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab); + int dst_idx = src_idx; + for (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir) + { + // Reordered tabs must share the same section + const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i]; + if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder) + break; + if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_)) + break; + dst_idx = i; + + // Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered. + const float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x; + const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x; + //GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255)); + if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2)) + break; + } + + if (dst_idx != src_idx) + TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx); +} + +bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); + if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder)) + return false; + + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset; + if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) + return false; + + // Reordered tabs must share the same section + // (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too) + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + if (tab2->Flags & ImGuiTabItemFlags_NoReorder) + return false; + if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_)) + return false; + + ImGuiTabItem item_tmp = *tab1; + ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2; + ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1; + const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset; + memmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem)); + *tab2 = item_tmp; + + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + return true; +} + +static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const float scrolling_buttons_width = arrow_button_size.x * 2.0f; + + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + + int select_dir = 0; + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + const float backup_repeat_delay = g.IO.KeyRepeatDelay; + const float backup_repeat_rate = g.IO.KeyRepeatRate; + g.IO.KeyRepeatDelay = 0.250f; + g.IO.KeyRepeatRate = 0.200f; + float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width); + window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = -1; + window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = +1; + PopStyleColor(2); + g.IO.KeyRepeatRate = backup_repeat_rate; + g.IO.KeyRepeatDelay = backup_repeat_delay; + + ImGuiTabItem* tab_to_scroll_to = NULL; + if (select_dir != 0) + if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + { + int selected_order = tab_bar->GetTabOrder(tab_item); + int target_order = selected_order + select_dir; + + // Skip tab item buttons until another tab item is found or end is reached + while (tab_to_scroll_to == NULL) + { + // If we are at the end of the list, still scroll to make our tab visible + tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; + + // Cross through buttons + // (even if first/last item is a button, return it so we can update the scroll) + if (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button) + { + target_order += select_dir; + selected_order += select_dir; + tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; + } + } + } + window->DC.CursorPos = backup_cursor_pos; + tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; + + return tab_to_scroll_to; +} + +static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We use g.Style.FramePadding.y to match the square ArrowButton size + const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); + tab_bar->BarRect.Min.x += tab_list_popup_button_width; + + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest); + PopStyleColor(2); + + ImGuiTabItem* tab_to_select = NULL; + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + if (tab->Flags & ImGuiTabItemFlags_Button) + continue; + + const char* tab_name = tab_bar->GetTabName(tab); + if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) + tab_to_select = tab; + } + EndCombo(); + } + + window->DC.CursorPos = backup_cursor_pos; + return tab_to_select; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +//------------------------------------------------------------------------- +// - BeginTabItem() +// - EndTabItem() +// - TabItemButton() +// - TabItemEx() [Internal] +// - SetTabItemClosed() +// - TabItemCalcSize() [Internal] +// - TabItemBackground() [Internal] +// - TabItemLabelAndCloseButton() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + + bool ret = TabItemEx(tab_bar, label, p_open, flags); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + } + return ret; +} + +void ImGui::EndTabItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return; + } + IM_ASSERT(tab_bar->LastTabItemIdx >= 0); + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) + PopID(); +} + +bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + // Layout whole tab bar if not already done + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label); + + // If the user called us with *p_open == false, we early out and don't render. + // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + if (p_open && !*p_open) + { + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus); + return false; + } + + IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing + + // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) + if (flags & ImGuiTabItemFlags_NoCloseButton) + p_open = NULL; + else if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, p_open != NULL); + + // Acquire tab data + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + bool tab_is_new = false; + if (tab == NULL) + { + tab_bar->Tabs.push_back(ImGuiTabItem()); + tab = &tab_bar->Tabs.back(); + tab->ID = id; + tab->Width = size.x; + tab_bar->TabsAddedNew = true; + tab_is_new = true; + } + tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab); + tab->ContentWidth = size.x; + tab->BeginOrder = tab_bar->TabsActiveCount++; + + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; + const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + + // Append name with zero-terminator + tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); + + // Update selected tab + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; // New tabs gets activated + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; + + // Lock visibility + // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!) + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing) + if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) + tab_contents_visible = true; + + // Note that tab_is_new is not necessarily the same as tab_appearing! When a tab bar stops being submitted + // and then gets submitted again, the tabs will have 'tab_appearing=true' but 'tab_is_new=false'. + if (tab_appearing && (!tab_bar_appearing || tab_is_new)) + { + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus); + if (is_tab_button) + return false; + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + // Backup current layout position + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + // Layout + const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + size.x = tab->Width; + if (is_central_section) + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + else + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); + + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) + const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); + if (want_clip_rect) + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); + + ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; + ItemSize(bb.GetSize(), style.FramePadding.y); + window->DC.CursorMaxPos = backup_cursor_max_pos; + + if (!ItemAdd(bb, id)) + { + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + return tab_contents_visible; + } + + // Click to Select a tab + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap); + if (g.DragDropActive) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (pressed && !is_tab_button) + tab_bar->NextSelectedTabId = id; + + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) + if (g.ActiveId != id) + SetItemAllowOverlap(); + + // Drag and drop: re-order tabs + if (held && !tab_appearing && IsMouseDragging(0)) + { + if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth) + { + // Enlarge tab display when hovering + bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); + display_draw_list = GetForegroundDrawList(window); + TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); + } +#endif + + // Render tab shape + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + if (!is_tab_button) + tab_bar->NextSelectedTabId = id; + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; + bool just_closed; + bool text_clipped; + TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Restore main window position so user can draw there + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + // Tooltip + // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // FIXME: This is a mess. + // FIXME: We may want disabled tab to still display the tooltip? + if (text_clipped && g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay && IsItemHovered()) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected + if (is_tab_button) + return pressed; + return tab_contents_visible; +} + +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. +// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar(). +// Tabs closed by the close button will automatically be flagged to avoid this issue. +void ImGui::SetTabItemClosed(const char* label) +{ + ImGuiContext& g = *GImGui; + bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode); + if (is_within_manual_tab_bar) + { + ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab->WantClose = true; // Will be processed by next call to TabBarLayout() + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); + if (has_close_button) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + else + size.x += g.Style.FramePadding.x + 1.0f; + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. + ImGuiContext& g = *GImGui; + const float width = bb.GetWidth(); + IM_UNUSED(flags); + IM_ASSERT(width > 0.0f); + const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); + const float y1 = bb.Min.y + 1.0f; + const float y2 = bb.Max.y - 1.0f; + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathFillConvex(col); + if (g.Style.TabBorderSize > 0.0f) + { + draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize); + } +} + +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic +// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. +void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + if (out_just_closed) + *out_just_closed = false; + if (out_text_clipped) + *out_text_clipped = false; + + if (bb.GetWidth() <= 1.0f) + return; + + // In Style V2 we'll have full override of all colors per state (e.g. focused, selected) + // But right now if you want to alter text color of tabs this is what you need to do. +#if 0 + const float backup_alpha = g.Style.Alpha; + if (!is_contents_visible) + g.Style.Alpha *= 0.7f; +#endif + + // Render text label (with clipping + alpha gradient) + unsaved marker + ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Return clipped state ignoring the close button + if (out_text_clipped) + { + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x; + //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); + } + + const float button_sz = g.FontSize; + const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); + + // Close Button & Unsaved Marker + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // 'hovered' will be true when hovering the Tab but NOT when hovering the close button + // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton)) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id) + close_button_visible = true; + bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); + + if (close_button_visible) + { + ImGuiLastItemData last_item_backup = g.LastItemData; + PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); + if (CloseButton(close_button_id, button_pos)) + close_button_pressed = true; + PopStyleVar(); + g.LastItemData = last_item_backup; + + // Close with middle mouse button + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + } + else if (unsaved_marker_visible) + { + const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f); + RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); + } + + // This is all rather complicated + // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) + // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + if (close_button_visible || unsaved_marker_visible) + { + text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); + text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; + ellipsis_max_x = text_pixel_clip_bb.Max.x; + } + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); + +#if 0 + if (!is_contents_visible) + g.Style.Alpha = backup_alpha; +#endif + + if (out_just_closed) + *out_just_closed = close_button_pressed; +} + + +#endif // #ifndef IMGUI_DISABLE diff --git a/thirdparty/imgui/imstb_rectpack.h b/thirdparty/imgui/imstb_rectpack.h new file mode 100644 index 0000000..3958952 --- /dev/null +++ b/thirdparty/imgui/imstb_rectpack.h @@ -0,0 +1,639 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_rect_pack.h 1.00. +// Those changes would need to be pushed into nothings/stb: +// - Added STBRP__CDECL +// Grep for [DEAR IMGUI] to find the changes. + +// stb_rect_pack.h - v1.00 - public domain - rectangle packing +// Sean Barrett 2014 +// +// Useful for e.g. packing rectangular textures into an atlas. +// Does not do rotation. +// +// Not necessarily the awesomest packing method, but better than +// the totally naive one in stb_truetype (which is primarily what +// this is meant to replace). +// +// Has only had a few tests run, may have issues. +// +// More docs to come. +// +// No memory allocations; uses qsort() and assert() from stdlib. +// Can override those by defining STBRP_SORT and STBRP_ASSERT. +// +// This library currently uses the Skyline Bottom-Left algorithm. +// +// Please note: better rectangle packers are welcome! Please +// implement them to the same API, but with a different init +// function. +// +// Credits +// +// Library +// Sean Barrett +// Minor features +// Martins Mozeiko +// github:IntellectualKitty +// +// Bugfixes / warning fixes +// Jeremy Jaussaud +// Fabian Giesen +// +// Version history: +// +// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles +// 0.99 (2019-02-07) warning fixes +// 0.11 (2017-03-03) return packing success/fail result +// 0.10 (2016-10-25) remove cast-away-const to avoid warnings +// 0.09 (2016-08-27) fix compiler warnings +// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) +// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) +// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort +// 0.05: added STBRP_ASSERT to allow replacing assert +// 0.04: fixed minor bug in STBRP_LARGE_RECTS support +// 0.01: initial release +// +// LICENSE +// +// See end of file for license information. + +////////////////////////////////////////////////////////////////////////////// +// +// INCLUDE SECTION +// + +#ifndef STB_INCLUDE_STB_RECT_PACK_H +#define STB_INCLUDE_STB_RECT_PACK_H + +#define STB_RECT_PACK_VERSION 1 + +#ifdef STBRP_STATIC +#define STBRP_DEF static +#else +#define STBRP_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct stbrp_context stbrp_context; +typedef struct stbrp_node stbrp_node; +typedef struct stbrp_rect stbrp_rect; + +#ifdef STBRP_LARGE_RECTS +typedef int stbrp_coord; +#else +typedef unsigned short stbrp_coord; +#endif + +STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); +// Assign packed locations to rectangles. The rectangles are of type +// 'stbrp_rect' defined below, stored in the array 'rects', and there +// are 'num_rects' many of them. +// +// Rectangles which are successfully packed have the 'was_packed' flag +// set to a non-zero value and 'x' and 'y' store the minimum location +// on each axis (i.e. bottom-left in cartesian coordinates, top-left +// if you imagine y increasing downwards). Rectangles which do not fit +// have the 'was_packed' flag set to 0. +// +// You should not try to access the 'rects' array from another thread +// while this function is running, as the function temporarily reorders +// the array while it executes. +// +// To pack into another rectangle, you need to call stbrp_init_target +// again. To continue packing into the same rectangle, you can call +// this function again. Calling this multiple times with multiple rect +// arrays will probably produce worse packing results than calling it +// a single time with the full rectangle array, but the option is +// available. +// +// The function returns 1 if all of the rectangles were successfully +// packed and 0 otherwise. + +struct stbrp_rect +{ + // reserved for your use: + int id; + + // input: + stbrp_coord w, h; + + // output: + stbrp_coord x, y; + int was_packed; // non-zero if valid packing + +}; // 16 bytes, nominally + + +STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); +// Initialize a rectangle packer to: +// pack a rectangle that is 'width' by 'height' in dimensions +// using temporary storage provided by the array 'nodes', which is 'num_nodes' long +// +// You must call this function every time you start packing into a new target. +// +// There is no "shutdown" function. The 'nodes' memory must stay valid for +// the following stbrp_pack_rects() call (or calls), but can be freed after +// the call (or calls) finish. +// +// Note: to guarantee best results, either: +// 1. make sure 'num_nodes' >= 'width' +// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' +// +// If you don't do either of the above things, widths will be quantized to multiples +// of small integers to guarantee the algorithm doesn't run out of temporary storage. +// +// If you do #2, then the non-quantized algorithm will be used, but the algorithm +// may run out of temporary storage and be unable to pack some rectangles. + +STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); +// Optionally call this function after init but before doing any packing to +// change the handling of the out-of-temp-memory scenario, described above. +// If you call init again, this will be reset to the default (false). + + +STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); +// Optionally select which packing heuristic the library should use. Different +// heuristics will produce better/worse results for different data sets. +// If you call init again, this will be reset to the default. + +enum +{ + STBRP_HEURISTIC_Skyline_default=0, + STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, + STBRP_HEURISTIC_Skyline_BF_sortHeight +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// the details of the following structures don't matter to you, but they must +// be visible so you can handle the memory allocations for them + +struct stbrp_node +{ + stbrp_coord x,y; + stbrp_node *next; +}; + +struct stbrp_context +{ + int width; + int height; + int align; + int init_mode; + int heuristic; + int num_nodes; + stbrp_node *active_head; + stbrp_node *free_head; + stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' +}; + +#ifdef __cplusplus +} +#endif + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION SECTION +// + +#ifdef STB_RECT_PACK_IMPLEMENTATION +#ifndef STBRP_SORT +#include +#define STBRP_SORT qsort +#endif + +#ifndef STBRP_ASSERT +#include +#define STBRP_ASSERT assert +#endif + +// [DEAR IMGUI] Added STBRP__CDECL +#ifdef _MSC_VER +#define STBRP__NOTUSED(v) (void)(v) +#define STBRP__CDECL __cdecl +#else +#define STBRP__NOTUSED(v) (void)sizeof(v) +#define STBRP__CDECL +#endif + +enum +{ + STBRP__INIT_skyline = 1 +}; + +STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) +{ + switch (context->init_mode) { + case STBRP__INIT_skyline: + STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); + context->heuristic = heuristic; + break; + default: + STBRP_ASSERT(0); + } +} + +STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) +{ + if (allow_out_of_mem) + // if it's ok to run out of memory, then don't bother aligning them; + // this gives better packing, but may fail due to OOM (even though + // the rectangles easily fit). @TODO a smarter approach would be to only + // quantize once we've hit OOM, then we could get rid of this parameter. + context->align = 1; + else { + // if it's not ok to run out of memory, then quantize the widths + // so that num_nodes is always enough nodes. + // + // I.e. num_nodes * align >= width + // align >= width / num_nodes + // align = ceil(width/num_nodes) + + context->align = (context->width + context->num_nodes-1) / context->num_nodes; + } +} + +STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) +{ + int i; +#ifndef STBRP_LARGE_RECTS + STBRP_ASSERT(width <= 0xffff && height <= 0xffff); +#endif + + for (i=0; i < num_nodes-1; ++i) + nodes[i].next = &nodes[i+1]; + nodes[i].next = NULL; + context->init_mode = STBRP__INIT_skyline; + context->heuristic = STBRP_HEURISTIC_Skyline_default; + context->free_head = &nodes[0]; + context->active_head = &context->extra[0]; + context->width = width; + context->height = height; + context->num_nodes = num_nodes; + stbrp_setup_allow_out_of_mem(context, 0); + + // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) + context->extra[0].x = 0; + context->extra[0].y = 0; + context->extra[0].next = &context->extra[1]; + context->extra[1].x = (stbrp_coord) width; +#ifdef STBRP_LARGE_RECTS + context->extra[1].y = (1<<30); +#else + context->extra[1].y = 65535; +#endif + context->extra[1].next = NULL; +} + +// find minimum y position if it starts at x1 +static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) +{ + stbrp_node *node = first; + int x1 = x0 + width; + int min_y, visited_width, waste_area; + + STBRP__NOTUSED(c); + + STBRP_ASSERT(first->x <= x0); + + #if 0 + // skip in case we're past the node + while (node->next->x <= x0) + ++node; + #else + STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency + #endif + + STBRP_ASSERT(node->x <= x0); + + min_y = 0; + waste_area = 0; + visited_width = 0; + while (node->x < x1) { + if (node->y > min_y) { + // raise min_y higher. + // we've accounted for all waste up to min_y, + // but we'll now add more waste for everything we've visted + waste_area += visited_width * (node->y - min_y); + min_y = node->y; + // the first time through, visited_width might be reduced + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; + } else { + // add waste area + int under_width = node->next->x - node->x; + if (under_width + visited_width > width) + under_width = width - visited_width; + waste_area += under_width * (min_y - node->y); + visited_width += under_width; + } + node = node->next; + } + + *pwaste = waste_area; + return min_y; +} + +typedef struct +{ + int x,y; + stbrp_node **prev_link; +} stbrp__findresult; + +static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) +{ + int best_waste = (1<<30), best_x, best_y = (1 << 30); + stbrp__findresult fr; + stbrp_node **prev, *node, *tail, **best = NULL; + + // align to multiple of c->align + width = (width + c->align - 1); + width -= width % c->align; + STBRP_ASSERT(width % c->align == 0); + + // if it can't possibly fit, bail immediately + if (width > c->width || height > c->height) { + fr.prev_link = NULL; + fr.x = fr.y = 0; + return fr; + } + + node = c->active_head; + prev = &c->active_head; + while (node->x + width <= c->width) { + int y,waste; + y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); + if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL + // bottom left + if (y < best_y) { + best_y = y; + best = prev; + } + } else { + // best-fit + if (y + height <= c->height) { + // can only use it if it first vertically + if (y < best_y || (y == best_y && waste < best_waste)) { + best_y = y; + best_waste = waste; + best = prev; + } + } + } + prev = &node->next; + node = node->next; + } + + best_x = (best == NULL) ? 0 : (*best)->x; + + // if doing best-fit (BF), we also have to try aligning right edge to each node position + // + // e.g, if fitting + // + // ____________________ + // |____________________| + // + // into + // + // | | + // | ____________| + // |____________| + // + // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned + // + // This makes BF take about 2x the time + + if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { + tail = c->active_head; + node = c->active_head; + prev = &c->active_head; + // find first node that's admissible + while (tail->x < width) + tail = tail->next; + while (tail) { + int xpos = tail->x - width; + int y,waste; + STBRP_ASSERT(xpos >= 0); + // find the left position that matches this + while (node->next->x <= xpos) { + prev = &node->next; + node = node->next; + } + STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); + y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); + if (y + height <= c->height) { + if (y <= best_y) { + if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { + best_x = xpos; + STBRP_ASSERT(y <= best_y); + best_y = y; + best_waste = waste; + best = prev; + } + } + } + tail = tail->next; + } + } + + fr.prev_link = best; + fr.x = best_x; + fr.y = best_y; + return fr; +} + +static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) +{ + // find best position according to heuristic + stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); + stbrp_node *node, *cur; + + // bail if: + // 1. it failed + // 2. the best node doesn't fit (we don't always check this) + // 3. we're out of memory + if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { + res.prev_link = NULL; + return res; + } + + // on success, create new node + node = context->free_head; + node->x = (stbrp_coord) res.x; + node->y = (stbrp_coord) (res.y + height); + + context->free_head = node->next; + + // insert the new node into the right starting point, and + // let 'cur' point to the remaining nodes needing to be + // stiched back in + + cur = *res.prev_link; + if (cur->x < res.x) { + // preserve the existing one, so start testing with the next one + stbrp_node *next = cur->next; + cur->next = node; + cur = next; + } else { + *res.prev_link = node; + } + + // from here, traverse cur and free the nodes, until we get to one + // that shouldn't be freed + while (cur->next && cur->next->x <= res.x + width) { + stbrp_node *next = cur->next; + // move the current node to the free list + cur->next = context->free_head; + context->free_head = cur; + cur = next; + } + + // stitch the list back in + node->next = cur; + + if (cur->x < res.x + width) + cur->x = (stbrp_coord) (res.x + width); + +#ifdef _DEBUG + cur = context->active_head; + while (cur->x < context->width) { + STBRP_ASSERT(cur->x < cur->next->x); + cur = cur->next; + } + STBRP_ASSERT(cur->next == NULL); + + { + int count=0; + cur = context->active_head; + while (cur) { + cur = cur->next; + ++count; + } + cur = context->free_head; + while (cur) { + cur = cur->next; + ++count; + } + STBRP_ASSERT(count == context->num_nodes+2); + } +#endif + + return res; +} + +// [DEAR IMGUI] Added STBRP__CDECL +static int STBRP__CDECL rect_height_compare(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + if (p->h > q->h) + return -1; + if (p->h < q->h) + return 1; + return (p->w > q->w) ? -1 : (p->w < q->w); +} + +// [DEAR IMGUI] Added STBRP__CDECL +static int STBRP__CDECL rect_original_order(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); +} + +#ifdef STBRP_LARGE_RECTS +#define STBRP__MAXVAL 0xffffffff +#else +#define STBRP__MAXVAL 0xffff +#endif + +STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) +{ + int i, all_rects_packed = 1; + + // we use the 'was_packed' field internally to allow sorting/unsorting + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = i; + } + + // sort according to heuristic + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); + + for (i=0; i < num_rects; ++i) { + if (rects[i].w == 0 || rects[i].h == 0) { + rects[i].x = rects[i].y = 0; // empty rect needs no space + } else { + stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); + if (fr.prev_link) { + rects[i].x = (stbrp_coord) fr.x; + rects[i].y = (stbrp_coord) fr.y; + } else { + rects[i].x = rects[i].y = STBRP__MAXVAL; + } + } + } + + // unsort + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); + + // set was_packed flags and all_rects_packed status + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); + if (!rects[i].was_packed) + all_rects_packed = 0; + } + + // return the all_rects_packed status + return all_rects_packed; +} +#endif + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/thirdparty/imgui/imstb_textedit.h b/thirdparty/imgui/imstb_textedit.h new file mode 100644 index 0000000..2c635b2 --- /dev/null +++ b/thirdparty/imgui/imstb_textedit.h @@ -0,0 +1,1449 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_textedit.h 1.13. +// Those changes would need to be pushed into nothings/stb: +// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) +// Grep for [DEAR IMGUI] to find the changes. + +// stb_textedit.h - v1.13 - public domain - Sean Barrett +// Development of this library was sponsored by RAD Game Tools +// +// This C header file implements the guts of a multi-line text-editing +// widget; you implement display, word-wrapping, and low-level string +// insertion/deletion, and stb_textedit will map user inputs into +// insertions & deletions, plus updates to the cursor position, +// selection state, and undo state. +// +// It is intended for use in games and other systems that need to build +// their own custom widgets and which do not have heavy text-editing +// requirements (this library is not recommended for use for editing large +// texts, as its performance does not scale and it has limited undo). +// +// Non-trivial behaviors are modelled after Windows text controls. +// +// +// LICENSE +// +// See end of file for license information. +// +// +// DEPENDENCIES +// +// Uses the C runtime function 'memmove', which you can override +// by defining STB_TEXTEDIT_memmove before the implementation. +// Uses no other functions. Performs no runtime allocations. +// +// +// VERSION HISTORY +// +// 1.13 (2019-02-07) fix bug in undo size management +// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash +// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield +// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual +// 1.9 (2016-08-27) customizable move-by-word +// 1.8 (2016-04-02) better keyboard handling when mouse button is down +// 1.7 (2015-09-13) change y range handling in case baseline is non-0 +// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove +// 1.5 (2014-09-10) add support for secondary keys for OS X +// 1.4 (2014-08-17) fix signed/unsigned warnings +// 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary +// 1.2 (2014-05-27) fix some RAD types that had crept into the new code +// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) +// 1.0 (2012-07-26) improve documentation, initial public release +// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode +// 0.2 (2011-11-28) fixes to undo/redo +// 0.1 (2010-07-08) initial version +// +// ADDITIONAL CONTRIBUTORS +// +// Ulf Winklemann: move-by-word in 1.1 +// Fabian Giesen: secondary key inputs in 1.5 +// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 +// +// Bugfixes: +// Scott Graham +// Daniel Keller +// Omar Cornut +// Dan Thompson +// +// USAGE +// +// This file behaves differently depending on what symbols you define +// before including it. +// +// +// Header-file mode: +// +// If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, +// it will operate in "header file" mode. In this mode, it declares a +// single public symbol, STB_TexteditState, which encapsulates the current +// state of a text widget (except for the string, which you will store +// separately). +// +// To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a +// primitive type that defines a single character (e.g. char, wchar_t, etc). +// +// To save space or increase undo-ability, you can optionally define the +// following things that are used by the undo system: +// +// STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// If you don't define these, they are set to permissive types and +// moderate sizes. The undo system does no memory allocations, so +// it grows STB_TexteditState by the worst-case storage which is (in bytes): +// +// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT +// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT +// +// +// Implementation mode: +// +// If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it +// will compile the implementation of the text edit widget, depending +// on a large number of symbols which must be defined before the include. +// +// The implementation is defined only as static functions. You will then +// need to provide your own APIs in the same file which will access the +// static functions. +// +// The basic concept is that you provide a "string" object which +// behaves like an array of characters. stb_textedit uses indices to +// refer to positions in the string, implicitly representing positions +// in the displayed textedit. This is true for both plain text and +// rich text; even with rich text stb_truetype interacts with your +// code as if there was an array of all the displayed characters. +// +// Symbols that must be the same in header-file and implementation mode: +// +// STB_TEXTEDIT_CHARTYPE the character type +// STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// Symbols you must define for implementation mode: +// +// STB_TEXTEDIT_STRING the type of object representing a string being edited, +// typically this is a wrapper object with other data you need +// +// STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) +// STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters +// starting from character #n (see discussion below) +// STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character +// to the xpos of the i+1'th char for a line of characters +// starting at character #n (i.e. accounts for kerning +// with previous char) +// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character +// (return type is int, -1 means not valid to insert) +// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based +// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize +// as manually wordwrapping for end-of-line positioning +// +// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i +// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) +// +// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key +// +// STB_TEXTEDIT_K_LEFT keyboard input to move cursor left +// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right +// STB_TEXTEDIT_K_UP keyboard input to move cursor up +// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down +// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page +// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page +// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME +// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END +// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME +// STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END +// STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor +// STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor +// STB_TEXTEDIT_K_UNDO keyboard input to perform undo +// STB_TEXTEDIT_K_REDO keyboard input to perform redo +// +// Optional: +// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode +// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), +// required for default WORDLEFT/WORDRIGHT handlers +// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to +// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to +// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT +// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT +// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line +// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line +// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text +// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text +// +// Keyboard input must be encoded as a single integer value; e.g. a character code +// and some bitflags that represent shift states. to simplify the interface, SHIFT must +// be a bitflag, so we can test the shifted state of cursor movements to allow selection, +// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. +// +// You can encode other things, such as CONTROL or ALT, in additional bits, and +// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, +// my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN +// bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, +// and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the +// API below. The control keys will only match WM_KEYDOWN events because of the +// keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN +// bit so it only decodes WM_CHAR events. +// +// STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed +// row of characters assuming they start on the i'th character--the width and +// the height and the number of characters consumed. This allows this library +// to traverse the entire layout incrementally. You need to compute word-wrapping +// here. +// +// Each textfield keeps its own insert mode state, which is not how normal +// applications work. To keep an app-wide insert mode, update/copy the +// "insert_mode" field of STB_TexteditState before/after calling API functions. +// +// API +// +// void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +// +// void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) +// +// Each of these functions potentially updates the string and updates the +// state. +// +// initialize_state: +// set the textedit state to a known good default state when initially +// constructing the textedit. +// +// click: +// call this with the mouse x,y on a mouse down; it will update the cursor +// and reset the selection start/end to the cursor point. the x,y must +// be relative to the text widget, with (0,0) being the top left. +// +// drag: +// call this with the mouse x,y on a mouse drag/up; it will update the +// cursor and the selection end point +// +// cut: +// call this to delete the current selection; returns true if there was +// one. you should FIRST copy the current selection to the system paste buffer. +// (To copy, just copy the current selection out of the string yourself.) +// +// paste: +// call this to paste text at the current cursor point or over the current +// selection if there is one. +// +// key: +// call this for keyboard inputs sent to the textfield. you can use it +// for "key down" events or for "translated" key events. if you need to +// do both (as in Win32), or distinguish Unicode characters from control +// inputs, set a high bit to distinguish the two; then you can define the +// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit +// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is +// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to +// anything other type you wante before including. +// +// +// When rendering, you can read the cursor position and selection state from +// the STB_TexteditState. +// +// +// Notes: +// +// This is designed to be usable in IMGUI, so it allows for the possibility of +// running in an IMGUI that has NOT cached the multi-line layout. For this +// reason, it provides an interface that is compatible with computing the +// layout incrementally--we try to make sure we make as few passes through +// as possible. (For example, to locate the mouse pointer in the text, we +// could define functions that return the X and Y positions of characters +// and binary search Y and then X, but if we're doing dynamic layout this +// will run the layout algorithm many times, so instead we manually search +// forward in one pass. Similar logic applies to e.g. up-arrow and +// down-arrow movement.) +// +// If it's run in a widget that *has* cached the layout, then this is less +// efficient, but it's not horrible on modern computers. But you wouldn't +// want to edit million-line files with it. + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Header-file mode +//// +//// + +#ifndef INCLUDE_STB_TEXTEDIT_H +#define INCLUDE_STB_TEXTEDIT_H + +//////////////////////////////////////////////////////////////////////// +// +// STB_TexteditState +// +// Definition of STB_TexteditState which you should store +// per-textfield; it includes cursor position, selection state, +// and undo state. +// + +#ifndef STB_TEXTEDIT_UNDOSTATECOUNT +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#endif +#ifndef STB_TEXTEDIT_UNDOCHARCOUNT +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#endif +#ifndef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_CHARTYPE int +#endif +#ifndef STB_TEXTEDIT_POSITIONTYPE +#define STB_TEXTEDIT_POSITIONTYPE int +#endif + +typedef struct +{ + // private data + STB_TEXTEDIT_POSITIONTYPE where; + STB_TEXTEDIT_POSITIONTYPE insert_length; + STB_TEXTEDIT_POSITIONTYPE delete_length; + int char_storage; +} StbUndoRecord; + +typedef struct +{ + // private data + StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; + STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; + short undo_point, redo_point; + int undo_char_point, redo_char_point; +} StbUndoState; + +typedef struct +{ + ///////////////////// + // + // public data + // + + int cursor; + // position of the text cursor within the string + + int select_start; // selection start point + int select_end; + // selection start and end point in characters; if equal, no selection. + // note that start may be less than or greater than end (e.g. when + // dragging the mouse, start is where the initial click was, and you + // can drag in either direction) + + unsigned char insert_mode; + // each textfield keeps its own insert mode state. to keep an app-wide + // insert mode, copy this value in/out of the app state + + int row_count_per_page; + // page size in number of row. + // this value MUST be set to >0 for pageup or pagedown in multilines documents. + + ///////////////////// + // + // private data + // + unsigned char cursor_at_end_of_line; // not implemented yet + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; // this determines where the cursor up/down tries to seek to along x + StbUndoState undostate; +} STB_TexteditState; + + +//////////////////////////////////////////////////////////////////////// +// +// StbTexteditRow +// +// Result of layout query, used by stb_textedit to determine where +// the text in each row is. + +// result of layout query +typedef struct +{ + float x0,x1; // starting x location, end x location (allows for align=right, etc) + float baseline_y_delta; // position of baseline relative to previous row's baseline + float ymin,ymax; // height of row above and below baseline + int num_chars; +} StbTexteditRow; +#endif //INCLUDE_STB_TEXTEDIT_H + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Implementation mode +//// +//// + + +// implementation isn't include-guarded, since it might have indirectly +// included just the "header" portion +#ifdef STB_TEXTEDIT_IMPLEMENTATION + +#ifndef STB_TEXTEDIT_memmove +#include +#define STB_TEXTEDIT_memmove memmove +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Mouse input handling +// + +// traverse the layout to locate the nearest character to a display position +static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) +{ + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + float base_y = 0, prev_x; + int i=0, k; + + r.x0 = r.x1 = 0; + r.ymin = r.ymax = 0; + r.num_chars = 0; + + // search rows to find one that straddles 'y' + while (i < n) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + return n; + + if (i==0 && y < base_y + r.ymin) + return 0; + + if (y < base_y + r.ymax) + break; + + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // below all text, return 'after' last character + if (i >= n) + return n; + + // check if it's before the beginning of the line + if (x < r.x0) + return i; + + // check if it's before the end of the line + if (x < r.x1) { + // search characters in row for one that straddles 'x' + prev_x = r.x0; + for (k=0; k < r.num_chars; ++k) { + float w = STB_TEXTEDIT_GETWIDTH(str, i, k); + if (x < prev_x+w) { + if (x < prev_x+w/2) + return k+i; + else + return k+i+1; + } + prev_x += w; + } + // shouldn't happen, but if it does, fall through to end-of-line case + } + + // if the last character is a newline, return that. otherwise return 'after' the last character + if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) + return i+r.num_chars-1; + else + return i+r.num_chars; +} + +// API click: on mouse down, move the cursor to the clicked location, and reset the selection +static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + state->cursor = stb_text_locate_coord(str, x, y); + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; +} + +// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location +static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + int p = 0; + + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + if (state->select_start == state->select_end) + state->select_start = state->cursor; + + p = stb_text_locate_coord(str, x, y); + state->cursor = state->select_end = p; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Keyboard input handling +// + +// forward declarations +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); + +typedef struct +{ + float x,y; // position of n'th character + float height; // height of line + int first_char, length; // first char of row, and length + int prev_first; // first char of previous row +} StbFindState; + +// find the x/y location of a character, and remember info about the previous row in +// case we get a move-up event (for page up, we'll have to rescan) +static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) +{ + StbTexteditRow r; + int prev_start = 0; + int z = STB_TEXTEDIT_STRINGLEN(str); + int i=0, first; + + if (n == z) { + // if it's at the end, then find the last line -- simpler than trying to + // explicitly handle this case in the regular code + if (single_line) { + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + find->y = 0; + find->first_char = 0; + find->length = z; + find->height = r.ymax - r.ymin; + find->x = r.x1; + } else { + find->y = 0; + find->x = 0; + find->height = 1; + while (i < z) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + prev_start = i; + i += r.num_chars; + } + find->first_char = i; + find->length = 0; + find->prev_first = prev_start; + } + return; + } + + // search rows to find the one that straddles character n + find->y = 0; + + for(;;) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (n < i + r.num_chars) + break; + prev_start = i; + i += r.num_chars; + find->y += r.baseline_y_delta; + } + + find->first_char = first = i; + find->length = r.num_chars; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + + // now scan to find xpos + find->x = r.x0; + for (i=0; first+i < n; ++i) + find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); +} + +#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) + +// make the selection/cursor state valid if client altered the string +static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + int n = STB_TEXTEDIT_STRINGLEN(str); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start > n) state->select_start = n; + if (state->select_end > n) state->select_end = n; + // if clamping forced them to be equal, move the cursor to match + if (state->select_start == state->select_end) + state->cursor = state->select_start; + } + if (state->cursor > n) state->cursor = n; +} + +// delete characters while updating undo +static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) +{ + stb_text_makeundo_delete(str, state, where, len); + STB_TEXTEDIT_DELETECHARS(str, where, len); + state->has_preferred_x = 0; +} + +// delete the section +static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + stb_textedit_clamp(str, state); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start < state->select_end) { + stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); + state->select_end = state->cursor = state->select_start; + } else { + stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); + state->select_start = state->cursor = state->select_end; + } + state->has_preferred_x = 0; + } +} + +// canoncialize the selection so start <= end +static void stb_textedit_sortselection(STB_TexteditState *state) +{ + if (state->select_end < state->select_start) { + int temp = state->select_end; + state->select_end = state->select_start; + state->select_start = temp; + } +} + +// move cursor to first character of selection +static void stb_textedit_move_to_first(STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + state->cursor = state->select_start; + state->select_end = state->select_start; + state->has_preferred_x = 0; + } +} + +// move cursor to last character of selection +static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->select_start = state->select_end; + state->has_preferred_x = 0; + } +} + +#ifdef STB_TEXTEDIT_IS_SPACE +static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) +{ + return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; +} + +#ifndef STB_TEXTEDIT_MOVEWORDLEFT +static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) +{ + --c; // always move at least one character + while( c >= 0 && !is_word_boundary( str, c ) ) + --c; + + if( c < 0 ) + c = 0; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous +#endif + +#ifndef STB_TEXTEDIT_MOVEWORDRIGHT +static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) +{ + const int len = STB_TEXTEDIT_STRINGLEN(str); + ++c; // always move at least one character + while( c < len && !is_word_boundary( str, c ) ) + ++c; + + if( c > len ) + c = len; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next +#endif + +#endif + +// update selection and cursor to match each other +static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) +{ + if (!STB_TEXT_HAS_SELECTION(state)) + state->select_start = state->select_end = state->cursor; + else + state->cursor = state->select_end; +} + +// API cut: delete selection +static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_delete_selection(str,state); // implicitly clamps + state->has_preferred_x = 0; + return 1; + } + return 0; +} + +// API paste: replace existing selection with passed-in text +static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +{ + // if there's a selection, the paste should delete it + stb_textedit_clamp(str, state); + stb_textedit_delete_selection(str,state); + // try to insert the characters + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { + stb_text_makeundo_insert(state, state->cursor, len); + state->cursor += len; + state->has_preferred_x = 0; + return 1; + } + // [DEAR IMGUI] + //// remove the undo since we didn't actually insert the characters + //if (state->undostate.undo_point) + // --state->undostate.undo_point; + // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) + return 0; +} + +#ifndef STB_TEXTEDIT_KEYTYPE +#define STB_TEXTEDIT_KEYTYPE int +#endif + +// API key: process a keyboard input +static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) +{ +retry: + switch (key) { + default: { + int c = STB_TEXTEDIT_KEYTOTEXT(key); + if (c > 0) { + STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; + + // can't add newline in single-line mode + if (c == '\n' && state->single_line) + break; + + if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { + stb_text_makeundo_replace(str, state, state->cursor, 1, 1); + STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + ++state->cursor; + state->has_preferred_x = 0; + } + } else { + stb_textedit_delete_selection(str,state); // implicitly clamps + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + stb_text_makeundo_insert(state, state->cursor, 1); + ++state->cursor; + state->has_preferred_x = 0; + } + } + } + break; + } + +#ifdef STB_TEXTEDIT_K_INSERT + case STB_TEXTEDIT_K_INSERT: + state->insert_mode = !state->insert_mode; + break; +#endif + + case STB_TEXTEDIT_K_UNDO: + stb_text_undo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_REDO: + stb_text_redo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT: + // if currently there's a selection, move cursor to start of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else + if (state->cursor > 0) + --state->cursor; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_RIGHT: + // if currently there's a selection, move cursor to end of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else + ++state->cursor; + stb_textedit_clamp(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + // move selection left + if (state->select_end > 0) + --state->select_end; + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_MOVEWORDLEFT + case STB_TEXTEDIT_K_WORDLEFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + +#ifdef STB_TEXTEDIT_MOVEWORDRIGHT + case STB_TEXTEDIT_K_WORDRIGHT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + + case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + // move selection right + ++state->select_end; + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_DOWN: + case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGDOWN: + case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; + int row_count = is_page ? state->row_count_per_page : 1; + + if (!is_page && state->single_line) { + // on windows, up&down in single-line behave like left&right + key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; + int start = find.first_char + find.length; + + if (find.length == 0) + break; + + // [DEAR IMGUI] + // going down while being on the last line shouldn't bring us to that line end + if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) + break; + + // now find character position down a row + state->cursor = start; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + + // go to next line + find.first_char = find.first_char + find.length; + find.length = row.num_chars; + } + break; + } + + case STB_TEXTEDIT_K_UP: + case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGUP: + case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; + int row_count = is_page ? state->row_count_per_page : 1; + + if (!is_page && state->single_line) { + // on windows, up&down become left&right + key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; + + // can only go up if there's a previous row + if (find.prev_first == find.first_char) + break; + + // now find character position up a row + state->cursor = find.prev_first; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + + // go to previous line + // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) + prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; + while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) + --prev_scan; + find.first_char = find.prev_first; + find.prev_first = prev_scan; + } + break; + } + + case STB_TEXTEDIT_K_DELETE: + case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + int n = STB_TEXTEDIT_STRINGLEN(str); + if (state->cursor < n) + stb_textedit_delete(str, state, state->cursor, 1); + } + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_BACKSPACE: + case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + stb_textedit_clamp(str, state); + if (state->cursor > 0) { + stb_textedit_delete(str, state, state->cursor-1, 1); + --state->cursor; + } + } + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2: +#endif + case STB_TEXTEDIT_K_TEXTSTART: + state->cursor = state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2: +#endif + case STB_TEXTEDIT_K_TEXTEND: + state->cursor = STB_TEXTEDIT_STRINGLEN(str); + state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); + state->has_preferred_x = 0; + break; + + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2: +#endif + case STB_TEXTEDIT_K_LINESTART: + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2: +#endif + case STB_TEXTEDIT_K_LINEEND: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->has_preferred_x = 0; + break; + } + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Undo processing +// +// @OPTIMIZE: the undo/redo buffer should be circular + +static void stb_textedit_flush_redo(StbUndoState *state) +{ + state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; +} + +// discard the oldest entry in the undo list +static void stb_textedit_discard_undo(StbUndoState *state) +{ + if (state->undo_point > 0) { + // if the 0th undo state has characters, clean those up + if (state->undo_rec[0].char_storage >= 0) { + int n = state->undo_rec[0].insert_length, i; + // delete n characters from all other records + state->undo_char_point -= n; + STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); + for (i=0; i < state->undo_point; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it + } + --state->undo_point; + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); + } +} + +// discard the oldest entry in the redo list--it's bad if this +// ever happens, but because undo & redo have to store the actual +// characters in different cases, the redo character buffer can +// fill up even though the undo buffer didn't +static void stb_textedit_discard_redo(StbUndoState *state) +{ + int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; + + if (state->redo_point <= k) { + // if the k'th undo state has characters, clean those up + if (state->undo_rec[k].char_storage >= 0) { + int n = state->undo_rec[k].insert_length, i; + // move the remaining redo character data to the end of the buffer + state->redo_char_point += n; + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + // adjust the position of all the other records to account for above memmove + for (i=state->redo_point; i < k; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage += n; + } + // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' + // [DEAR IMGUI] + size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); + const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; + const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; + IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); + IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); + + // now move redo_point to point to the new one + ++state->redo_point; + } +} + +static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) +{ + // any time we create a new undo record, we discard redo + stb_textedit_flush_redo(state); + + // if we have no free records, we have to make room, by sliding the + // existing records down + if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + stb_textedit_discard_undo(state); + + // if the characters to store won't possibly fit in the buffer, we can't undo + if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { + state->undo_point = 0; + state->undo_char_point = 0; + return NULL; + } + + // if we don't have enough free characters in the buffer, we have to make room + while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) + stb_textedit_discard_undo(state); + + return &state->undo_rec[state->undo_point++]; +} + +static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) +{ + StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); + if (r == NULL) + return NULL; + + r->where = pos; + r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; + r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; + + if (insert_len == 0) { + r->char_storage = -1; + return NULL; + } else { + r->char_storage = state->undo_char_point; + state->undo_char_point += insert_len; + return &state->undo_char[r->char_storage]; + } +} + +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord u, *r; + if (s->undo_point == 0) + return; + + // we need to do two things: apply the undo record, and create a redo record + u = s->undo_rec[s->undo_point-1]; + r = &s->undo_rec[s->redo_point-1]; + r->char_storage = -1; + + r->insert_length = u.delete_length; + r->delete_length = u.insert_length; + r->where = u.where; + + if (u.delete_length) { + // if the undo record says to delete characters, then the redo record will + // need to re-insert the characters that get deleted, so we need to store + // them. + + // there are three cases: + // there's enough room to store the characters + // characters stored for *redoing* don't leave room for redo + // characters stored for *undoing* don't leave room for redo + // if the last is true, we have to bail + + if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { + // the undo records take up too much character space; there's no space to store the redo characters + r->insert_length = 0; + } else { + int i; + + // there's definitely room to store the characters eventually + while (s->undo_char_point + u.delete_length > s->redo_char_point) { + // should never happen: + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + // there's currently not enough room, so discard a redo record + stb_textedit_discard_redo(s); + } + r = &s->undo_rec[s->redo_point-1]; + + r->char_storage = s->redo_char_point - u.delete_length; + s->redo_char_point = s->redo_char_point - u.delete_length; + + // now save the characters + for (i=0; i < u.delete_length; ++i) + s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); + } + + // now we can carry out the deletion + STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); + } + + // check type of recorded action: + if (u.insert_length) { + // easy case: was a deletion, so we need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); + s->undo_char_point -= u.insert_length; + } + + state->cursor = u.where + u.insert_length; + + s->undo_point--; + s->redo_point--; +} + +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord *u, r; + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + + // we need to do two things: apply the redo record, and create an undo record + u = &s->undo_rec[s->undo_point]; + r = s->undo_rec[s->redo_point]; + + // we KNOW there must be room for the undo record, because the redo record + // was derived from an undo record + + u->delete_length = r.insert_length; + u->insert_length = r.delete_length; + u->where = r.where; + u->char_storage = -1; + + if (r.delete_length) { + // the redo record requires us to delete characters, so the undo record + // needs to store the characters + + if (s->undo_char_point + u->insert_length > s->redo_char_point) { + u->insert_length = 0; + u->delete_length = 0; + } else { + int i; + u->char_storage = s->undo_char_point; + s->undo_char_point = s->undo_char_point + u->insert_length; + + // now save the characters + for (i=0; i < u->insert_length; ++i) + s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); + } + + STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); + } + + if (r.insert_length) { + // easy case: need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + s->redo_char_point += r.insert_length; + } + + state->cursor = r.where + r.insert_length; + + s->undo_point++; + s->redo_point++; +} + +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) +{ + stb_text_createundo(&state->undostate, where, 0, length); +} + +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); + if (p) { + for (i=0; i < length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); + if (p) { + for (i=0; i < old_length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +// reset the state to default +static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) +{ + state->undostate.undo_point = 0; + state->undostate.undo_char_point = 0; + state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; + state->select_end = state->select_start = 0; + state->cursor = 0; + state->has_preferred_x = 0; + state->preferred_x = 0; + state->cursor_at_end_of_line = 0; + state->initialized = 1; + state->single_line = (unsigned char) is_single_line; + state->insert_mode = 0; + state->row_count_per_page = 0; +} + +// API initialize +static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +{ + stb_textedit_clear_state(state, is_single_line); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) +{ + return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif//STB_TEXTEDIT_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/thirdparty/imgui/imstb_truetype.h b/thirdparty/imgui/imstb_truetype.h new file mode 100644 index 0000000..48c2026 --- /dev/null +++ b/thirdparty/imgui/imstb_truetype.h @@ -0,0 +1,4903 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_truetype.h 1.20. +// Mostly fixing for compiler and static analyzer warnings. +// Grep for [DEAR IMGUI] to find the changes. + +// stb_truetype.h - v1.20 - public domain +// authored from 2009-2016 by Sean Barrett / RAD Game Tools +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen +// Cass Everitt Martins Mozeiko +// stoiko (Haemimont Games) Cap Petschulat +// Brian Hook Omar Cornut +// Walter van Niftrik github:aloucks +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. github:oyvindjam +// Brian Costabile github:vassvik +// +// VERSION HISTORY +// +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours == -1) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else if (numberOfContours < 0) { + // @TODO other compound variations? + STBTT_assert(0); + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // fallthrough + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch(coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + } break; + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch(classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + + // [DEAR IMGUI] Commented to fix static analyzer warning + //classDefTable = classDef1ValueArray + 2 * glyphCount; + } break; + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + + // [DEAR IMGUI] Commented to fix static analyzer warning + //classDefTable = classRangeRecords + 6 * classRangeCount; + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + } break; + } + + return -1; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } break; + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + STBTT_assert(glyph1class < class1Count); + STBTT_assert(glyph2class < class2Count); + + // TODO: Support more formats. + STBTT_GPOS_TODO_assert(valueFormat1 == 4); + if (valueFormat1 != 4) return 0; + STBTT_GPOS_TODO_assert(valueFormat2 == 0); + if (valueFormat2 != 0) return 0; + + if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) { + stbtt_uint8 *class1Records = table + 16; + stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count); + stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } + } break; + + default: { + // There are no other cases. + STBTT_assert(0); + break; + } // [DEAR IMGUI] removed ; + } + } + break; + } // [DEAR IMGUI] removed ; + + default: + // TODO: Implement other stuff. + break; + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + + if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = sy1 - sy0; + STBTT_assert(x >= 0 && x < len); + scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height; + scanline_fill[x] += e->direction * height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + // [DEAR IMGUI] Fix static analyzer warning + (void)dx; // [ImGui: fix static analyzer warning] + } + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = (x1+1 - x0) * dy + y_top; + + sign = e->direction; + // area of the rectangle covered from y0..y_crossing + area = sign * (y_crossing-sy0); + // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) + scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2); + + step = sign * dy; + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; + area += step; + } + y_crossing += dy * (x2 - (x1+1)); + + STBTT_assert(STBTT_fabs(area) <= 1.01f); + + scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && spc->skip_missing) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value; // [DEAR IMGUI] removed = 1 + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + orig[0] = x; + //orig[1] = y; // [DEAR IMGUI] commented double assignment + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + c*x^2 + b*x + a = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + // if one scale is 0, use same scale for both + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) return NULL; // if both scales are 0, return NULL + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve + float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (verts[i].type == STBTT_vline) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3],px,py,t,it; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/thirdparty/jansson/CMakeLists.txt b/thirdparty/jansson/CMakeLists.txt new file mode 100644 index 0000000..2684d88 --- /dev/null +++ b/thirdparty/jansson/CMakeLists.txt @@ -0,0 +1,663 @@ +cmake_minimum_required (VERSION 3.1) +project(jansson C) + +# Options +option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF) +option(USE_URANDOM "Use /dev/urandom to seed the hash function." ON) +option(USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON) + +if (MSVC) + # This option must match the settings used in your program, in particular if you + # are linking statically + option(JANSSON_STATIC_CRT "Link the static CRT libraries" OFF ) +endif () + +option(JANSSON_EXAMPLES "Compile example applications" OFF) + +if (UNIX) + option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF) +endif () + +# Set some nicer output dirs. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(JANSSON_TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/tmp) + +# Give the debug version a different postfix for windows, +# so both the debug and release version can be built in the +# same build-tree on Windows (MSVC). +if (WIN32 AND NOT CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "_d") +endif() + +# This is how I thought it should go +# set (JANSSON_VERSION "2.3.1") +# set (JANSSON_SOVERSION 2) + +set(JANSSON_DISPLAY_VERSION "2.14") + +# This is what is required to match the same numbers as automake's +set(JANSSON_VERSION "4.14.0") +set(JANSSON_SOVERSION 4) + +# for CheckFunctionKeywords +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include (CheckCSourceCompiles) +include (CheckFunctionExists) +include (CheckFunctionKeywords) +include (CheckIncludeFiles) +include (CheckTypeSize) + +# suppress format-truncation warning +include (CheckCCompilerFlag) +check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION) +if (HAS_NO_FORMAT_TRUNCATION) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation") +endif() + +if (MSVC) + # Turn off Microsofts "security" warnings. + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" ) + + if (JANSSON_STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") + endif() +endif() + +message("C compiler: ${CMAKE_C_COMPILER_ID}") + +if (JANSSON_COVERAGE) + include(CodeCoverage) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endif() + +check_include_files (endian.h HAVE_ENDIAN_H) +check_include_files (fcntl.h HAVE_FCNTL_H) +check_include_files (sched.h HAVE_SCHED_H) +check_include_files (unistd.h HAVE_UNISTD_H) +check_include_files (sys/param.h HAVE_SYS_PARAM_H) +check_include_files (sys/stat.h HAVE_SYS_STAT_H) +check_include_files (sys/time.h HAVE_SYS_TIME_H) +check_include_files (sys/types.h HAVE_SYS_TYPES_H) + +check_function_exists (close HAVE_CLOSE) +check_function_exists (getpid HAVE_GETPID) +check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists (open HAVE_OPEN) +check_function_exists (read HAVE_READ) +check_function_exists (sched_yield HAVE_SCHED_YIELD) + +# Check for the int-type includes +check_include_files (stdint.h HAVE_STDINT_H) + +# Check our 64 bit integer sizes +check_type_size (__int64 __INT64) +check_type_size (int64_t INT64_T) +check_type_size ("long long" LONG_LONG_INT) + +# Check our 32 bit integer sizes +check_type_size (int32_t INT32_T) +check_type_size (__int32 __INT32) +check_type_size ("long" LONG_INT) +check_type_size ("int" INT) +if (HAVE_INT32_T) + set (JSON_INT32 int32_t) +elseif (HAVE___INT32) + set (JSON_INT32 __int32) +elseif (HAVE_LONG_INT AND (LONG_INT EQUAL 4)) + set (JSON_INT32 long) +elseif (HAVE_INT AND (INT EQUAL 4)) + set (JSON_INT32 int) +else () + message (FATAL_ERROR "Could not detect a valid 32-bit integer type") +endif () + +check_type_size ("unsigned long" UNSIGNED_LONG_INT) +check_type_size ("unsigned int" UNSIGNED_INT) +check_type_size ("unsigned short" UNSIGNED_SHORT) + +check_type_size (uint32_t UINT32_T) +check_type_size (__uint32 __UINT32) +if (HAVE_UINT32_T) + set (JSON_UINT32 uint32_t) +elseif (HAVE___UINT32) + set (JSON_UINT32 __uint32) +elseif (HAVE_UNSIGNED_LONG_INT AND (UNSIGNED_LONG_INT EQUAL 4)) + set (JSON_UINT32 "unsigned long") +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 4)) + set (JSON_UINT32 "unsigned int") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type") +endif () + +check_type_size (uint16_t UINT16_T) +check_type_size (__uint16 __UINT16) +if (HAVE_UINT16_T) + set (JSON_UINT16 uint16_t) +elseif (HAVE___UINT16) + set (JSON_UINT16 __uint16) +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 2)) + set (JSON_UINT16 "unsigned int") +elseif (HAVE_UNSIGNED_SHORT AND (UNSIGNED_SHORT EQUAL 2)) + set (JSON_UINT16 "unsigned short") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type") +endif () + +check_type_size (uint8_t UINT8_T) +check_type_size (__uint8 __UINT8) +if (HAVE_UINT8_T) + set (JSON_UINT8 uint8_t) +elseif (HAVE___UINT8) + set (JSON_UINT8 __uint8) +else () + set (JSON_UINT8 "unsigned char") +endif () + +# Check for ssize_t and SSIZE_T existence. +check_type_size(ssize_t SSIZE_T) +check_type_size(SSIZE_T UPPERCASE_SSIZE_T) +if(NOT HAVE_SSIZE_T) + if(HAVE_UPPERCASE_SSIZE_T) + set(JSON_SSIZE SSIZE_T) + else() + set(JSON_SSIZE int) + endif() +endif() +set(CMAKE_EXTRA_INCLUDE_FILES "") + +# Check for all the variants of strtoll +check_function_exists (strtoll HAVE_STRTOLL) +check_function_exists (strtoq HAVE_STRTOQ) +check_function_exists (_strtoi64 HAVE__STRTOI64) + +# Figure out what variant we should use +if (HAVE_STRTOLL) + set (JSON_STRTOINT strtoll) +elseif (HAVE_STRTOQ) + set (JSON_STRTOINT strtoq) +elseif (HAVE__STRTOI64) + set (JSON_STRTOINT _strtoi64) +else () + # fallback to strtol (32 bit) + # this will set all the required variables + set (JSON_STRTOINT strtol) + set (JSON_INT_T long) + set (JSON_INTEGER_FORMAT "\"ld\"") +endif () + +# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function. +# detect what to use for the 64 bit type. +# Note: I will prefer long long if I can get it, as that is what the automake system aimed for. +if (NOT DEFINED JSON_INT_T) + if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8)) + set (JSON_INT_T "long long") + elseif (HAVE_INT64_T) + set (JSON_INT_T int64_t) + elseif (HAVE___INT64) + set (JSON_INT_T __int64) + else () + message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent") + endif () + + # Apparently, Borland BCC and MSVC wants I64d, + # Borland BCC could also accept LD + # and gcc wants ldd, + # I am not sure what cygwin will want, so I will assume I64d + + if (WIN32) # matches both msvc and cygwin + set (JSON_INTEGER_FORMAT "\"I64d\"") + else () + set (JSON_INTEGER_FORMAT "\"lld\"") + endif () +endif () + + +# If locale.h and localeconv() are available, define to 1, otherwise to 0. +check_include_files (locale.h HAVE_LOCALE_H) +check_function_exists (localeconv HAVE_LOCALECONV) + +if (HAVE_LOCALECONV AND HAVE_LOCALE_H) + set (JSON_HAVE_LOCALECONV 1) +else () + set (JSON_HAVE_LOCALECONV 0) +endif() + +# check if we have setlocale +check_function_exists(setlocale HAVE_SETLOCALE) + +# Check what the inline keyword is. +# Note that the original JSON_INLINE was always set to just 'inline', so this goes further. +check_function_keywords("inline") +check_function_keywords("__inline") +check_function_keywords("__inline__") + +if (HAVE_INLINE) + set(JSON_INLINE inline) +elseif (HAVE___INLINE) + set(JSON_INLINE __inline) +elseif (HAVE___INLINE__) + set(JSON_INLINE __inline__) +else() + # no inline on this platform + set (JSON_INLINE) +endif() + +check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS) +check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS) + +if (HAVE_SYNC_BUILTINS) + set(JSON_HAVE_SYNC_BUILTINS 1) +else() + set(JSON_HAVE_SYNC_BUILTINS 0) +endif() + +if (HAVE_ATOMIC_BUILTINS) + set(JSON_HAVE_ATOMIC_BUILTINS 1) +else() + set(JSON_HAVE_ATOMIC_BUILTINS 0) +endif() + +set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.") + +# configure the public config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + +add_definitions(-DJANSSON_USING_CMAKE) + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +# and tell the source code to include it +add_definitions(-DHAVE_CONFIG_H) + +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) + +# Add the lib sources. +file(GLOB JANSSON_SRC src/*.c) + +set(JANSSON_HDR_PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_private.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/strbuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +set(JANSSON_HDR_PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h) + +source_group("Library Sources" FILES ${JANSSON_SRC}) +source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE}) +source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC}) + +if(JANSSON_BUILD_SHARED_LIBS) + add_library(jansson SHARED + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC} + src/jansson.def) + +# check if linker support --default-symver + list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver") + check_c_source_compiles( + " + int main (void) + { + return 0; + } + " + DSYMVER_WORKS + ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver") + + if (SYMVER_WORKS) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--default-symver") + else() +# some linkers may only support --version-script + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/jansson.sym" "JANSSON_${JANSSON_SOVERSION} { + global: + *; +}; +") + list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + check_c_source_compiles( + " + int main (void) + { + return 0; + } + " + VSCRIPT_WORKS + ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + if (VSCRIPT_WORKS) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + endif() + endif() + + set_target_properties(jansson PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) +else() + add_library(jansson STATIC + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC}) + set_target_properties(jansson PROPERTIES + POSITION_INDEPENDENT_CODE true) +endif() + +if (JANSSON_EXAMPLES) + add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c") + target_link_libraries(simple_parse jansson) +endif() + +# For building Documentation (uses Sphinx) +option(JANSSON_BUILD_DOCS "Build documentation (uses python-sphinx)." OFF) +if (JANSSON_BUILD_DOCS) + find_package(Sphinx) + + if (NOT SPHINX_FOUND) + message(WARNING "Sphinx not found. Cannot generate documentation! + Set -DJANSSON_BUILD_DOCS=OFF to get rid of this message.") + else() + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Your Sphinx version is too old! + This project requires Sphinx v1.0 or above to produce + proper documentation (you have v${Sphinx_VERSION_STRING}). + You will get output but it will have errors.") + endif() + + # configured documentation tools and intermediate build results + set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") + + # Sphinx cache with pickled ReST documents + set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") + + # CMake could be used to build the conf.py file too, + # eg it could automatically write the version of the program or change the theme. + # if(NOT DEFINED SPHINX_THEME) + # set(SPHINX_THEME default) + # endif() + # + # if(NOT DEFINED SPHINX_THEME_DIR) + # set(SPHINX_THEME_DIR) + # endif() + # + # configure_file( + # "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + # "${BINARY_BUILD_DIR}/conf.py" + # @ONLY) + + # TODO: Add support for all sphinx builders: http://sphinx-doc.org/builders.html + + # Add documentation targets. + set(DOC_TARGETS html) + + option(JANSSON_BUILD_MAN "Create a target for building man pages." ON) + + if (JANSSON_BUILD_MAN) + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.") + else() + list(APPEND DOC_TARGETS man) + endif() + endif() + + option(JANSSON_BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF) + + if (JANSSON_BUILD_LATEX) + find_package(LATEX) + + if (NOT LATEX_COMPILER) + message("Couldn't find Latex, can't build latex docs using Sphinx") + else() + message("Latex found! If you have problems building, see Sphinx documentation for required Latex packages.") + list(APPEND DOC_TARGETS latex) + endif() + endif() + + # The doc target will build all documentation targets. + add_custom_target(doc) + + foreach (DOC_TARGET ${DOC_TARGETS}) + add_custom_target(${DOC_TARGET} + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b ${DOC_TARGET} + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${CMAKE_CURRENT_BINARY_DIR}/doc/${DOC_TARGET}" + COMMENT "Building ${DOC_TARGET} documentation with Sphinx") + + add_dependencies(doc ${DOC_TARGET}) + endforeach() + + message("Building documentation enabled for: ${DOC_TARGETS}") + endif() +endif () + + +option(JANSSON_WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" ON) + +if (NOT JANSSON_WITHOUT_TESTS) + option(JANSSON_TEST_WITH_VALGRIND "Enable valgrind tests." OFF) + + ENABLE_TESTING() + + if (JANSSON_TEST_WITH_VALGRIND) + # TODO: Add FindValgrind.cmake instead of having a hardcoded path. + + add_definitions(-DVALGRIND) + + # enable valgrind + set(CMAKE_MEMORYCHECK_COMMAND valgrind) + set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS + "--error-exitcode=1 --leak-check=full --show-reachable=yes --track-origins=yes -q") + + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") + separate_arguments(MEMCHECK_COMMAND) + endif () + + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement) + endif () + + set(api_tests + test_array + test_chaos + test_copy + test_dump + test_dump_callback + test_equal + test_fixed_size + test_load + test_load_callback + test_loadb + test_number + test_object + test_pack + test_simple + test_sprintf + test_unpack) + + # Doing arithmetic on void pointers is not allowed by Microsofts compiler + # such as secure_malloc and secure_free is doing, so exclude it for now. + if (NOT MSVC) + list(APPEND api_tests test_memory_funcs) + endif() + + # Helper macro for building and linking a test program. + macro(build_testprog name dir) + add_executable(${name} ${dir}/${name}.c) + add_dependencies(${name} jansson) + target_link_libraries(${name} jansson) + endmacro(build_testprog) + + # Create executables and tests/valgrind tests for API tests. + foreach (test ${api_tests}) + build_testprog(${test} ${CMAKE_CURRENT_SOURCE_DIR}/test/suites/api) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${test} + ${MEMCHECK_COMMAND} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + else() + add_test(${test} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + endif () + endforeach () + + # Test harness for the suites tests. + build_testprog(json_process ${CMAKE_CURRENT_SOURCE_DIR}/test/bin) + + set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process) + set(SUITES encoding-flags valid invalid invalid-unicode) + foreach (SUITE ${SUITES}) + file(GLOB TESTDIRS test/suites/${SUITE}/*) + + foreach (TESTDIR ${TESTDIRS}) + if (IS_DIRECTORY ${TESTDIR}) + get_filename_component(TNAME ${TESTDIR} NAME) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME} + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME} + ${SUITE_TEST_CMD} ${TESTDIR}) + endif() + + if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip) + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME}__strip + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} --strip ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME}__strip + ${SUITE_TEST_CMD} --strip ${TESTDIR}) + endif() + endif () + endif () + endforeach () + endforeach () + + if (JANSSON_COVERAGE) + SETUP_TARGET_FOR_COVERAGE(coverage coverage ctest) + endif () + + # Enable using "make check" just like the autotools project. + # By default cmake creates a target "make test" + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS json_process ${api_tests}) +endif () + +# +# Installation preparation. +# + +# Allow the user to override installation directories. +set(JANSSON_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set(JANSSON_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set(JANSSON_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +if(WIN32 AND NOT CYGWIN) + set(DEF_INSTALL_CMAKE_DIR cmake) +else() + set(DEF_INSTALL_CMAKE_DIR lib/cmake/jansson) +endif() + +set(JANSSON_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") + +# Create pkg-conf file. +# (We use the same files as ./configure does, so we +# have to defined the same variables used there). +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix "\${prefix}") +set(libdir "\${exec_prefix}/${JANSSON_INSTALL_LIB_DIR}") +set(includedir "\${prefix}/${JANSSON_INSTALL_INCLUDE_DIR}") +set(VERSION ${JANSSON_DISPLAY_VERSION}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY) + +# Make sure the paths are relative. +foreach(p LIB BIN INCLUDE CMAKE) + set(var JANSSON_INSTALL_${p}_DIR) +endforeach() + +# Generate the config file for the build-tree. +set(JANSSON__INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include") +set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake + @ONLY) + + +# Generate the config file for the installation tree. +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake" + VERSION ${JANSSON_VERSION} + COMPATIBILITY ExactVersion +) + +configure_package_config_file( + "cmake/janssonConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake" + INSTALL_DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" +) + +# +# Install targets. +# +option(JANSSON_INSTALL "Generate installation target" OFF) +if (JANSSON_INSTALL) + install(TARGETS jansson + EXPORT janssonTargets + LIBRARY DESTINATION "lib" + ARCHIVE DESTINATION "lib" + RUNTIME DESTINATION "bin" + INCLUDES DESTINATION "include") + + install(FILES ${JANSSON_HDR_PUBLIC} + DESTINATION "include") + + # Install the pkg-config. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc + DESTINATION lib/pkgconfig) + + # Install the configs. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") + + # Install exports for the install-tree. + install(EXPORT janssonTargets + NAMESPACE jansson:: + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") +endif() + +# For use when simply using add_library from a parent project to build jansson. +set(JANSSON_LIBRARIES jansson CACHE STRING "jansson libraries") +set_target_properties(jansson PROPERTIES FOLDER "thirdparty") diff --git a/thirdparty/jansson/LICENSE b/thirdparty/jansson/LICENSE new file mode 100644 index 0000000..483459c --- /dev/null +++ b/thirdparty/jansson/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009-2020 Petri Lehtinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/thirdparty/jansson/cmake/CheckFunctionKeywords.cmake b/thirdparty/jansson/cmake/CheckFunctionKeywords.cmake new file mode 100644 index 0000000..44601fd --- /dev/null +++ b/thirdparty/jansson/cmake/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/thirdparty/jansson/cmake/CodeCoverage.cmake b/thirdparty/jansson/cmake/CodeCoverage.cmake new file mode 100644 index 0000000..3a21d3d --- /dev/null +++ b/thirdparty/jansson/cmake/CodeCoverage.cmake @@ -0,0 +1,163 @@ +# +# Boost Software License - Version 1.0 - August 17th, 2003 +# +# Permission is hereby granted, free of charge, to any person or organization +# obtaining a copy of the software and accompanying documentation covered by +# this license (the "Software") to use, reproduce, display, distribute, +# execute, and transmit the Software, and to prepare derivative works of the +# Software, and to permit third-parties to whom the Software is furnished to +# do so, all subject to the following: +# +# The copyright notices in the Software and this entire statement, including +# the above license grant, this restriction and the following disclaimer, +# must be included in all copies of the Software, in whole or in part, and +# all derivative works of the Software, unless such copies or derivative +# works are solely in the form of machine-executable object code generated by +# a source language processor. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# USAGE: +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt: +# INCLUDE(CodeCoverage) +# +# 3. Set compiler flags to turn off optimization and enable coverage: +# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# +# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target +# which runs your test executable and produces a lcov code coverage report: +# Example: +# SETUP_TARGET_FOR_COVERAGE( +# my_coverage_target # Name for custom target. +# test_driver # Name of the test driver executable that runs the tests. +# # NOTE! This should always have a ZERO as exit code +# # otherwise the coverage generation will not complete. +# coverage # Name of output directory. +# ) +# +# 4. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# +# + +# Check prereqs +FIND_PROGRAM( GCOV_PATH gcov ) +FIND_PROGRAM( LCOV_PATH lcov ) +FIND_PROGRAM( GENHTML_PATH genhtml ) +FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) + +IF(NOT GCOV_PATH) + MESSAGE(FATAL_ERROR "gcov not found! Aborting...") +ENDIF() # NOT GCOV_PATH + +IF(NOT (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)) + # Clang version 3.0.0 and greater now supports gcov as well. + MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") + + IF(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + MESSAGE(FATAL_ERROR "Compiler is not GNU gcc or Clang! Aborting...") + ENDIF() +ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX + +IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) + MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) +ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" + + +# Param _targetname The name of new the custom make target +# Param _outputname lcov output is generated as _outputname.info +# HTML report is generated in _outputname/index.html +# Param _testrunner The name of the target which runs the tests. +# MUST return ZERO always, even on errors. +# If not, no coverage report will be created! +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner) + + IF(NOT LCOV_PATH) + MESSAGE(FATAL_ERROR "lcov not found! Aborting...") + ENDIF() # NOT LCOV_PATH + + IF(NOT GENHTML_PATH) + MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") + ENDIF() # NOT GENHTML_PATH + + # Setup target + ADD_CUSTOM_TARGET(${_targetname} + + # Cleanup lcov + ${LCOV_PATH} --directory . --zerocounters + + # Run tests + COMMAND ${_testrunner} ${ARGV3} + + # Capturing lcov counters and generating report + COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1 + COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info --rc lcov_branch_coverage=1 + # COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned + # COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned + + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE + +# Param _targetname The name of new the custom make target +# Param _testrunner The name of the target which runs the tests +# Param _outputname cobertura output is generated as _outputname.xml +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) + + IF(NOT PYTHON_EXECUTABLE) + MESSAGE(FATAL_ERROR "Python not found! Aborting...") + ENDIF() # NOT PYTHON_EXECUTABLE + + IF(NOT GCOVR_PATH) + MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") + ENDIF() # NOT GCOVR_PATH + + ADD_CUSTOM_TARGET(${_targetname} + + # Run tests + ${_testrunner} ${ARGV3} + + # Running gcovr + COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA + diff --git a/thirdparty/jansson/cmake/FindSphinx.cmake b/thirdparty/jansson/cmake/FindSphinx.cmake new file mode 100644 index 0000000..3bf0a5d --- /dev/null +++ b/thirdparty/jansson/cmake/FindSphinx.cmake @@ -0,0 +1,315 @@ +# +# PART B. DOWNLOADING AGREEMENT - LICENSE FROM SBIA WITH RIGHT TO SUBLICENSE ("SOFTWARE LICENSE"). +# ------------------------------------------------------------------------------------------------ +# +# 1. As used in this Software License, "you" means the individual downloading and/or +# using, reproducing, modifying, displaying and/or distributing the Software and +# the institution or entity which employs or is otherwise affiliated with such +# individual in connection therewith. The Section of Biomedical Image Analysis, +# Department of Radiology at the Universiy of Pennsylvania ("SBIA") hereby grants +# you, with right to sublicense, with respect to SBIA's rights in the software, +# and data, if any, which is the subject of this Software License (collectively, +# the "Software"), a royalty-free, non-exclusive license to use, reproduce, make +# derivative works of, display and distribute the Software, provided that: +# (a) you accept and adhere to all of the terms and conditions of this Software +# License; (b) in connection with any copy of or sublicense of all or any portion +# of the Software, all of the terms and conditions in this Software License shall +# appear in and shall apply to such copy and such sublicense, including without +# limitation all source and executable forms and on any user documentation, +# prefaced with the following words: "All or portions of this licensed product +# (such portions are the "Software") have been obtained under license from the +# Section of Biomedical Image Analysis, Department of Radiology at the University +# of Pennsylvania and are subject to the following terms and conditions:" +# (c) you preserve and maintain all applicable attributions, copyright notices +# and licenses included in or applicable to the Software; (d) modified versions +# of the Software must be clearly identified and marked as such, and must not +# be misrepresented as being the original Software; and (e) you consider making, +# but are under no obligation to make, the source code of any of your modifications +# to the Software freely available to others on an open source basis. +# +# 2. The license granted in this Software License includes without limitation the +# right to (i) incorporate the Software into proprietary programs (subject to +# any restrictions applicable to such programs), (ii) add your own copyright +# statement to your modifications of the Software, and (iii) provide additional +# or different license terms and conditions in your sublicenses of modifications +# of the Software; provided that in each case your use, reproduction or +# distribution of such modifications otherwise complies with the conditions +# stated in this Software License. +# +# 3. This Software License does not grant any rights with respect to third party +# software, except those rights that SBIA has been authorized by a third +# party to grant to you, and accordingly you are solely responsible for +# (i) obtaining any permissions from third parties that you need to use, +# reproduce, make derivative works of, display and distribute the Software, +# and (ii) informing your sublicensees, including without limitation your +# end-users, of their obligations to secure any such required permissions. +# +# 4. The Software has been designed for research purposes only and has not been +# reviewed or approved by the Food and Drug Administration or by any other +# agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL APPLICATIONS ARE NEITHER +# RECOMMENDED NOR ADVISED. Any commercialization of the Software is at the +# sole risk of the party or parties engaged in such commercialization. +# You further agree to use, reproduce, make derivative works of, display +# and distribute the Software in compliance with all applicable governmental +# laws, regulations and orders, including without limitation those relating +# to export and import control. +# +# 5. The Software is provided "AS IS" and neither SBIA nor any contributor to +# the software (each a "Contributor") shall have any obligation to provide +# maintenance, support, updates, enhancements or modifications thereto. +# SBIA AND ALL CONTRIBUTORS SPECIFICALLY DISCLAIM ALL EXPRESS AND IMPLIED +# WARRANTIES OF ANY KIND INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL SBIA OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR +# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED +# TO THE SOFTWARE, EVEN IF SBIA OR ANY CONTRIBUTOR HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT NOT PROHIBITED BY LAW OR +# REGULATION, YOU FURTHER ASSUME ALL LIABILITY FOR YOUR USE, REPRODUCTION, +# MAKING OF DERIVATIVE WORKS, DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE +# AND AGREE TO INDEMNIFY AND HOLD HARMLESS SBIA AND ALL CONTRIBUTORS FROM +# AND AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS ARISING +# THEREFROM. +# +# 6. None of the names, logos or trademarks of SBIA or any of SBIA's affiliates +# or any of the Contributors, or any funding agency, may be used to endorse +# or promote products produced in whole or in part by operation of the Software +# or derived from or based on the Software without specific prior written +# permission from the applicable party. +# +# 7. Any use, reproduction or distribution of the Software which is not in accordance +# with this Software License shall automatically revoke all rights granted to you +# under this Software License and render Paragraphs 1 and 2 of this Software +# License null and void. +# +# 8. This Software License does not grant any rights in or to any intellectual +# property owned by SBIA or any Contributor except those rights expressly +# granted hereunder. +# +# +# PART C. MISCELLANEOUS +# --------------------- +# +# This Agreement shall be governed by and construed in accordance with the laws +# of The Commonwealth of Pennsylvania without regard to principles of conflicts +# of law. This Agreement shall supercede and replace any license terms that you +# may have agreed to previously with respect to Software from SBIA. +# +############################################################################## +# @file FindSphinx.cmake +# @brief Find Sphinx documentation build tools. +# +# @par Input variables: +# +# +# @tp @b Sphinx_DIR @endtp +# +# +# +# @tp @b SPHINX_DIR @endtp +# +# +# +# @tp @b Sphinx_FIND_COMPONENTS @endtp +# +# +#
Installation directory of Sphinx tools. Can also be set as environment variable.
Alternative environment variable for @c Sphinx_DIR.
Sphinx build tools to look for, i.e., 'apidoc' and/or 'build'.
+# +# @par Output variables: +# +# +# @tp @b Sphinx_FOUND @endtp +# +# +# +# @tp @b SPHINX_FOUND @endtp +# +# +# @tp @b SPHINX_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_OPTIONS @endtp +# +# +# +# @tp @b Sphinx-build_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx-apidoc_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_VERSION_STRING @endtp +# +# +# +# @tp @b Sphinx_VERSION_MAJOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_MINOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_PATCH @endtp +# +# +#
Whether all or only the requested Sphinx build tools were found.
Alias for @c Sphinx_FOUND. +#
Non-cached alias for @c Sphinx-build_EXECUTABLE.
Python executable used to run sphinx-build. This is either the +# by default found Python interpreter or a specific version as +# specified by the shebang (#!) of the sphinx-build script.
A list of Python options extracted from the shebang (#!) of the +# sphinx-build script. The -E option is added by this module +# if the Python executable is not the system default to avoid +# problems with a differing setting of the @c PYTHONHOME.
Absolute path of the found sphinx-build tool.
Absolute path of the found sphinx-apidoc tool.
Sphinx version found e.g. 1.1.2.
Sphinx major version found e.g. 1.
Sphinx minor version found e.g. 1.
Sphinx patch version found e.g. 2.
+# +# @ingroup CMakeFindModules +############################################################################## + +set (_Sphinx_REQUIRED_VARS) + +# ---------------------------------------------------------------------------- +# initialize search +if (NOT Sphinx_DIR) + if (NOT $ENV{Sphinx_DIR} STREQUAL "") + set (Sphinx_DIR "$ENV{Sphinx_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + else () + set (Sphinx_DIR "$ENV{SPHINX_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + endif () +endif () + +# ---------------------------------------------------------------------------- +# default components to look for +if (NOT Sphinx_FIND_COMPONENTS) + set (Sphinx_FIND_COMPONENTS "build") +elseif (NOT Sphinx_FIND_COMPONENTS MATCHES "^(build|apidoc)$") + message (FATAL_ERROR "Invalid Sphinx component in: ${Sphinx_FIND_COMPONENTS}") +endif () + +# ---------------------------------------------------------------------------- +# find components, i.e., build tools +foreach (_Sphinx_TOOL IN LISTS Sphinx_FIND_COMPONENTS) + if (Sphinx_DIR) + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + HINTS "${Sphinx_DIR}" + PATH_SUFFIXES bin + DOC "The sphinx-${_Sphinx_TOOL} Python script." + NO_DEFAULT_PATH + ) + else () + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + DOC "The sphinx-${_Sphinx_TOOL} Python script." + ) + endif () + mark_as_advanced (Sphinx-${_Sphinx_TOOL}_EXECUTABLE) + list (APPEND _Sphinx_REQUIRED_VARS Sphinx-${_Sphinx_TOOL}_EXECUTABLE) +endforeach () + +# ---------------------------------------------------------------------------- +# determine Python executable used by Sphinx +if (Sphinx-build_EXECUTABLE) + # extract python executable from shebang of sphinx-build + find_package (PythonInterp QUIET) + set (Sphinx_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") + set (Sphinx_PYTHON_OPTIONS) + file (STRINGS "${Sphinx-build_EXECUTABLE}" FIRST_LINE LIMIT_COUNT 1) + if (FIRST_LINE MATCHES "^#!(.*/python.*)") # does not match "#!/usr/bin/env python" ! + string (REGEX REPLACE "^ +| +$" "" Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + if (Sphinx_PYTHON_EXECUTABLE MATCHES "([^ ]+) (.*)") + set (Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + string (REGEX REPLACE " +" ";" Sphinx_PYTHON_OPTIONS "${CMAKE_MATCH_2}") + endif () + endif () + # this is done to avoid problems with multiple Python versions being installed + # remember: CMake command if(STR EQUAL STR) is bad and may cause many troubles ! + string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" _Sphinx_PYTHON_EXECUTABLE_RE "${PYTHON_EXECUTABLE}") + list (FIND Sphinx_PYTHON_OPTIONS -E IDX) + if (IDX EQUAL -1 AND NOT Sphinx_PYTHON_EXECUTABLE MATCHES "^${_Sphinx_PYTHON_EXECUTABLE_RE}$") + list (INSERT Sphinx_PYTHON_OPTIONS 0 -E) + endif () + unset (_Sphinx_PYTHON_EXECUTABLE_RE) +endif () + +# ---------------------------------------------------------------------------- +# determine Sphinx version +# some quick experiments by @ploxiln +# - sphinx 1.7 and later have the version output format like "sphinx-build 1.7.2" +# - sphinx 1.2 through 1.6 have the version output format like "Sphinx (sphinx-build) 1.2.2" +# - sphinx 1.1 and before do not have a "--version" flag, but it causes the help output like "-h" does which includes version like "Sphinx v1.0.2" +if (Sphinx-build_EXECUTABLE) + # intentionally use invalid -h option here as the help that is shown then + # will include the Sphinx version information + if (Sphinx_PYTHON_EXECUTABLE) + execute_process ( + COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" --version + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + elseif (UNIX) + execute_process ( + COMMAND "${Sphinx-build_EXECUTABLE}" --version + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + endif () + + # The sphinx version can also contain a "b" instead of the last dot. + # For example "Sphinx v1.2b1" or "Sphinx 1.7.0b2" so we cannot just split on "." + if (_Sphinx_VERSION MATCHES "sphinx-build ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + elseif (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + elseif (_Sphinx_VERSION MATCHES "Sphinx \\(sphinx-build\\) ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + endif () +endif () + +if(_SPHINX_VERSION_FOUND) + string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING}) + + # v1.2.0 -> v1.2 + if (Sphinx_VERSION_PATCH EQUAL 0) + string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}") + endif () +endif () + +# ---------------------------------------------------------------------------- +# compatibility with FindPythonInterp.cmake and FindPerl.cmake +set (SPHINX_EXECUTABLE "${Sphinx-build_EXECUTABLE}") + +# ---------------------------------------------------------------------------- +# handle the QUIETLY and REQUIRED arguments and set SPHINX_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( + Sphinx + REQUIRED_VARS + ${_Sphinx_REQUIRED_VARS} +# VERSION_VAR # This isn't available until CMake 2.8.8 so don't use it. + Sphinx_VERSION_STRING +) + +# ---------------------------------------------------------------------------- +# set Sphinx_DIR +if (NOT Sphinx_DIR AND Sphinx-build_EXECUTABLE) + get_filename_component (Sphinx_DIR "${Sphinx-build_EXECUTABLE}" PATH) + string (REGEX REPLACE "/bin/?" "" Sphinx_DIR "${Sphinx_DIR}") + set (Sphinx_DIR "${Sphinx_DIR}" CACHE PATH "Installation directory of Sphinx tools." FORCE) +endif () + +unset (_Sphinx_VERSION) +unset (_Sphinx_REQUIRED_VARS) \ No newline at end of file diff --git a/thirdparty/jansson/cmake/janssonConfig.cmake.in b/thirdparty/jansson/cmake/janssonConfig.cmake.in new file mode 100644 index 0000000..abd6793 --- /dev/null +++ b/thirdparty/jansson/cmake/janssonConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/thirdparty/jansson/cmake/jansson_config.h.cmake b/thirdparty/jansson/cmake/jansson_config.h.cmake new file mode 100644 index 0000000..2f248cb --- /dev/null +++ b/thirdparty/jansson/cmake/jansson_config.h.cmake @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @JSON_INLINE@ +#endif + + +#define json_int_t @JSON_INT_T@ +#define json_strtoint @JSON_STRTOINT@ +#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/thirdparty/jansson/cmake/jansson_private_config.h.cmake b/thirdparty/jansson/cmake/jansson_private_config.h.cmake new file mode 100644 index 0000000..b7c4514 --- /dev/null +++ b/thirdparty/jansson/cmake/jansson_private_config.h.cmake @@ -0,0 +1,53 @@ +#cmakedefine HAVE_ENDIAN_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_SCHED_H 1 +#cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_SYS_PARAM_H 1 +#cmakedefine HAVE_SYS_STAT_H 1 +#cmakedefine HAVE_SYS_TIME_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_STDINT_H 1 + +#cmakedefine HAVE_CLOSE 1 +#cmakedefine HAVE_GETPID 1 +#cmakedefine HAVE_GETTIMEOFDAY 1 +#cmakedefine HAVE_OPEN 1 +#cmakedefine HAVE_READ 1 +#cmakedefine HAVE_SCHED_YIELD 1 + +#cmakedefine HAVE_SYNC_BUILTINS 1 +#cmakedefine HAVE_ATOMIC_BUILTINS 1 + +#cmakedefine HAVE_LOCALE_H 1 +#cmakedefine HAVE_SETLOCALE 1 + +#cmakedefine HAVE_INT32_T 1 +#ifndef HAVE_INT32_T +# define int32_t @JSON_INT32@ +#endif + +#cmakedefine HAVE_UINT32_T 1 +#ifndef HAVE_UINT32_T +# define uint32_t @JSON_UINT32@ +#endif + +#cmakedefine HAVE_UINT16_T 1 +#ifndef HAVE_UINT16_T +# define uint16_t @JSON_UINT16@ +#endif + +#cmakedefine HAVE_UINT8_T 1 +#ifndef HAVE_UINT8_T +# define uint8_t @JSON_UINT8@ +#endif + +#cmakedefine HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t @JSON_SSIZE@ +#endif + +#cmakedefine USE_URANDOM 1 +#cmakedefine USE_WINDOWS_CRYPTOAPI 1 + +#define INITIAL_HASHTABLE_ORDER @JANSSON_INITIAL_HASHTABLE_ORDER@ diff --git a/thirdparty/jansson/jansson.pc.in b/thirdparty/jansson/jansson.pc.in new file mode 100644 index 0000000..69c9a43 --- /dev/null +++ b/thirdparty/jansson/jansson.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Jansson +Description: Library for encoding, decoding and manipulating JSON data +Version: @VERSION@ +Libs: -L${libdir} -ljansson +Cflags: -I${includedir} diff --git a/thirdparty/jansson/scripts/clang-format b/thirdparty/jansson/scripts/clang-format new file mode 100644 index 0000000..d46056c --- /dev/null +++ b/thirdparty/jansson/scripts/clang-format @@ -0,0 +1,3 @@ +#!/bin/bash + +find . -type f -a '(' -name '*.c' -o -name '*.h' ')' | xargs clang-format -i diff --git a/thirdparty/jansson/scripts/clang-format-check b/thirdparty/jansson/scripts/clang-format-check new file mode 100644 index 0000000..983e55d --- /dev/null +++ b/thirdparty/jansson/scripts/clang-format-check @@ -0,0 +1,27 @@ +#!/bin/bash + +CLANG_FORMAT=${CLANG_FORMAT:-clang-format} +CLANG_FORMAT_VERSION=${CLANG_FORMAT_VERSION:-} + +if ! type $CLANG_FORMAT >/dev/null || \ + ! $CLANG_FORMAT --version | grep -q "version ${CLANG_FORMAT_VERSION}"; then + # If running tests, mark this test as skipped. + exit 77 +fi + +errors=0 +paths=$(git ls-files | grep '\.[ch]$') +for path in $paths; do + in=$(cat $path) + out=$($CLANG_FORMAT $path) + + if [ "$in" != "$out" ]; then + diff -u -L $path -L "$path.formatted" $path - <<<$out + errors=1 + fi +done + +if [ $errors -ne 0 ]; then + echo "Formatting errors detected, run ./scripts/clang-format to fix!" + exit 1 +fi diff --git a/thirdparty/jansson/src/Makefile.am b/thirdparty/jansson/src/Makefile.am new file mode 100644 index 0000000..63eda32 --- /dev/null +++ b/thirdparty/jansson/src/Makefile.am @@ -0,0 +1,30 @@ +EXTRA_DIST = jansson.def + +include_HEADERS = jansson.h +nodist_include_HEADERS = jansson_config.h + +lib_LTLIBRARIES = libjansson.la +libjansson_la_SOURCES = \ + dump.c \ + error.c \ + hashtable.c \ + hashtable.h \ + hashtable_seed.c \ + jansson_private.h \ + load.c \ + lookup3.h \ + memory.c \ + pack_unpack.c \ + strbuffer.c \ + strbuffer.h \ + strconv.c \ + utf.c \ + utf.h \ + value.c \ + version.c +libjansson_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^json_|^jansson_' \ + -version-info 18:0:14 \ + @JSON_SYMVER_LDFLAGS@ \ + @JSON_BSYMBOLIC_LDFLAGS@ diff --git a/thirdparty/jansson/src/dump.c b/thirdparty/jansson/src/dump.c new file mode 100644 index 0000000..dae7b4c --- /dev/null +++ b/thirdparty/jansson/src/dump.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define MAX_INTEGER_STR_LENGTH 100 +#define MAX_REAL_STR_LENGTH 100 + +#define FLAGS_TO_INDENT(f) ((f)&0x1F) +#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F) + +struct buffer { + const size_t size; + size_t used; + char *data; +}; + +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) { + return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); +} + +static int dump_to_buffer(const char *buffer, size_t size, void *data) { + struct buffer *buf = (struct buffer *)data; + + if (buf->used + size <= buf->size) + memcpy(&buf->data[buf->used], buffer, size); + + buf->used += size; + return 0; +} + +static int dump_to_file(const char *buffer, size_t size, void *data) { + FILE *dest = (FILE *)data; + if (fwrite(buffer, size, 1, dest) != 1) + return -1; + return 0; +} + +static int dump_to_fd(const char *buffer, size_t size, void *data) { +#ifdef HAVE_UNISTD_H + int *dest = (int *)data; + if (write(*dest, buffer, size) == (ssize_t)size) + return 0; +#endif + return -1; +} + +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; + +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, + void *data) { + if (FLAGS_TO_INDENT(flags) > 0) { + unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count; + + if (dump("\n", 1, data)) + return -1; + + while (n_spaces > 0) { + int cur_n = + n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1; + + if (dump(whitespace, cur_n, data)) + return -1; + + n_spaces -= cur_n; + } + } else if (space && !(flags & JSON_COMPACT)) { + return dump(" ", 1, data); + } + return 0; +} + +static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, + size_t flags) { + const char *pos, *end, *lim; + int32_t codepoint = 0; + + if (dump("\"", 1, data)) + return -1; + + end = pos = str; + lim = str + len; + while (1) { + const char *text; + char seq[13]; + int length; + + while (end < lim) { + end = utf8_iterate(pos, lim - pos, &codepoint); + if (!end) + return -1; + + /* mandatory escape or control char */ + if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20) + break; + + /* slash */ + if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + + /* non-ASCII */ + if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) + break; + + pos = end; + } + + if (pos != str) { + if (dump(str, pos - str, data)) + return -1; + } + + if (end == pos) + break; + + /* handle \, /, ", and control codes */ + length = 2; + switch (codepoint) { + case '\\': + text = "\\\\"; + break; + case '\"': + text = "\\\""; + break; + case '\b': + text = "\\b"; + break; + case '\f': + text = "\\f"; + break; + case '\n': + text = "\\n"; + break; + case '\r': + text = "\\r"; + break; + case '\t': + text = "\\t"; + break; + case '/': + text = "\\/"; + break; + default: { + /* codepoint is in BMP */ + if (codepoint < 0x10000) { + snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint); + length = 6; + } + + /* not in BMP -> construct a UTF-16 surrogate pair */ + else { + int32_t first, last; + + codepoint -= 0x10000; + first = 0xD800 | ((codepoint & 0xffc00) >> 10); + last = 0xDC00 | (codepoint & 0x003ff); + + snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, + (unsigned int)last); + length = 12; + } + + text = seq; + break; + } + } + + if (dump(text, length, data)) + return -1; + + str = pos = end; + } + + return dump("\"", 1, data); +} + +struct key_len { + const char *key; + int len; +}; + +static int compare_keys(const void *key1, const void *key2) { + const struct key_len *k1 = key1; + const struct key_len *k2 = key2; + const size_t min_size = k1->len < k2->len ? k1->len : k2->len; + int res = memcmp(k1->key, k2->key, min_size); + + if (res) + return res; + + return k1->len - k2->len; +} + +static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents, + json_dump_callback_t dump, void *data) { + int embed = flags & JSON_EMBED; + + flags &= ~JSON_EMBED; + + if (!json) + return -1; + + switch (json_typeof(json)) { + case JSON_NULL: + return dump("null", 4, data); + + case JSON_TRUE: + return dump("true", 4, data); + + case JSON_FALSE: + return dump("false", 5, data); + + case JSON_INTEGER: { + char buffer[MAX_INTEGER_STR_LENGTH]; + int size; + + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if (size < 0 || size >= MAX_INTEGER_STR_LENGTH) + return -1; + + return dump(buffer, size, data); + } + + case JSON_REAL: { + char buffer[MAX_REAL_STR_LENGTH]; + int size; + double value = json_real_value(json); + + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value, + FLAGS_TO_PRECISION(flags)); + if (size < 0) + return -1; + + return dump(buffer, size, data); + } + + case JSON_STRING: + return dump_string(json_string_value(json), json_string_length(json), dump, + data, flags); + + case JSON_ARRAY: { + size_t n; + size_t i; + /* Space for "0x", double the sizeof a pointer for the hex and a + * terminator. */ + char key[2 + (sizeof(json) * 2) + 1]; + size_t key_len; + + /* detect circular references */ + if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len)) + return -1; + + n = json_array_size(json); + + if (!embed && dump("[", 1, data)) + return -1; + if (n == 0) { + hashtable_del(parents, key, key_len); + return embed ? 0 : dump("]", 1, data); + } + if (dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + for (i = 0; i < n; ++i) { + if (do_dump(json_array_get(json, i), flags, depth + 1, parents, dump, + data)) + return -1; + + if (i < n - 1) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } else { + if (dump_indent(flags, depth, 0, dump, data)) + return -1; + } + } + + hashtable_del(parents, key, key_len); + return embed ? 0 : dump("]", 1, data); + } + + case JSON_OBJECT: { + void *iter; + const char *separator; + int separator_length; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (flags & JSON_COMPACT) { + separator = ":"; + separator_length = 1; + } else { + separator = ": "; + separator_length = 2; + } + + /* detect circular references */ + if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key), + &loop_key_len)) + return -1; + + iter = json_object_iter((json_t *)json); + + if (!embed && dump("{", 1, data)) + return -1; + if (!iter) { + hashtable_del(parents, loop_key, loop_key_len); + return embed ? 0 : dump("}", 1, data); + } + if (dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + if (flags & JSON_SORT_KEYS) { + struct key_len *keys; + size_t size, i; + + size = json_object_size(json); + keys = jsonp_malloc(size * sizeof(struct key_len)); + if (!keys) + return -1; + + i = 0; + while (iter) { + struct key_len *keylen = &keys[i]; + + keylen->key = json_object_iter_key(iter); + keylen->len = (int)json_object_iter_key_len(iter); + + iter = json_object_iter_next((json_t *)json, iter); + i++; + } + assert(i == size); + + qsort(keys, size, sizeof(struct key_len), compare_keys); + + for (i = 0; i < size; i++) { + const struct key_len *key; + json_t *value; + + key = &keys[i]; + value = json_object_getn(json, key->key, key->len); + assert(value); + + dump_string(key->key, key->len, dump, data, flags); + if (dump(separator, separator_length, data) || + do_dump(value, flags, depth + 1, parents, dump, data)) { + jsonp_free(keys); + return -1; + } + + if (i < size - 1) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) { + jsonp_free(keys); + return -1; + } + } else { + if (dump_indent(flags, depth, 0, dump, data)) { + jsonp_free(keys); + return -1; + } + } + } + + jsonp_free(keys); + } else { + /* Don't sort keys */ + + while (iter) { + void *next = json_object_iter_next((json_t *)json, iter); + const char *key = json_object_iter_key(iter); + const size_t key_len = json_object_iter_key_len(iter); + + dump_string(key, key_len, dump, data, flags); + if (dump(separator, separator_length, data) || + do_dump(json_object_iter_value(iter), flags, depth + 1, parents, + dump, data)) + return -1; + + if (next) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } else { + if (dump_indent(flags, depth, 0, dump, data)) + return -1; + } + + iter = next; + } + } + + hashtable_del(parents, loop_key, loop_key_len); + return embed ? 0 : dump("}", 1, data); + } + + default: + /* not reached */ + return -1; + } +} + +char *json_dumps(const json_t *json, size_t flags) { + strbuffer_t strbuff; + char *result; + + if (strbuffer_init(&strbuff)) + return NULL; + + if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); + + strbuffer_close(&strbuff); + return result; +} + +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) { + struct buffer buf = {size, 0, buffer}; + + if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) + return 0; + + return buf.used; +} + +int json_dumpf(const json_t *json, FILE *output, size_t flags) { + return json_dump_callback(json, dump_to_file, (void *)output, flags); +} + +int json_dumpfd(const json_t *json, int output, size_t flags) { + return json_dump_callback(json, dump_to_fd, (void *)&output, flags); +} + +int json_dump_file(const json_t *json, const char *path, size_t flags) { + int result; + + FILE *output = fopen(path, "w"); + if (!output) + return -1; + + result = json_dumpf(json, output, flags); + + if (fclose(output) != 0) + return -1; + + return result; +} + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, + size_t flags) { + int res; + hashtable_t parents_set; + + if (!(flags & JSON_ENCODE_ANY)) { + if (!json_is_array(json) && !json_is_object(json)) + return -1; + } + + if (hashtable_init(&parents_set)) + return -1; + res = do_dump(json, flags, 0, &parents_set, callback, data); + hashtable_close(&parents_set); + + return res; +} diff --git a/thirdparty/jansson/src/error.c b/thirdparty/jansson/src/error.c new file mode 100644 index 0000000..14d0047 --- /dev/null +++ b/thirdparty/jansson/src/error.c @@ -0,0 +1,59 @@ +#include "jansson_private.h" +#include + +void jsonp_error_init(json_error_t *error, const char *source) { + if (error) { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if (source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) { + size_t length; + + if (!error || !source) + return; + + length = strlen(source); + if (length < JSON_ERROR_SOURCE_LENGTH) + strncpy(error->source, source, length + 1); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + memcpy(error->source, "...", 3); + strncpy(error->source + 3, source + extra, length - extra + 1); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, code, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, va_list ap) { + if (!error) + return; + + if (error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = (int)position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0'; + error->text[JSON_ERROR_TEXT_LENGTH - 1] = code; +} diff --git a/thirdparty/jansson/src/hashtable.c b/thirdparty/jansson/src/hashtable.c new file mode 100644 index 0000000..1508d74 --- /dev/null +++ b/thirdparty/jansson/src/hashtable.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#if HAVE_STDINT_H +#include +#endif + +#include "hashtable.h" +#include "jansson_private.h" /* for container_of() */ +#include /* for JSON_INLINE */ + +#ifndef INITIAL_HASHTABLE_ORDER +#define INITIAL_HASHTABLE_ORDER 3 +#endif + +typedef struct hashtable_list list_t; +typedef struct hashtable_pair pair_t; +typedef struct hashtable_bucket bucket_t; + +extern volatile uint32_t hashtable_seed; + +/* Implementation of the hash function */ +#include "lookup3.h" + +#define list_to_pair(list_) container_of(list_, pair_t, list) +#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) +#define hash_str(key, len) ((size_t)hashlittle((key), len, hashtable_seed)) + +static JSON_INLINE void list_init(list_t *list) { + list->next = list; + list->prev = list; +} + +static JSON_INLINE void list_insert(list_t *list, list_t *node) { + node->next = list; + node->prev = list->prev; + list->prev->next = node; + list->prev = node; +} + +static JSON_INLINE void list_remove(list_t *list) { + list->prev->next = list->next; + list->next->prev = list->prev; +} + +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) { + return bucket->first == &hashtable->list && bucket->first == bucket->last; +} + +static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *list) { + if (bucket_is_empty(hashtable, bucket)) { + list_insert(&hashtable->list, list); + bucket->first = bucket->last = list; + } else { + list_insert(bucket->first, list); + bucket->first = list; + } +} + +static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, + const char *key, size_t key_len, size_t hash) { + list_t *list; + pair_t *pair; + + if (bucket_is_empty(hashtable, bucket)) + return NULL; + + list = bucket->first; + while (1) { + pair = list_to_pair(list); + if (pair->hash == hash && pair->key_len == key_len && + memcmp(pair->key, key, key_len) == 0) + return pair; + + if (list == bucket->last) + break; + + list = list->next; + } + + return NULL; +} + +/* returns 0 on success, -1 if key was not found */ +static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len, + size_t hash) { + pair_t *pair; + bucket_t *bucket; + size_t index; + + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return -1; + + if (&pair->list == bucket->first && &pair->list == bucket->last) + bucket->first = bucket->last = &hashtable->list; + + else if (&pair->list == bucket->first) + bucket->first = pair->list.next; + + else if (&pair->list == bucket->last) + bucket->last = pair->list.prev; + + list_remove(&pair->list); + list_remove(&pair->ordered_list); + json_decref(pair->value); + + jsonp_free(pair); + hashtable->size--; + + return 0; +} + +static void hashtable_do_clear(hashtable_t *hashtable) { + list_t *list, *next; + pair_t *pair; + + for (list = hashtable->list.next; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + json_decref(pair->value); + jsonp_free(pair); + } +} + +static int hashtable_do_rehash(hashtable_t *hashtable) { + list_t *list, *next; + pair_t *pair; + size_t i, index, new_size, new_order; + struct hashtable_bucket *new_buckets; + + new_order = hashtable->order + 1; + new_size = hashsize(new_order); + + new_buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if (!new_buckets) + return -1; + + jsonp_free(hashtable->buckets); + hashtable->buckets = new_buckets; + hashtable->order = new_order; + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + list = hashtable->list.next; + list_init(&hashtable->list); + + for (; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + index = pair->hash % new_size; + insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); + } + + return 0; +} + +int hashtable_init(hashtable_t *hashtable) { + size_t i; + + hashtable->size = 0; + hashtable->order = INITIAL_HASHTABLE_ORDER; + hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); + if (!hashtable->buckets) + return -1; + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + return 0; +} + +void hashtable_close(hashtable_t *hashtable) { + hashtable_do_clear(hashtable); + jsonp_free(hashtable->buckets); +} + +static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) { + pair_t *pair; + + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + + if (key_len >= (size_t)-1 - offsetof(pair_t, key)) { + /* Avoid an overflow if the key is very long */ + return NULL; + } + + pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1); + + if (!pair) + return NULL; + + pair->hash = hash; + memcpy(pair->key, key, key_len); + pair->key[key_len] = '\0'; + pair->key_len = key_len; + pair->value = value; + + list_init(&pair->list); + list_init(&pair->ordered_list); + + return pair; +} + +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, + json_t *value) { + pair_t *pair; + bucket_t *bucket; + size_t hash, index; + + /* rehash if the load ratio exceeds 1 */ + if (hashtable->size >= hashsize(hashtable->order)) + if (hashtable_do_rehash(hashtable)) + return -1; + + hash = hash_str(key, key_len); + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + + if (pair) { + json_decref(pair->value); + pair->value = value; + } else { + pair = init_pair(value, key, key_len, hash); + + if (!pair) + return -1; + + insert_to_bucket(hashtable, bucket, &pair->list); + list_insert(&hashtable->ordered_list, &pair->ordered_list); + + hashtable->size++; + } + return 0; +} + +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) { + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key, key_len); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return NULL; + + return pair->value; +} + +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) { + size_t hash = hash_str(key, key_len); + return hashtable_do_del(hashtable, key, key_len, hash); +} + +void hashtable_clear(hashtable_t *hashtable) { + size_t i; + + hashtable_do_clear(hashtable); + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + hashtable->size = 0; +} + +void *hashtable_iter(hashtable_t *hashtable) { + return hashtable_iter_next(hashtable, &hashtable->ordered_list); +} + +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) { + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key, key_len); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return NULL; + + return &pair->ordered_list; +} + +void *hashtable_iter_next(hashtable_t *hashtable, void *iter) { + list_t *list = (list_t *)iter; + if (list->next == &hashtable->ordered_list) + return NULL; + return list->next; +} + +void *hashtable_iter_key(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->key; +} + +size_t hashtable_iter_key_len(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->key_len; +} + +void *hashtable_iter_value(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->value; +} + +void hashtable_iter_set(void *iter, json_t *value) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + + json_decref(pair->value); + pair->value = value; +} diff --git a/thirdparty/jansson/src/hashtable.h b/thirdparty/jansson/src/hashtable.h new file mode 100644 index 0000000..03a1f5a --- /dev/null +++ b/thirdparty/jansson/src/hashtable.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include "jansson.h" +#include + +struct hashtable_list { + struct hashtable_list *prev; + struct hashtable_list *next; +}; + +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ +struct hashtable_pair { + struct hashtable_list list; + struct hashtable_list ordered_list; + size_t hash; + json_t *value; + size_t key_len; + char key[1]; +}; + +struct hashtable_bucket { + struct hashtable_list *first; + struct hashtable_list *last; +}; + +typedef struct hashtable { + size_t size; + struct hashtable_bucket *buckets; + size_t order; /* hashtable has pow(2, order) buckets */ + struct hashtable_list list; + struct hashtable_list ordered_list; +} hashtable_t; + +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->ordered_list)) + +/** + * hashtable_init - Initialize a hashtable object + * + * @hashtable: The (statically allocated) hashtable object + * + * Initializes a statically allocated hashtable object. The object + * should be cleared with hashtable_close when it's no longer used. + * + * Returns 0 on success, -1 on error (out of memory). + */ +int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result)); + +/** + * hashtable_close - Release all resources used by a hashtable object + * + * @hashtable: The hashtable + * + * Destroys a statically allocated hashtable object. + */ +void hashtable_close(hashtable_t *hashtable); + +/** + * hashtable_set - Add/modify value in hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * @serial: For addition order of keys + * @value: The value + * + * If a value with the given key already exists, its value is replaced + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. + * + * Returns 0 on success, -1 on failure (out of memory). + */ +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value); + +/** + * hashtable_get - Get a value associated with a key + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * + * Returns value if it is found, or NULL otherwise. + */ +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_del - Remove a value from the hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * + * Returns 0 on success, or -1 if the key was not found. + */ +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + +/** + * hashtable_iter - Iterate over hashtable + * + * @hashtable: The hashtable object + * + * Returns an opaque iterator to the first element in the hashtable. + * The iterator should be passed to hashtable_iter_* functions. + * The hashtable items are not iterated over in any particular order. + * + * There's no need to free the iterator in any way. The iterator is + * valid as long as the item that is referenced by the iterator is not + * deleted. Other values may be added or deleted. In particular, + * hashtable_iter_next() may be called on an iterator, and after that + * the key/value pair pointed by the old iterator may be deleted. + */ +void *hashtable_iter(hashtable_t *hashtable); + +/** + * hashtable_iter_at - Return an iterator at a specific key + * + * @hashtable: The hashtable object + * @key: The key that the iterator should point to + * @key: The length of key + * + * Like hashtable_iter() but returns an iterator pointing to a + * specific key. + */ +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_iter_next - Advance an iterator + * + * @hashtable: The hashtable object + * @iter: The iterator + * + * Returns a new iterator pointing to the next element in the + * hashtable or NULL if the whole hastable has been iterated over. + */ +void *hashtable_iter_next(hashtable_t *hashtable, void *iter); + +/** + * hashtable_iter_key - Retrieve the key pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_key(void *iter); + +/** + * hashtable_iter_key_len - Retrieve the key length pointed by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_key_len(void *iter); + +/** + * hashtable_iter_value - Retrieve the value pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_value(void *iter); + +/** + * hashtable_iter_set - Set the value pointed by an iterator + * + * @iter: The iterator + * @value: The value to set + */ +void hashtable_iter_set(void *iter, json_t *value); + +#endif diff --git a/thirdparty/jansson/src/hashtable_seed.c b/thirdparty/jansson/src/hashtable_seed.c new file mode 100644 index 0000000..d156b40 --- /dev/null +++ b/thirdparty/jansson/src/hashtable_seed.c @@ -0,0 +1,277 @@ +/* Generate sizeof(uint32_t) bytes of as random data as possible to seed + the hash function. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if defined(_WIN32) +/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */ +#include +#endif + +#include "jansson.h" + +static uint32_t buf_to_uint32(char *data) { + size_t i; + uint32_t result = 0; + + for (i = 0; i < sizeof(uint32_t); i++) + result = (result << 8) | (unsigned char)data[i]; + + return result; +} + +/* /dev/urandom */ +#if !defined(_WIN32) && defined(USE_URANDOM) +static int seed_from_urandom(uint32_t *seed) { + /* Use unbuffered I/O if we have open(), close() and read(). Otherwise + fall back to fopen() */ + + char data[sizeof(uint32_t)]; + int ok; + +#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ) + int urandom; + urandom = open("/dev/urandom", O_RDONLY); + if (urandom == -1) + return 1; + + ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t); + close(urandom); +#else + FILE *urandom; + + urandom = fopen("/dev/urandom", "rb"); + if (!urandom) + return 1; + + ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t); + fclose(urandom); +#endif + + if (!ok) + return 1; + + *seed = buf_to_uint32(data); + return 0; +} +#endif + +/* Windows Crypto API */ +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) +#include + +typedef BOOL(WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, + LPCSTR pszProvider, DWORD dwProvType, + DWORD dwFlags); +typedef BOOL(WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); +typedef BOOL(WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +static int seed_from_windows_cryptoapi(uint32_t *seed) { + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + CRYPTGENRANDOM pCryptGenRandom = NULL; + CRYPTRELEASECONTEXT pCryptReleaseContext = NULL; + HCRYPTPROV hCryptProv = 0; + BYTE data[sizeof(uint32_t)]; + int ok; + + hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll")); + if (hAdvAPI32 == NULL) + return 1; + + pCryptAcquireContext = + (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); + if (!pCryptAcquireContext) + return 1; + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom"); + if (!pCryptGenRandom) + return 1; + + pCryptReleaseContext = + (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext"); + if (!pCryptReleaseContext) + return 1; + + if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return 1; + + ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data); + pCryptReleaseContext(hCryptProv, 0); + + if (!ok) + return 1; + + *seed = buf_to_uint32((char *)data); + return 0; +} +#endif + +/* gettimeofday() and getpid() */ +static int seed_from_timestamp_and_pid(uint32_t *seed) { +#ifdef HAVE_GETTIMEOFDAY + /* XOR of seconds and microseconds */ + struct timeval tv; + gettimeofday(&tv, NULL); + *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec; +#else + /* Seconds only */ + *seed = (uint32_t)time(NULL); +#endif + + /* XOR with PID for more randomness */ +#if defined(_WIN32) + *seed ^= (uint32_t)GetCurrentProcessId(); +#elif defined(HAVE_GETPID) + *seed ^= (uint32_t)getpid(); +#endif + + return 0; +} + +static uint32_t generate_seed() { + uint32_t seed = 0; + int done = 0; + +#if !defined(_WIN32) && defined(USE_URANDOM) + if (seed_from_urandom(&seed) == 0) + done = 1; +#endif + +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) + if (seed_from_windows_cryptoapi(&seed) == 0) + done = 1; +#endif + + if (!done) { + /* Fall back to timestamp and PID if no better randomness is + available */ + seed_from_timestamp_and_pid(&seed); + } + + /* Make sure the seed is never zero */ + if (seed == 0) + seed = 1; + + return seed; +} + +volatile uint32_t hashtable_seed = 0; + +#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +static volatile char seed_initialized = 0; + +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE); + } else { + /* Wait for another thread to do the seeding */ + do { +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } while (__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0); + } + } +} +#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) { + /* Explicit synchronization fences are not supported by the + __sync builtins, so every thread getting here has to + generate the seed value. + */ + new_seed = generate_seed(); + } + + do { + if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) { + /* We were the first to seed */ + break; + } else { + /* Wait for another thread to do the seeding */ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } + } while (hashtable_seed == 0); + } +} +#elif defined(_WIN32) +static long seed_initialized = 0; +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (InterlockedIncrement(&seed_initialized) == 1) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } else { + /* Wait for another thread to do the seeding */ + do { + SwitchToThread(); + } while (hashtable_seed == 0); + } + } +} +#else +/* Fall back to a thread-unsafe version */ +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } +} +#endif diff --git a/thirdparty/jansson/src/jansson.def b/thirdparty/jansson/src/jansson.def new file mode 100644 index 0000000..5c76c2f --- /dev/null +++ b/thirdparty/jansson/src/jansson.def @@ -0,0 +1,83 @@ +EXPORTS + json_delete + json_true + json_false + json_null + json_sprintf + json_vsprintf + json_string + json_stringn + json_string_nocheck + json_stringn_nocheck + json_string_value + json_string_length + json_string_set + json_string_setn + json_string_set_nocheck + json_string_setn_nocheck + json_integer + json_integer_value + json_integer_set + json_real + json_real_value + json_real_set + json_number_value + json_array + json_array_size + json_array_get + json_array_set_new + json_array_append_new + json_array_insert_new + json_array_remove + json_array_clear + json_array_extend + json_object + json_object_size + json_object_get + json_object_getn + json_object_set_new + json_object_setn_new + json_object_set_new_nocheck + json_object_setn_new_nocheck + json_object_del + json_object_deln + json_object_clear + json_object_update + json_object_update_existing + json_object_update_missing + json_object_update_recursive + json_object_iter + json_object_iter_at + json_object_iter_next + json_object_iter_key + json_object_iter_key_len + json_object_iter_value + json_object_iter_set_new + json_object_key_to_iter + json_object_seed + json_dumps + json_dumpb + json_dumpf + json_dumpfd + json_dump_file + json_dump_callback + json_loads + json_loadb + json_loadf + json_loadfd + json_load_file + json_load_callback + json_equal + json_copy + json_deep_copy + json_pack + json_pack_ex + json_vpack_ex + json_unpack + json_unpack_ex + json_vunpack_ex + json_set_alloc_funcs + json_get_alloc_funcs + jansson_version_str + jansson_version_cmp + diff --git a/thirdparty/jansson/src/jansson.h b/thirdparty/jansson/src/jansson.h new file mode 100644 index 0000000..391c85e --- /dev/null +++ b/thirdparty/jansson/src/jansson.h @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include +#include +#include /* for size_t */ + +#include "jansson_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 14 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.14" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX \ + ((JANSSON_MAJOR_VERSION << 16) | (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + +/* If __atomic or __sync builtins are available the library is thread + * safe for all read-only functions plus reference counting. */ +#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS +#define JANSSON_THREAD_SAFE_REFCOUNT 1 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JANSSON_ATTRS(x) __attribute__(x) +#else +#define JANSSON_ATTRS(x) +#endif + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct json_t { + json_type type; + volatile size_t refcount; +} json_t; + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE) +#define json_boolean_value json_is_true +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_stringn(const char *value, size_t len); +json_t *json_string_nocheck(const char *value); +json_t *json_stringn_nocheck(const char *value, size_t len); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */ +#if JSON_HAVE_ATOMIC_BUILTINS +#define JSON_INTERNAL_INCREF(json) \ + __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE) +#define JSON_INTERNAL_DECREF(json) \ + __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE) +#elif JSON_HAVE_SYNC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1) +#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1) +#else +#define JSON_INTERNAL_INCREF(json) (++json->refcount) +#define JSON_INTERNAL_DECREF(json) (--json->refcount) +#endif + +static JSON_INLINE json_t *json_incref(json_t *json) { + if (json && json->refcount != (size_t)-1) + JSON_INTERNAL_INCREF(json); + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE void json_decref(json_t *json) { + if (json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0) + json_delete(json); +} + +#if defined(__GNUC__) || defined(__clang__) +static JSON_INLINE void json_decrefp(json_t **json) { + if (json) { + json_decref(*json); + *json = NULL; + } +} + +#define json_auto_t json_t __attribute__((cleanup(json_decrefp))) +#endif + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct json_error_t { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + +enum json_error_code { + json_error_unknown, + json_error_out_of_memory, + json_error_stack_overflow, + json_error_cannot_open_file, + json_error_invalid_argument, + json_error_invalid_utf8, + json_error_premature_end_of_input, + json_error_end_of_input_expected, + json_error_invalid_syntax, + json_error_invalid_format, + json_error_wrong_type, + json_error_null_character, + json_error_null_value, + json_error_null_byte_in_key, + json_error_duplicate_key, + json_error_numeric_overflow, + json_error_item_not_found, + json_error_index_out_of_range +}; + +static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) { + return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1]; +} + +/* getters, setters, manipulation */ + +void json_object_seed(size_t seed); +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_object_getn(const json_t *object, const char *key, size_t key_len) + JANSSON_ATTRS((warn_unused_result)); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len, + json_t *value); +int json_object_del(json_t *object, const char *key); +int json_object_deln(json_t *object, const char *key, size_t key_len); +int json_object_clear(json_t *object); +int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); +int json_object_update_recursive(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); +void *json_object_iter_next(json_t *object, void *iter); +const char *json_object_iter_key(void *iter); +size_t json_object_iter_key_len(void *iter); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for (key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key( \ + json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_object_keylen_foreach(object, key, key_len, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key( \ + json_object_iter_next(object, json_object_key_to_iter(key))), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key))) + +#define json_object_foreach_safe(object, n, key, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + +#define json_object_keylen_foreach_safe(object, n, key, key_len, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), key_len = json_object_iter_key_len(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + +#define json_array_foreach(array, index, value) \ + for (index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + +static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) { + return json_object_set_new(object, key, json_incref(value)); +} + +static JSON_INLINE int json_object_setn(json_t *object, const char *key, size_t key_len, + json_t *value) { + return json_object_setn_new(object, key, key_len, json_incref(value)); +} + +static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key, + json_t *value) { + return json_object_set_new_nocheck(object, key, json_incref(value)); +} + +static JSON_INLINE int json_object_setn_nocheck(json_t *object, const char *key, + size_t key_len, json_t *value) { + return json_object_setn_new_nocheck(object, key, key_len, json_incref(value)); +} + +static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) { + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +static JSON_INLINE int json_object_update_new(json_t *object, json_t *other) { + int ret = json_object_update(object, other); + json_decref(other); + return ret; +} + +static JSON_INLINE int json_object_update_existing_new(json_t *object, json_t *other) { + int ret = json_object_update_existing(object, other); + json_decref(other); + return ret; +} + +static JSON_INLINE int json_object_update_missing_new(json_t *object, json_t *other) { + int ret = json_object_update_missing(object, other); + json_decref(other); + return ret; +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index) + JANSSON_ATTRS((warn_unused_result)); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE int json_array_set(json_t *array, size_t ind, json_t *value) { + return json_array_set_new(array, ind, json_incref(value)); +} + +static JSON_INLINE int json_array_append(json_t *array, json_t *value) { + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE int json_array_insert(json_t *array, size_t ind, json_t *value) { + return json_array_insert_new(array, ind, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +size_t json_string_length(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_setn(json_t *string, const char *value, size_t len); +int json_string_set_nocheck(json_t *string, const char *value); +int json_string_setn_nocheck(json_t *string, const char *value, size_t len); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result)); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) + JANSSON_ATTRS((warn_unused_result)); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + va_list ap); + +/* sprintf */ + +json_t *json_sprintf(const char *fmt, ...) + JANSSON_ATTRS((warn_unused_result, format(printf, 1, 2))); +json_t *json_vsprintf(const char *fmt, va_list ap) + JANSSON_ATTRS((warn_unused_result, format(printf, 1, 0))); + +/* equality */ + +int json_equal(const json_t *value1, const json_t *value2); + +/* copying */ + +json_t *json_copy(json_t *value) JANSSON_ATTRS((warn_unused_result)); +json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS((warn_unused_result)); + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 +#define JSON_ALLOW_NUL 0x10 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadfd(int input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, + json_error_t *error) JANSSON_ATTRS((warn_unused_result)); + +/* encoding */ + +#define JSON_MAX_INDENT 0x1F +#define JSON_INDENT(n) ((n)&JSON_MAX_INDENT) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 +#define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11) +#define JSON_EMBED 0x10000 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS((warn_unused_result)); +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dumpfd(const json_t *json, int output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, + size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn); + +/* runtime version checking */ + +const char *jansson_version_str(void); +int jansson_version_cmp(int major, int minor, int micro); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/jansson/src/jansson_config.h.in b/thirdparty/jansson/src/jansson_config.h.in new file mode 100644 index 0000000..fe692ab --- /dev/null +++ b/thirdparty/jansson/src/jansson_config.h.in @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @json_inline@ +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @json_have_localeconv@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/thirdparty/jansson/src/jansson_private.h b/thirdparty/jansson/src/jansson_private.h new file mode 100644 index 0000000..ea2593c --- /dev/null +++ b/thirdparty/jansson/src/jansson_private.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_PRIVATE_H +#define JANSSON_PRIVATE_H + +#include "hashtable.h" +#include "jansson.h" +#include "jansson_private_config.h" +#include "strbuffer.h" +#include + +#define container_of(ptr_, type_, member_) \ + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif + +typedef struct { + json_t json; + hashtable_t hashtable; +} json_object_t; + +typedef struct { + json_t json; + size_t size; + size_t entries; + json_t **table; +} json_array_t; + +typedef struct { + json_t json; + char *value; + size_t length; +} json_string_t; + +typedef struct { + json_t json; + double value; +} json_real_t; + +typedef struct { + json_t json; + json_int_t value; +} json_integer_t; + +#define json_to_object(json_) container_of(json_, json_object_t, json) +#define json_to_array(json_) container_of(json_, json_array_t, json) +#define json_to_string(json_) container_of(json_, json_string_t, json) +#define json_to_real(json_) container_of(json_, json_real_t, json) +#define json_to_integer(json_) container_of(json_, json_integer_t, json) + +/* Create a string by taking ownership of an existing buffer */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); + +/* Error message formatting */ +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value, int prec); + +/* Wrappers for custom memory functions */ +void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result)); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result)); +char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result)); +char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result)); + +/* Circular reference check*/ +/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ +#define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1) +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out); + +/* Windows compatibility */ +#if defined(_WIN32) || defined(WIN32) +#if defined(_MSC_VER) /* MS compiller */ +#if (_MSC_VER < 1900) && \ + !defined(snprintf) /* snprintf not defined yet & not introduced */ +#define snprintf _snprintf +#endif +#if (_MSC_VER < 1500) && \ + !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */ +#define vsnprintf(b, c, f, a) _vsnprintf(b, c, f, a) +#endif +#else /* Other Windows compiller, old definition */ +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif +#endif + +#endif diff --git a/thirdparty/jansson/src/load.c b/thirdparty/jansson/src/load.c new file mode 100644 index 0000000..8ae7abd --- /dev/null +++ b/thirdparty/jansson/src/load.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + +#define TOKEN_INVALID -1 +#define TOKEN_EOF 0 +#define TOKEN_STRING 256 +#define TOKEN_INTEGER 257 +#define TOKEN_REAL 258 +#define TOKEN_TRUE 259 +#define TOKEN_FALSE 260 +#define TOKEN_NULL 261 + +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ +typedef int (*get_func)(void *data); + +typedef struct { + get_func get; + void *data; + char buffer[5]; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; +} stream_t; + +typedef struct { + stream_t stream; + strbuffer_t saved_text; + size_t flags; + size_t depth; + int token; + union { + struct { + char *val; + size_t len; + } string; + json_int_t integer; + double real; + } value; +} lex_t; + +#define stream_to_lex(stream) container_of(stream, lex_t, stream) + +/*** error reporting ***/ + +static void error_set(json_error_t *error, const lex_t *lex, enum json_error_code code, + const char *msg, ...) { + va_list ap; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; + + if (!error) + return; + + va_start(ap, msg); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + va_end(ap); + + if (lex) { + const char *saved_text = strbuffer_value(&lex->saved_text); + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + + if (saved_text && saved_text[0]) { + if (lex->saved_text.length <= 20) { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near '%s'", + msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } else { + if (code == json_error_invalid_syntax) { + /* More specific error code for premature end of file. */ + code = json_error_premature_end_of_input; + } + if (lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near end of file", + msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + } + + jsonp_error_set(error, line, col, pos, code, "%s", result); +} + +/*** lexical analyzer ***/ + +static void stream_init(stream_t *stream, get_func get, void *data) { + stream->get = get; + stream->data = data; + stream->buffer[0] = '\0'; + stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; +} + +static int stream_get(stream_t *stream, json_error_t *error) { + int c; + + if (stream->state != STREAM_STATE_OK) + return stream->state; + + if (!stream->buffer[stream->buffer_pos]) { + c = stream->get(stream->data); + if (c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } + + stream->buffer[0] = c; + stream->buffer_pos = 0; + + if (0x80 <= c && c <= 0xFF) { + /* multi-byte UTF-8 sequence */ + size_t i, count; + + count = utf8_check_first(c); + if (!count) + goto out; + + assert(count >= 2); + + for (i = 1; i < count; i++) + stream->buffer[i] = stream->get(stream->data); + + if (!utf8_check_full(stream->buffer, count, NULL)) + goto out; + + stream->buffer[count] = '\0'; + } else + stream->buffer[1] = '\0'; + } + + c = stream->buffer[stream->buffer_pos++]; + + stream->position++; + if (c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } else if (utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } + + return c; + +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), json_error_invalid_utf8, + "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; +} + +static void stream_unget(stream_t *stream, int c) { + if (c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if (c == '\n') { + stream->line--; + stream->column = stream->last_column; + } else if (utf8_check_first(c)) + stream->column--; + + assert(stream->buffer_pos > 0); + stream->buffer_pos--; + assert(stream->buffer[stream->buffer_pos] == c); +} + +static int lex_get(lex_t *lex, json_error_t *error) { + return stream_get(&lex->stream, error); +} + +static void lex_save(lex_t *lex, int c) { strbuffer_append_byte(&lex->saved_text, c); } + +static int lex_get_save(lex_t *lex, json_error_t *error) { + int c = stream_get(&lex->stream, error); + if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); + return c; +} + +static void lex_unget(lex_t *lex, int c) { stream_unget(&lex->stream, c); } + +static void lex_unget_unsave(lex_t *lex, int c) { + if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { +/* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ +#ifndef NDEBUG + char d; +#endif + stream_unget(&lex->stream, c); +#ifndef NDEBUG + d = +#endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } +} + +static void lex_save_cached(lex_t *lex) { + while (lex->stream.buffer[lex->stream.buffer_pos] != '\0') { + lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); + lex->stream.buffer_pos++; + lex->stream.position++; + } +} + +static void lex_free_string(lex_t *lex) { + jsonp_free(lex->value.string.val); + lex->value.string.val = NULL; + lex->value.string.len = 0; +} + +/* assumes that str points to 'u' plus at least 4 valid hex digits */ +static int32_t decode_unicode_escape(const char *str) { + int i; + int32_t value = 0; + + assert(str[0] == 'u'); + + for (i = 1; i <= 4; i++) { + char c = str[i]; + value <<= 4; + if (l_isdigit(c)) + value += c - '0'; + else if (l_islower(c)) + value += c - 'a' + 10; + else if (l_isupper(c)) + value += c - 'A' + 10; + else + return -1; + } + + return value; +} + +static void lex_scan_string(lex_t *lex, json_error_t *error) { + int c; + const char *p; + char *t; + int i; + + lex->value.string.val = NULL; + lex->token = TOKEN_INVALID; + + c = lex_get_save(lex, error); + + while (c != '"') { + if (c == STREAM_STATE_ERROR) + goto out; + + else if (c == STREAM_STATE_EOF) { + error_set(error, lex, json_error_premature_end_of_input, + "premature end of input"); + goto out; + } + + else if (0 <= c && c <= 0x1F) { + /* control character */ + lex_unget_unsave(lex, c); + if (c == '\n') + error_set(error, lex, json_error_invalid_syntax, "unexpected newline"); + else + error_set(error, lex, json_error_invalid_syntax, "control character 0x%x", + c); + goto out; + } + + else if (c == '\\') { + c = lex_get_save(lex, error); + if (c == 'u') { + c = lex_get_save(lex, error); + for (i = 0; i < 4; i++) { + if (!l_isxdigit(c)) { + error_set(error, lex, json_error_invalid_syntax, + "invalid escape"); + goto out; + } + c = lex_get_save(lex, error); + } + } else if (c == '"' || c == '\\' || c == '/' || c == 'b' || c == 'f' || + c == 'n' || c == 'r' || c == 't') + c = lex_get_save(lex, error); + else { + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); + goto out; + } + } else + c = lex_get_save(lex, error); + } + + /* the actual value is at most of the same length as the source + string, because: + - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte + - a single \uXXXX escape (length 6) is converted to at most 3 bytes + - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair + are converted to 4 bytes + */ + t = jsonp_malloc(lex->saved_text.length + 1); + if (!t) { + /* this is not very nice, since TOKEN_INVALID is returned */ + goto out; + } + lex->value.string.val = t; + + /* + 1 to skip the " */ + p = strbuffer_value(&lex->saved_text) + 1; + + while (*p != '"') { + if (*p == '\\') { + p++; + if (*p == 'u') { + size_t length; + int32_t value; + + value = decode_unicode_escape(p); + if (value < 0) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if (0xD800 <= value && value <= 0xDBFF) { + /* surrogate pair */ + if (*p == '\\' && *(p + 1) == 'u') { + int32_t value2 = decode_unicode_escape(++p); + if (value2 < 0) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if (0xDC00 <= value2 && value2 <= 0xDFFF) { + /* valid second surrogate */ + value = + ((value - 0xD800) << 10) + (value2 - 0xDC00) + 0x10000; + } else { + /* invalid second surrogate */ + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X\\u%04X'", value, value2); + goto out; + } + } else { + /* no second surrogate */ + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X'", value); + goto out; + } + } else if (0xDC00 <= value && value <= 0xDFFF) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X'", value); + goto out; + } + + if (utf8_encode(value, t, &length)) + assert(0); + t += length; + } else { + switch (*p) { + case '"': + case '\\': + case '/': + *t = *p; + break; + case 'b': + *t = '\b'; + break; + case 'f': + *t = '\f'; + break; + case 'n': + *t = '\n'; + break; + case 'r': + *t = '\r'; + break; + case 't': + *t = '\t'; + break; + default: + assert(0); + } + t++; + p++; + } + } else + *(t++) = *(p++); + } + *t = '\0'; + lex->value.string.len = t - lex->value.string.val; + lex->token = TOKEN_STRING; + return; + +out: + lex_free_string(lex); +} + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { + const char *saved_text; + char *end; + double doubleval; + + lex->token = TOKEN_INVALID; + + if (c == '-') + c = lex_get_save(lex, error); + + if (c == '0') { + c = lex_get_save(lex, error); + if (l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + } else if (l_isdigit(c)) { + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } else { + lex_unget_unsave(lex, c); + goto out; + } + + if (!(lex->flags & JSON_DECODE_INT_AS_REAL) && c != '.' && c != 'E' && c != 'e') { + json_int_t intval; + + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + errno = 0; + intval = json_strtoint(saved_text, &end, 10); + if (errno == ERANGE) { + if (intval < 0) + error_set(error, lex, json_error_numeric_overflow, + "too big negative integer"); + else + error_set(error, lex, json_error_numeric_overflow, "too big integer"); + goto out; + } + + assert(end == saved_text + lex->saved_text.length); + + lex->token = TOKEN_INTEGER; + lex->value.integer = intval; + return 0; + } + + if (c == '.') { + c = lex_get(lex, error); + if (!l_isdigit(c)) { + lex_unget(lex, c); + goto out; + } + lex_save(lex, c); + + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } + + if (c == 'E' || c == 'e') { + c = lex_get_save(lex, error); + if (c == '+' || c == '-') + c = lex_get_save(lex, error); + + if (!l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } + + lex_unget_unsave(lex, c); + + if (jsonp_strtod(&lex->saved_text, &doubleval)) { + error_set(error, lex, json_error_numeric_overflow, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = doubleval; + return 0; + +out: + return -1; +} + +static int lex_scan(lex_t *lex, json_error_t *error) { + int c; + + strbuffer_clear(&lex->saved_text); + + if (lex->token == TOKEN_STRING) + lex_free_string(lex); + + do + c = lex_get(lex, error); + while (c == ' ' || c == '\t' || c == '\n' || c == '\r'); + + if (c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; + } + + if (c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; + goto out; + } + + lex_save(lex, c); + + if (c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') + lex->token = c; + + else if (c == '"') + lex_scan_string(lex, error); + + else if (l_isdigit(c) || c == '-') { + if (lex_scan_number(lex, c, error)) + goto out; + } + + else if (l_isalpha(c)) { + /* eat up the whole identifier for clearer error messages */ + const char *saved_text; + + do + c = lex_get_save(lex, error); + while (l_isalpha(c)); + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + if (strcmp(saved_text, "true") == 0) + lex->token = TOKEN_TRUE; + else if (strcmp(saved_text, "false") == 0) + lex->token = TOKEN_FALSE; + else if (strcmp(saved_text, "null") == 0) + lex->token = TOKEN_NULL; + else + lex->token = TOKEN_INVALID; + } + + else { + /* save the rest of the input UTF-8 sequence to get an error + message of valid UTF-8 */ + lex_save_cached(lex); + lex->token = TOKEN_INVALID; + } + +out: + return lex->token; +} + +static char *lex_steal_string(lex_t *lex, size_t *out_len) { + char *result = NULL; + if (lex->token == TOKEN_STRING) { + result = lex->value.string.val; + *out_len = lex->value.string.len; + lex->value.string.val = NULL; + lex->value.string.len = 0; + } + return result; +} + +static int lex_init(lex_t *lex, get_func get, size_t flags, void *data) { + stream_init(&lex->stream, get, data); + if (strbuffer_init(&lex->saved_text)) + return -1; + + lex->flags = flags; + lex->token = TOKEN_INVALID; + return 0; +} + +static void lex_close(lex_t *lex) { + if (lex->token == TOKEN_STRING) + lex_free_string(lex); + strbuffer_close(&lex->saved_text); +} + +/*** parser ***/ + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); + +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { + json_t *object = json_object(); + if (!object) + return NULL; + + lex_scan(lex, error); + if (lex->token == '}') + return object; + + while (1) { + char *key; + size_t len; + json_t *value; + + if (lex->token != TOKEN_STRING) { + error_set(error, lex, json_error_invalid_syntax, "string or '}' expected"); + goto error; + } + + key = lex_steal_string(lex, &len); + if (!key) + return NULL; + if (memchr(key, '\0', len)) { + jsonp_free(key); + error_set(error, lex, json_error_null_byte_in_key, + "NUL byte in object key not supported"); + goto error; + } + + if (flags & JSON_REJECT_DUPLICATES) { + if (json_object_getn(object, key, len)) { + jsonp_free(key); + error_set(error, lex, json_error_duplicate_key, "duplicate object key"); + goto error; + } + } + + lex_scan(lex, error); + if (lex->token != ':') { + jsonp_free(key); + error_set(error, lex, json_error_invalid_syntax, "':' expected"); + goto error; + } + + lex_scan(lex, error); + value = parse_value(lex, flags, error); + if (!value) { + jsonp_free(key); + goto error; + } + + if (json_object_setn_new_nocheck(object, key, len, value)) { + jsonp_free(key); + goto error; + } + + jsonp_free(key); + + lex_scan(lex, error); + if (lex->token != ',') + break; + + lex_scan(lex, error); + } + + if (lex->token != '}') { + error_set(error, lex, json_error_invalid_syntax, "'}' expected"); + goto error; + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) { + json_t *array = json_array(); + if (!array) + return NULL; + + lex_scan(lex, error); + if (lex->token == ']') + return array; + + while (lex->token) { + json_t *elem = parse_value(lex, flags, error); + if (!elem) + goto error; + + if (json_array_append_new(array, elem)) { + goto error; + } + + lex_scan(lex, error); + if (lex->token != ',') + break; + + lex_scan(lex, error); + } + + if (lex->token != ']') { + error_set(error, lex, json_error_invalid_syntax, "']' expected"); + goto error; + } + + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) { + json_t *json; + + lex->depth++; + if (lex->depth > JSON_PARSER_MAX_DEPTH) { + error_set(error, lex, json_error_stack_overflow, "maximum parsing depth reached"); + return NULL; + } + + switch (lex->token) { + case TOKEN_STRING: { + const char *value = lex->value.string.val; + size_t len = lex->value.string.len; + + if (!(flags & JSON_ALLOW_NUL)) { + if (memchr(value, '\0', len)) { + error_set(error, lex, json_error_null_character, + "\\u0000 is not allowed without JSON_ALLOW_NUL"); + return NULL; + } + } + + json = jsonp_stringn_nocheck_own(value, len); + lex->value.string.val = NULL; + lex->value.string.len = 0; + break; + } + + case TOKEN_INTEGER: { + json = json_integer(lex->value.integer); + break; + } + + case TOKEN_REAL: { + json = json_real(lex->value.real); + break; + } + + case TOKEN_TRUE: + json = json_true(); + break; + + case TOKEN_FALSE: + json = json_false(); + break; + + case TOKEN_NULL: + json = json_null(); + break; + + case '{': + json = parse_object(lex, flags, error); + break; + + case '[': + json = parse_array(lex, flags, error); + break; + + case TOKEN_INVALID: + error_set(error, lex, json_error_invalid_syntax, "invalid token"); + return NULL; + + default: + error_set(error, lex, json_error_invalid_syntax, "unexpected token"); + return NULL; + } + + if (!json) + return NULL; + + lex->depth--; + return json; +} + +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) { + json_t *result; + + lex->depth = 0; + + lex_scan(lex, error); + if (!(flags & JSON_DECODE_ANY)) { + if (lex->token != '[' && lex->token != '{') { + error_set(error, lex, json_error_invalid_syntax, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if (!result) + return NULL; + + if (!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if (lex->token != TOKEN_EOF) { + error_set(error, lex, json_error_end_of_input_expected, + "end of file expected"); + json_decref(result); + return NULL; + } + } + + if (error) { + /* Save the position even though there was no error */ + error->position = (int)lex->stream.position; + } + + return result; +} + +typedef struct { + const char *data; + size_t pos; +} string_data_t; + +static int string_get(void *data) { + char c; + string_data_t *stream = (string_data_t *)data; + c = stream->data[stream->pos]; + if (c == '\0') + return EOF; + else { + stream->pos++; + return (unsigned char)c; + } +} + +json_t *json_loads(const char *string, size_t flags, json_error_t *error) { + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if (lex_init(&lex, string_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct { + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) { + char c; + buffer_data_t *stream = data; + if (stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) { + lex_t lex; + json_t *result; + buffer_data_t stream_data; + + jsonp_error_init(error, ""); + + if (buffer == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; + + if (lex_init(&lex, buffer_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) { + lex_t lex; + const char *source; + json_t *result; + + if (input == stdin) + source = ""; + else + source = ""; + + jsonp_error_init(error, source); + + if (input == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)fgetc, flags, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +static int fd_get_func(int *fd) { +#ifdef HAVE_UNISTD_H + uint8_t c; + if (read(*fd, &c, 1) == 1) + return c; +#endif + return EOF; +} + +json_t *json_loadfd(int input, size_t flags, json_error_t *error) { + lex_t lex; + const char *source; + json_t *result; + +#ifdef HAVE_UNISTD_H + if (input == STDIN_FILENO) + source = ""; + else +#endif + source = ""; + + jsonp_error_init(error, source); + + if (input < 0) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)fd_get_func, flags, &input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) { + json_t *result; + FILE *fp; + + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + fp = fopen(path, "rb"); + if (!fp) { + error_set(error, NULL, json_error_cannot_open_file, "unable to open %s: %s", path, + strerror(errno)); + return NULL; + } + + result = json_loadf(fp, flags, error); + + fclose(fp); + return result; +} + +#define MAX_BUF_LEN 1024 + +typedef struct { + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) { + char c; + callback_data_t *stream = data; + + if (stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if (stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, + json_error_t *error) { + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)callback_get, flags, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/thirdparty/jansson/src/lookup3.h b/thirdparty/jansson/src/lookup3.h new file mode 100644 index 0000000..9b39aa1 --- /dev/null +++ b/thirdparty/jansson/src/lookup3.h @@ -0,0 +1,382 @@ +// clang-format off +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include /* defines uint32_t etc */ +#endif + +#ifdef HAVE_SYS_PARAM_H +#include /* attempt to define endianness */ +#endif + +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((size_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef NO_MASKING_TRICK + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; /* fall through */ + case 11: c+=((uint32_t)k[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k[9])<<8; /* fall through */ + case 9 : c+=k[8]; /* fall through */ + case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ + case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ + case 5 : b+=k[4]; /* fall through */ + case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ + case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} diff --git a/thirdparty/jansson/src/memory.c b/thirdparty/jansson/src/memory.c new file mode 100644 index 0000000..2733035 --- /dev/null +++ b/thirdparty/jansson/src/memory.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* C89 allows these to be macros */ +#undef malloc +#undef free + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) { + if (!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) { + if (!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) { return jsonp_strndup(str, strlen(str)); } + +char *jsonp_strndup(const char *str, size_t len) { + char *new_str; + + new_str = jsonp_malloc(len + 1); + if (!new_str) + return NULL; + + memcpy(new_str, str, len); + new_str[len] = '\0'; + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) { + do_malloc = malloc_fn; + do_free = free_fn; +} + +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) { + if (malloc_fn) + *malloc_fn = do_malloc; + if (free_fn) + *free_fn = do_free; +} diff --git a/thirdparty/jansson/src/pack_unpack.c b/thirdparty/jansson/src/pack_unpack.c new file mode 100644 index 0000000..04c116e --- /dev/null +++ b/thirdparty/jansson/src/pack_unpack.c @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" +#include + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; + int has_error; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char *const type_names[] = {"object", "array", "string", "integer", + "real", "true", "false", "null"}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + +static void scanner_init(scanner_t *s, json_error_t *error, size_t flags, + const char *fmt) { + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; + s->has_error = 0; +} + +static void next_token(scanner_t *s) { + const char *t; + s->prev_token = s->token; + + if (s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + if (!token(s) && !*s->fmt) + return; + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while (*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if (*t == '\n') { + s->line++; + s->column = 1; + } else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + if (*t) + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) { + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, enum json_error_code code, + const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, code, fmt, + ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, const char *purpose, size_t *out_len, + int *ours, int optional) { + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + + next_token(s); + t = token(s); + prev_token(s); + + *ours = 0; + if (t != '#' && t != '%' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if (!str) { + if (!optional) { + set_error(s, "", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + return NULL; + } + + length = strlen(str); + + if (!utf8_check_string(str, length)) { + set_error(s, "", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + s->has_error = 1; + return NULL; + } + + *out_len = length; + return (char *)str; + } else if (optional) { + set_error(s, "", json_error_invalid_format, + "Cannot use '%c' on optional strings", t); + s->has_error = 1; + + return NULL; + } + + if (strbuffer_init(&strbuff)) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + while (1) { + str = va_arg(*ap, const char *); + if (!str) { + set_error(s, "", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + + next_token(s); + + if (token(s) == '#') { + length = va_arg(*ap, int); + } else if (token(s) == '%') { + length = va_arg(*ap, size_t); + } else { + prev_token(s); + length = s->has_error ? 0 : strlen(str); + } + + if (!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + next_token(s); + if (token(s) != '+') { + prev_token(s); + break; + } + } + + if (s->has_error) { + strbuffer_close(&strbuff); + return NULL; + } + + if (!utf8_check_string(strbuff.value, strbuff.length)) { + set_error(s, "", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + strbuffer_close(&strbuff); + s->has_error = 1; + return NULL; + } + + *out_len = strbuff.length; + *ours = 1; + return strbuffer_steal_value(&strbuff); +} + +static json_t *pack_object(scanner_t *s, va_list *ap) { + json_t *object = json_object(); + next_token(s); + + while (token(s) != '}') { + char *key; + size_t len; + int ours; + json_t *value; + char valueOptional; + + if (!token(s)) { + set_error(s, "", json_error_invalid_format, + "Unexpected end of format string"); + goto error; + } + + if (token(s) != 's') { + set_error(s, "", json_error_invalid_format, + "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &len, &ours, 0); + + next_token(s); + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if (!value) { + if (ours) + jsonp_free(key); + + if (valueOptional != '*') { + set_error(s, "", json_error_null_value, "NULL object value"); + s->has_error = 1; + } + + next_token(s); + continue; + } + + if (s->has_error) + json_decref(value); + + if (!s->has_error && json_object_set_new_nocheck(object, key, value)) { + set_error(s, "", json_error_out_of_memory, + "Unable to add key \"%s\"", key); + s->has_error = 1; + } + + if (ours) + jsonp_free(key); + + next_token(s); + } + + if (!s->has_error) + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) { + json_t *array = json_array(); + next_token(s); + + while (token(s) != ']') { + json_t *value; + char valueOptional; + + if (!token(s)) { + set_error(s, "", json_error_invalid_format, + "Unexpected end of format string"); + /* Format string errors are unrecoverable. */ + goto error; + } + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if (!value) { + if (valueOptional != '*') { + s->has_error = 1; + } + + next_token(s); + continue; + } + + if (s->has_error) + json_decref(value); + + if (!s->has_error && json_array_append_new(array, value)) { + set_error(s, "", json_error_out_of_memory, + "Unable to append to array"); + s->has_error = 1; + } + + next_token(s); + } + + if (!s->has_error) + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack_string(scanner_t *s, va_list *ap) { + char *str; + char t; + size_t len; + int ours; + int optional; + + next_token(s); + t = token(s); + optional = t == '?' || t == '*'; + if (!optional) + prev_token(s); + + str = read_string(s, ap, "string", &len, &ours, optional); + + if (!str) + return t == '?' && !s->has_error ? json_null() : NULL; + + if (s->has_error) { + /* It's impossible to reach this point if ours != 0, do not free str. */ + return NULL; + } + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + + return json_stringn_nocheck(str, len); +} + +static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) { + json_t *json; + char ntoken; + + next_token(s); + ntoken = token(s); + + if (ntoken != '?' && ntoken != '*') + prev_token(s); + + json = va_arg(*ap, json_t *); + + if (json) + return need_incref ? json_incref(json) : json; + + switch (ntoken) { + case '?': + return json_null(); + case '*': + return NULL; + default: + break; + } + + set_error(s, "", json_error_null_value, "NULL object"); + s->has_error = 1; + return NULL; +} + +static json_t *pack_integer(scanner_t *s, json_int_t value) { + json_t *json = json_integer(value); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + return json; +} + +static json_t *pack_real(scanner_t *s, double value) { + /* Allocate without setting value so we can identify OOM error. */ + json_t *json = json_real(0.0); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + + return NULL; + } + + if (json_real_set(json, value)) { + json_decref(json); + + set_error(s, "", json_error_numeric_overflow, + "Invalid floating point value"); + s->has_error = 1; + + return NULL; + } + + return json; +} + +static json_t *pack(scanner_t *s, va_list *ap) { + switch (token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': /* string */ + return pack_string(s, ap); + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return pack_integer(s, va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return pack_integer(s, va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return pack_real(s, va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return pack_object_inter(s, ap, 1); + + case 'o': /* a json_t object; doesn't increment refcount */ + return pack_object_inter(s, ap, 0); + + default: + set_error(s, "", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + s->has_error = 1; + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { + int ret = -1; + int strict = 0; + int gotopt = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if (hashtable_init(&key_set)) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + return -1; + } + + if (root && !json_is_object(root)) { + set_error(s, "", json_error_wrong_type, "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while (token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if (strict != 0) { + set_error(s, "", json_error_invalid_format, + "Expected '}' after '%c', got '%c'", (strict == 1 ? '!' : '*'), + token(s)); + goto out; + } + + if (!token(s)) { + set_error(s, "", json_error_invalid_format, + "Unexpected end of format string"); + goto out; + } + + if (token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if (token(s) != 's') { + set_error(s, "", json_error_invalid_format, + "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if (!key) { + set_error(s, "", json_error_null_value, "NULL object key"); + goto out; + } + + next_token(s); + + if (token(s) == '?') { + opt = gotopt = 1; + next_token(s); + } + + if (!root) { + /* skipping */ + value = NULL; + } else { + value = json_object_get(root, key); + if (!value && !opt) { + set_error(s, "", json_error_item_not_found, + "Object item not found: %s", key); + goto out; + } + } + + if (unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, strlen(key), json_null()); + next_token(s); + } + + if (strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if (root && strict == 1) { + /* We need to check that all non optional items have been parsed */ + const char *key; + size_t key_len; + /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ + int keys_res = 1; + strbuffer_t unrecognized_keys; + json_t *value; + long unpacked = 0; + + if (gotopt || json_object_size(root) != key_set.size) { + json_object_foreach(root, key, value) { + key_len = strlen(key); + if (!hashtable_get(&key_set, key, key_len)) { + unpacked++; + + /* Save unrecognized keys for the error message */ + if (keys_res == 1) { + keys_res = strbuffer_init(&unrecognized_keys); + } else if (!keys_res) { + keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + + if (!keys_res) + keys_res = + strbuffer_append_bytes(&unrecognized_keys, key, key_len); + } + } + } + if (unpacked) { + set_error(s, "", json_error_end_of_input_expected, + "%li object item(s) left unpacked: %s", unpacked, + keys_res ? "" : strbuffer_value(&unrecognized_keys)); + strbuffer_close(&unrecognized_keys); + goto out; + } + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) { + size_t i = 0; + int strict = 0; + + if (root && !json_is_array(root)) { + set_error(s, "", json_error_wrong_type, "Expected array, got %s", + type_name(root)); + return -1; + } + next_token(s); + + while (token(s) != ']') { + json_t *value; + + if (strict != 0) { + set_error(s, "", json_error_invalid_format, + "Expected ']' after '%c', got '%c'", (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if (!token(s)) { + set_error(s, "", json_error_invalid_format, + "Unexpected end of format string"); + return -1; + } + + if (token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if (!strchr(unpack_value_starters, token(s))) { + set_error(s, "", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + return -1; + } + + if (!root) { + /* skipping */ + value = NULL; + } else { + value = json_array_get(root, i); + if (!value) { + set_error(s, "", json_error_index_out_of_range, + "Array index %lu out of range", (unsigned long)i); + return -1; + } + } + + if (unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if (strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if (root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", json_error_end_of_input_expected, + "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) { + switch (token(s)) { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if (root && !json_is_string(root)) { + set_error(s, "", json_error_wrong_type, + "Expected string, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + const char **str_target; + size_t *len_target = NULL; + + str_target = va_arg(*ap, const char **); + if (!str_target) { + set_error(s, "", json_error_null_value, "NULL string argument"); + return -1; + } + + next_token(s); + + if (token(s) == '%') { + len_target = va_arg(*ap, size_t *); + if (!len_target) { + set_error(s, "", json_error_null_value, + "NULL string length argument"); + return -1; + } + } else + prev_token(s); + + if (root) { + *str_target = json_string_value(root); + if (len_target) + *len_target = json_string_length(root); + } + } + return 0; + + case 'i': + if (root && !json_is_integer(root)) { + set_error(s, "", json_error_wrong_type, + "Expected integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int *); + if (root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if (root && !json_is_integer(root)) { + set_error(s, "", json_error_wrong_type, + "Expected integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t *); + if (root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if (root && !json_is_boolean(root)) { + set_error(s, "", json_error_wrong_type, + "Expected true or false, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int *); + if (root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if (root && !json_is_real(root)) { + set_error(s, "", json_error_wrong_type, + "Expected real, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double *); + if (root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if (root && !json_is_number(root)) { + set_error(s, "", json_error_wrong_type, + "Expected real or integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double *); + if (root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if (root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if (!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t **); + if (root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if (root && !json_is_null(root)) { + set_error(s, "", json_error_wrong_type, + "Expected null, got %s", type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) { + scanner_t s; + va_list ap_copy; + json_t *value; + + if (!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, + "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + /* This will cover all situations where s.has_error is true */ + if (!value) + return NULL; + + next_token(&s); + if (token(&s)) { + json_decref(value); + set_error(&s, "", json_error_invalid_format, + "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) { + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) { + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + va_list ap) { + scanner_t s; + va_list ap_copy; + + if (!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_null_value, "NULL root value"); + return -1; + } + + if (!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, + "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if (unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if (token(&s)) { + set_error(&s, "", json_error_invalid_format, + "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + ...) { + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) { + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/thirdparty/jansson/src/strbuffer.c b/thirdparty/jansson/src/strbuffer.c new file mode 100644 index 0000000..d9bcd43 --- /dev/null +++ b/thirdparty/jansson/src/strbuffer.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "strbuffer.h" +#include "jansson_private.h" +#include +#include + +#define STRBUFFER_MIN_SIZE 16 +#define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) + +int strbuffer_init(strbuffer_t *strbuff) { + strbuff->size = STRBUFFER_MIN_SIZE; + strbuff->length = 0; + + strbuff->value = jsonp_malloc(strbuff->size); + if (!strbuff->value) + return -1; + + /* initialize to empty */ + strbuff->value[0] = '\0'; + return 0; +} + +void strbuffer_close(strbuffer_t *strbuff) { + if (strbuff->value) + jsonp_free(strbuff->value); + + strbuff->size = 0; + strbuff->length = 0; + strbuff->value = NULL; +} + +void strbuffer_clear(strbuffer_t *strbuff) { + strbuff->length = 0; + strbuff->value[0] = '\0'; +} + +const char *strbuffer_value(const strbuffer_t *strbuff) { return strbuff->value; } + +char *strbuffer_steal_value(strbuffer_t *strbuff) { + char *result = strbuff->value; + strbuff->value = NULL; + return result; +} + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte) { + return strbuffer_append_bytes(strbuff, &byte, 1); +} + +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { + if (size >= strbuff->size - strbuff->length) { + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR || + size > STRBUFFER_SIZE_MAX - 1 || + strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, strbuff->length + size + 1); + + new_value = jsonp_malloc(new_size); + if (!new_value) + return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; + } + + memcpy(strbuff->value + strbuff->length, data, size); + strbuff->length += size; + strbuff->value[strbuff->length] = '\0'; + + return 0; +} + +char strbuffer_pop(strbuffer_t *strbuff) { + if (strbuff->length > 0) { + char c = strbuff->value[--strbuff->length]; + strbuff->value[strbuff->length] = '\0'; + return c; + } else + return '\0'; +} diff --git a/thirdparty/jansson/src/strbuffer.h b/thirdparty/jansson/src/strbuffer.h new file mode 100644 index 0000000..70f2646 --- /dev/null +++ b/thirdparty/jansson/src/strbuffer.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STRBUFFER_H +#define STRBUFFER_H + +#include "jansson.h" +#include + +typedef struct { + char *value; + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ +} strbuffer_t; + +int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result)); +void strbuffer_close(strbuffer_t *strbuff); + +void strbuffer_clear(strbuffer_t *strbuff); + +const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ +char *strbuffer_steal_value(strbuffer_t *strbuff); + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); + +char strbuffer_pop(strbuffer_t *strbuff); + +#endif diff --git a/thirdparty/jansson/src/strconv.c b/thirdparty/jansson/src/strconv.c new file mode 100644 index 0000000..c6f4fd1 --- /dev/null +++ b/thirdparty/jansson/src/strconv.c @@ -0,0 +1,132 @@ +#include "jansson_private.h" +#include "strbuffer.h" +#include +#include +#include +#include +#include + +/* need jansson_private_config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) { + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if (*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if (pos) + *pos = *point; +} + +static void from_locale(char *buffer) { + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if (*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if (pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) { + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value, int precision) { + int ret; + char *start, *end; + size_t length; + + if (precision == 0) + precision = 17; + + ret = snprintf(buffer, size, "%.*g", precision, value); + if (ret < 0) + return -1; + + length = (size_t)ret; + if (length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if (strchr(buffer, '.') == NULL && strchr(buffer, 'e') == NULL) { + if (length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if (start) { + start++; + end = start + 1; + + if (*start == '-') + start++; + + while (*end == '0') + end++; + + if (end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/thirdparty/jansson/src/utf.c b/thirdparty/jansson/src/utf.c new file mode 100644 index 0000000..28b2f7d --- /dev/null +++ b/thirdparty/jansson/src/utf.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "utf.h" +#include + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size) { + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) { + buffer[0] = (char)codepoint; + *size = 1; + } else if (codepoint < 0x800) { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } else if (codepoint < 0x10000) { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } else if (codepoint <= 0x10FFFF) { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } else + return -1; + + return 0; +} + +size_t utf8_check_first(char byte) { + unsigned char u = (unsigned char)byte; + + if (u < 0x80) + return 1; + + if (0x80 <= u && u <= 0xBF) { + /* second, third or fourth byte of a multi-byte + sequence, i.e. a "continuation byte" */ + return 0; + } else if (u == 0xC0 || u == 0xC1) { + /* overlong encoding of an ASCII byte */ + return 0; + } else if (0xC2 <= u && u <= 0xDF) { + /* 2-byte sequence */ + return 2; + } + + else if (0xE0 <= u && u <= 0xEF) { + /* 3-byte sequence */ + return 3; + } else if (0xF0 <= u && u <= 0xF4) { + /* 4-byte sequence */ + return 4; + } else { /* u >= 0xF5 */ + /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid + UTF-8 */ + return 0; + } +} + +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) { + size_t i; + int32_t value = 0; + unsigned char u = (unsigned char)buffer[0]; + + if (size == 2) { + value = u & 0x1F; + } else if (size == 3) { + value = u & 0xF; + } else if (size == 4) { + value = u & 0x7; + } else + return 0; + + for (i = 1; i < size; i++) { + u = (unsigned char)buffer[i]; + + if (u < 0x80 || u > 0xBF) { + /* not a continuation byte */ + return 0; + } + + value = (value << 6) + (u & 0x3F); + } + + if (value > 0x10FFFF) { + /* not in Unicode range */ + return 0; + } + + else if (0xD800 <= value && value <= 0xDFFF) { + /* invalid code point (UTF-16 surrogate halves) */ + return 0; + } + + else if ((size == 2 && value < 0x80) || (size == 3 && value < 0x800) || + (size == 4 && value < 0x10000)) { + /* overlong encoding */ + return 0; + } + + if (codepoint) + *codepoint = value; + + return 1; +} + +const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) { + size_t count; + int32_t value; + + if (!bufsize) + return buffer; + + count = utf8_check_first(buffer[0]); + if (count <= 0) + return NULL; + + if (count == 1) + value = (unsigned char)buffer[0]; + else { + if (count > bufsize || !utf8_check_full(buffer, count, &value)) + return NULL; + } + + if (codepoint) + *codepoint = value; + + return buffer + count; +} + +int utf8_check_string(const char *string, size_t length) { + size_t i; + + for (i = 0; i < length; i++) { + size_t count = utf8_check_first(string[i]); + if (count == 0) + return 0; + else if (count > 1) { + if (count > length - i) + return 0; + + if (!utf8_check_full(&string[i], count, NULL)) + return 0; + + i += count - 1; + } + } + + return 1; +} diff --git a/thirdparty/jansson/src/utf.h b/thirdparty/jansson/src/utf.h new file mode 100644 index 0000000..5db99df --- /dev/null +++ b/thirdparty/jansson/src/utf.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTF_H +#define UTF_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDINT_H +#include +#endif + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size); + +size_t utf8_check_first(char byte); +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint); +const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint); + +int utf8_check_string(const char *string, size_t length); + +#endif diff --git a/thirdparty/jansson/src/value.c b/thirdparty/jansson/src/value.c new file mode 100644 index 0000000..07af087 --- /dev/null +++ b/thirdparty/jansson/src/value.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "hashtable.h" +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +#ifndef __sun +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif + +json_t *do_deep_copy(const json_t *json, hashtable_t *parents); + +static JSON_INLINE void json_init(json_t *json, json_type type) { + json->type = type; + json->refcount = 1; +} + +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out) { + size_t key_len = snprintf(key, key_size, "%p", json); + + if (key_len_out) + *key_len_out = key_len; + + if (hashtable_get(parents, key, key_len)) + return -1; + + return hashtable_set(parents, key, key_len, json_null()); +} + +/*** object ***/ + +extern volatile uint32_t hashtable_seed; + +json_t *json_object(void) { + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); + if (!object) + return NULL; + + if (!hashtable_seed) { + /* Autoseed */ + json_object_seed(0); + } + + json_init(&object->json, JSON_OBJECT); + + if (hashtable_init(&object->hashtable)) { + jsonp_free(object); + return NULL; + } + + return &object->json; +} + +static void json_delete_object(json_object_t *object) { + hashtable_close(&object->hashtable); + jsonp_free(object); +} + +size_t json_object_size(const json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return 0; + + object = json_to_object(json); + return object->hashtable.size; +} + +json_t *json_object_get(const json_t *json, const char *key) { + if (!key) + return NULL; + + return json_object_getn(json, key, strlen(key)); +} + +json_t *json_object_getn(const json_t *json, const char *key, size_t key_len) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_get(&object->hashtable, key, key_len); +} + +int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { + if (!key) { + json_decref(value); + return -1; + } + return json_object_setn_new_nocheck(json, key, strlen(key), value); +} + +int json_object_setn_new_nocheck(json_t *json, const char *key, size_t key_len, + json_t *value) { + json_object_t *object; + + if (!value) + return -1; + + if (!key || !json_is_object(json) || json == value) { + json_decref(value); + return -1; + } + object = json_to_object(json); + + if (hashtable_set(&object->hashtable, key, key_len, value)) { + json_decref(value); + return -1; + } + + return 0; +} + +int json_object_set_new(json_t *json, const char *key, json_t *value) { + if (!key) { + json_decref(value); + return -1; + } + + return json_object_setn_new(json, key, strlen(key), value); +} + +int json_object_setn_new(json_t *json, const char *key, size_t key_len, json_t *value) { + if (!key || !utf8_check_string(key, key_len)) { + json_decref(value); + return -1; + } + + return json_object_setn_new_nocheck(json, key, key_len, value); +} + +int json_object_del(json_t *json, const char *key) { + if (!key) + return -1; + + return json_object_deln(json, key, strlen(key)); +} + +int json_object_deln(json_t *json, const char *key, size_t key_len) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return -1; + + object = json_to_object(json); + return hashtable_del(&object->hashtable, key, key_len); +} + +int json_object_clear(json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return -1; + + object = json_to_object(json); + hashtable_clear(&object->hashtable); + + return 0; +} + +int json_object_update(json_t *object, json_t *other) { + const char *key; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if (json_object_set_nocheck(object, key, value)) + return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) { + const char *key; + size_t key_len; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + if (json_object_getn(object, key, key_len)) + json_object_setn_nocheck(object, key, key_len, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) { + const char *key; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if (!json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) { + const char *key; + size_t key_len; + json_t *value; + char loop_key[LOOP_KEY_LEN]; + int res = 0; + size_t loop_key_len; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key), &loop_key_len)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + json_t *v = json_object_get(object, key); + + if (json_is_object(v) && json_is_object(value)) { + if (do_object_update_recursive(v, value, parents)) { + res = -1; + break; + } + } else { + if (json_object_setn_nocheck(object, key, key_len, value)) { + res = -1; + break; + } + } + } + + hashtable_del(parents, loop_key, loop_key_len); + + return res; +} + +int json_object_update_recursive(json_t *object, json_t *other) { + int res; + hashtable_t parents_set; + + if (hashtable_init(&parents_set)) + return -1; + res = do_object_update_recursive(object, other, &parents_set); + hashtable_close(&parents_set); + + return res; +} + +void *json_object_iter(json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter(&object->hashtable); +} + +void *json_object_iter_at(json_t *json, const char *key) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter_at(&object->hashtable, key, strlen(key)); +} + +void *json_object_iter_next(json_t *json, void *iter) { + json_object_t *object; + + if (!json_is_object(json) || iter == NULL) + return NULL; + + object = json_to_object(json); + return hashtable_iter_next(&object->hashtable, iter); +} + +const char *json_object_iter_key(void *iter) { + if (!iter) + return NULL; + + return hashtable_iter_key(iter); +} + +size_t json_object_iter_key_len(void *iter) { + if (!iter) + return 0; + + return hashtable_iter_key_len(iter); +} + +json_t *json_object_iter_value(void *iter) { + if (!iter) + return NULL; + + return (json_t *)hashtable_iter_value(iter); +} + +int json_object_iter_set_new(json_t *json, void *iter, json_t *value) { + if (!json_is_object(json) || !iter || !value) { + json_decref(value); + return -1; + } + + hashtable_iter_set(iter, value); + return 0; +} + +void *json_object_key_to_iter(const char *key) { + if (!key) + return NULL; + + return hashtable_key_to_iter(key); +} + +static int json_object_equal(const json_t *object1, const json_t *object2) { + const char *key; + const json_t *value1, *value2; + + if (json_object_size(object1) != json_object_size(object2)) + return 0; + + json_object_foreach((json_t *)object1, key, value1) { + value2 = json_object_get(object2, key); + + if (!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_object_copy(json_t *object) { + json_t *result; + + const char *key; + json_t *value; + + result = json_object(); + if (!result) + return NULL; + + json_object_foreach(object, key, value) json_object_set_nocheck(result, key, value); + + return result; +} + +static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents) { + json_t *result; + void *iter; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key), &loop_key_len)) + return NULL; + + result = json_object(); + if (!result) + goto out; + + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while (iter) { + const char *key; + const json_t *value; + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + + if (json_object_set_new_nocheck(result, key, do_deep_copy(value, parents))) { + json_decref(result); + result = NULL; + break; + } + iter = json_object_iter_next((json_t *)object, iter); + } + +out: + hashtable_del(parents, loop_key, loop_key_len); + + return result; +} + +/*** array ***/ + +json_t *json_array(void) { + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); + if (!array) + return NULL; + json_init(&array->json, JSON_ARRAY); + + array->entries = 0; + array->size = 8; + + array->table = jsonp_malloc(array->size * sizeof(json_t *)); + if (!array->table) { + jsonp_free(array); + return NULL; + } + + return &array->json; +} + +static void json_delete_array(json_array_t *array) { + size_t i; + + for (i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + jsonp_free(array->table); + jsonp_free(array); +} + +size_t json_array_size(const json_t *json) { + if (!json_is_array(json)) + return 0; + + return json_to_array(json)->entries; +} + +json_t *json_array_get(const json_t *json, size_t index) { + json_array_t *array; + if (!json_is_array(json)) + return NULL; + array = json_to_array(json); + + if (index >= array->entries) + return NULL; + + return array->table[index]; +} + +int json_array_set_new(json_t *json, size_t index, json_t *value) { + json_array_t *array; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (index >= array->entries) { + json_decref(value); + return -1; + } + + json_decref(array->table[index]); + array->table[index] = value; + + return 0; +} + +static void array_move(json_array_t *array, size_t dest, size_t src, size_t count) { + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, size_t dpos, json_t **src, size_t spos, + size_t count) { + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, size_t amount, int copy) { + size_t new_size; + json_t **old_table, **new_table; + + if (array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); + if (!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if (copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + jsonp_free(old_table); + return array->table; + } + + return old_table; +} + +int json_array_append_new(json_t *json, json_t *value) { + json_array_t *array; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; + } + + array->table[array->entries] = value; + array->entries++; + + return 0; +} + +int json_array_insert_new(json_t *json, size_t index, json_t *value) { + json_array_t *array; + json_t **old_table; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if (!old_table) { + json_decref(value); + return -1; + } + + if (old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, array->entries - index); + jsonp_free(old_table); + } else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, size_t index) { + json_array_t *array; + + if (!json_is_array(json)) + return -1; + array = json_to_array(json); + + if (index >= array->entries) + return -1; + + json_decref(array->table[index]); + + /* If we're removing the last element, nothing has to be moved */ + if (index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) { + json_array_t *array; + size_t i; + + if (!json_is_array(json)) + return -1; + array = json_to_array(json); + + for (i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) { + json_array_t *array, *other; + size_t i; + + if (!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if (!json_array_grow(array, other->entries, 1)) + return -1; + + for (i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + +static int json_array_equal(const json_t *array1, const json_t *array2) { + size_t i, size; + + size = json_array_size(array1); + if (size != json_array_size(array2)) + return 0; + + for (i = 0; i < size; i++) { + json_t *value1, *value2; + + value1 = json_array_get(array1, i); + value2 = json_array_get(array2, i); + + if (!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_array_copy(json_t *array) { + json_t *result; + size_t i; + + result = json_array(); + if (!result) + return NULL; + + for (i = 0; i < json_array_size(array); i++) + json_array_append(result, json_array_get(array, i)); + + return result; +} + +static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) { + json_t *result; + size_t i; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key), &loop_key_len)) + return NULL; + + result = json_array(); + if (!result) + goto out; + + for (i = 0; i < json_array_size(array); i++) { + if (json_array_append_new(result, + do_deep_copy(json_array_get(array, i), parents))) { + json_decref(result); + result = NULL; + break; + } + } + +out: + hashtable_del(parents, loop_key, loop_key_len); + + return result; +} + +/*** string ***/ + +static json_t *string_create(const char *value, size_t len, int own) { + char *v; + json_string_t *string; + + if (!value) + return NULL; + + if (own) + v = (char *)value; + else { + v = jsonp_strndup(value, len); + if (!v) + return NULL; + } + + string = jsonp_malloc(sizeof(json_string_t)); + if (!string) { + jsonp_free(v); + return NULL; + } + json_init(&string->json, JSON_STRING); + string->value = v; + string->length = len; + + return &string->json; +} + +json_t *json_string_nocheck(const char *value) { + if (!value) + return NULL; + + return string_create(value, strlen(value), 0); +} + +json_t *json_stringn_nocheck(const char *value, size_t len) { + return string_create(value, len, 0); +} + +/* this is private; "steal" is not a public API concept */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len) { + return string_create(value, len, 1); +} + +json_t *json_string(const char *value) { + if (!value) + return NULL; + + return json_stringn(value, strlen(value)); +} + +json_t *json_stringn(const char *value, size_t len) { + if (!value || !utf8_check_string(value, len)) + return NULL; + + return json_stringn_nocheck(value, len); +} + +const char *json_string_value(const json_t *json) { + if (!json_is_string(json)) + return NULL; + + return json_to_string(json)->value; +} + +size_t json_string_length(const json_t *json) { + if (!json_is_string(json)) + return 0; + + return json_to_string(json)->length; +} + +int json_string_set_nocheck(json_t *json, const char *value) { + if (!value) + return -1; + + return json_string_setn_nocheck(json, value, strlen(value)); +} + +int json_string_setn_nocheck(json_t *json, const char *value, size_t len) { + char *dup; + json_string_t *string; + + if (!json_is_string(json) || !value) + return -1; + + dup = jsonp_strndup(value, len); + if (!dup) + return -1; + + string = json_to_string(json); + jsonp_free(string->value); + string->value = dup; + string->length = len; + + return 0; +} + +int json_string_set(json_t *json, const char *value) { + if (!value) + return -1; + + return json_string_setn(json, value, strlen(value)); +} + +int json_string_setn(json_t *json, const char *value, size_t len) { + if (!value || !utf8_check_string(value, len)) + return -1; + + return json_string_setn_nocheck(json, value, len); +} + +static void json_delete_string(json_string_t *string) { + jsonp_free(string->value); + jsonp_free(string); +} + +static int json_string_equal(const json_t *string1, const json_t *string2) { + json_string_t *s1, *s2; + + s1 = json_to_string(string1); + s2 = json_to_string(string2); + return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); +} + +static json_t *json_string_copy(const json_t *string) { + json_string_t *s; + + s = json_to_string(string); + return json_stringn_nocheck(s->value, s->length); +} + +json_t *json_vsprintf(const char *fmt, va_list ap) { + json_t *json = NULL; + int length; + char *buf; + va_list aq; + va_copy(aq, ap); + + length = vsnprintf(NULL, 0, fmt, ap); + if (length < 0) + goto out; + if (length == 0) { + json = json_string(""); + goto out; + } + + buf = jsonp_malloc((size_t)length + 1); + if (!buf) + goto out; + + vsnprintf(buf, (size_t)length + 1, fmt, aq); + if (!utf8_check_string(buf, length)) { + jsonp_free(buf); + goto out; + } + + json = jsonp_stringn_nocheck_own(buf, length); + +out: + va_end(aq); + return json; +} + +json_t *json_sprintf(const char *fmt, ...) { + json_t *result; + va_list ap; + + va_start(ap, fmt); + result = json_vsprintf(fmt, ap); + va_end(ap); + + return result; +} + +/*** integer ***/ + +json_t *json_integer(json_int_t value) { + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); + if (!integer) + return NULL; + json_init(&integer->json, JSON_INTEGER); + + integer->value = value; + return &integer->json; +} + +json_int_t json_integer_value(const json_t *json) { + if (!json_is_integer(json)) + return 0; + + return json_to_integer(json)->value; +} + +int json_integer_set(json_t *json, json_int_t value) { + if (!json_is_integer(json)) + return -1; + + json_to_integer(json)->value = value; + + return 0; +} + +static void json_delete_integer(json_integer_t *integer) { jsonp_free(integer); } + +static int json_integer_equal(const json_t *integer1, const json_t *integer2) { + return json_integer_value(integer1) == json_integer_value(integer2); +} + +static json_t *json_integer_copy(const json_t *integer) { + return json_integer(json_integer_value(integer)); +} + +/*** real ***/ + +json_t *json_real(double value) { + json_real_t *real; + + if (isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); + if (!real) + return NULL; + json_init(&real->json, JSON_REAL); + + real->value = value; + return &real->json; +} + +double json_real_value(const json_t *json) { + if (!json_is_real(json)) + return 0; + + return json_to_real(json)->value; +} + +int json_real_set(json_t *json, double value) { + if (!json_is_real(json) || isnan(value) || isinf(value)) + return -1; + + json_to_real(json)->value = value; + + return 0; +} + +static void json_delete_real(json_real_t *real) { jsonp_free(real); } + +static int json_real_equal(const json_t *real1, const json_t *real2) { + return json_real_value(real1) == json_real_value(real2); +} + +static json_t *json_real_copy(const json_t *real) { + return json_real(json_real_value(real)); +} + +/*** number ***/ + +double json_number_value(const json_t *json) { + if (json_is_integer(json)) + return (double)json_integer_value(json); + else if (json_is_real(json)) + return json_real_value(json); + else + return 0.0; +} + +/*** simple values ***/ + +json_t *json_true(void) { + static json_t the_true = {JSON_TRUE, (size_t)-1}; + return &the_true; +} + +json_t *json_false(void) { + static json_t the_false = {JSON_FALSE, (size_t)-1}; + return &the_false; +} + +json_t *json_null(void) { + static json_t the_null = {JSON_NULL, (size_t)-1}; + return &the_null; +} + +/*** deletion ***/ + +void json_delete(json_t *json) { + if (!json) + return; + + switch (json_typeof(json)) { + case JSON_OBJECT: + json_delete_object(json_to_object(json)); + break; + case JSON_ARRAY: + json_delete_array(json_to_array(json)); + break; + case JSON_STRING: + json_delete_string(json_to_string(json)); + break; + case JSON_INTEGER: + json_delete_integer(json_to_integer(json)); + break; + case JSON_REAL: + json_delete_real(json_to_real(json)); + break; + default: + return; + } + + /* json_delete is not called for true, false or null */ +} + +/*** equality ***/ + +int json_equal(const json_t *json1, const json_t *json2) { + if (!json1 || !json2) + return 0; + + if (json_typeof(json1) != json_typeof(json2)) + return 0; + + /* this covers true, false and null as they are singletons */ + if (json1 == json2) + return 1; + + switch (json_typeof(json1)) { + case JSON_OBJECT: + return json_object_equal(json1, json2); + case JSON_ARRAY: + return json_array_equal(json1, json2); + case JSON_STRING: + return json_string_equal(json1, json2); + case JSON_INTEGER: + return json_integer_equal(json1, json2); + case JSON_REAL: + return json_real_equal(json1, json2); + default: + return 0; + } +} + +/*** copying ***/ + +json_t *json_copy(json_t *json) { + if (!json) + return NULL; + + switch (json_typeof(json)) { + case JSON_OBJECT: + return json_object_copy(json); + case JSON_ARRAY: + return json_array_copy(json); + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return json; + default: + return NULL; + } +} + +json_t *json_deep_copy(const json_t *json) { + json_t *res; + hashtable_t parents_set; + + if (hashtable_init(&parents_set)) + return NULL; + res = do_deep_copy(json, &parents_set); + hashtable_close(&parents_set); + + return res; +} + +json_t *do_deep_copy(const json_t *json, hashtable_t *parents) { + if (!json) + return NULL; + + switch (json_typeof(json)) { + case JSON_OBJECT: + return json_object_deep_copy(json, parents); + case JSON_ARRAY: + return json_array_deep_copy(json, parents); + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return (json_t *)json; + default: + return NULL; + } +} diff --git a/thirdparty/jansson/src/version.c b/thirdparty/jansson/src/version.c new file mode 100644 index 0000000..f1026af --- /dev/null +++ b/thirdparty/jansson/src/version.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Sean Bright + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson.h" + +const char *jansson_version_str(void) { return JANSSON_VERSION; } + +int jansson_version_cmp(int major, int minor, int micro) { + int diff; + + if ((diff = JANSSON_MAJOR_VERSION - major)) { + return diff; + } + + if ((diff = JANSSON_MINOR_VERSION - minor)) { + return diff; + } + + return JANSSON_MICRO_VERSION - micro; +} diff --git a/thirdparty/mikktspace/CMakeLists.txt b/thirdparty/mikktspace/CMakeLists.txt new file mode 100644 index 0000000..6b38aed --- /dev/null +++ b/thirdparty/mikktspace/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(mikktspace + mikktspace.h + mikktspace.c +) +target_include_directories(mikktspace PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(mikktspace PROPERTIES FOLDER "thirdparty") diff --git a/thirdparty/mikktspace/mikktspace.c b/thirdparty/mikktspace/mikktspace.c new file mode 100644 index 0000000..0342ae0 --- /dev/null +++ b/thirdparty/mikktspace/mikktspace.c @@ -0,0 +1,1899 @@ +/** \file mikktspace/mikktspace.c + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include +#include +#include +#include +#include +#include + +#include "mikktspace.h" + +#define TFALSE 0 +#define TTRUE 1 + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#define INTERNAL_RND_SORT_SEED 39871946 + +// internal structure +typedef struct { + float x, y, z; +} SVec3; + +static tbool veq( const SVec3 v1, const SVec3 v2 ) +{ + return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); +} + +static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x + v2.x; + vRes.y = v1.y + v2.y; + vRes.z = v1.z + v2.z; + + return vRes; +} + + +static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x - v2.x; + vRes.y = v1.y - v2.y; + vRes.z = v1.z - v2.z; + + return vRes; +} + +static SVec3 vscale(const float fS, const SVec3 v) +{ + SVec3 vRes; + + vRes.x = fS * v.x; + vRes.y = fS * v.y; + vRes.z = fS * v.z; + + return vRes; +} + +static float LengthSquared( const SVec3 v ) +{ + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +static float Length( const SVec3 v ) +{ + return sqrtf(LengthSquared(v)); +} + +static SVec3 Normalize( const SVec3 v ) +{ + return vscale(1 / Length(v), v); +} + +static float vdot( const SVec3 v1, const SVec3 v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + + +static tbool NotZero(const float fX) +{ + // could possibly use FLT_EPSILON instead + return fabsf(fX) > FLT_MIN; +} + +static tbool VNotZero(const SVec3 v) +{ + // might change this to an epsilon based test + return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); +} + + + +typedef struct { + int iNrFaces; + int * pTriMembers; +} SSubGroup; + +typedef struct { + int iNrFaces; + int * pFaceIndices; + int iVertexRepresentitive; + tbool bOrientPreservering; +} SGroup; + +// +#define MARK_DEGENERATE 1 +#define QUAD_ONE_DEGEN_TRI 2 +#define GROUP_WITH_ANY 4 +#define ORIENT_PRESERVING 8 + + + +typedef struct { + int FaceNeighbors[3]; + SGroup * AssignedGroup[3]; + + // normalized first order face derivatives + SVec3 vOs, vOt; + float fMagS, fMagT; // original magnitudes + + // determines if the current and the next triangle are a quad. + int iOrgFaceNumber; + int iFlag, iTSpacesOffs; + unsigned char vert_num[4]; +} STriInfo; + +typedef struct { + SVec3 vOs; + float fMagS; + SVec3 vOt; + float fMagT; + int iCounter; // this is to average back into quads. + tbool bOrient; +} STSpace; + +static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn); +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext); + +static int MakeIndex(const int iFace, const int iVert) +{ + assert(iVert>=0 && iVert<4 && iFace>=0); + return (iFace<<2) | (iVert&0x3); +} + +static void IndexToData(int * piFace, int * piVert, const int iIndexIn) +{ + piVert[0] = iIndexIn&0x3; + piFace[0] = iIndexIn>>2; +} + +static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) +{ + STSpace ts_res; + + // this if is important. Due to floating point precision + // averaging when ts0==ts1 will cause a slight difference + // which results in tangent space splits later on + if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT && + veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt)) + { + ts_res.fMagS = pTS0->fMagS; + ts_res.fMagT = pTS0->fMagT; + ts_res.vOs = pTS0->vOs; + ts_res.vOt = pTS0->vOt; + } + else + { + ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS); + ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); + ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); + ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); + if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); + if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); + } + + return ts_res; +} + + + +static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); + + +// degen triangles +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris); +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris); + + +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext) +{ + return genTangSpace(pContext, 180.0f); +} + +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold) +{ + // count nr_triangles + int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL; + STriInfo * pTriInfos = NULL; + SGroup * pGroups = NULL; + STSpace * psTspace = NULL; + int iNrTrianglesIn = 0, f=0, t=0, i=0; + int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; + int iNrActiveGroups = 0, index = 0; + const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); + tbool bRes = TFALSE; + const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); + + // verify all call-backs have been set + if ( pContext->m_pInterface->m_getNumFaces==NULL || + pContext->m_pInterface->m_getNumVerticesOfFace==NULL || + pContext->m_pInterface->m_getPosition==NULL || + pContext->m_pInterface->m_getNormal==NULL || + pContext->m_pInterface->m_getTexCoord==NULL ) + return TFALSE; + + // count triangles on supported faces + for (f=0; fm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts==3) ++iNrTrianglesIn; + else if (verts==4) iNrTrianglesIn += 2; + } + if (iNrTrianglesIn<=0) return TFALSE; + + // allocate memory for an index list + piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); + pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); + if (piTriListIn==NULL || pTriInfos==NULL) + { + if (piTriListIn!=NULL) free(piTriListIn); + if (pTriInfos!=NULL) free(pTriInfos); + return TFALSE; + } + + // make an initial triangle --> face index list + iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); + + // make a welded index list of identical positions and attributes (pos, norm, texc) + //printf("gen welded index list begin\n"); + GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn); + //printf("gen welded index list end\n"); + + // Mark all degenerate triangles + iTotTris = iNrTrianglesIn; + iDegenTriangles = 0; + for (t=0; tm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + + // I've decided to let degenerate triangles and group-with-anythings + // vary between left/right hand coordinate systems at the vertices. + // All healthy triangles on the other hand are built to always be either or. + + /*// force the coordinate system orientation to be uniform for every face. + // (this is already the case for good triangles but not for + // degenerate ones and those with bGroupWithAnything==true) + bool bOrient = psTspace[index].bOrient; + if (psTspace[index].iCounter == 0) // tspace was not derived from a group + { + // look for a space created in GenerateTSpaces() by iCounter>0 + bool bNotFound = true; + int i=1; + while (i 0) bNotFound=false; + else ++i; + } + if (!bNotFound) bOrient = psTspace[index+i].bOrient; + }*/ + + // set data + for (i=0; ivOs.x, pTSpace->vOs.y, pTSpace->vOs.z}; + float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z}; + if (pContext->m_pInterface->m_setTSpace!=NULL) + pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i); + if (pContext->m_pInterface->m_setTSpaceBasic!=NULL) + pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i); + + ++index; + } + } + + free(psTspace); + + + return TTRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef struct { + float vert[3]; + int index; +} STmpVert; + +static const int g_iCells = 2048; + +#ifdef _MSC_VER +# define NOINLINE __declspec(noinline) +#else +# define NOINLINE __attribute__ ((noinline)) +#endif + +// it is IMPORTANT that this function is called to evaluate the hash since +// inlining could potentially reorder instructions and generate different +// results for the same effective input value fVal. +static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) +{ + const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); + const int iIndex = (int)fIndex; + return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1); +} + +static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in); +static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries); +static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); + +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + + // Generate bounding box + int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL; + STmpVert * pTmpVert = NULL; + int i=0, iChannel=0, k=0, e=0; + int iMaxCount=0; + SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim; + float fMin, fMax; + for (i=1; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + + const SVec3 vP = GetPosition(pContext, index); + if (vMin.x > vP.x) vMin.x = vP.x; + else if (vMax.x < vP.x) vMax.x = vP.x; + if (vMin.y > vP.y) vMin.y = vP.y; + else if (vMax.y < vP.y) vMax.y = vP.y; + if (vMin.z > vP.z) vMin.z = vP.z; + else if (vMax.z < vP.z) vMax.z = vP.z; + } + + vDim = vsub(vMax,vMin); + iChannel = 0; + fMin = vMin.x; fMax=vMax.x; + if (vDim.y>vDim.x && vDim.y>vDim.z) + { + iChannel=1; + fMin = vMin.y; + fMax = vMax.y; + } + else if (vDim.z>vDim.x) + { + iChannel=2; + fMin = vMin.z; + fMax = vMax.z; + } + + // make allocations + piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piHashCount = (int *) malloc(sizeof(int)*g_iCells); + piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); + piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); + + if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL) + { + if (piHashTable!=NULL) free(piHashTable); + if (piHashCount!=NULL) free(piHashCount); + if (piHashOffsets!=NULL) free(piHashOffsets); + if (piHashCount2!=NULL) free(piHashCount2); + GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn); + return; + } + memset(piHashCount, 0, sizeof(int)*g_iCells); + memset(piHashCount2, 0, sizeof(int)*g_iCells); + + // count amount of elements in each cell unit + for (i=0; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); + const int iCell = FindGridCell(fMin, fMax, fVal); + ++piHashCount[iCell]; + } + + // evaluate start index of each cell. + piHashOffsets[0]=0; + for (k=1; kpTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c]; + if (fvMax[c]dx && dy>dz) channel=1; + else if (dz>dx) channel=2; + + fSep = 0.5f*(fvMax[channel]+fvMin[channel]); + + // stop if all vertices are NaNs + if (!isfinite(fSep)) + return; + + // terminate recursion when the separation/average value + // is no longer strictly between fMin and fMax values. + if (fSep>=fvMax[channel] || fSep<=fvMin[channel]) + { + // complete the weld + for (l=iL_in; l<=iR_in; l++) + { + int i = pTmpVert[l].index; + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bNotFound = TTRUE; + int l2=iL_in, i2rec=-1; + while (l20); // at least 2 entries + + // separate (by fSep) all points between iL_in and iR_in in pTmpVert[] + while (iL < iR) + { + tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE; + while ((!bReadyLeftSwap) && iL=iL_in && iL<=iR_in); + bReadyLeftSwap = !(pTmpVert[iL].vert[channel]=iL_in && iR<=iR_in); + bReadyRightSwap = pTmpVert[iR].vert[channel]m_pInterface->m_getNumFaces(pContext); f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs; + + if (verts==3) + { + unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num; + pVerts[0]=0; pVerts[1]=1; pVerts[2]=2; + piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0); + piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1); + piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2); + ++iDstTriIndex; // next + } + else + { + { + pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs; + } + + { + // need an order independent way to evaluate + // tspace on quads. This is done by splitting + // along the shortest diagonal. + const int i0 = MakeIndex(f, 0); + const int i1 = MakeIndex(f, 1); + const int i2 = MakeIndex(f, 2); + const int i3 = MakeIndex(f, 3); + const SVec3 T0 = GetTexCoord(pContext, i0); + const SVec3 T1 = GetTexCoord(pContext, i1); + const SVec3 T2 = GetTexCoord(pContext, i2); + const SVec3 T3 = GetTexCoord(pContext, i3); + const float distSQ_02 = LengthSquared(vsub(T2,T0)); + const float distSQ_13 = LengthSquared(vsub(T3,T1)); + tbool bQuadDiagIs_02; + if (distSQ_02m_pInterface->m_getPosition(pContext, pos, iF, iI); + res.x=pos[0]; res.y=pos[1]; res.z=pos[2]; + return res; +} + +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float norm[3]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI); + res.x=norm[0]; res.y=norm[1]; res.z=norm[2]; + return res; +} + +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float texc[2]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI); + res.x=texc[0]; res.y=texc[1]; res.z=1.0f; + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union { + struct + { + int i0, i1, f; + }; + int array[3]; +} SEdge; + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn); +static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn); + +// returns the texture area times 2 +static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[]) +{ + const SVec3 t1 = GetTexCoord(pContext, indices[0]); + const SVec3 t2 = GetTexCoord(pContext, indices[1]); + const SVec3 t3 = GetTexCoord(pContext, indices[2]); + + const float t21x = t2.x-t1.x; + const float t21y = t2.y-t1.y; + const float t31x = t3.x-t1.x; + const float t31y = t3.y-t1.y; + + const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; + + return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2; +} + +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int f=0, i=0, t=0; + // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function. + + // generate neighbor info list + for (f=0; f0 ? ORIENT_PRESERVING : 0); + + if ( NotZero(fSignedAreaSTx2) ) + { + const float fAbsArea = fabsf(fSignedAreaSTx2); + const float fLenOs = Length(vOs); + const float fLenOt = Length(vOt); + const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f; + if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs); + if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt); + + // evaluate magnitudes prior to normalization of vOs and vOt + pTriInfos[f].fMagS = fLenOs / fAbsArea; + pTriInfos[f].fMagT = fLenOt / fAbsArea; + + // if this is a good triangle + if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) + pTriInfos[f].iFlag &= (~GROUP_WITH_ANY); + } + } + + // force otherwise healthy quads to a fixed orientation + while (t<(iNrTrianglesIn-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + + // bad triangles should already have been removed by + // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false + if ((bIsDeg_a||bIsDeg_b)==TFALSE) + { + const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + // if this happens the quad has extremely bad mapping!! + if (bOrientA!=bOrientB) + { + //printf("found quad with bad mapping\n"); + tbool bChooseOrientFirstTri = TFALSE; + if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE; + else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) ) + bChooseOrientFirstTri = TTRUE; + + // force match + { + const int t0 = bChooseOrientFirstTri ? t : (t+1); + const int t1 = bChooseOrientFirstTri ? (t+1) : t; + pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first + pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit + } + } + } + t += 2; + } + else + ++t; + } + + // match up edge pairs + { + SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); + if (pEdges==NULL) + BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); + else + { + BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn); + + free(pEdges); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); + +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) +{ + const int iNrMaxGroups = iNrTrianglesIn*3; + int iNrActiveGroups = 0; + int iOffset = 0, f=0, i=0; + (void)iNrMaxGroups; /* quiet warnings in non debug mode */ + for (f=0; fiVertexRepresentitive = vert_index; + pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0; + pTriInfos[f].AssignedGroup[i]->iNrFaces = 0; + pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset]; + ++iNrActiveGroups; + + AddTriToGroup(pTriInfos[f].AssignedGroup[i], f); + bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + neigh_indexL = pTriInfos[f].FaceNeighbors[i]; + neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexL, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + if (neigh_indexR>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexR, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + + // update offset + iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces; + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + assert(iOffset <= iNrMaxGroups); + } + } + } + + return iNrActiveGroups; +} + +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) +{ + pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; + ++pGroup->iNrFaces; +} + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], + const int iMyTriIndex, SGroup * pGroup) +{ + STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex]; + + // track down vertex + const int iVertRep = pGroup->iVertexRepresentitive; + const int * pVerts = &piTriListIn[3*iMyTriIndex+0]; + int i=-1; + if (pVerts[0]==iVertRep) i=0; + else if (pVerts[1]==iVertRep) i=1; + else if (pVerts[2]==iVertRep) i=2; + assert(i>=0 && i<3); + + // early out + if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE; + else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE; + if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0) + { + // first to group with a group-with-anything triangle + // determines it's orientation. + // This is the only existing order dependency in the code!! + if ( pMyTriInfo->AssignedGroup[0] == NULL && + pMyTriInfo->AssignedGroup[1] == NULL && + pMyTriInfo->AssignedGroup[2] == NULL ) + { + pMyTriInfo->iFlag &= (~ORIENT_PRESERVING); + pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0); + } + } + { + const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + if (bOrient != pGroup->bOrientPreservering) return TFALSE; + } + + AddTriToGroup(pGroup, iMyTriIndex); + pMyTriInfo->AssignedGroup[i] = pGroup; + + { + const int neigh_indexL = pMyTriInfo->FaceNeighbors[i]; + const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); + if (neigh_indexR>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); + } + + + + return TTRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2); +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed); +static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive); + +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext) +{ + STSpace * pSubGroupTspace = NULL; + SSubGroup * pUniSubGroups = NULL; + int * pTmpMembers = NULL; + int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0; + for (g=0; giNrFaces; i++) // triangles + { + const int f = pGroup->pFaceIndices[i]; // triangle number + int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0; + SSubGroup tmp_group; + tbool bFound; + SVec3 n, vOs, vOt; + if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0; + else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1; + else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2; + assert(index>=0 && index<3); + + iVertIndex = piTriListIn[f*3+index]; + assert(iVertIndex==pGroup->iVertexRepresentitive); + + // is normalized already + n = GetNormal(pContext, iVertIndex); + + // project + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + // original face number + iOF_1 = pTriInfos[f].iOrgFaceNumber; + + iMembers = 0; + for (j=0; jiNrFaces; j++) + { + const int t = pGroup->pFaceIndices[j]; // triangle number + const int iOF_2 = pTriInfos[t].iOrgFaceNumber; + + // project + SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); + SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); + if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); + if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); + + { + const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; + // make sure triangles which belong to the same quad are joined. + const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE; + + const float fCosS = vdot(vOs,vOs2); + const float fCosT = vdot(vOt,vOt2); + + assert(f!=t || bSameOrgFace); // sanity check + if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos)) + pTmpMembers[iMembers++] = t; + } + } + + // sort pTmpMembers + tmp_group.iNrFaces = iMembers; + tmp_group.pTriMembers = pTmpMembers; + if (iMembers>1) + { + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + QuickSort(pTmpMembers, 0, iMembers-1, uSeed); + } + + // look for an existing match + bFound = TFALSE; + l=0; + while (liVertexRepresentitive); + ++iUniqueSubGroups; + } + + // output tspace + { + const int iOffs = pTriInfos[f].iTSpacesOffs; + const int iVert = pTriInfos[f].vert_num[index]; + STSpace * pTS_out = &psTspace[iOffs+iVert]; + assert(pTS_out->iCounter<2); + assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering); + if (pTS_out->iCounter==1) + { + *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]); + pTS_out->iCounter = 2; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + else + { + assert(pTS_out->iCounter==0); + *pTS_out = pSubGroupTspace[l]; + pTS_out->iCounter = 1; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + } + } + + // clean up and offset iUniqueTspaces + for (s=0; s=0 && i<3); + + // project + index = piTriListIn[3*f+i]; + n = GetNormal(pContext, index); + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + i2 = piTriListIn[3*f + (i<2?(i+1):0)]; + i1 = piTriListIn[3*f + i]; + i0 = piTriListIn[3*f + (i>0?(i-1):2)]; + + p0 = GetPosition(pContext, i0); + p1 = GetPosition(pContext, i1); + p2 = GetPosition(pContext, i2); + v1 = vsub(p0,p1); + v2 = vsub(p2,p1); + + // project + v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1); + v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2); + + // weight contribution by the angle + // between the two edge vectors + fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); + fAngle = (float) acos(fCos); + fMagS = pTriInfos[f].fMagS; + fMagT = pTriInfos[f].fMagT; + + res.vOs=vadd(res.vOs, vscale(fAngle,vOs)); + res.vOt=vadd(res.vOt,vscale(fAngle,vOt)); + res.fMagS+=(fAngle*fMagS); + res.fMagT+=(fAngle*fMagT); + fAngleSum += fAngle; + } + } + + // normalize + if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); + if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); + if (fAngleSum>0) + { + res.fMagS /= fAngleSum; + res.fMagT /= fAngleSum; + } + + return res; +} + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2) +{ + tbool bStillSame=TTRUE; + int i=0; + if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE; + while (iiNrFaces && bStillSame) + { + bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE; + if (bStillSame) ++i; + } + return bStillSame; +} + +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed) +{ + int iL, iR, n, index, iMid, iTmp; + + // Random + unsigned int t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL=iLeft; iR=iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL]; + + + do + { + while (pSortBuffer[iL] < iMid) + ++iL; + while (pSortBuffer[iR] > iMid) + --iR; + + if (iL <= iR) + { + iTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = iTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSort(pSortBuffer, iLeft, iR, uSeed); + if (iL < iRight) + QuickSort(pSortBuffer, iL, iRight, uSeed); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// + +static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed); +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in); + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn) +{ + // build array of edges + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + int iEntries=0, iCurStartIndex=-1, f=0, i=0; + for (f=0; f pSortBuffer[iRight].array[channel]) + { + sTmp = pSortBuffer[iLeft]; + pSortBuffer[iLeft] = pSortBuffer[iRight]; + pSortBuffer[iRight] = sTmp; + } + return; + } + + // Random + t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL = iLeft; + iR = iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL].array[channel]; + + do + { + while (pSortBuffer[iL].array[channel] < iMid) + ++iL; + while (pSortBuffer[iR].array[channel] > iMid) + --iR; + + if (iL <= iR) + { + sTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = sTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); + if (iL < iRight) + QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); +} + +// resolve ordering and edge number +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in) +{ + *edgenum_out = -1; + + // test if first index is on the edge + if (indices[0]==i0_in || indices[0]==i1_in) + { + // test if second index is on the edge + if (indices[1]==i0_in || indices[1]==i1_in) + { + edgenum_out[0]=0; // first edge + i0_out[0]=indices[0]; + i1_out[0]=indices[1]; + } + else + { + edgenum_out[0]=2; // third edge + i0_out[0]=indices[2]; + i1_out[0]=indices[0]; + } + } + else + { + // only second and third index is on the edge + edgenum_out[0]=1; // second edge + i0_out[0]=indices[1]; + i1_out[0]=indices[2]; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Degenerate triangles //////////////////////////////////// + +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris) +{ + int iNextGoodTriangleSearchIndex=-1; + tbool bStillFindingGoodOnes; + + // locate quads with only one good triangle + int t=0; + while (t<(iTotTris-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + if ((bIsDeg_a^bIsDeg_b)!=0) + { + pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI; + pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI; + } + t += 2; + } + else + ++t; + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + iNextGoodTriangleSearchIndex = 1; + t=0; + bStillFindingGoodOnes = TTRUE; + while (t (t+1)); + + // swap triangle t0 and t1 + if (!bJustADegenerate) + { + int i=0; + for (i=0; i<3; i++) + { + const int index = piTriList_out[t0*3+i]; + piTriList_out[t0*3+i] = piTriList_out[t1*3+i]; + piTriList_out[t1*3+i] = index; + } + { + const STriInfo tri_info = pTriInfos[t0]; + pTriInfos[t0] = pTriInfos[t1]; + pTriInfos[t1] = tri_info; + } + } + else + bStillFindingGoodOnes = TFALSE; // this is not supposed to happen + } + + if (bStillFindingGoodOnes) ++t; + } + + assert(bStillFindingGoodOnes); // code will still work. + assert(iNrTrianglesIn == t); +} + +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) +{ + int t=0, i=0; + // deal with degenerate triangles + // punishment for degenerate triangles is O(N^2) + for (t=iNrTrianglesIn; t http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparty/sokol_app/sokol_app.c b/thirdparty/sokol_app/sokol_app.c index f04cea5..5f77f6c 100644 --- a/thirdparty/sokol_app/sokol_app.c +++ b/thirdparty/sokol_app/sokol_app.c @@ -1,4 +1,5 @@ #define SOKOL_APP_IMPL 1 #define SOKOL_D3D11 1 +#define SOKOL_NO_ENTRY 1 #include "sokol_app.h" diff --git a/thirdparty/sokol_app/sokol_app.h b/thirdparty/sokol_app/sokol_app.h index b0732bf..808a4fd 100644 --- a/thirdparty/sokol_app/sokol_app.h +++ b/thirdparty/sokol_app/sokol_app.h @@ -2669,7 +2669,7 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { sapp_desc desc = *in_desc; desc.sample_count = _sapp_def(desc.sample_count, 1); - desc.swap_interval = _sapp_def(desc.swap_interval, 1); + desc.swap_interval = _sapp_def(desc.swap_interval, 0); desc.html5_canvas_name = _sapp_def(desc.html5_canvas_name, "canvas"); desc.clipboard_size = _sapp_def(desc.clipboard_size, 8192); desc.max_dropped_files = _sapp_def(desc.max_dropped_files, 1); diff --git a/thirdparty/sokol_gfx/CMakeLists.txt b/thirdparty/sokol_gfx/CMakeLists.txt new file mode 100644 index 0000000..c8cf66a --- /dev/null +++ b/thirdparty/sokol_gfx/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(sokol_gfx STATIC + sokol_gfx.h + sokol_gfx.c +) +set_target_properties(sokol_gfx PROPERTIES FOLDER "thirdparty") +target_include_directories(sokol_gfx PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/thirdparty/sokol_gfx/sokol_gfx.c b/thirdparty/sokol_gfx/sokol_gfx.c new file mode 100644 index 0000000..5686b54 --- /dev/null +++ b/thirdparty/sokol_gfx/sokol_gfx.c @@ -0,0 +1,3 @@ +#define SOKOL_GFX_IMPL 1 +#define SOKOL_D3D11 1 +#include "sokol_gfx.h" \ No newline at end of file diff --git a/thirdparty/sokol_gfx/sokol_gfx.h b/thirdparty/sokol_gfx/sokol_gfx.h new file mode 100644 index 0000000..98bb1b4 --- /dev/null +++ b/thirdparty/sokol_gfx/sokol_gfx.h @@ -0,0 +1,16066 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMPL) +#define SOKOL_GFX_IMPL +#endif +#ifndef SOKOL_GFX_INCLUDED +/* + sokol_gfx.h -- simple 3D API wrapper + + Project URL: https://github.com/floooh/sokol + + Example code: https://github.com/floooh/sokol-samples + + Do this: + #define SOKOL_IMPL or + #define SOKOL_GFX_IMPL + before you include this file in *one* C or C++ file to create the + implementation. + + In the same place define one of the following to select the rendering + backend: + #define SOKOL_GLCORE33 + #define SOKOL_GLES2 + #define SOKOL_GLES3 + #define SOKOL_D3D11 + #define SOKOL_METAL + #define SOKOL_WGPU + #define SOKOL_DUMMY_BACKEND + + I.e. for the GL 3.3 Core Profile it should look like this: + + #include ... + #include ... + #define SOKOL_IMPL + #define SOKOL_GLCORE33 + #include "sokol_gfx.h" + + The dummy backend replaces the platform-specific backend code with empty + stub functions. This is useful for writing tests that need to run on the + command line. + + Optionally provide the following defines with your own implementations: + + SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) + SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) + SOKOL_FREE(p) - your own free function (default: free(p)) + SOKOL_LOG(msg) - your own logging function (default: puts(msg)) + SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) + SOKOL_GFX_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_GFX_API_DECL + SOKOL_API_IMPL - public function implementation prefix (default: -) + SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS) + SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case + sokol_gfx.h will not include any platform GL headers and disable + the integrated Win32 GL loader + + If sokol_gfx.h is compiled as a DLL, define the following before + including the declaration or implementation: + + SOKOL_DLL + + On Windows, SOKOL_DLL will define SOKOL_GFX_API_DECL as __declspec(dllexport) + or __declspec(dllimport) as needed. + + If you want to compile without deprecated structs and functions, + define: + + SOKOL_NO_DEPRECATED + + Optionally define the following to force debug checks and validations + even in release mode: + + SOKOL_DEBUG - by default this is defined if _DEBUG is defined + + sokol_gfx DOES NOT: + =================== + - create a window or the 3D-API context/device, you must do this + before sokol_gfx is initialized, and pass any required information + (like 3D device pointers) to the sokol_gfx initialization call + + - present the rendered frame, how this is done exactly usually depends + on how the window and 3D-API context/device was created + + - provide a unified shader language, instead 3D-API-specific shader + source-code or shader-bytecode must be provided (for the "official" + offline shader cross-compiler, see here: + https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) + + STEP BY STEP + ============ + --- to initialize sokol_gfx, after creating a window and a 3D-API + context/device, call: + + sg_setup(const sg_desc*) + + --- create resource objects (at least buffers, shaders and pipelines, + and optionally images and passes): + + sg_buffer sg_make_buffer(const sg_buffer_desc*) + sg_image sg_make_image(const sg_image_desc*) + sg_shader sg_make_shader(const sg_shader_desc*) + sg_pipeline sg_make_pipeline(const sg_pipeline_desc*) + sg_pass sg_make_pass(const sg_pass_desc*) + + --- start rendering to the default frame buffer with: + + sg_begin_default_pass(const sg_pass_action* action, int width, int height) + + ...or alternatively with: + + sg_begin_default_passf(const sg_pass_action* action, float width, float height) + + ...which takes the framebuffer width and height as float values. + + --- or start rendering to an offscreen framebuffer with: + + sg_begin_pass(sg_pass pass, const sg_pass_action* action) + + --- set the pipeline state for the next draw call with: + + sg_apply_pipeline(sg_pipeline pip) + + --- fill an sg_bindings struct with the resource bindings for the next + draw call (1..N vertex buffers, 0 or 1 index buffer, 0..N image objects + to use as textures each on the vertex-shader- and fragment-shader-stage + and then call + + sg_apply_bindings(const sg_bindings* bindings) + + to update the resource bindings + + --- optionally update shader uniform data with: + + sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) + + Read the section 'UNIFORM DATA LAYOUT' to learn about the expected memory layout + of the uniform data passed into sg_apply_uniforms(). + + --- kick off a draw call with: + + sg_draw(int base_element, int num_elements, int num_instances) + + The sg_draw() function unifies all the different ways to render primitives + in a single call (indexed vs non-indexed rendering, and instanced vs non-instanced + rendering). In case of indexed rendering, base_element and num_element specify + indices in the currently bound index buffer. In case of non-indexed rendering + base_element and num_elements specify vertices in the currently bound + vertex-buffer(s). To perform instanced rendering, the rendering pipeline + must be setup for instancing (see sg_pipeline_desc below), a separate vertex buffer + containing per-instance data must be bound, and the num_instances parameter + must be > 1. + + --- finish the current rendering pass with: + + sg_end_pass() + + --- when done with the current frame, call + + sg_commit() + + --- at the end of your program, shutdown sokol_gfx with: + + sg_shutdown() + + --- if you need to destroy resources before sg_shutdown(), call: + + sg_destroy_buffer(sg_buffer buf) + sg_destroy_image(sg_image img) + sg_destroy_shader(sg_shader shd) + sg_destroy_pipeline(sg_pipeline pip) + sg_destroy_pass(sg_pass pass) + + --- to set a new viewport rectangle, call + + sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) + + ...or if you want to specifiy the viewport rectangle with float values: + + sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) + + --- to set a new scissor rect, call: + + sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) + + ...or with float values: + + sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) + + Both sg_apply_viewport() and sg_apply_scissor_rect() must be called + inside a rendering pass + + Note that sg_begin_default_pass() and sg_begin_pass() will reset both the + viewport and scissor rectangles to cover the entire framebuffer. + + --- to update (overwrite) the content of buffer and image resources, call: + + sg_update_buffer(sg_buffer buf, const sg_range* data) + sg_update_image(sg_image img, const sg_image_data* data) + + Buffers and images to be updated must have been created with + SG_USAGE_DYNAMIC or SG_USAGE_STREAM + + Only one update per frame is allowed for buffer and image resources when + using the sg_update_*() functions. The rationale is to have a simple + countermeasure to avoid the CPU scribbling over data the GPU is currently + using, or the CPU having to wait for the GPU + + Buffer and image updates can be partial, as long as a rendering + operation only references the valid (updated) data in the + buffer or image. + + --- to append a chunk of data to a buffer resource, call: + + int sg_append_buffer(sg_buffer buf, const sg_range* data) + + The difference to sg_update_buffer() is that sg_append_buffer() + can be called multiple times per frame to append new data to the + buffer piece by piece, optionally interleaved with draw calls referencing + the previously written data. + + sg_append_buffer() returns a byte offset to the start of the + written data, this offset can be assigned to + sg_bindings.vertex_buffer_offsets[n] or + sg_bindings.index_buffer_offset + + Code example: + + for (...) { + const void* data = ...; + const int num_bytes = ...; + int offset = sg_append_buffer(buf, &(sg_range) { .ptr=data, .size=num_bytes }); + bindings.vertex_buffer_offsets[0] = offset; + sg_apply_pipeline(pip); + sg_apply_bindings(&bindings); + sg_apply_uniforms(...); + sg_draw(...); + } + + A buffer to be used with sg_append_buffer() must have been created + with SG_USAGE_DYNAMIC or SG_USAGE_STREAM. + + If the application appends more data to the buffer then fits into + the buffer, the buffer will go into the "overflow" state for the + rest of the frame. + + Any draw calls attempting to render an overflown buffer will be + silently dropped (in debug mode this will also result in a + validation error). + + You can also check manually if a buffer is in overflow-state by calling + + bool sg_query_buffer_overflow(sg_buffer buf) + + NOTE: Due to restrictions in underlying 3D-APIs, appended chunks of + data will be 4-byte aligned in the destination buffer. This means + that there will be gaps in index buffers containing 16-bit indices + when the number of indices in a call to sg_append_buffer() is + odd. This isn't a problem when each call to sg_append_buffer() + is associated with one draw call, but will be problematic when + a single indexed draw call spans several appended chunks of indices. + + --- to check at runtime for optional features, limits and pixelformat support, + call: + + sg_features sg_query_features() + sg_limits sg_query_limits() + sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt) + + --- if you need to call into the underlying 3D-API directly, you must call: + + sg_reset_state_cache() + + ...before calling sokol_gfx functions again + + --- you can inspect the original sg_desc structure handed to sg_setup() + by calling sg_query_desc(). This will return an sg_desc struct with + the default values patched in instead of any zero-initialized values + + --- you can inspect various internal resource attributes via: + + sg_buffer_info sg_query_buffer_info(sg_buffer buf) + sg_image_info sg_query_image_info(sg_image img) + sg_shader_info sg_query_shader_info(sg_shader shd) + sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip) + sg_pass_info sg_query_pass_info(sg_pass pass) + + ...please note that the returned info-structs are tied quite closely + to sokol_gfx.h internals, and may change more often than other + public API functions and structs. + + --- you can ask at runtime what backend sokol_gfx.h has been compiled + for, or whether the GLES3 backend had to fall back to GLES2 with: + + sg_backend sg_query_backend(void) + + --- you can query the default resource creation parameters through the functions + + sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc) + sg_image_desc sg_query_image_defaults(const sg_image_desc* desc) + sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc) + sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc) + sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc) + + These functions take a pointer to a desc structure which may contain + zero-initialized items for default values. These zero-init values + will be replaced with their concrete values in the returned desc + struct. + + ON INITIALIZATION: + ================== + When calling sg_setup(), a pointer to an sg_desc struct must be provided + which contains initialization options. These options provide two types + of information to sokol-gfx: + + (1) upper bounds and limits needed to allocate various internal + data structures: + - the max number of resources of each type that can + be alive at the same time, this is used for allocating + internal pools + - the max overall size of uniform data that can be + updated per frame, including a worst-case alignment + per uniform update (this worst-case alignment is 256 bytes) + - the max size of all dynamic resource updates (sg_update_buffer, + sg_append_buffer and sg_update_image) per frame + - the max number of entries in the texture sampler cache + (how many unique texture sampler can exist at the same time) + Not all of those limit values are used by all backends, but it is + good practice to provide them none-the-less. + + (2) 3D-API "context information" (sometimes also called "bindings"): + sokol_gfx.h doesn't create or initialize 3D API objects which are + closely related to the presentation layer (this includes the "rendering + device", the swapchain, and any objects which depend on the + swapchain). These API objects (or callback functions to obtain + them, if those objects might change between frames), must + be provided in a nested sg_context_desc struct inside the + sg_desc struct. If sokol_gfx.h is used together with + sokol_app.h, have a look at the sokol_glue.h header which provides + a convenience function to get a sg_context_desc struct filled out + with context information provided by sokol_app.h + + See the documention block of the sg_desc struct below for more information. + + + UNIFORM DATA LAYOUT: + ==================== + NOTE: if you use the sokol-shdc shader compiler tool, you don't need to worry + about the following details. + + The data that's passed into the sg_apply_uniforms() function must adhere to + specific layout rules so that the GPU shader finds the uniform block + items at the right offset. + + For the D3D11 and Metal backends, sokol-gfx only cares about the size of uniform + blocks, but not about the internal layout. The data will just be copied into + a uniform/constant buffer in a single operation and it's up you to arrange the + CPU-side layout so that it matches the GPU side layout. This also means that with + the D3D11 and Metal backends you are not limited to a 'cross-platform' subset + of uniform variable types. + + If you ever only use one of the D3D11, Metal *or* WebGPU backend, you can stop reading here. + + For the GL backends, the internal layout of uniform blocks matters though, + and you are limited to a small number of uniform variable types. This is + because sokol-gfx must be able to locate the uniform block members in order + to upload them to the GPU with glUniformXXX() calls. + + To describe the uniform block layout to sokol-gfx, the following information + must be passed to the sg_make_shader() call in the sg_shader_desc struct: + + - a hint about the used packing rule (either SG_UNIFORMLAYOUT_NATIVE or + SG_UNIFORMLAYOUT_STD140) + - a list of the uniform block members types in the correct order they + appear on the CPU side + + For example if the GLSL shader has the following uniform declarations: + + uniform mat4 mvp; + uniform vec2 offset0; + uniform vec2 offset1; + uniform vec2 offset2; + + ...and on the CPU side, there's a similar C struct: + + typedef struct { + float mvp[16]; + float offset0[2]; + float offset1[2]; + float offset2[2]; + } params_t; + + ...the uniform block description in the sg_shader_desc must look like this: + + sg_shader_desc desc = { + .vs.uniform_blocks[0] = { + .size = sizeof(params_t), + .layout = SG_UNIFORMLAYOUT_NATIVE, // this is the default and can be omitted + .uniforms = { + // order must be the same as in 'params_t': + [0] = { .name = "mvp", .type = SG_UNIFORMTYPE_MAT4 }, + [1] = { .name = "offset0", .type = SG_UNIFORMTYPE_VEC2 }, + [2] = { .name = "offset1", .type = SG_UNIFORMTYPE_VEC2 }, + [3] = { .name = "offset2", .type = SG_UNIFORMTYPE_VEC2 }, + } + } + }; + + With this information sokol-gfx can now compute the correct offsets of the data items + within the uniform block struct. + + The SG_UNIFORMLAYOUT_NATIVE packing rule works fine if only the GL backends are used, + but for proper D3D11/Metal/GL a subset of the std140 layout must be used which is + described in the next section: + + + CROSS-BACKEND COMMON UNIFORM DATA LAYOUT + ======================================== + For cross-platform / cross-3D-backend code it is important that the same uniform block + layout on the CPU side can be used for all sokol-gfx backends. To achieve this, + a common subset of the std140 layout must be used: + + - The uniform block layout hint in sg_shader_desc must be explicitely set to + SG_UNIFORMLAYOUT_STD140. + - Only the following GLSL uniform types can be used (with their associated sokol-gfx enums): + - float => SG_UNIFORMTYPE_FLOAT + - vec2 => SG_UNIFORMTYPE_FLOAT2 + - vec3 => SG_UNIFORMTYPE_FLOAT3 + - vec4 => SG_UNIFORMTYPE_FLOAT4 + - int => SG_UNIFORMTYPE_INT + - ivec2 => SG_UNIFORMTYPE_INT2 + - ivec3 => SG_UNIFORMTYPE_INT3 + - ivec4 => SG_UNIFORMTYPE_INT4 + - mat4 => SG_UNIFORMTYPE_MAT4 + - Alignment for those types must be as follows (in bytes): + - float => 4 + - vec2 => 8 + - vec3 => 16 + - vec4 => 16 + - int => 4 + - ivec2 => 8 + - ivec3 => 16 + - ivec4 => 16 + - mat4 => 16 + - Arrays are only allowed for the following types: vec4, int4, mat4. + + Note that the HLSL cbuffer layout rules are slightly different from the + std140 layout rules, this means that the cbuffer declarations in HLSL code + must be tweaked so that the layout is compatible with std140. + + The by far easiest way to tacke the common uniform block layout problem is + to use the sokol-shdc shader cross-compiler tool! + + + BACKEND-SPECIFIC TOPICS: + ======================== + --- The GL backends need to know about the internal structure of uniform + blocks, and the texture sampler-name and -type. The uniform layout details + are described in the UNIFORM DATA LAYOUT section above. + + // uniform block structure and texture image definition in sg_shader_desc: + sg_shader_desc desc = { + // uniform block description (size and internal structure) + .vs.uniform_blocks[0] = { + ... + }, + // one texture on the fragment-shader-stage, GLES2/WebGL needs name and image type + .fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_ARRAY } + ... + }; + + --- the Metal and D3D11 backends only need to know the size of uniform blocks, + not their internal member structure, and they only need to know + the type of a texture sampler, not its name: + + sg_shader_desc desc = { + .vs.uniform_blocks[0].size = sizeof(params_t), + .fs.images[0].type = SG_IMAGETYPE_ARRAY, + ... + }; + + --- when creating a shader object, GLES2/WebGL need to know the vertex + attribute names as used in the vertex shader: + + sg_shader_desc desc = { + .attrs = { + [0] = { .name="position" }, + [1] = { .name="color1" } + } + }; + + The vertex attribute names provided when creating a shader will be + used later in sg_create_pipeline() for matching the vertex layout + to vertex shader inputs. + + --- on D3D11 you need to provide a semantic name and semantic index in the + shader description struct instead (see the D3D11 documentation on + D3D11_INPUT_ELEMENT_DESC for details): + + sg_shader_desc desc = { + .attrs = { + [0] = { .sem_name="POSITION", .sem_index=0 } + [1] = { .sem_name="COLOR", .sem_index=1 } + } + }; + + The provided semantic information will be used later in sg_create_pipeline() + to match the vertex layout to vertex shader inputs. + + --- on D3D11, and when passing HLSL source code (instead of byte code) to shader + creation, you can optionally define the shader model targets on the vertex + stage: + + sg_shader_Desc desc = { + .vs = { + ... + .d3d11_target = "vs_5_0" + }, + .fs = { + ... + .d3d11_target = "ps_5_0" + } + }; + + The default targets are "ps_4_0" and "fs_4_0". Note that those target names + are only used when compiling shaders from source. They are ignored when + creating a shader from bytecode. + + --- on Metal, GL 3.3 or GLES3/WebGL2, you don't need to provide an attribute + name or semantic name, since vertex attributes can be bound by their slot index + (this is mandatory in Metal, and optional in GL): + + sg_pipeline_desc desc = { + .layout = { + .attrs = { + [0] = { .format=SG_VERTEXFORMAT_FLOAT3 }, + [1] = { .format=SG_VERTEXFORMAT_FLOAT4 } + } + } + }; + + WORKING WITH CONTEXTS + ===================== + sokol-gfx allows to switch between different rendering contexts and + associate resource objects with contexts. This is useful to + create GL applications that render into multiple windows. + + A rendering context keeps track of all resources created while + the context is active. When the context is destroyed, all resources + "belonging to the context" are destroyed as well. + + A default context will be created and activated implicitly in + sg_setup(), and destroyed in sg_shutdown(). So for a typical application + which *doesn't* use multiple contexts, nothing changes, and calling + the context functions isn't necessary. + + Three functions have been added to work with contexts: + + --- sg_context sg_setup_context(): + This must be called once after a GL context has been created and + made active. + + --- void sg_activate_context(sg_context ctx) + This must be called after making a different GL context active. + Apart from 3D-API-specific actions, the call to sg_activate_context() + will internally call sg_reset_state_cache(). + + --- void sg_discard_context(sg_context ctx) + This must be called right before a GL context is destroyed and + will destroy all resources associated with the context (that + have been created while the context was active) The GL context must be + active at the time sg_discard_context(sg_context ctx) is called. + + Also note that resources (buffers, images, shaders and pipelines) must + only be used or destroyed while the same GL context is active that + was also active while the resource was created (an exception is + resource sharing on GL, such resources can be used while + another context is active, but must still be destroyed under + the same context that was active during creation). + + For more information, check out the multiwindow-glfw sample: + + https://github.com/floooh/sokol-samples/blob/master/glfw/multiwindow-glfw.c + + TRACE HOOKS: + ============ + sokol_gfx.h optionally allows to install "trace hook" callbacks for + each public API functions. When a public API function is called, and + a trace hook callback has been installed for this function, the + callback will be invoked with the parameters and result of the function. + This is useful for things like debugging- and profiling-tools, or + keeping track of resource creation and destruction. + + To use the trace hook feature: + + --- Define SOKOL_TRACE_HOOKS before including the implementation. + + --- Setup an sg_trace_hooks structure with your callback function + pointers (keep all function pointers you're not interested + in zero-initialized), optionally set the user_data member + in the sg_trace_hooks struct. + + --- Install the trace hooks by calling sg_install_trace_hooks(), + the return value of this function is another sg_trace_hooks + struct which contains the previously set of trace hooks. + You should keep this struct around, and call those previous + functions pointers from your own trace callbacks for proper + chaining. + + As an example of how trace hooks are used, have a look at the + imgui/sokol_gfx_imgui.h header which implements a realtime + debugging UI for sokol_gfx.h on top of Dear ImGui. + + A NOTE ON PORTABLE PACKED VERTEX FORMATS: + ========================================= + There are two things to consider when using packed + vertex formats like UBYTE4, SHORT2, etc which need to work + across all backends: + + - D3D11 can only convert *normalized* vertex formats to + floating point during vertex fetch, normalized formats + have a trailing 'N', and are "normalized" to a range + -1.0..+1.0 (for the signed formats) or 0.0..1.0 (for the + unsigned formats): + + - SG_VERTEXFORMAT_BYTE4N + - SG_VERTEXFORMAT_UBYTE4N + - SG_VERTEXFORMAT_SHORT2N + - SG_VERTEXFORMAT_USHORT2N + - SG_VERTEXFORMAT_SHORT4N + - SG_VERTEXFORMAT_USHORT4N + + D3D11 will not convert *non-normalized* vertex formats to floating point + vertex shader inputs, those can only be uses with the *ivecn* vertex shader + input types when D3D11 is used as backend (GL and Metal can use both formats) + + - SG_VERTEXFORMAT_BYTE4, + - SG_VERTEXFORMAT_UBYTE4 + - SG_VERTEXFORMAT_SHORT2 + - SG_VERTEXFORMAT_SHORT4 + + - WebGL/GLES2 cannot use integer vertex shader inputs (int or ivecn) + + - SG_VERTEXFORMAT_UINT10_N2 is not supported on WebGL/GLES2 + + So for a vertex input layout which works on all platforms, only use the following + vertex formats, and if needed "expand" the normalized vertex shader + inputs in the vertex shader by multiplying with 127.0, 255.0, 32767.0 or + 65535.0: + + - SG_VERTEXFORMAT_FLOAT, + - SG_VERTEXFORMAT_FLOAT2, + - SG_VERTEXFORMAT_FLOAT3, + - SG_VERTEXFORMAT_FLOAT4, + - SG_VERTEXFORMAT_BYTE4N, + - SG_VERTEXFORMAT_UBYTE4N, + - SG_VERTEXFORMAT_SHORT2N, + - SG_VERTEXFORMAT_USHORT2N + - SG_VERTEXFORMAT_SHORT4N, + - SG_VERTEXFORMAT_USHORT4N + + TODO: + ==== + - talk about asynchronous resource creation + + zlib/libpng license + + Copyright (c) 2018 Andre Weissflog + + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from the + use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +#define SOKOL_GFX_INCLUDED (1) +#include // size_t +#include +#include + +#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_API_DECL) +#define SOKOL_GFX_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_GFX_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMPL) +#define SOKOL_GFX_API_DECL __declspec(dllexport) +#elif defined(_WIN32) && defined(SOKOL_DLL) +#define SOKOL_GFX_API_DECL __declspec(dllimport) +#else +#define SOKOL_GFX_API_DECL extern +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Resource id typedefs: + + sg_buffer: vertex- and index-buffers + sg_image: textures and render targets + sg_shader: vertex- and fragment-shaders, uniform blocks + sg_pipeline: associated shader and vertex-layouts, and render states + sg_pass: a bundle of render targets and actions on them + sg_context: a 'context handle' for switching between 3D-API contexts + + Instead of pointers, resource creation functions return a 32-bit + number which uniquely identifies the resource object. + + The 32-bit resource id is split into a 16-bit pool index in the lower bits, + and a 16-bit 'unique counter' in the upper bits. The index allows fast + pool lookups, and combined with the unique-mask it allows to detect + 'dangling accesses' (trying to use an object which no longer exists, and + its pool slot has been reused for a new object) + + The resource ids are wrapped into a struct so that the compiler + can complain when the wrong resource type is used. +*/ +typedef struct sg_buffer { uint32_t id; } sg_buffer; +typedef struct sg_image { uint32_t id; } sg_image; +typedef struct sg_shader { uint32_t id; } sg_shader; +typedef struct sg_pipeline { uint32_t id; } sg_pipeline; +typedef struct sg_pass { uint32_t id; } sg_pass; +typedef struct sg_context { uint32_t id; } sg_context; + +/* + sg_range is a pointer-size-pair struct used to pass memory blobs into + sokol-gfx. When initialized from a value type (array or struct), you can + use the SG_RANGE() macro to build an sg_range struct. For functions which + take either a sg_range pointer, or a (C++) sg_range reference, use the + SG_RANGE_REF macro as a solution which compiles both in C and C++. +*/ +typedef struct sg_range { + const void* ptr; + size_t size; +} sg_range; + +// disabling this for every includer isn't great, but the warnings are also quite pointless +#if defined(_MSC_VER) +#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ +#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */ +#endif +#if defined(__cplusplus) +#define SG_RANGE(x) sg_range{ &x, sizeof(x) } +#define SG_RANGE_REF(x) sg_range{ &x, sizeof(x) } +#else +#define SG_RANGE(x) (sg_range){ &x, sizeof(x) } +#define SG_RANGE_REF(x) &(sg_range){ &x, sizeof(x) } +#endif + +// various compile-time constants +enum { + SG_INVALID_ID = 0, + SG_NUM_SHADER_STAGES = 2, + SG_NUM_INFLIGHT_FRAMES = 2, + SG_MAX_COLOR_ATTACHMENTS = 4, + SG_MAX_SHADERSTAGE_BUFFERS = 8, + SG_MAX_SHADERSTAGE_IMAGES = 12, + SG_MAX_SHADERSTAGE_UBS = 4, + SG_MAX_UB_MEMBERS = 16, + SG_MAX_VERTEX_ATTRIBUTES = 16, /* NOTE: actual max vertex attrs can be less on GLES2, see sg_limits! */ + SG_MAX_MIPMAPS = 16, + SG_MAX_TEXTUREARRAY_LAYERS = 128 +}; + +/* + sg_color + + An RGBA color value. +*/ +typedef struct sg_color { float r, g, b, a; } sg_color; + +/* + sg_backend + + The active 3D-API backend, use the function sg_query_backend() + to get the currently active backend. + + NOTE that SG_BACKEND_GLES2 will be returned if sokol-gfx was + compiled with SOKOL_GLES3, but the runtime platform doesn't support + GLES3/WebGL2 and sokol-gfx had to fallback to GLES2/WebGL. +*/ +typedef enum sg_backend { + SG_BACKEND_GLCORE33, + SG_BACKEND_GLES2, + SG_BACKEND_GLES3, + SG_BACKEND_D3D11, + SG_BACKEND_METAL_IOS, + SG_BACKEND_METAL_MACOS, + SG_BACKEND_METAL_SIMULATOR, + SG_BACKEND_WGPU, + SG_BACKEND_DUMMY, +} sg_backend; + +/* + sg_pixel_format + + sokol_gfx.h basically uses the same pixel formats as WebGPU, since these + are supported on most newer GPUs. GLES2 and WebGL only supports a much + smaller subset of actually available pixel formats. Call + sg_query_pixelformat() to check at runtime if a pixel format supports the + desired features. + + A pixelformat name consist of three parts: + + - components (R, RG, RGB or RGBA) + - bit width per component (8, 16 or 32) + - component data type: + - unsigned normalized (no postfix) + - signed normalized (SN postfix) + - unsigned integer (UI postfix) + - signed integer (SI postfix) + - float (F postfix) + + Not all pixel formats can be used for everything, call sg_query_pixelformat() + to inspect the capabilities of a given pixelformat. The function returns + an sg_pixelformat_info struct with the following bool members: + + - sample: the pixelformat can be sampled as texture at least with + nearest filtering + - filter: the pixelformat can be samples as texture with linear + filtering + - render: the pixelformat can be used for render targets + - blend: blending is supported when using the pixelformat for + render targets + - msaa: multisample-antialiasing is supported when using the + pixelformat for render targets + - depth: the pixelformat can be used for depth-stencil attachments + + When targeting GLES2/WebGL, the only safe formats to use + as texture are SG_PIXELFORMAT_R8 and SG_PIXELFORMAT_RGBA8. For rendering + in GLES2/WebGL, only SG_PIXELFORMAT_RGBA8 is safe. All other formats + must be checked via sg_query_pixelformats(). + + The default pixel format for texture images is SG_PIXELFORMAT_RGBA8. + + The default pixel format for render target images is platform-dependent: + - for Metal and D3D11 it is SG_PIXELFORMAT_BGRA8 + - for GL backends it is SG_PIXELFORMAT_RGBA8 + + This is mainly because of the default framebuffer which is setup outside + of sokol_gfx.h. On some backends, using BGRA for the default frame buffer + allows more efficient frame flips. For your own offscreen-render-targets, + use whatever renderable pixel format is convenient for you. +*/ +typedef enum sg_pixel_format { + _SG_PIXELFORMAT_DEFAULT, /* value 0 reserved for default-init */ + SG_PIXELFORMAT_NONE, + + SG_PIXELFORMAT_R8, + SG_PIXELFORMAT_R8SN, + SG_PIXELFORMAT_R8UI, + SG_PIXELFORMAT_R8SI, + + SG_PIXELFORMAT_R16, + SG_PIXELFORMAT_R16SN, + SG_PIXELFORMAT_R16UI, + SG_PIXELFORMAT_R16SI, + SG_PIXELFORMAT_R16F, + SG_PIXELFORMAT_RG8, + SG_PIXELFORMAT_RG8SN, + SG_PIXELFORMAT_RG8UI, + SG_PIXELFORMAT_RG8SI, + + SG_PIXELFORMAT_R32UI, + SG_PIXELFORMAT_R32SI, + SG_PIXELFORMAT_R32F, + SG_PIXELFORMAT_RG16, + SG_PIXELFORMAT_RG16SN, + SG_PIXELFORMAT_RG16UI, + SG_PIXELFORMAT_RG16SI, + SG_PIXELFORMAT_RG16F, + SG_PIXELFORMAT_RGBA8, + SG_PIXELFORMAT_RGBA8SN, + SG_PIXELFORMAT_RGBA8UI, + SG_PIXELFORMAT_RGBA8SI, + SG_PIXELFORMAT_BGRA8, + SG_PIXELFORMAT_RGB10A2, + SG_PIXELFORMAT_RG11B10F, + + SG_PIXELFORMAT_RG32UI, + SG_PIXELFORMAT_RG32SI, + SG_PIXELFORMAT_RG32F, + SG_PIXELFORMAT_RGBA16, + SG_PIXELFORMAT_RGBA16SN, + SG_PIXELFORMAT_RGBA16UI, + SG_PIXELFORMAT_RGBA16SI, + SG_PIXELFORMAT_RGBA16F, + + SG_PIXELFORMAT_RGBA32UI, + SG_PIXELFORMAT_RGBA32SI, + SG_PIXELFORMAT_RGBA32F, + + SG_PIXELFORMAT_DEPTH, + SG_PIXELFORMAT_DEPTH_STENCIL, + + SG_PIXELFORMAT_BC1_RGBA, + SG_PIXELFORMAT_BC2_RGBA, + SG_PIXELFORMAT_BC3_RGBA, + SG_PIXELFORMAT_BC4_R, + SG_PIXELFORMAT_BC4_RSN, + SG_PIXELFORMAT_BC5_RG, + SG_PIXELFORMAT_BC5_RGSN, + SG_PIXELFORMAT_BC6H_RGBF, + SG_PIXELFORMAT_BC6H_RGBUF, + SG_PIXELFORMAT_BC7_RGBA, + SG_PIXELFORMAT_PVRTC_RGB_2BPP, + SG_PIXELFORMAT_PVRTC_RGB_4BPP, + SG_PIXELFORMAT_PVRTC_RGBA_2BPP, + SG_PIXELFORMAT_PVRTC_RGBA_4BPP, + SG_PIXELFORMAT_ETC2_RGB8, + SG_PIXELFORMAT_ETC2_RGB8A1, + SG_PIXELFORMAT_ETC2_RGBA8, + SG_PIXELFORMAT_ETC2_RG11, + SG_PIXELFORMAT_ETC2_RG11SN, + + _SG_PIXELFORMAT_NUM, + _SG_PIXELFORMAT_FORCE_U32 = 0x7FFFFFFF +} sg_pixel_format; + +/* + Runtime information about a pixel format, returned + by sg_query_pixelformat(). +*/ +typedef struct sg_pixelformat_info { + bool sample; // pixel format can be sampled in shaders + bool filter; // pixel format can be sampled with filtering + bool render; // pixel format can be used as render target + bool blend; // alpha-blending is supported + bool msaa; // pixel format can be used as MSAA render target + bool depth; // pixel format is a depth format + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[3]; + #endif +} sg_pixelformat_info; + +/* + Runtime information about available optional features, + returned by sg_query_features() +*/ +typedef struct sg_features { + bool instancing; // hardware instancing supported + bool origin_top_left; // framebuffer and texture origin is in top left corner + bool multiple_render_targets; // offscreen render passes can have multiple render targets attached + bool msaa_render_targets; // offscreen render passes support MSAA antialiasing + bool imagetype_3d; // creation of SG_IMAGETYPE_3D images is supported + bool imagetype_array; // creation of SG_IMAGETYPE_ARRAY images is supported + bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported + bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state + bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[3]; + #endif +} sg_features; + +/* + Runtime information about resource limits, returned by sg_query_limit() +*/ +typedef struct sg_limits { + int max_image_size_2d; // max width/height of SG_IMAGETYPE_2D images + int max_image_size_cube; // max width/height of SG_IMAGETYPE_CUBE images + int max_image_size_3d; // max width/height/depth of SG_IMAGETYPE_3D images + int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images + int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images + int max_vertex_attrs; // <= SG_MAX_VERTEX_ATTRIBUTES or less (on some GLES2 impls) + int gl_max_vertex_uniform_vectors; // <= GL_MAX_VERTEX_UNIFORM_VECTORS (only on GL backends) +} sg_limits; + +/* + sg_resource_state + + The current state of a resource in its resource pool. + Resources start in the INITIAL state, which means the + pool slot is unoccupied and can be allocated. When a resource is + created, first an id is allocated, and the resource pool slot + is set to state ALLOC. After allocation, the resource is + initialized, which may result in the VALID or FAILED state. The + reason why allocation and initialization are separate is because + some resource types (e.g. buffers and images) might be asynchronously + initialized by the user application. If a resource which is not + in the VALID state is attempted to be used for rendering, rendering + operations will silently be dropped. + + The special INVALID state is returned in sg_query_xxx_state() if no + resource object exists for the provided resource id. +*/ +typedef enum sg_resource_state { + SG_RESOURCESTATE_INITIAL, + SG_RESOURCESTATE_ALLOC, + SG_RESOURCESTATE_VALID, + SG_RESOURCESTATE_FAILED, + SG_RESOURCESTATE_INVALID, + _SG_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF +} sg_resource_state; + +/* + sg_usage + + A resource usage hint describing the update strategy of + buffers and images. This is used in the sg_buffer_desc.usage + and sg_image_desc.usage members when creating buffers + and images: + + SG_USAGE_IMMUTABLE: the resource will never be updated with + new data, instead the content of the + resource must be provided on creation + SG_USAGE_DYNAMIC: the resource will be updated infrequently + with new data (this could range from "once + after creation", to "quite often but not + every frame") + SG_USAGE_STREAM: the resource will be updated each frame + with new content + + The rendering backends use this hint to prevent that the + CPU needs to wait for the GPU when attempting to update + a resource that might be currently accessed by the GPU. + + Resource content is updated with the functions sg_update_buffer() or + sg_append_buffer() for buffer objects, and sg_update_image() for image + objects. For the sg_update_*() functions, only one update is allowed per + frame and resource object, while sg_append_buffer() can be called + multiple times per frame on the same buffer. The application must update + all data required for rendering (this means that the update data can be + smaller than the resource size, if only a part of the overall resource + size is used for rendering, you only need to make sure that the data that + *is* used is valid). + + The default usage is SG_USAGE_IMMUTABLE. +*/ +typedef enum sg_usage { + _SG_USAGE_DEFAULT, /* value 0 reserved for default-init */ + SG_USAGE_IMMUTABLE, + SG_USAGE_DYNAMIC, + SG_USAGE_STREAM, + _SG_USAGE_NUM, + _SG_USAGE_FORCE_U32 = 0x7FFFFFFF +} sg_usage; + +/* + sg_buffer_type + + This indicates whether a buffer contains vertex- or index-data, + used in the sg_buffer_desc.type member when creating a buffer. + + The default value is SG_BUFFERTYPE_VERTEXBUFFER. +*/ +typedef enum sg_buffer_type { + _SG_BUFFERTYPE_DEFAULT, /* value 0 reserved for default-init */ + SG_BUFFERTYPE_VERTEXBUFFER, + SG_BUFFERTYPE_INDEXBUFFER, + _SG_BUFFERTYPE_NUM, + _SG_BUFFERTYPE_FORCE_U32 = 0x7FFFFFFF +} sg_buffer_type; + +/* + sg_index_type + + Indicates whether indexed rendering (fetching vertex-indices from an + index buffer) is used, and if yes, the index data type (16- or 32-bits). + This is used in the sg_pipeline_desc.index_type member when creating a + pipeline object. + + The default index type is SG_INDEXTYPE_NONE. +*/ +typedef enum sg_index_type { + _SG_INDEXTYPE_DEFAULT, /* value 0 reserved for default-init */ + SG_INDEXTYPE_NONE, + SG_INDEXTYPE_UINT16, + SG_INDEXTYPE_UINT32, + _SG_INDEXTYPE_NUM, + _SG_INDEXTYPE_FORCE_U32 = 0x7FFFFFFF +} sg_index_type; + +/* + sg_image_type + + Indicates the basic type of an image object (2D-texture, cubemap, + 3D-texture or 2D-array-texture). 3D- and array-textures are not supported + on the GLES2/WebGL backend (use sg_query_features().imagetype_3d and + sg_query_features().imagetype_array to check for support). The image type + is used in the sg_image_desc.type member when creating an image, and + in sg_shader_image_desc when describing a shader's texture sampler binding. + + The default image type when creating an image is SG_IMAGETYPE_2D. +*/ +typedef enum sg_image_type { + _SG_IMAGETYPE_DEFAULT, /* value 0 reserved for default-init */ + SG_IMAGETYPE_2D, + SG_IMAGETYPE_CUBE, + SG_IMAGETYPE_3D, + SG_IMAGETYPE_ARRAY, + _SG_IMAGETYPE_NUM, + _SG_IMAGETYPE_FORCE_U32 = 0x7FFFFFFF +} sg_image_type; + +/* + sg_sampler_type + + Indicates the basic data type of a shader's texture sampler which + can be float , unsigned integer or signed integer. The sampler + type is used in the sg_shader_image_desc to describe the + sampler type of a shader's texture sampler binding. + + The default sampler type is SG_SAMPLERTYPE_FLOAT. +*/ +typedef enum sg_sampler_type { + _SG_SAMPLERTYPE_DEFAULT, /* value 0 reserved for default-init */ + SG_SAMPLERTYPE_FLOAT, + SG_SAMPLERTYPE_SINT, + SG_SAMPLERTYPE_UINT, +} sg_sampler_type; + +/* + sg_cube_face + + The cubemap faces. Use these as indices in the sg_image_desc.content + array. +*/ +typedef enum sg_cube_face { + SG_CUBEFACE_POS_X, + SG_CUBEFACE_NEG_X, + SG_CUBEFACE_POS_Y, + SG_CUBEFACE_NEG_Y, + SG_CUBEFACE_POS_Z, + SG_CUBEFACE_NEG_Z, + SG_CUBEFACE_NUM, + _SG_CUBEFACE_FORCE_U32 = 0x7FFFFFFF +} sg_cube_face; + +/* + sg_shader_stage + + There are 2 shader stages: vertex- and fragment-shader-stage. + Each shader stage consists of: + + - one slot for a shader function (provided as source- or byte-code) + - SG_MAX_SHADERSTAGE_UBS slots for uniform blocks + - SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures by + the shader function +*/ +typedef enum sg_shader_stage { + SG_SHADERSTAGE_VS, + SG_SHADERSTAGE_FS, + _SG_SHADERSTAGE_FORCE_U32 = 0x7FFFFFFF +} sg_shader_stage; + +/* + sg_primitive_type + + This is the common subset of 3D primitive types supported across all 3D + APIs. This is used in the sg_pipeline_desc.primitive_type member when + creating a pipeline object. + + The default primitive type is SG_PRIMITIVETYPE_TRIANGLES. +*/ +typedef enum sg_primitive_type { + _SG_PRIMITIVETYPE_DEFAULT, /* value 0 reserved for default-init */ + SG_PRIMITIVETYPE_POINTS, + SG_PRIMITIVETYPE_LINES, + SG_PRIMITIVETYPE_LINE_STRIP, + SG_PRIMITIVETYPE_TRIANGLES, + SG_PRIMITIVETYPE_TRIANGLE_STRIP, + _SG_PRIMITIVETYPE_NUM, + _SG_PRIMITIVETYPE_FORCE_U32 = 0x7FFFFFFF +} sg_primitive_type; + +/* + sg_filter + + The filtering mode when sampling a texture image. This is + used in the sg_image_desc.min_filter and sg_image_desc.mag_filter + members when creating an image object. + + The default filter mode is SG_FILTER_NEAREST. +*/ +typedef enum sg_filter { + _SG_FILTER_DEFAULT, /* value 0 reserved for default-init */ + SG_FILTER_NEAREST, + SG_FILTER_LINEAR, + SG_FILTER_NEAREST_MIPMAP_NEAREST, + SG_FILTER_NEAREST_MIPMAP_LINEAR, + SG_FILTER_LINEAR_MIPMAP_NEAREST, + SG_FILTER_LINEAR_MIPMAP_LINEAR, + _SG_FILTER_NUM, + _SG_FILTER_FORCE_U32 = 0x7FFFFFFF +} sg_filter; + +/* + sg_wrap + + The texture coordinates wrapping mode when sampling a texture + image. This is used in the sg_image_desc.wrap_u, .wrap_v + and .wrap_w members when creating an image. + + The default wrap mode is SG_WRAP_REPEAT. + + NOTE: SG_WRAP_CLAMP_TO_BORDER is not supported on all backends + and platforms. To check for support, call sg_query_features() + and check the "clamp_to_border" boolean in the returned + sg_features struct. + + Platforms which don't support SG_WRAP_CLAMP_TO_BORDER will silently fall back + to SG_WRAP_CLAMP_TO_EDGE without a validation error. + + Platforms which support clamp-to-border are: + + - all desktop GL platforms + - Metal on macOS + - D3D11 + + Platforms which do not support clamp-to-border: + + - GLES2/3 and WebGL/WebGL2 + - Metal on iOS +*/ +typedef enum sg_wrap { + _SG_WRAP_DEFAULT, /* value 0 reserved for default-init */ + SG_WRAP_REPEAT, + SG_WRAP_CLAMP_TO_EDGE, + SG_WRAP_CLAMP_TO_BORDER, + SG_WRAP_MIRRORED_REPEAT, + _SG_WRAP_NUM, + _SG_WRAP_FORCE_U32 = 0x7FFFFFFF +} sg_wrap; + +/* + sg_border_color + + The border color to use when sampling a texture, and the UV wrap + mode is SG_WRAP_CLAMP_TO_BORDER. + + The default border color is SG_BORDERCOLOR_OPAQUE_BLACK +*/ +typedef enum sg_border_color { + _SG_BORDERCOLOR_DEFAULT, /* value 0 reserved for default-init */ + SG_BORDERCOLOR_TRANSPARENT_BLACK, + SG_BORDERCOLOR_OPAQUE_BLACK, + SG_BORDERCOLOR_OPAQUE_WHITE, + _SG_BORDERCOLOR_NUM, + _SG_BORDERCOLOR_FORCE_U32 = 0x7FFFFFFF +} sg_border_color; + +/* + sg_vertex_format + + The data type of a vertex component. This is used to describe + the layout of vertex data when creating a pipeline object. +*/ +typedef enum sg_vertex_format { + SG_VERTEXFORMAT_INVALID, + SG_VERTEXFORMAT_FLOAT, + SG_VERTEXFORMAT_FLOAT2, + SG_VERTEXFORMAT_FLOAT3, + SG_VERTEXFORMAT_FLOAT4, + SG_VERTEXFORMAT_BYTE4, + SG_VERTEXFORMAT_BYTE4N, + SG_VERTEXFORMAT_UBYTE4, + SG_VERTEXFORMAT_UBYTE4N, + SG_VERTEXFORMAT_SHORT2, + SG_VERTEXFORMAT_SHORT2N, + SG_VERTEXFORMAT_USHORT2N, + SG_VERTEXFORMAT_SHORT4, + SG_VERTEXFORMAT_SHORT4N, + SG_VERTEXFORMAT_USHORT4N, + SG_VERTEXFORMAT_UINT10_N2, + _SG_VERTEXFORMAT_NUM, + _SG_VERTEXFORMAT_FORCE_U32 = 0x7FFFFFFF +} sg_vertex_format; + +/* + sg_vertex_step + + Defines whether the input pointer of a vertex input stream is advanced + 'per vertex' or 'per instance'. The default step-func is + SG_VERTEXSTEP_PER_VERTEX. SG_VERTEXSTEP_PER_INSTANCE is used with + instanced-rendering. + + The vertex-step is part of the vertex-layout definition + when creating pipeline objects. +*/ +typedef enum sg_vertex_step { + _SG_VERTEXSTEP_DEFAULT, /* value 0 reserved for default-init */ + SG_VERTEXSTEP_PER_VERTEX, + SG_VERTEXSTEP_PER_INSTANCE, + _SG_VERTEXSTEP_NUM, + _SG_VERTEXSTEP_FORCE_U32 = 0x7FFFFFFF +} sg_vertex_step; + +/* + sg_uniform_type + + The data type of a uniform block member. This is used to + describe the internal layout of uniform blocks when creating + a shader object. +*/ +typedef enum sg_uniform_type { + SG_UNIFORMTYPE_INVALID, + SG_UNIFORMTYPE_FLOAT, + SG_UNIFORMTYPE_FLOAT2, + SG_UNIFORMTYPE_FLOAT3, + SG_UNIFORMTYPE_FLOAT4, + SG_UNIFORMTYPE_INT, + SG_UNIFORMTYPE_INT2, + SG_UNIFORMTYPE_INT3, + SG_UNIFORMTYPE_INT4, + SG_UNIFORMTYPE_MAT4, + _SG_UNIFORMTYPE_NUM, + _SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF +} sg_uniform_type; + +/* + sg_uniform_layout + + A hint for the interior memory layout of uniform blocks. This is + only really relevant for the GL backend where the internal layout + of uniform blocks must be known to sokol-gfx. For all other backends the + internal memory layout of uniform blocks doesn't matter, sokol-gfx + will just pass uniform data as a single memory blob to the + 3D backend. + + SG_UNIFORMLAYOUT_NATIVE (default) + Native layout means that a 'backend-native' memory layout + is used. For the GL backend this means that uniforms + are packed tightly in memory (e.g. there are no padding + bytes). + + SG_UNIFORMLAYOUT_STD140 + The memory layout is a subset of std140. Arrays are only + allowed for the FLOAT4, INT4 and MAT4. Alignment is as + is as follows: + + FLOAT, INT: 4 byte alignment + FLOAT2, INT2: 8 byte alignment + FLOAT3, INT3: 16 byte alignment(!) + FLOAT4, INT4: 16 byte alignment + MAT4: 16 byte alignment + FLOAT4[], INT4[]: 16 byte alignment + + The overall size of the uniform block must be a multiple + of 16. + + For more information search for 'UNIFORM DATA LAYOUT' in the documentation block + at the start of the header. +*/ +typedef enum sg_uniform_layout { + _SG_UNIFORMLAYOUT_DEFAULT, /* value 0 reserved for default-init */ + SG_UNIFORMLAYOUT_NATIVE, /* default: layout depends on currently active backend */ + SG_UNIFORMLAYOUT_STD140, /* std140: memory layout according to std140 */ + _SG_UNIFORMLAYOUT_NUM, + _SG_UNIFORMLAYOUT_FORCE_U32 = 0x7FFFFFFF +} sg_uniform_layout; + +/* + sg_cull_mode + + The face-culling mode, this is used in the + sg_pipeline_desc.cull_mode member when creating a + pipeline object. + + The default cull mode is SG_CULLMODE_NONE +*/ +typedef enum sg_cull_mode { + _SG_CULLMODE_DEFAULT, /* value 0 reserved for default-init */ + SG_CULLMODE_NONE, + SG_CULLMODE_FRONT, + SG_CULLMODE_BACK, + _SG_CULLMODE_NUM, + _SG_CULLMODE_FORCE_U32 = 0x7FFFFFFF +} sg_cull_mode; + +/* + sg_face_winding + + The vertex-winding rule that determines a front-facing primitive. This + is used in the member sg_pipeline_desc.face_winding + when creating a pipeline object. + + The default winding is SG_FACEWINDING_CW (clockwise) +*/ +typedef enum sg_face_winding { + _SG_FACEWINDING_DEFAULT, /* value 0 reserved for default-init */ + SG_FACEWINDING_CCW, + SG_FACEWINDING_CW, + _SG_FACEWINDING_NUM, + _SG_FACEWINDING_FORCE_U32 = 0x7FFFFFFF +} sg_face_winding; + +/* + sg_compare_func + + The compare-function for depth- and stencil-ref tests. + This is used when creating pipeline objects in the members: + + sg_pipeline_desc + .depth + .compare + .stencil + .front.compare + .back.compar + + The default compare func for depth- and stencil-tests is + SG_COMPAREFUNC_ALWAYS. +*/ +typedef enum sg_compare_func { + _SG_COMPAREFUNC_DEFAULT, /* value 0 reserved for default-init */ + SG_COMPAREFUNC_NEVER, + SG_COMPAREFUNC_LESS, + SG_COMPAREFUNC_EQUAL, + SG_COMPAREFUNC_LESS_EQUAL, + SG_COMPAREFUNC_GREATER, + SG_COMPAREFUNC_NOT_EQUAL, + SG_COMPAREFUNC_GREATER_EQUAL, + SG_COMPAREFUNC_ALWAYS, + _SG_COMPAREFUNC_NUM, + _SG_COMPAREFUNC_FORCE_U32 = 0x7FFFFFFF +} sg_compare_func; + +/* + sg_stencil_op + + The operation performed on a currently stored stencil-value when a + comparison test passes or fails. This is used when creating a pipeline + object in the members: + + sg_pipeline_desc + .stencil + .front + .fail_op + .depth_fail_op + .pass_op + .back + .fail_op + .depth_fail_op + .pass_op + + The default value is SG_STENCILOP_KEEP. +*/ +typedef enum sg_stencil_op { + _SG_STENCILOP_DEFAULT, /* value 0 reserved for default-init */ + SG_STENCILOP_KEEP, + SG_STENCILOP_ZERO, + SG_STENCILOP_REPLACE, + SG_STENCILOP_INCR_CLAMP, + SG_STENCILOP_DECR_CLAMP, + SG_STENCILOP_INVERT, + SG_STENCILOP_INCR_WRAP, + SG_STENCILOP_DECR_WRAP, + _SG_STENCILOP_NUM, + _SG_STENCILOP_FORCE_U32 = 0x7FFFFFFF +} sg_stencil_op; + +/* + sg_blend_factor + + The source and destination factors in blending operations. + This is used in the following members when creating a pipeline object: + + sg_pipeline_desc + .colors[i] + .blend + .src_factor_rgb + .dst_factor_rgb + .src_factor_alpha + .dst_factor_alpha + + The default value is SG_BLENDFACTOR_ONE for source + factors, and SG_BLENDFACTOR_ZERO for destination factors. +*/ +typedef enum sg_blend_factor { + _SG_BLENDFACTOR_DEFAULT, /* value 0 reserved for default-init */ + SG_BLENDFACTOR_ZERO, + SG_BLENDFACTOR_ONE, + SG_BLENDFACTOR_SRC_COLOR, + SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR, + SG_BLENDFACTOR_SRC_ALPHA, + SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + SG_BLENDFACTOR_DST_COLOR, + SG_BLENDFACTOR_ONE_MINUS_DST_COLOR, + SG_BLENDFACTOR_DST_ALPHA, + SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA, + SG_BLENDFACTOR_SRC_ALPHA_SATURATED, + SG_BLENDFACTOR_BLEND_COLOR, + SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR, + SG_BLENDFACTOR_BLEND_ALPHA, + SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA, + _SG_BLENDFACTOR_NUM, + _SG_BLENDFACTOR_FORCE_U32 = 0x7FFFFFFF +} sg_blend_factor; + +/* + sg_blend_op + + Describes how the source and destination values are combined in the + fragment blending operation. It is used in the following members when + creating a pipeline object: + + sg_pipeline_desc + .colors[i] + .blend + .op_rgb + .op_alpha + + The default value is SG_BLENDOP_ADD. +*/ +typedef enum sg_blend_op { + _SG_BLENDOP_DEFAULT, /* value 0 reserved for default-init */ + SG_BLENDOP_ADD, + SG_BLENDOP_SUBTRACT, + SG_BLENDOP_REVERSE_SUBTRACT, + _SG_BLENDOP_NUM, + _SG_BLENDOP_FORCE_U32 = 0x7FFFFFFF +} sg_blend_op; + +/* + sg_color_mask + + Selects the active color channels when writing a fragment color to the + framebuffer. This is used in the members + sg_pipeline_desc.colors[i].write_mask when creating a pipeline object. + + The default colormask is SG_COLORMASK_RGBA (write all colors channels) + + NOTE: since the color mask value 0 is reserved for the default value + (SG_COLORMASK_RGBA), use SG_COLORMASK_NONE if all color channels + should be disabled. +*/ +typedef enum sg_color_mask { + _SG_COLORMASK_DEFAULT = 0, /* value 0 reserved for default-init */ + SG_COLORMASK_NONE = 0x10, /* special value for 'all channels disabled */ + SG_COLORMASK_R = 0x1, + SG_COLORMASK_G = 0x2, + SG_COLORMASK_RG = 0x3, + SG_COLORMASK_B = 0x4, + SG_COLORMASK_RB = 0x5, + SG_COLORMASK_GB = 0x6, + SG_COLORMASK_RGB = 0x7, + SG_COLORMASK_A = 0x8, + SG_COLORMASK_RA = 0x9, + SG_COLORMASK_GA = 0xA, + SG_COLORMASK_RGA = 0xB, + SG_COLORMASK_BA = 0xC, + SG_COLORMASK_RBA = 0xD, + SG_COLORMASK_GBA = 0xE, + SG_COLORMASK_RGBA = 0xF, + _SG_COLORMASK_FORCE_U32 = 0x7FFFFFFF +} sg_color_mask; + +/* + sg_action + + Defines what action should be performed at the start of a render pass: + + SG_ACTION_CLEAR: clear the render target image + SG_ACTION_LOAD: load the previous content of the render target image + SG_ACTION_DONTCARE: leave the render target image content undefined + + This is used in the sg_pass_action structure. + + The default action for all pass attachments is SG_ACTION_CLEAR, with the + clear color rgba = {0.5f, 0.5f, 0.5f, 1.0f], depth=1.0 and stencil=0. + + If you want to override the default behaviour, it is important to not + only set the clear color, but the 'action' field as well (as long as this + is in its _SG_ACTION_DEFAULT, the value fields will be ignored). +*/ +typedef enum sg_action { + _SG_ACTION_DEFAULT, + SG_ACTION_CLEAR, + SG_ACTION_LOAD, + SG_ACTION_DONTCARE, + _SG_ACTION_NUM, + _SG_ACTION_FORCE_U32 = 0x7FFFFFFF +} sg_action; + +/* + sg_pass_action + + The sg_pass_action struct defines the actions to be performed + at the start of a rendering pass in the functions sg_begin_pass() + and sg_begin_default_pass(). + + A separate action and clear values can be defined for each + color attachment, and for the depth-stencil attachment. + + The default clear values are defined by the macros: + + - SG_DEFAULT_CLEAR_RED: 0.5f + - SG_DEFAULT_CLEAR_GREEN: 0.5f + - SG_DEFAULT_CLEAR_BLUE: 0.5f + - SG_DEFAULT_CLEAR_ALPHA: 1.0f + - SG_DEFAULT_CLEAR_DEPTH: 1.0f + - SG_DEFAULT_CLEAR_STENCIL: 0 +*/ +typedef struct sg_color_attachment_action { + sg_action action; + sg_color value; +} sg_color_attachment_action; + +typedef struct sg_depth_attachment_action { + sg_action action; + float value; +} sg_depth_attachment_action; + +typedef struct sg_stencil_attachment_action { + sg_action action; + uint8_t value; +} sg_stencil_attachment_action; + +typedef struct sg_pass_action { + uint32_t _start_canary; + sg_color_attachment_action colors[SG_MAX_COLOR_ATTACHMENTS]; + sg_depth_attachment_action depth; + sg_stencil_attachment_action stencil; + uint32_t _end_canary; +} sg_pass_action; + +/* + sg_bindings + + The sg_bindings structure defines the resource binding slots + of the sokol_gfx render pipeline, used as argument to the + sg_apply_bindings() function. + + A resource binding struct contains: + + - 1..N vertex buffers + - 0..N vertex buffer offsets + - 0..1 index buffers + - 0..1 index buffer offsets + - 0..N vertex shader stage images + - 0..N fragment shader stage images + + The max number of vertex buffer and shader stage images + are defined by the SG_MAX_SHADERSTAGE_BUFFERS and + SG_MAX_SHADERSTAGE_IMAGES configuration constants. + + The optional buffer offsets can be used to put different unrelated + chunks of vertex- and/or index-data into the same buffer objects. +*/ +typedef struct sg_bindings { + uint32_t _start_canary; + sg_buffer vertex_buffers[SG_MAX_SHADERSTAGE_BUFFERS]; + int vertex_buffer_offsets[SG_MAX_SHADERSTAGE_BUFFERS]; + sg_buffer index_buffer; + int index_buffer_offset; + sg_image vs_images[SG_MAX_SHADERSTAGE_IMAGES]; + sg_image fs_images[SG_MAX_SHADERSTAGE_IMAGES]; + uint32_t _end_canary; +} sg_bindings; + +/* + sg_buffer_desc + + Creation parameters for sg_buffer objects, used in the + sg_make_buffer() call. + + The default configuration is: + + .size: 0 (*must* be >0 for buffers without data) + .type: SG_BUFFERTYPE_VERTEXBUFFER + .usage: SG_USAGE_IMMUTABLE + .data.ptr 0 (*must* be valid for immutable buffers) + .data.size 0 (*must* be > 0 for immutable buffers) + .label 0 (optional string label for trace hooks) + + The label will be ignored by sokol_gfx.h, it is only useful + when hooking into sg_make_buffer() or sg_init_buffer() via + the sg_install_trace_hooks() function. + + For immutable buffers which are initialized with initial data, + keep the .size item zero-initialized, and set the size together with the + pointer to the initial data in the .data item. + + For mutable buffers without initial data, keep the .data item + zero-initialized, and set the buffer size in the .size item instead. + + You can also set both size values, but currently both size values must + be identical (this may change in the future when the dynamic resource + management may become more flexible). + + ADVANCED TOPIC: Injecting native 3D-API buffers: + + The following struct members allow to inject your own GL, Metal + or D3D11 buffers into sokol_gfx: + + .gl_buffers[SG_NUM_INFLIGHT_FRAMES] + .mtl_buffers[SG_NUM_INFLIGHT_FRAMES] + .d3d11_buffer + + You must still provide all other struct items except the .data item, and + these must match the creation parameters of the native buffers you + provide. For SG_USAGE_IMMUTABLE, only provide a single native 3D-API + buffer, otherwise you need to provide SG_NUM_INFLIGHT_FRAMES buffers + (only for GL and Metal, not D3D11). Providing multiple buffers for GL and + Metal is necessary because sokol_gfx will rotate through them when + calling sg_update_buffer() to prevent lock-stalls. + + Note that it is expected that immutable injected buffer have already been + initialized with content, and the .content member must be 0! + + Also you need to call sg_reset_state_cache() after calling native 3D-API + functions, and before calling any sokol_gfx function. +*/ +typedef struct sg_buffer_desc { + uint32_t _start_canary; + size_t size; + sg_buffer_type type; + sg_usage usage; + sg_range data; + const char* label; + /* GL specific */ + uint32_t gl_buffers[SG_NUM_INFLIGHT_FRAMES]; + /* Metal specific */ + const void* mtl_buffers[SG_NUM_INFLIGHT_FRAMES]; + /* D3D11 specific */ + const void* d3d11_buffer; + /* WebGPU specific */ + const void* wgpu_buffer; + uint32_t _end_canary; +} sg_buffer_desc; + +/* + sg_image_data + + Defines the content of an image through a 2D array of sg_range structs. + The first array dimension is the cubemap face, and the second array + dimension the mipmap level. +*/ +typedef struct sg_image_data { + sg_range subimage[SG_CUBEFACE_NUM][SG_MAX_MIPMAPS]; +} sg_image_data; + +/* + sg_image_desc + + Creation parameters for sg_image objects, used in the sg_make_image() + call. + + The default configuration is: + + .type: SG_IMAGETYPE_2D + .render_target: false + .width 0 (must be set to >0) + .height 0 (must be set to >0) + .num_slices 1 (3D textures: depth; array textures: number of layers) + .num_mipmaps: 1 + .usage: SG_USAGE_IMMUTABLE + .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.context.color_format for render targets + .sample_count: 1 for textures, or sg_desc.context.sample_count for render targets + .min_filter: SG_FILTER_NEAREST + .mag_filter: SG_FILTER_NEAREST + .wrap_u: SG_WRAP_REPEAT + .wrap_v: SG_WRAP_REPEAT + .wrap_w: SG_WRAP_REPEAT (only SG_IMAGETYPE_3D) + .border_color SG_BORDERCOLOR_OPAQUE_BLACK + .max_anisotropy 1 (must be 1..16) + .min_lod 0.0f + .max_lod FLT_MAX + .data an sg_image_data struct to define the initial content + .label 0 (optional string label for trace hooks) + + Q: Why is the default sample_count for render targets identical with the + "default sample count" from sg_desc.context.sample_count? + + A: So that it matches the default sample count in pipeline objects. Even + though it is a bit strange/confusing that offscreen render targets by default + get the same sample count as the default framebuffer, but it's better that + an offscreen render target created with default parameters matches + a pipeline object created with default parameters. + + NOTE: + + SG_IMAGETYPE_ARRAY and SG_IMAGETYPE_3D are not supported on WebGL/GLES2, + use sg_query_features().imagetype_array and + sg_query_features().imagetype_3d at runtime to check if array- and + 3D-textures are supported. + + Images with usage SG_USAGE_IMMUTABLE must be fully initialized by + providing a valid .data member which points to initialization data. + + ADVANCED TOPIC: Injecting native 3D-API textures: + + The following struct members allow to inject your own GL, Metal or D3D11 + textures into sokol_gfx: + + .gl_textures[SG_NUM_INFLIGHT_FRAMES] + .mtl_textures[SG_NUM_INFLIGHT_FRAMES] + .d3d11_texture + .d3d11_shader_resource_view + + For GL, you can also specify the texture target or leave it empty to use + the default texture target for the image type (GL_TEXTURE_2D for + SG_IMAGETYPE_2D etc) + + For D3D11, you can provide either a D3D11 texture, or a + shader-resource-view, or both. If only a texture is provided, a matching + shader-resource-view will be created. If only a shader-resource-view is + provided, the texture will be looked up from the shader-resource-view. + + The same rules apply as for injecting native buffers (see sg_buffer_desc + documentation for more details). +*/ +typedef struct sg_image_desc { + uint32_t _start_canary; + sg_image_type type; + bool render_target; + int width; + int height; + int num_slices; + int num_mipmaps; + sg_usage usage; + sg_pixel_format pixel_format; + int sample_count; + sg_filter min_filter; + sg_filter mag_filter; + sg_wrap wrap_u; + sg_wrap wrap_v; + sg_wrap wrap_w; + sg_border_color border_color; + uint32_t max_anisotropy; + float min_lod; + float max_lod; + sg_image_data data; + const char* label; + /* GL specific */ + uint32_t gl_textures[SG_NUM_INFLIGHT_FRAMES]; + uint32_t gl_texture_target; + /* Metal specific */ + const void* mtl_textures[SG_NUM_INFLIGHT_FRAMES]; + /* D3D11 specific */ + const void* d3d11_texture; + const void* d3d11_shader_resource_view; + /* WebGPU specific */ + const void* wgpu_texture; + uint32_t _end_canary; +} sg_image_desc; + +/* + sg_shader_desc + + The structure sg_shader_desc defines all creation parameters for shader + programs, used as input to the sg_make_shader() function: + + - reflection information for vertex attributes (vertex shader inputs): + - vertex attribute name (required for GLES2, optional for GLES3 and GL) + - a semantic name and index (required for D3D11) + - for each shader-stage (vertex and fragment): + - the shader source or bytecode + - an optional entry function name + - an optional compile target (only for D3D11 when source is provided, + defaults are "vs_4_0" and "ps_4_0") + - reflection info for each uniform block used by the shader stage: + - the size of the uniform block in bytes + - a memory layout hint (native vs std140, only required for GL backends) + - reflection info for each uniform block member (only required for GL backends): + - member name + - member type (SG_UNIFORMTYPE_xxx) + - if the member is an array, the number of array items + - reflection info for the texture images used by the shader stage: + - the image type (SG_IMAGETYPE_xxx) + - the sampler type (SG_SAMPLERTYPE_xxx, default is SG_SAMPLERTYPE_FLOAT) + - the name of the texture sampler (required for GLES2, optional everywhere else) + + For all GL backends, shader source-code must be provided. For D3D11 and Metal, + either shader source-code or byte-code can be provided. + + For D3D11, if source code is provided, the d3dcompiler_47.dll will be loaded + on demand. If this fails, shader creation will fail. When compiling HLSL + source code, you can provide an optional target string via + sg_shader_stage_desc.d3d11_target, the default target is "vs_4_0" for the + vertex shader stage and "ps_4_0" for the pixel shader stage. +*/ +typedef struct sg_shader_attr_desc { + const char* name; // GLSL vertex attribute name (only strictly required for GLES2) + const char* sem_name; // HLSL semantic name + int sem_index; // HLSL semantic index +} sg_shader_attr_desc; + +typedef struct sg_shader_uniform_desc { + const char* name; + sg_uniform_type type; + int array_count; +} sg_shader_uniform_desc; + +typedef struct sg_shader_uniform_block_desc { + size_t size; + sg_uniform_layout layout; + sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS]; +} sg_shader_uniform_block_desc; + +typedef struct sg_shader_image_desc { + const char* name; + sg_image_type image_type; + sg_sampler_type sampler_type; +} sg_shader_image_desc; + +typedef struct sg_shader_stage_desc { + const char* source; + sg_range bytecode; + const char* entry; + const char* d3d11_target; + sg_shader_uniform_block_desc uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; + sg_shader_image_desc images[SG_MAX_SHADERSTAGE_IMAGES]; +} sg_shader_stage_desc; + +typedef struct sg_shader_desc { + uint32_t _start_canary; + sg_shader_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES]; + sg_shader_stage_desc vs; + sg_shader_stage_desc fs; + const char* label; + uint32_t _end_canary; +} sg_shader_desc; + +/* + sg_pipeline_desc + + The sg_pipeline_desc struct defines all creation parameters for an + sg_pipeline object, used as argument to the sg_make_pipeline() function: + + - the vertex layout for all input vertex buffers + - a shader object + - the 3D primitive type (points, lines, triangles, ...) + - the index type (none, 16- or 32-bit) + - all the fixed-function-pipeline state (depth-, stencil-, blend-state, etc...) + + If the vertex data has no gaps between vertex components, you can omit + the .layout.buffers[].stride and layout.attrs[].offset items (leave them + default-initialized to 0), sokol-gfx will then compute the offsets and + strides from the vertex component formats (.layout.attrs[].format). + Please note that ALL vertex attribute offsets must be 0 in order for the + automatic offset computation to kick in. + + The default configuration is as follows: + + .shader: 0 (must be initialized with a valid sg_shader id!) + .layout: + .buffers[]: vertex buffer layouts + .stride: 0 (if no stride is given it will be computed) + .step_func SG_VERTEXSTEP_PER_VERTEX + .step_rate 1 + .attrs[]: vertex attribute declarations + .buffer_index 0 the vertex buffer bind slot + .offset 0 (offsets can be omitted if the vertex layout has no gaps) + .format SG_VERTEXFORMAT_INVALID (must be initialized!) + .depth: + .pixel_format: sg_desc.context.depth_format + .compare: SG_COMPAREFUNC_ALWAYS + .write_enabled: false + .bias: 0.0f + .bias_slope_scale: 0.0f + .bias_clamp: 0.0f + .stencil: + .enabled: false + .front/back: + .compare: SG_COMPAREFUNC_ALWAYS + .depth_fail_op: SG_STENCILOP_KEEP + .pass_op: SG_STENCILOP_KEEP + .compare: SG_COMPAREFUNC_ALWAYS + .read_mask: 0 + .write_mask: 0 + .ref: 0 + .color_count 1 + .colors[0..color_count] + .pixel_format sg_desc.context.color_format + .write_mask: SG_COLORMASK_RGBA + .blend: + .enabled: false + .src_factor_rgb: SG_BLENDFACTOR_ONE + .dst_factor_rgb: SG_BLENDFACTOR_ZERO + .op_rgb: SG_BLENDOP_ADD + .src_factor_alpha: SG_BLENDFACTOR_ONE + .dst_factor_alpha: SG_BLENDFACTOR_ZERO + .op_alpha: SG_BLENDOP_ADD + .primitive_type: SG_PRIMITIVETYPE_TRIANGLES + .index_type: SG_INDEXTYPE_NONE + .cull_mode: SG_CULLMODE_NONE + .face_winding: SG_FACEWINDING_CW + .sample_count: sg_desc.context.sample_count + .blend_color: (sg_color) { 0.0f, 0.0f, 0.0f, 0.0f } + .alpha_to_coverage_enabled: false + .label 0 (optional string label for trace hooks) +*/ +typedef struct sg_buffer_layout_desc { + int stride; + sg_vertex_step step_func; + int step_rate; + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[2]; + #endif +} sg_buffer_layout_desc; + +typedef struct sg_vertex_attr_desc { + int buffer_index; + int offset; + sg_vertex_format format; + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[2]; + #endif +} sg_vertex_attr_desc; + +typedef struct sg_layout_desc { + sg_buffer_layout_desc buffers[SG_MAX_SHADERSTAGE_BUFFERS]; + sg_vertex_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES]; +} sg_layout_desc; + +typedef struct sg_stencil_face_state { + sg_compare_func compare; + sg_stencil_op fail_op; + sg_stencil_op depth_fail_op; + sg_stencil_op pass_op; +} sg_stencil_face_state; + +typedef struct sg_stencil_state { + bool enabled; + sg_stencil_face_state front; + sg_stencil_face_state back; + uint8_t read_mask; + uint8_t write_mask; + uint8_t ref; +} sg_stencil_state; + +typedef struct sg_depth_state { + sg_pixel_format pixel_format; + sg_compare_func compare; + bool write_enabled; + float bias; + float bias_slope_scale; + float bias_clamp; +} sg_depth_state; + +typedef struct sg_blend_state { + bool enabled; + sg_blend_factor src_factor_rgb; + sg_blend_factor dst_factor_rgb; + sg_blend_op op_rgb; + sg_blend_factor src_factor_alpha; + sg_blend_factor dst_factor_alpha; + sg_blend_op op_alpha; +} sg_blend_state; + +typedef struct sg_color_state { + sg_pixel_format pixel_format; + sg_color_mask write_mask; + sg_blend_state blend; +} sg_color_state; + +typedef struct sg_pipeline_desc { + uint32_t _start_canary; + sg_shader shader; + sg_layout_desc layout; + sg_depth_state depth; + sg_stencil_state stencil; + int color_count; + sg_color_state colors[SG_MAX_COLOR_ATTACHMENTS]; + sg_primitive_type primitive_type; + sg_index_type index_type; + sg_cull_mode cull_mode; + sg_face_winding face_winding; + int sample_count; + sg_color blend_color; + bool alpha_to_coverage_enabled; + const char* label; + uint32_t _end_canary; +} sg_pipeline_desc; + +/* + sg_pass_desc + + Creation parameters for an sg_pass object, used as argument + to the sg_make_pass() function. + + A pass object contains 1..4 color-attachments and none, or one, + depth-stencil-attachment. Each attachment consists of + an image, and two additional indices describing + which subimage the pass will render to: one mipmap index, and + if the image is a cubemap, array-texture or 3D-texture, the + face-index, array-layer or depth-slice. + + Pass images must fulfill the following requirements: + + All images must have: + - been created as render target (sg_image_desc.render_target = true) + - the same size + - the same sample count + + In addition, all color-attachment images must have the same pixel format. +*/ +typedef struct sg_pass_attachment_desc { + sg_image image; + int mip_level; + int slice; /* cube texture: face; array texture: layer; 3D texture: slice */ +} sg_pass_attachment_desc; + +typedef struct sg_pass_desc { + uint32_t _start_canary; + sg_pass_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS]; + sg_pass_attachment_desc depth_stencil_attachment; + const char* label; + uint32_t _end_canary; +} sg_pass_desc; + +/* + sg_trace_hooks + + Installable callback functions to keep track of the sokol-gfx calls, + this is useful for debugging, or keeping track of resource creation + and destruction. + + Trace hooks are installed with sg_install_trace_hooks(), this returns + another sg_trace_hooks struct with the previous set of + trace hook function pointers. These should be invoked by the + new trace hooks to form a proper call chain. +*/ +typedef struct sg_trace_hooks { + void* user_data; + void (*reset_state_cache)(void* user_data); + void (*make_buffer)(const sg_buffer_desc* desc, sg_buffer result, void* user_data); + void (*make_image)(const sg_image_desc* desc, sg_image result, void* user_data); + void (*make_shader)(const sg_shader_desc* desc, sg_shader result, void* user_data); + void (*make_pipeline)(const sg_pipeline_desc* desc, sg_pipeline result, void* user_data); + void (*make_pass)(const sg_pass_desc* desc, sg_pass result, void* user_data); + void (*destroy_buffer)(sg_buffer buf, void* user_data); + void (*destroy_image)(sg_image img, void* user_data); + void (*destroy_shader)(sg_shader shd, void* user_data); + void (*destroy_pipeline)(sg_pipeline pip, void* user_data); + void (*destroy_pass)(sg_pass pass, void* user_data); + void (*update_buffer)(sg_buffer buf, const sg_range* data, void* user_data); + void (*update_image)(sg_image img, const sg_image_data* data, void* user_data); + void (*append_buffer)(sg_buffer buf, const sg_range* data, int result, void* user_data); + void (*begin_default_pass)(const sg_pass_action* pass_action, int width, int height, void* user_data); + void (*begin_pass)(sg_pass pass, const sg_pass_action* pass_action, void* user_data); + void (*apply_viewport)(int x, int y, int width, int height, bool origin_top_left, void* user_data); + void (*apply_scissor_rect)(int x, int y, int width, int height, bool origin_top_left, void* user_data); + void (*apply_pipeline)(sg_pipeline pip, void* user_data); + void (*apply_bindings)(const sg_bindings* bindings, void* user_data); + void (*apply_uniforms)(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data); + void (*draw)(int base_element, int num_elements, int num_instances, void* user_data); + void (*end_pass)(void* user_data); + void (*commit)(void* user_data); + void (*alloc_buffer)(sg_buffer result, void* user_data); + void (*alloc_image)(sg_image result, void* user_data); + void (*alloc_shader)(sg_shader result, void* user_data); + void (*alloc_pipeline)(sg_pipeline result, void* user_data); + void (*alloc_pass)(sg_pass result, void* user_data); + void (*dealloc_buffer)(sg_buffer buf_id, void* user_data); + void (*dealloc_image)(sg_image img_id, void* user_data); + void (*dealloc_shader)(sg_shader shd_id, void* user_data); + void (*dealloc_pipeline)(sg_pipeline pip_id, void* user_data); + void (*dealloc_pass)(sg_pass pass_id, void* user_data); + void (*init_buffer)(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data); + void (*init_image)(sg_image img_id, const sg_image_desc* desc, void* user_data); + void (*init_shader)(sg_shader shd_id, const sg_shader_desc* desc, void* user_data); + void (*init_pipeline)(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data); + void (*init_pass)(sg_pass pass_id, const sg_pass_desc* desc, void* user_data); + void (*uninit_buffer)(sg_buffer buf_id, void* user_data); + void (*uninit_image)(sg_image img_id, void* user_data); + void (*uninit_shader)(sg_shader shd_id, void* user_data); + void (*uninit_pipeline)(sg_pipeline pip_id, void* user_data); + void (*uninit_pass)(sg_pass pass_id, void* user_data); + void (*fail_buffer)(sg_buffer buf_id, void* user_data); + void (*fail_image)(sg_image img_id, void* user_data); + void (*fail_shader)(sg_shader shd_id, void* user_data); + void (*fail_pipeline)(sg_pipeline pip_id, void* user_data); + void (*fail_pass)(sg_pass pass_id, void* user_data); + void (*push_debug_group)(const char* name, void* user_data); + void (*pop_debug_group)(void* user_data); + void (*err_buffer_pool_exhausted)(void* user_data); + void (*err_image_pool_exhausted)(void* user_data); + void (*err_shader_pool_exhausted)(void* user_data); + void (*err_pipeline_pool_exhausted)(void* user_data); + void (*err_pass_pool_exhausted)(void* user_data); + void (*err_context_mismatch)(void* user_data); + void (*err_pass_invalid)(void* user_data); + void (*err_draw_invalid)(void* user_data); + void (*err_bindings_invalid)(void* user_data); +} sg_trace_hooks; + +/* + sg_buffer_info + sg_image_info + sg_shader_info + sg_pipeline_info + sg_pass_info + + These structs contain various internal resource attributes which + might be useful for debug-inspection. Please don't rely on the + actual content of those structs too much, as they are quite closely + tied to sokol_gfx.h internals and may change more frequently than + the other public API elements. + + The *_info structs are used as the return values of the following functions: + + sg_query_buffer_info() + sg_query_image_info() + sg_query_shader_info() + sg_query_pipeline_info() + sg_query_pass_info() +*/ +typedef struct sg_slot_info { + sg_resource_state state; /* the current state of this resource slot */ + uint32_t res_id; /* type-neutral resource if (e.g. sg_buffer.id) */ + uint32_t ctx_id; /* the context this resource belongs to */ +} sg_slot_info; + +typedef struct sg_buffer_info { + sg_slot_info slot; /* resource pool slot info */ + uint32_t update_frame_index; /* frame index of last sg_update_buffer() */ + uint32_t append_frame_index; /* frame index of last sg_append_buffer() */ + int append_pos; /* current position in buffer for sg_append_buffer() */ + bool append_overflow; /* is buffer in overflow state (due to sg_append_buffer) */ + int num_slots; /* number of renaming-slots for dynamically updated buffers */ + int active_slot; /* currently active write-slot for dynamically updated buffers */ +} sg_buffer_info; + +typedef struct sg_image_info { + sg_slot_info slot; /* resource pool slot info */ + uint32_t upd_frame_index; /* frame index of last sg_update_image() */ + int num_slots; /* number of renaming-slots for dynamically updated images */ + int active_slot; /* currently active write-slot for dynamically updated images */ + int width; /* image width */ + int height; /* image height */ +} sg_image_info; + +typedef struct sg_shader_info { + sg_slot_info slot; /* resoure pool slot info */ +} sg_shader_info; + +typedef struct sg_pipeline_info { + sg_slot_info slot; /* resource pool slot info */ +} sg_pipeline_info; + +typedef struct sg_pass_info { + sg_slot_info slot; /* resource pool slot info */ +} sg_pass_info; + +/* + sg_desc + + The sg_desc struct contains configuration values for sokol_gfx, + it is used as parameter to the sg_setup() call. + + NOTE that all callback function pointers come in two versions, one without + a userdata pointer, and one with a userdata pointer. You would + either initialize one or the other depending on whether you pass data + to your callbacks. + + FIXME: explain the various configuration options + + The default configuration is: + + .buffer_pool_size 128 + .image_pool_size 128 + .shader_pool_size 32 + .pipeline_pool_size 64 + .pass_pool_size 16 + .context_pool_size 16 + .sampler_cache_size 64 + .uniform_buffer_size 4 MB (4*1024*1024) + .staging_buffer_size 8 MB (8*1024*1024) + + .context.color_format: default value depends on selected backend: + all GL backends: SG_PIXELFORMAT_RGBA8 + Metal and D3D11: SG_PIXELFORMAT_BGRA8 + WGPU: *no default* (must be queried from WGPU swapchain) + .context.depth_format SG_PIXELFORMAT_DEPTH_STENCIL + .context.sample_count 1 + + GL specific: + .context.gl.force_gles2 + if this is true the GL backend will act in "GLES2 fallback mode" even + when compiled with SOKOL_GLES3, this is useful to fall back + to traditional WebGL if a browser doesn't support a WebGL2 context + + Metal specific: + (NOTE: All Objective-C object references are transferred through + a bridged (const void*) to sokol_gfx, which will use a unretained + bridged cast (__bridged id) to retrieve the Objective-C + references back. Since the bridge cast is unretained, the caller + must hold a strong reference to the Objective-C object for the + duration of the sokol_gfx call! + + .context.metal.device + a pointer to the MTLDevice object + .context.metal.renderpass_descriptor_cb + .context.metal_renderpass_descriptor_userdata_cb + A C callback function to obtain the MTLRenderPassDescriptor for the + current frame when rendering to the default framebuffer, will be called + in sg_begin_default_pass(). + .context.metal.drawable_cb + .context.metal.drawable_userdata_cb + a C callback function to obtain a MTLDrawable for the current + frame when rendering to the default framebuffer, will be called in + sg_end_pass() of the default pass + .context.metal.user_data + optional user data pointer passed to the userdata versions of + callback functions + + D3D11 specific: + .context.d3d11.device + a pointer to the ID3D11Device object, this must have been created + before sg_setup() is called + .context.d3d11.device_context + a pointer to the ID3D11DeviceContext object + .context.d3d11.render_target_view_cb + .context.d3d11.render_target_view_userdata_cb + a C callback function to obtain a pointer to the current + ID3D11RenderTargetView object of the default framebuffer, + this function will be called in sg_begin_pass() when rendering + to the default framebuffer + .context.d3d11.depth_stencil_view_cb + .context.d3d11.depth_stencil_view_userdata_cb + a C callback function to obtain a pointer to the current + ID3D11DepthStencilView object of the default framebuffer, + this function will be called in sg_begin_pass() when rendering + to the default framebuffer + .context.metal.user_data + optional user data pointer passed to the userdata versions of + callback functions + + WebGPU specific: + .context.wgpu.device + a WGPUDevice handle + .context.wgpu.render_format + WGPUTextureFormat of the swap chain surface + .context.wgpu.render_view_cb + .context.wgpu.render_view_userdata_cb + callback to get the current WGPUTextureView of the swapchain's + rendering attachment (may be an MSAA surface) + .context.wgpu.resolve_view_cb + .context.wgpu.resolve_view_userdata_cb + callback to get the current WGPUTextureView of the swapchain's + MSAA-resolve-target surface, must return 0 if not MSAA rendering + .context.wgpu.depth_stencil_view_cb + .context.wgpu.depth_stencil_view_userdata_cb + callback to get current default-pass depth-stencil-surface WGPUTextureView + the pixel format of the default WGPUTextureView must be WGPUTextureFormat_Depth24Plus8 + .context.metal.user_data + optional user data pointer passed to the userdata versions of + callback functions + + When using sokol_gfx.h and sokol_app.h together, consider using the + helper function sapp_sgcontext() in the sokol_glue.h header to + initialize the sg_desc.context nested struct. sapp_sgcontext() returns + a completely initialized sg_context_desc struct with information + provided by sokol_app.h. +*/ +typedef struct sg_gl_context_desc { + bool force_gles2; +} sg_gl_context_desc; + +typedef struct sg_metal_context_desc { + const void* device; + const void* (*renderpass_descriptor_cb)(void); + const void* (*renderpass_descriptor_userdata_cb)(void*); + const void* (*drawable_cb)(void); + const void* (*drawable_userdata_cb)(void*); + void* user_data; +} sg_metal_context_desc; + +typedef struct sg_d3d11_context_desc { + const void* device; + const void* device_context; + const void* (*render_target_view_cb)(void); + const void* (*render_target_view_userdata_cb)(void*); + const void* (*depth_stencil_view_cb)(void); + const void* (*depth_stencil_view_userdata_cb)(void*); + void* user_data; +} sg_d3d11_context_desc; + +typedef struct sg_wgpu_context_desc { + const void* device; /* WGPUDevice */ + const void* (*render_view_cb)(void); /* returns WGPUTextureView */ + const void* (*render_view_userdata_cb)(void*); + const void* (*resolve_view_cb)(void); /* returns WGPUTextureView */ + const void* (*resolve_view_userdata_cb)(void*); + const void* (*depth_stencil_view_cb)(void); /* returns WGPUTextureView, must be WGPUTextureFormat_Depth24Plus8 */ + const void* (*depth_stencil_view_userdata_cb)(void*); + void* user_data; +} sg_wgpu_context_desc; + +typedef struct sg_context_desc { + sg_pixel_format color_format; + sg_pixel_format depth_format; + int sample_count; + sg_gl_context_desc gl; + sg_metal_context_desc metal; + sg_d3d11_context_desc d3d11; + sg_wgpu_context_desc wgpu; +} sg_context_desc; + +typedef struct sg_desc { + uint32_t _start_canary; + int buffer_pool_size; + int image_pool_size; + int shader_pool_size; + int pipeline_pool_size; + int pass_pool_size; + int context_pool_size; + int uniform_buffer_size; + int staging_buffer_size; + int sampler_cache_size; + sg_context_desc context; + uint32_t _end_canary; +} sg_desc; + +/* setup and misc functions */ +SOKOL_GFX_API_DECL void sg_setup(const sg_desc* desc); +SOKOL_GFX_API_DECL void sg_shutdown(void); +SOKOL_GFX_API_DECL bool sg_isvalid(void); +SOKOL_GFX_API_DECL void sg_reset_state_cache(void); +SOKOL_GFX_API_DECL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks); +SOKOL_GFX_API_DECL void sg_push_debug_group(const char* name); +SOKOL_GFX_API_DECL void sg_pop_debug_group(void); + +/* resource creation, destruction and updating */ +SOKOL_GFX_API_DECL sg_buffer sg_make_buffer(const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL sg_image sg_make_image(const sg_image_desc* desc); +SOKOL_GFX_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc); +SOKOL_GFX_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL sg_pass sg_make_pass(const sg_pass_desc* desc); +SOKOL_GFX_API_DECL void sg_destroy_buffer(sg_buffer buf); +SOKOL_GFX_API_DECL void sg_destroy_image(sg_image img); +SOKOL_GFX_API_DECL void sg_destroy_shader(sg_shader shd); +SOKOL_GFX_API_DECL void sg_destroy_pipeline(sg_pipeline pip); +SOKOL_GFX_API_DECL void sg_destroy_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_update_buffer(sg_buffer buf, const sg_range* data); +SOKOL_GFX_API_DECL void sg_update_image(sg_image img, const sg_image_data* data); +SOKOL_GFX_API_DECL int sg_append_buffer(sg_buffer buf, const sg_range* data); +SOKOL_GFX_API_DECL bool sg_query_buffer_overflow(sg_buffer buf); + +/* rendering functions */ +SOKOL_GFX_API_DECL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height); +SOKOL_GFX_API_DECL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height); +SOKOL_GFX_API_DECL void sg_begin_pass(sg_pass pass, const sg_pass_action* pass_action); +SOKOL_GFX_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_pipeline(sg_pipeline pip); +SOKOL_GFX_API_DECL void sg_apply_bindings(const sg_bindings* bindings); +SOKOL_GFX_API_DECL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data); +SOKOL_GFX_API_DECL void sg_draw(int base_element, int num_elements, int num_instances); +SOKOL_GFX_API_DECL void sg_end_pass(void); +SOKOL_GFX_API_DECL void sg_commit(void); + +/* getting information */ +SOKOL_GFX_API_DECL sg_desc sg_query_desc(void); +SOKOL_GFX_API_DECL sg_backend sg_query_backend(void); +SOKOL_GFX_API_DECL sg_features sg_query_features(void); +SOKOL_GFX_API_DECL sg_limits sg_query_limits(void); +SOKOL_GFX_API_DECL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt); +/* get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID) */ +SOKOL_GFX_API_DECL sg_resource_state sg_query_buffer_state(sg_buffer buf); +SOKOL_GFX_API_DECL sg_resource_state sg_query_image_state(sg_image img); +SOKOL_GFX_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd); +SOKOL_GFX_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip); +SOKOL_GFX_API_DECL sg_resource_state sg_query_pass_state(sg_pass pass); +/* get runtime information about a resource */ +SOKOL_GFX_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf); +SOKOL_GFX_API_DECL sg_image_info sg_query_image_info(sg_image img); +SOKOL_GFX_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd); +SOKOL_GFX_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip); +SOKOL_GFX_API_DECL sg_pass_info sg_query_pass_info(sg_pass pass); +/* get resource creation desc struct with their default values replaced */ +SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); +SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); +SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc); + +/* separate resource allocation and initialization (for async setup) */ +SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void); +SOKOL_GFX_API_DECL sg_image sg_alloc_image(void); +SOKOL_GFX_API_DECL sg_shader sg_alloc_shader(void); +SOKOL_GFX_API_DECL sg_pipeline sg_alloc_pipeline(void); +SOKOL_GFX_API_DECL sg_pass sg_alloc_pass(void); +SOKOL_GFX_API_DECL void sg_dealloc_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL void sg_dealloc_image(sg_image img_id); +SOKOL_GFX_API_DECL void sg_dealloc_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL void sg_dealloc_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL void sg_dealloc_pass(sg_pass pass_id); +SOKOL_GFX_API_DECL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL void sg_init_image(sg_image img_id, const sg_image_desc* desc); +SOKOL_GFX_API_DECL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc); +SOKOL_GFX_API_DECL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc); +SOKOL_GFX_API_DECL bool sg_uninit_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL bool sg_uninit_image(sg_image img_id); +SOKOL_GFX_API_DECL bool sg_uninit_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL bool sg_uninit_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL bool sg_uninit_pass(sg_pass pass_id); +SOKOL_GFX_API_DECL void sg_fail_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL void sg_fail_image(sg_image img_id); +SOKOL_GFX_API_DECL void sg_fail_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL void sg_fail_pass(sg_pass pass_id); + +/* rendering contexts (optional) */ +SOKOL_GFX_API_DECL sg_context sg_setup_context(void); +SOKOL_GFX_API_DECL void sg_activate_context(sg_context ctx_id); +SOKOL_GFX_API_DECL void sg_discard_context(sg_context ctx_id); + +/* Backend-specific helper functions, these may come in handy for mixing + sokol-gfx rendering with 'native backend' rendering functions. + + This group of functions will be expanded as needed. +*/ + +/* D3D11: return ID3D11Device */ +SOKOL_GFX_API_DECL const void* sg_d3d11_device(void); + +/* Metal: return __bridge-casted MTLDevice */ +SOKOL_GFX_API_DECL const void* sg_mtl_device(void); + +/* Metal: return __bridge-casted MTLRenderCommandEncoder in current pass (or zero if outside pass) */ +SOKOL_GFX_API_DECL const void* sg_mtl_render_command_encoder(void); + +#ifdef __cplusplus +} /* extern "C" */ + +/* reference-based equivalents for c++ */ +inline void sg_setup(const sg_desc& desc) { return sg_setup(&desc); } + +inline sg_buffer sg_make_buffer(const sg_buffer_desc& desc) { return sg_make_buffer(&desc); } +inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image(&desc); } +inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); } +inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); } +inline sg_pass sg_make_pass(const sg_pass_desc& desc) { return sg_make_pass(&desc); } +inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); } + +inline void sg_begin_default_pass(const sg_pass_action& pass_action, int width, int height) { return sg_begin_default_pass(&pass_action, width, height); } +inline void sg_begin_default_passf(const sg_pass_action& pass_action, float width, float height) { return sg_begin_default_passf(&pass_action, width, height); } +inline void sg_begin_pass(sg_pass pass, const sg_pass_action& pass_action) { return sg_begin_pass(pass, &pass_action); } +inline void sg_apply_bindings(const sg_bindings& bindings) { return sg_apply_bindings(&bindings); } +inline void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range& data) { return sg_apply_uniforms(stage, ub_index, &data); } + +inline sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc& desc) { return sg_query_buffer_defaults(&desc); } +inline sg_image_desc sg_query_image_defaults(const sg_image_desc& desc) { return sg_query_image_defaults(&desc); } +inline sg_shader_desc sg_query_shader_defaults(const sg_shader_desc& desc) { return sg_query_shader_defaults(&desc); } +inline sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc& desc) { return sg_query_pipeline_defaults(&desc); } +inline sg_pass_desc sg_query_pass_defaults(const sg_pass_desc& desc) { return sg_query_pass_defaults(&desc); } + +inline void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc& desc) { return sg_init_buffer(buf_id, &desc); } +inline void sg_init_image(sg_image img_id, const sg_image_desc& desc) { return sg_init_image(img_id, &desc); } +inline void sg_init_shader(sg_shader shd_id, const sg_shader_desc& desc) { return sg_init_shader(shd_id, &desc); } +inline void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc& desc) { return sg_init_pipeline(pip_id, &desc); } +inline void sg_init_pass(sg_pass pass_id, const sg_pass_desc& desc) { return sg_init_pass(pass_id, &desc); } + +inline void sg_update_buffer(sg_buffer buf_id, const sg_range& data) { return sg_update_buffer(buf_id, &data); } +inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_append_buffer(buf_id, &data); } +#endif +#endif // SOKOL_GFX_INCLUDED + +/*--- IMPLEMENTATION ---------------------------------------------------------*/ +#ifdef SOKOL_GFX_IMPL +#define SOKOL_GFX_IMPL_INCLUDED (1) + +#if !(defined(SOKOL_GLCORE33)||defined(SOKOL_GLES2)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) +#error "Please select a backend with SOKOL_GLCORE33, SOKOL_GLES2, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND" +#endif +#include /* memset */ +#include /* FLT_MAX */ + +#ifndef SOKOL_API_IMPL + #define SOKOL_API_IMPL +#endif +#ifndef SOKOL_DEBUG + #ifndef NDEBUG + #define SOKOL_DEBUG (1) + #endif +#endif +#ifndef SOKOL_ASSERT + #include + #define SOKOL_ASSERT(c) assert(c) +#endif +#ifndef SOKOL_VALIDATE_BEGIN + #define SOKOL_VALIDATE_BEGIN() _sg_validate_begin() +#endif +#ifndef SOKOL_VALIDATE + #define SOKOL_VALIDATE(cond, err) _sg_validate((cond), err) +#endif +#ifndef SOKOL_VALIDATE_END + #define SOKOL_VALIDATE_END() _sg_validate_end() +#endif +#ifndef SOKOL_UNREACHABLE + #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) +#endif +#ifndef SOKOL_MALLOC + #include + #define SOKOL_MALLOC(s) malloc(s) + #define SOKOL_FREE(p) free(p) +#endif +#ifndef SOKOL_LOG + #ifdef SOKOL_DEBUG + #include + #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #else + #define SOKOL_LOG(s) + #endif +#endif + +#ifndef _SOKOL_PRIVATE + #if defined(__GNUC__) || defined(__clang__) + #define _SOKOL_PRIVATE __attribute__((unused)) static + #else + #define _SOKOL_PRIVATE static + #endif +#endif + +#ifndef _SOKOL_UNUSED + #define _SOKOL_UNUSED(x) (void)(x) +#endif + +#if defined(SOKOL_TRACE_HOOKS) +#define _SG_TRACE_ARGS(fn, ...) if (_sg.hooks.fn) { _sg.hooks.fn(__VA_ARGS__, _sg.hooks.user_data); } +#define _SG_TRACE_NOARGS(fn) if (_sg.hooks.fn) { _sg.hooks.fn(_sg.hooks.user_data); } +#else +#define _SG_TRACE_ARGS(fn, ...) +#define _SG_TRACE_NOARGS(fn) +#endif + +/* default clear values */ +#ifndef SG_DEFAULT_CLEAR_RED +#define SG_DEFAULT_CLEAR_RED (0.5f) +#endif +#ifndef SG_DEFAULT_CLEAR_GREEN +#define SG_DEFAULT_CLEAR_GREEN (0.5f) +#endif +#ifndef SG_DEFAULT_CLEAR_BLUE +#define SG_DEFAULT_CLEAR_BLUE (0.5f) +#endif +#ifndef SG_DEFAULT_CLEAR_ALPHA +#define SG_DEFAULT_CLEAR_ALPHA (1.0f) +#endif +#ifndef SG_DEFAULT_CLEAR_DEPTH +#define SG_DEFAULT_CLEAR_DEPTH (1.0f) +#endif +#ifndef SG_DEFAULT_CLEAR_STENCIL +#define SG_DEFAULT_CLEAR_STENCIL (0) +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4115) /* named type definition in parentheses */ +#pragma warning(disable:4505) /* unreferenced local function has been removed */ +#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union (needed by d3d11.h) */ +#pragma warning(disable:4054) /* 'type cast': from function pointer */ +#pragma warning(disable:4055) /* 'type cast': from data pointer */ +#endif + +#if defined(SOKOL_D3D11) + #ifndef D3D11_NO_HELPERS + #define D3D11_NO_HELPERS + #endif + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include + #include + #ifdef _MSC_VER + #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) + #pragma comment (lib, "WindowsApp") + #else + #pragma comment (lib, "kernel32") + #pragma comment (lib, "user32") + #pragma comment (lib, "dxgi") + #pragma comment (lib, "d3d11") + #endif + #endif +#elif defined(SOKOL_METAL) + // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting + #if !defined(__cplusplus) + #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) + #error "sokol_gfx.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" + #endif + #endif + #include + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #define _SG_TARGET_MACOS (1) + #else + #define _SG_TARGET_IOS (1) + #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR + #define _SG_TARGET_IOS_SIMULATOR (1) + #endif + #endif + #import +#elif defined(SOKOL_WGPU) + #if defined(__EMSCRIPTEN__) + #include + #else + #include + #endif +#elif defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + #define _SOKOL_ANY_GL (1) + + // include platform specific GL headers (or on Win32: use an embedded GL loader) + #if !defined(SOKOL_EXTERNAL_GL_LOADER) + #if defined(_WIN32) + #if defined(SOKOL_GLCORE33) && !defined(SOKOL_EXTERNAL_GL_LOADER) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include + #define _SOKOL_USE_WIN32_GL_LOADER (1) + #pragma comment (lib, "kernel32") // GetProcAddress() + #endif + #elif defined(__APPLE__) + #include + #ifndef GL_SILENCE_DEPRECATION + #define GL_SILENCE_DEPRECATION + #endif + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #include + #else + #include + #include + #endif + #elif defined(__EMSCRIPTEN__) || defined(__ANDROID__) + #if defined(SOKOL_GLES3) + #include + #elif defined(SOKOL_GLES2) + #ifndef GL_EXT_PROTOTYPES + #define GL_GLEXT_PROTOTYPES + #endif + #include + #include + #endif + #elif defined(__linux__) || defined(__unix__) + #define GL_GLEXT_PROTOTYPES + #include + #endif + #endif + + // optional GL loader definitions (only on Win32) + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + #define __gl_h_ 1 + #define __gl32_h_ 1 + #define __gl31_h_ 1 + #define __GL_H__ 1 + #define __glext_h_ 1 + #define __GLEXT_H_ 1 + #define __gltypes_h_ 1 + #define __glcorearb_h_ 1 + #define __gl_glcorearb_h_ 1 + #define GL_APIENTRY APIENTRY + + typedef unsigned int GLenum; + typedef unsigned int GLuint; + typedef int GLsizei; + typedef char GLchar; + typedef ptrdiff_t GLintptr; + typedef ptrdiff_t GLsizeiptr; + typedef double GLclampd; + typedef unsigned short GLushort; + typedef unsigned char GLubyte; + typedef unsigned char GLboolean; + typedef uint64_t GLuint64; + typedef double GLdouble; + typedef unsigned short GLhalf; + typedef float GLclampf; + typedef unsigned int GLbitfield; + typedef signed char GLbyte; + typedef short GLshort; + typedef void GLvoid; + typedef int64_t GLint64; + typedef float GLfloat; + typedef struct __GLsync * GLsync; + typedef int GLint; + #define GL_INT_2_10_10_10_REV 0x8D9F + #define GL_R32F 0x822E + #define GL_PROGRAM_POINT_SIZE 0x8642 + #define GL_STENCIL_ATTACHMENT 0x8D20 + #define GL_DEPTH_ATTACHMENT 0x8D00 + #define GL_COLOR_ATTACHMENT2 0x8CE2 + #define GL_COLOR_ATTACHMENT0 0x8CE0 + #define GL_R16F 0x822D + #define GL_COLOR_ATTACHMENT22 0x8CF6 + #define GL_DRAW_FRAMEBUFFER 0x8CA9 + #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 + #define GL_NUM_EXTENSIONS 0x821D + #define GL_INFO_LOG_LENGTH 0x8B84 + #define GL_VERTEX_SHADER 0x8B31 + #define GL_INCR 0x1E02 + #define GL_DYNAMIC_DRAW 0x88E8 + #define GL_STATIC_DRAW 0x88E4 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 + #define GL_TEXTURE_CUBE_MAP 0x8513 + #define GL_FUNC_SUBTRACT 0x800A + #define GL_FUNC_REVERSE_SUBTRACT 0x800B + #define GL_CONSTANT_COLOR 0x8001 + #define GL_DECR_WRAP 0x8508 + #define GL_R8 0x8229 + #define GL_LINEAR_MIPMAP_LINEAR 0x2703 + #define GL_ELEMENT_ARRAY_BUFFER 0x8893 + #define GL_SHORT 0x1402 + #define GL_DEPTH_TEST 0x0B71 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 + #define GL_LINK_STATUS 0x8B82 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 + #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E + #define GL_RGBA16F 0x881A + #define GL_CONSTANT_ALPHA 0x8003 + #define GL_READ_FRAMEBUFFER 0x8CA8 + #define GL_TEXTURE0 0x84C0 + #define GL_TEXTURE_MIN_LOD 0x813A + #define GL_CLAMP_TO_EDGE 0x812F + #define GL_UNSIGNED_SHORT_5_6_5 0x8363 + #define GL_TEXTURE_WRAP_R 0x8072 + #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 + #define GL_NEAREST_MIPMAP_NEAREST 0x2700 + #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 + #define GL_SRC_ALPHA_SATURATE 0x0308 + #define GL_STREAM_DRAW 0x88E0 + #define GL_ONE 1 + #define GL_NEAREST_MIPMAP_LINEAR 0x2702 + #define GL_RGB10_A2 0x8059 + #define GL_RGBA8 0x8058 + #define GL_COLOR_ATTACHMENT1 0x8CE1 + #define GL_RGBA4 0x8056 + #define GL_RGB8 0x8051 + #define GL_ARRAY_BUFFER 0x8892 + #define GL_STENCIL 0x1802 + #define GL_TEXTURE_2D 0x0DE1 + #define GL_DEPTH 0x1801 + #define GL_FRONT 0x0404 + #define GL_STENCIL_BUFFER_BIT 0x00000400 + #define GL_REPEAT 0x2901 + #define GL_RGBA 0x1908 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 + #define GL_DECR 0x1E03 + #define GL_FRAGMENT_SHADER 0x8B30 + #define GL_FLOAT 0x1406 + #define GL_TEXTURE_MAX_LOD 0x813B + #define GL_DEPTH_COMPONENT 0x1902 + #define GL_ONE_MINUS_DST_ALPHA 0x0305 + #define GL_COLOR 0x1800 + #define GL_TEXTURE_2D_ARRAY 0x8C1A + #define GL_TRIANGLES 0x0004 + #define GL_UNSIGNED_BYTE 0x1401 + #define GL_TEXTURE_MAG_FILTER 0x2800 + #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 + #define GL_NONE 0 + #define GL_SRC_COLOR 0x0300 + #define GL_BYTE 0x1400 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A + #define GL_LINE_STRIP 0x0003 + #define GL_TEXTURE_3D 0x806F + #define GL_CW 0x0900 + #define GL_LINEAR 0x2601 + #define GL_RENDERBUFFER 0x8D41 + #define GL_GEQUAL 0x0206 + #define GL_COLOR_BUFFER_BIT 0x00004000 + #define GL_RGBA32F 0x8814 + #define GL_BLEND 0x0BE2 + #define GL_ONE_MINUS_SRC_ALPHA 0x0303 + #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 + #define GL_TEXTURE_WRAP_T 0x2803 + #define GL_TEXTURE_WRAP_S 0x2802 + #define GL_TEXTURE_MIN_FILTER 0x2801 + #define GL_LINEAR_MIPMAP_NEAREST 0x2701 + #define GL_EXTENSIONS 0x1F03 + #define GL_NO_ERROR 0 + #define GL_REPLACE 0x1E01 + #define GL_KEEP 0x1E00 + #define GL_CCW 0x0901 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 + #define GL_RGB 0x1907 + #define GL_TRIANGLE_STRIP 0x0005 + #define GL_FALSE 0 + #define GL_ZERO 0 + #define GL_CULL_FACE 0x0B44 + #define GL_INVERT 0x150A + #define GL_INT 0x1404 + #define GL_UNSIGNED_INT 0x1405 + #define GL_UNSIGNED_SHORT 0x1403 + #define GL_NEAREST 0x2600 + #define GL_SCISSOR_TEST 0x0C11 + #define GL_LEQUAL 0x0203 + #define GL_STENCIL_TEST 0x0B90 + #define GL_DITHER 0x0BD0 + #define GL_DEPTH_COMPONENT16 0x81A5 + #define GL_EQUAL 0x0202 + #define GL_FRAMEBUFFER 0x8D40 + #define GL_RGB5 0x8050 + #define GL_LINES 0x0001 + #define GL_DEPTH_BUFFER_BIT 0x00000100 + #define GL_SRC_ALPHA 0x0302 + #define GL_INCR_WRAP 0x8507 + #define GL_LESS 0x0201 + #define GL_MULTISAMPLE 0x809D + #define GL_FRAMEBUFFER_BINDING 0x8CA6 + #define GL_BACK 0x0405 + #define GL_ALWAYS 0x0207 + #define GL_FUNC_ADD 0x8006 + #define GL_ONE_MINUS_DST_COLOR 0x0307 + #define GL_NOTEQUAL 0x0205 + #define GL_DST_COLOR 0x0306 + #define GL_COMPILE_STATUS 0x8B81 + #define GL_RED 0x1903 + #define GL_COLOR_ATTACHMENT3 0x8CE3 + #define GL_DST_ALPHA 0x0304 + #define GL_RGB5_A1 0x8057 + #define GL_GREATER 0x0204 + #define GL_POLYGON_OFFSET_FILL 0x8037 + #define GL_TRUE 1 + #define GL_NEVER 0x0200 + #define GL_POINTS 0x0000 + #define GL_ONE_MINUS_SRC_COLOR 0x0301 + #define GL_MIRRORED_REPEAT 0x8370 + #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D + #define GL_R11F_G11F_B10F 0x8C3A + #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B + #define GL_RGBA32UI 0x8D70 + #define GL_RGB32UI 0x8D71 + #define GL_RGBA16UI 0x8D76 + #define GL_RGB16UI 0x8D77 + #define GL_RGBA8UI 0x8D7C + #define GL_RGB8UI 0x8D7D + #define GL_RGBA32I 0x8D82 + #define GL_RGB32I 0x8D83 + #define GL_RGBA16I 0x8D88 + #define GL_RGB16I 0x8D89 + #define GL_RGBA8I 0x8D8E + #define GL_RGB8I 0x8D8F + #define GL_RED_INTEGER 0x8D94 + #define GL_RG 0x8227 + #define GL_RG_INTEGER 0x8228 + #define GL_R8 0x8229 + #define GL_R16 0x822A + #define GL_RG8 0x822B + #define GL_RG16 0x822C + #define GL_R16F 0x822D + #define GL_R32F 0x822E + #define GL_RG16F 0x822F + #define GL_RG32F 0x8230 + #define GL_R8I 0x8231 + #define GL_R8UI 0x8232 + #define GL_R16I 0x8233 + #define GL_R16UI 0x8234 + #define GL_R32I 0x8235 + #define GL_R32UI 0x8236 + #define GL_RG8I 0x8237 + #define GL_RG8UI 0x8238 + #define GL_RG16I 0x8239 + #define GL_RG16UI 0x823A + #define GL_RG32I 0x823B + #define GL_RG32UI 0x823C + #define GL_RGBA_INTEGER 0x8D99 + #define GL_R8_SNORM 0x8F94 + #define GL_RG8_SNORM 0x8F95 + #define GL_RGB8_SNORM 0x8F96 + #define GL_RGBA8_SNORM 0x8F97 + #define GL_R16_SNORM 0x8F98 + #define GL_RG16_SNORM 0x8F99 + #define GL_RGB16_SNORM 0x8F9A + #define GL_RGBA16_SNORM 0x8F9B + #define GL_RGBA16 0x805B + #define GL_MAX_TEXTURE_SIZE 0x0D33 + #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C + #define GL_MAX_3D_TEXTURE_SIZE 0x8073 + #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF + #define GL_MAX_VERTEX_ATTRIBS 0x8869 + #define GL_CLAMP_TO_BORDER 0x812D + #define GL_TEXTURE_BORDER_COLOR 0x1004 + #define GL_CURRENT_PROGRAM 0x8B8D + #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB + #endif + + #ifndef GL_UNSIGNED_INT_2_10_10_10_REV + #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 + #endif + #ifndef GL_UNSIGNED_INT_24_8 + #define GL_UNSIGNED_INT_24_8 0x84FA + #endif + #ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE + #endif + #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + #endif + #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 + #endif + #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 + #endif + #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 + #endif + #ifndef GL_COMPRESSED_RED_RGTC1 + #define GL_COMPRESSED_RED_RGTC1 0x8DBB + #endif + #ifndef GL_COMPRESSED_SIGNED_RED_RGTC1 + #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC + #endif + #ifndef GL_COMPRESSED_RED_GREEN_RGTC2 + #define GL_COMPRESSED_RED_GREEN_RGTC2 0x8DBD + #endif + #ifndef GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2 + #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2 0x8DBE + #endif + #ifndef GL_COMPRESSED_RGBA_BPTC_UNORM_ARB + #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C + #endif + #ifndef GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB + #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D + #endif + #ifndef GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB + #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E + #endif + #ifndef GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB + #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F + #endif + #ifndef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 + #endif + #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 + #endif + #ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG + #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 + #endif + #ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 + #endif + #ifndef GL_COMPRESSED_RGB8_ETC2 + #define GL_COMPRESSED_RGB8_ETC2 0x9274 + #endif + #ifndef GL_COMPRESSED_RGBA8_ETC2_EAC + #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 + #endif + #ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 + #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 + #endif + #ifndef GL_COMPRESSED_RG11_EAC + #define GL_COMPRESSED_RG11_EAC 0x9272 + #endif + #ifndef GL_COMPRESSED_SIGNED_RG11_EAC + #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 + #endif + #ifndef GL_DEPTH24_STENCIL8 + #define GL_DEPTH24_STENCIL8 0x88F0 + #endif + #ifndef GL_HALF_FLOAT + #define GL_HALF_FLOAT 0x140B + #endif + #ifndef GL_DEPTH_STENCIL + #define GL_DEPTH_STENCIL 0x84F9 + #endif + #ifndef GL_LUMINANCE + #define GL_LUMINANCE 0x1909 + #endif + + #ifdef SOKOL_GLES2 + #ifdef GL_ANGLE_instanced_arrays + #define _SOKOL_GL_INSTANCING_ENABLED + #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedANGLE(mode, first, count, instancecount) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedANGLE(mode, count, type, indices, instancecount) + #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorANGLE(index, divisor) + #elif defined(GL_EXT_draw_instanced) && defined(GL_EXT_instanced_arrays) + #define _SOKOL_GL_INSTANCING_ENABLED + #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedEXT(mode, first, count, instancecount) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedEXT(mode, count, type, indices, instancecount) + #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorEXT(index, divisor) + #else + #define _SOKOL_GLES2_INSTANCING_ERROR "Select GL_ANGLE_instanced_arrays or (GL_EXT_draw_instanced & GL_EXT_instanced_arrays) to enable instancing in GLES2" + #define glDrawArraysInstanced(mode, first, count, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #define glVertexAttribDivisor(index, divisor) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #endif + #else + #define _SOKOL_GL_INSTANCING_ENABLED + #endif + #define _SG_GL_CHECK_ERROR() { SOKOL_ASSERT(glGetError() == GL_NO_ERROR); } +#endif + +/*=== COMMON BACKEND STUFF ===================================================*/ + +/* resource pool slots */ +typedef struct { + uint32_t id; + uint32_t ctx_id; + sg_resource_state state; +} _sg_slot_t; + +/* constants */ +enum { + _SG_STRING_SIZE = 16, + _SG_SLOT_SHIFT = 16, + _SG_SLOT_MASK = (1<<_SG_SLOT_SHIFT)-1, + _SG_MAX_POOL_SIZE = (1<<_SG_SLOT_SHIFT), + _SG_DEFAULT_BUFFER_POOL_SIZE = 128, + _SG_DEFAULT_IMAGE_POOL_SIZE = 128, + _SG_DEFAULT_SHADER_POOL_SIZE = 32, + _SG_DEFAULT_PIPELINE_POOL_SIZE = 64, + _SG_DEFAULT_PASS_POOL_SIZE = 16, + _SG_DEFAULT_CONTEXT_POOL_SIZE = 16, + _SG_DEFAULT_SAMPLER_CACHE_CAPACITY = 64, + _SG_DEFAULT_UB_SIZE = 4 * 1024 * 1024, + _SG_DEFAULT_STAGING_SIZE = 8 * 1024 * 1024, +}; + +/* fixed-size string */ +typedef struct { + char buf[_SG_STRING_SIZE]; +} _sg_str_t; + +/* helper macros */ +#define _sg_def(val, def) (((val) == 0) ? (def) : (val)) +#define _sg_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) +#define _sg_min(a,b) (((a)<(b))?(a):(b)) +#define _sg_max(a,b) (((a)>(b))?(a):(b)) +#define _sg_clamp(v,v0,v1) (((v)<(v0))?(v0):(((v)>(v1))?(v1):(v))) +#define _sg_fequal(val,cmp,delta) ((((val)-(cmp))> -(delta))&&(((val)-(cmp))<(delta))) + +typedef struct { + int size; + int append_pos; + bool append_overflow; + sg_buffer_type type; + sg_usage usage; + uint32_t update_frame_index; + uint32_t append_frame_index; + int num_slots; + int active_slot; +} _sg_buffer_common_t; + +_SOKOL_PRIVATE void _sg_buffer_common_init(_sg_buffer_common_t* cmn, const sg_buffer_desc* desc) { + cmn->size = (int)desc->size; + cmn->append_pos = 0; + cmn->append_overflow = false; + cmn->type = desc->type; + cmn->usage = desc->usage; + cmn->update_frame_index = 0; + cmn->append_frame_index = 0; + cmn->num_slots = (cmn->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES; + cmn->active_slot = 0; +} + +typedef struct { + sg_image_type type; + bool render_target; + int width; + int height; + int num_slices; + int num_mipmaps; + sg_usage usage; + sg_pixel_format pixel_format; + int sample_count; + sg_filter min_filter; + sg_filter mag_filter; + sg_wrap wrap_u; + sg_wrap wrap_v; + sg_wrap wrap_w; + sg_border_color border_color; + uint32_t max_anisotropy; + uint32_t upd_frame_index; + int num_slots; + int active_slot; +} _sg_image_common_t; + +_SOKOL_PRIVATE void _sg_image_common_init(_sg_image_common_t* cmn, const sg_image_desc* desc) { + cmn->type = desc->type; + cmn->render_target = desc->render_target; + cmn->width = desc->width; + cmn->height = desc->height; + cmn->num_slices = desc->num_slices; + cmn->num_mipmaps = desc->num_mipmaps; + cmn->usage = desc->usage; + cmn->pixel_format = desc->pixel_format; + cmn->sample_count = desc->sample_count; + cmn->min_filter = desc->min_filter; + cmn->mag_filter = desc->mag_filter; + cmn->wrap_u = desc->wrap_u; + cmn->wrap_v = desc->wrap_v; + cmn->wrap_w = desc->wrap_w; + cmn->border_color = desc->border_color; + cmn->max_anisotropy = desc->max_anisotropy; + cmn->upd_frame_index = 0; + cmn->num_slots = (cmn->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES; + cmn->active_slot = 0; +} + +typedef struct { + size_t size; +} _sg_uniform_block_t; + +typedef struct { + sg_image_type image_type; + sg_sampler_type sampler_type; +} _sg_shader_image_t; + +typedef struct { + int num_uniform_blocks; + int num_images; + _sg_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; + _sg_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES]; +} _sg_shader_stage_t; + +typedef struct { + _sg_shader_stage_t stage[SG_NUM_SHADER_STAGES]; +} _sg_shader_common_t; + +_SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_shader_desc* desc) { + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; + _sg_shader_stage_t* stage = &cmn->stage[stage_index]; + SOKOL_ASSERT(stage->num_uniform_blocks == 0); + for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { + const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; + if (0 == ub_desc->size) { + break; + } + stage->uniform_blocks[ub_index].size = ub_desc->size; + stage->num_uniform_blocks++; + } + SOKOL_ASSERT(stage->num_images == 0); + for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { + const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; + if (img_desc->image_type == _SG_IMAGETYPE_DEFAULT) { + break; + } + stage->images[img_index].image_type = img_desc->image_type; + stage->images[img_index].sampler_type = img_desc->sampler_type; + stage->num_images++; + } + } +} + +typedef struct { + sg_shader shader_id; + sg_index_type index_type; + bool use_instanced_draw; + bool vertex_layout_valid[SG_MAX_SHADERSTAGE_BUFFERS]; + int color_attachment_count; + sg_pixel_format color_formats[SG_MAX_COLOR_ATTACHMENTS]; + sg_pixel_format depth_format; + int sample_count; + float depth_bias; + float depth_bias_slope_scale; + float depth_bias_clamp; + sg_color blend_color; +} _sg_pipeline_common_t; + +_SOKOL_PRIVATE void _sg_pipeline_common_init(_sg_pipeline_common_t* cmn, const sg_pipeline_desc* desc) { + SOKOL_ASSERT((desc->color_count >= 1) && (desc->color_count <= SG_MAX_COLOR_ATTACHMENTS)); + cmn->shader_id = desc->shader; + cmn->index_type = desc->index_type; + cmn->use_instanced_draw = false; + for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) { + cmn->vertex_layout_valid[i] = false; + } + cmn->color_attachment_count = desc->color_count; + for (int i = 0; i < cmn->color_attachment_count; i++) { + cmn->color_formats[i] = desc->colors[i].pixel_format; + } + cmn->depth_format = desc->depth.pixel_format; + cmn->sample_count = desc->sample_count; + cmn->depth_bias = desc->depth.bias; + cmn->depth_bias_slope_scale = desc->depth.bias_slope_scale; + cmn->depth_bias_clamp = desc->depth.bias_clamp; + cmn->blend_color = desc->blend_color; +} + +typedef struct { + sg_image image_id; + int mip_level; + int slice; +} _sg_pass_attachment_common_t; + +typedef struct { + int num_color_atts; + _sg_pass_attachment_common_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_pass_attachment_common_t ds_att; +} _sg_pass_common_t; + +_SOKOL_PRIVATE void _sg_pass_common_init(_sg_pass_common_t* cmn, const sg_pass_desc* desc) { + const sg_pass_attachment_desc* att_desc; + _sg_pass_attachment_common_t* att; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + att_desc = &desc->color_attachments[i]; + if (att_desc->image.id != SG_INVALID_ID) { + cmn->num_color_atts++; + att = &cmn->color_atts[i]; + att->image_id = att_desc->image; + att->mip_level = att_desc->mip_level; + att->slice = att_desc->slice; + } + } + att_desc = &desc->depth_stencil_attachment; + if (att_desc->image.id != SG_INVALID_ID) { + att = &cmn->ds_att; + att->image_id = att_desc->image; + att->mip_level = att_desc->mip_level; + att->slice = att_desc->slice; + } +} + +/*=== GENERIC SAMPLER CACHE ==================================================*/ + +/* + this is used by the Metal and WGPU backends to reduce the + number of sampler state objects created through the backend API +*/ +typedef struct { + sg_filter min_filter; + sg_filter mag_filter; + sg_wrap wrap_u; + sg_wrap wrap_v; + sg_wrap wrap_w; + sg_border_color border_color; + uint32_t max_anisotropy; + int min_lod; /* orig min/max_lod is float, this is int(min/max_lod*1000.0) */ + int max_lod; + uintptr_t sampler_handle; +} _sg_sampler_cache_item_t; + +typedef struct { + int capacity; + int num_items; + _sg_sampler_cache_item_t* items; +} _sg_sampler_cache_t; + +_SOKOL_PRIVATE void _sg_smpcache_init(_sg_sampler_cache_t* cache, int capacity) { + SOKOL_ASSERT(cache && (capacity > 0)); + memset(cache, 0, sizeof(_sg_sampler_cache_t)); + cache->capacity = capacity; + const size_t size = (size_t)cache->capacity * sizeof(_sg_sampler_cache_item_t); + cache->items = (_sg_sampler_cache_item_t*) SOKOL_MALLOC(size); + SOKOL_ASSERT(cache->items); + memset(cache->items, 0, size); +} + +_SOKOL_PRIVATE void _sg_smpcache_discard(_sg_sampler_cache_t* cache) { + SOKOL_ASSERT(cache && cache->items); + SOKOL_FREE(cache->items); + cache->items = 0; + cache->num_items = 0; + cache->capacity = 0; +} + +_SOKOL_PRIVATE int _sg_smpcache_minlod_int(float min_lod) { + return (int) (min_lod * 1000.0f); +} + +_SOKOL_PRIVATE int _sg_smpcache_maxlod_int(float max_lod) { + return (int) (_sg_clamp(max_lod, 0.0f, 1000.0f) * 1000.0f); +} + +_SOKOL_PRIVATE int _sg_smpcache_find_item(const _sg_sampler_cache_t* cache, const sg_image_desc* img_desc) { + /* return matching sampler cache item index or -1 */ + SOKOL_ASSERT(cache && cache->items); + SOKOL_ASSERT(img_desc); + const int min_lod = _sg_smpcache_minlod_int(img_desc->min_lod); + const int max_lod = _sg_smpcache_maxlod_int(img_desc->max_lod); + for (int i = 0; i < cache->num_items; i++) { + const _sg_sampler_cache_item_t* item = &cache->items[i]; + if ((img_desc->min_filter == item->min_filter) && + (img_desc->mag_filter == item->mag_filter) && + (img_desc->wrap_u == item->wrap_u) && + (img_desc->wrap_v == item->wrap_v) && + (img_desc->wrap_w == item->wrap_w) && + (img_desc->max_anisotropy == item->max_anisotropy) && + (img_desc->border_color == item->border_color) && + (min_lod == item->min_lod) && + (max_lod == item->max_lod)) + { + return i; + } + } + /* fallthrough: no matching cache item found */ + return -1; +} + +_SOKOL_PRIVATE void _sg_smpcache_add_item(_sg_sampler_cache_t* cache, const sg_image_desc* img_desc, uintptr_t sampler_handle) { + SOKOL_ASSERT(cache && cache->items); + SOKOL_ASSERT(img_desc); + SOKOL_ASSERT(cache->num_items < cache->capacity); + const int item_index = cache->num_items++; + _sg_sampler_cache_item_t* item = &cache->items[item_index]; + item->min_filter = img_desc->min_filter; + item->mag_filter = img_desc->mag_filter; + item->wrap_u = img_desc->wrap_u; + item->wrap_v = img_desc->wrap_v; + item->wrap_w = img_desc->wrap_w; + item->border_color = img_desc->border_color; + item->max_anisotropy = img_desc->max_anisotropy; + item->min_lod = _sg_smpcache_minlod_int(img_desc->min_lod); + item->max_lod = _sg_smpcache_maxlod_int(img_desc->max_lod); + item->sampler_handle = sampler_handle; +} + +_SOKOL_PRIVATE uintptr_t _sg_smpcache_sampler(_sg_sampler_cache_t* cache, int item_index) { + SOKOL_ASSERT(cache && cache->items); + SOKOL_ASSERT(item_index < cache->num_items); + return cache->items[item_index].sampler_handle; +} + +/*=== DUMMY BACKEND DECLARATIONS =============================================*/ +#if defined(SOKOL_DUMMY_BACKEND) +typedef struct { + _sg_slot_t slot; + _sg_buffer_common_t cmn; +} _sg_dummy_buffer_t; +typedef _sg_dummy_buffer_t _sg_buffer_t; + +typedef struct { + _sg_slot_t slot; + _sg_image_common_t cmn; +} _sg_dummy_image_t; +typedef _sg_dummy_image_t _sg_image_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_common_t cmn; +} _sg_dummy_shader_t; +typedef _sg_dummy_shader_t _sg_shader_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_t* shader; + _sg_pipeline_common_t cmn; +} _sg_dummy_pipeline_t; +typedef _sg_dummy_pipeline_t _sg_pipeline_t; + +typedef struct { + _sg_image_t* image; +} _sg_dummy_attachment_t; + +typedef struct { + _sg_slot_t slot; + _sg_pass_common_t cmn; + struct { + _sg_dummy_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_dummy_attachment_t ds_att; + } dmy; +} _sg_dummy_pass_t; +typedef _sg_dummy_pass_t _sg_pass_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; + +typedef struct { + _sg_slot_t slot; +} _sg_dummy_context_t; +typedef _sg_dummy_context_t _sg_context_t; + +/*== GL BACKEND DECLARATIONS =================================================*/ +#elif defined(_SOKOL_ANY_GL) +typedef struct { + _sg_slot_t slot; + _sg_buffer_common_t cmn; + struct { + GLuint buf[SG_NUM_INFLIGHT_FRAMES]; + bool ext_buffers; /* if true, external buffers were injected with sg_buffer_desc.gl_buffers */ + } gl; +} _sg_gl_buffer_t; +typedef _sg_gl_buffer_t _sg_buffer_t; + +typedef struct { + _sg_slot_t slot; + _sg_image_common_t cmn; + struct { + GLenum target; + GLuint depth_render_buffer; + GLuint msaa_render_buffer; + GLuint tex[SG_NUM_INFLIGHT_FRAMES]; + bool ext_textures; /* if true, external textures were injected with sg_image_desc.gl_textures */ + } gl; +} _sg_gl_image_t; +typedef _sg_gl_image_t _sg_image_t; + +typedef struct { + GLint gl_loc; + sg_uniform_type type; + uint16_t count; + uint16_t offset; +} _sg_gl_uniform_t; + +typedef struct { + int num_uniforms; + _sg_gl_uniform_t uniforms[SG_MAX_UB_MEMBERS]; +} _sg_gl_uniform_block_t; + +typedef struct { + int gl_tex_slot; +} _sg_gl_shader_image_t; + +typedef struct { + _sg_str_t name; +} _sg_gl_shader_attr_t; + +typedef struct { + _sg_gl_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; + _sg_gl_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES]; +} _sg_gl_shader_stage_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_common_t cmn; + struct { + GLuint prog; + _sg_gl_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; + _sg_gl_shader_stage_t stage[SG_NUM_SHADER_STAGES]; + } gl; +} _sg_gl_shader_t; +typedef _sg_gl_shader_t _sg_shader_t; + +typedef struct { + int8_t vb_index; /* -1 if attr is not enabled */ + int8_t divisor; /* -1 if not initialized */ + uint8_t stride; + uint8_t size; + uint8_t normalized; + int offset; + GLenum type; +} _sg_gl_attr_t; + +typedef struct { + _sg_slot_t slot; + _sg_pipeline_common_t cmn; + _sg_shader_t* shader; + struct { + _sg_gl_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; + sg_depth_state depth; + sg_stencil_state stencil; + sg_primitive_type primitive_type; + sg_blend_state blend; + sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; + sg_cull_mode cull_mode; + sg_face_winding face_winding; + int sample_count; + bool alpha_to_coverage_enabled; + } gl; +} _sg_gl_pipeline_t; +typedef _sg_gl_pipeline_t _sg_pipeline_t; + +typedef struct { + _sg_image_t* image; + GLuint gl_msaa_resolve_buffer; +} _sg_gl_attachment_t; + +typedef struct { + _sg_slot_t slot; + _sg_pass_common_t cmn; + struct { + GLuint fb; + _sg_gl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_gl_attachment_t ds_att; + } gl; +} _sg_gl_pass_t; +typedef _sg_gl_pass_t _sg_pass_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; + +typedef struct { + _sg_slot_t slot; + #if !defined(SOKOL_GLES2) + GLuint vao; + #endif + GLuint default_framebuffer; +} _sg_gl_context_t; +typedef _sg_gl_context_t _sg_context_t; + +typedef struct { + _sg_gl_attr_t gl_attr; + GLuint gl_vbuf; +} _sg_gl_cache_attr_t; + +typedef struct { + GLenum target; + GLuint texture; +} _sg_gl_texture_bind_slot; + +typedef struct { + sg_depth_state depth; + sg_stencil_state stencil; + sg_blend_state blend; + sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; + sg_cull_mode cull_mode; + sg_face_winding face_winding; + bool polygon_offset_enabled; + int sample_count; + sg_color blend_color; + bool alpha_to_coverage_enabled; + _sg_gl_cache_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; + GLuint vertex_buffer; + GLuint index_buffer; + GLuint stored_vertex_buffer; + GLuint stored_index_buffer; + GLuint prog; + _sg_gl_texture_bind_slot textures[SG_MAX_SHADERSTAGE_IMAGES]; + _sg_gl_texture_bind_slot stored_texture; + int cur_ib_offset; + GLenum cur_primitive_type; + GLenum cur_index_type; + GLenum cur_active_texture; + _sg_pipeline_t* cur_pipeline; + sg_pipeline cur_pipeline_id; +} _sg_gl_state_cache_t; + +typedef struct { + bool valid; + bool gles2; + bool in_pass; + int cur_pass_width; + int cur_pass_height; + _sg_context_t* cur_context; + _sg_pass_t* cur_pass; + sg_pass cur_pass_id; + _sg_gl_state_cache_t cache; + bool ext_anisotropic; + GLint max_anisotropy; + GLint max_combined_texture_image_units; + #if _SOKOL_USE_WIN32_GL_LOADER + HINSTANCE opengl32_dll; + #endif +} _sg_gl_backend_t; + +/*== D3D11 BACKEND DECLARATIONS ==============================================*/ +#elif defined(SOKOL_D3D11) + +typedef struct { + _sg_slot_t slot; + _sg_buffer_common_t cmn; + struct { + ID3D11Buffer* buf; + } d3d11; +} _sg_d3d11_buffer_t; +typedef _sg_d3d11_buffer_t _sg_buffer_t; + +typedef struct { + _sg_slot_t slot; + _sg_image_common_t cmn; + struct { + DXGI_FORMAT format; + ID3D11Texture2D* tex2d; + ID3D11Texture3D* tex3d; + ID3D11Texture2D* texds; + ID3D11Texture2D* texmsaa; + ID3D11ShaderResourceView* srv; + ID3D11SamplerState* smp; + } d3d11; +} _sg_d3d11_image_t; +typedef _sg_d3d11_image_t _sg_image_t; + +typedef struct { + _sg_str_t sem_name; + int sem_index; +} _sg_d3d11_shader_attr_t; + +typedef struct { + ID3D11Buffer* cbufs[SG_MAX_SHADERSTAGE_UBS]; +} _sg_d3d11_shader_stage_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_common_t cmn; + struct { + _sg_d3d11_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; + _sg_d3d11_shader_stage_t stage[SG_NUM_SHADER_STAGES]; + ID3D11VertexShader* vs; + ID3D11PixelShader* fs; + void* vs_blob; + size_t vs_blob_length; + } d3d11; +} _sg_d3d11_shader_t; +typedef _sg_d3d11_shader_t _sg_shader_t; + +typedef struct { + _sg_slot_t slot; + _sg_pipeline_common_t cmn; + _sg_shader_t* shader; + struct { + UINT stencil_ref; + UINT vb_strides[SG_MAX_SHADERSTAGE_BUFFERS]; + D3D_PRIMITIVE_TOPOLOGY topology; + DXGI_FORMAT index_format; + ID3D11InputLayout* il; + ID3D11RasterizerState* rs; + ID3D11DepthStencilState* dss; + ID3D11BlendState* bs; + } d3d11; +} _sg_d3d11_pipeline_t; +typedef _sg_d3d11_pipeline_t _sg_pipeline_t; + +typedef struct { + _sg_image_t* image; + ID3D11RenderTargetView* rtv; +} _sg_d3d11_color_attachment_t; + +typedef struct { + _sg_image_t* image; + ID3D11DepthStencilView* dsv; +} _sg_d3d11_ds_attachment_t; + +typedef struct { + _sg_slot_t slot; + _sg_pass_common_t cmn; + struct { + _sg_d3d11_color_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_d3d11_ds_attachment_t ds_att; + } d3d11; +} _sg_d3d11_pass_t; +typedef _sg_d3d11_pass_t _sg_pass_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; + +typedef struct { + _sg_slot_t slot; +} _sg_d3d11_context_t; +typedef _sg_d3d11_context_t _sg_context_t; + +typedef struct { + bool valid; + ID3D11Device* dev; + ID3D11DeviceContext* ctx; + const void* (*rtv_cb)(void); + const void* (*rtv_userdata_cb)(void*); + const void* (*dsv_cb)(void); + const void* (*dsv_userdata_cb)(void*); + void* user_data; + bool in_pass; + bool use_indexed_draw; + bool use_instanced_draw; + int cur_width; + int cur_height; + int num_rtvs; + _sg_pass_t* cur_pass; + sg_pass cur_pass_id; + _sg_pipeline_t* cur_pipeline; + sg_pipeline cur_pipeline_id; + ID3D11RenderTargetView* cur_rtvs[SG_MAX_COLOR_ATTACHMENTS]; + ID3D11DepthStencilView* cur_dsv; + /* on-demand loaded d3dcompiler_47.dll handles */ + HINSTANCE d3dcompiler_dll; + bool d3dcompiler_dll_load_failed; + pD3DCompile D3DCompile_func; + /* global subresourcedata array for texture updates */ + D3D11_SUBRESOURCE_DATA subres_data[SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS]; +} _sg_d3d11_backend_t; + +/*=== METAL BACKEND DECLARATIONS =============================================*/ +#elif defined(SOKOL_METAL) + +#if defined(_SG_TARGET_MACOS) || defined(_SG_TARGET_IOS_SIMULATOR) +#define _SG_MTL_UB_ALIGN (256) +#else +#define _SG_MTL_UB_ALIGN (16) +#endif +#define _SG_MTL_INVALID_SLOT_INDEX (0) + +typedef struct { + uint32_t frame_index; /* frame index at which it is safe to release this resource */ + int slot_index; +} _sg_mtl_release_item_t; + +typedef struct { + NSMutableArray* pool; + int num_slots; + int free_queue_top; + int* free_queue; + int release_queue_front; + int release_queue_back; + _sg_mtl_release_item_t* release_queue; +} _sg_mtl_idpool_t; + +typedef struct { + _sg_slot_t slot; + _sg_buffer_common_t cmn; + struct { + int buf[SG_NUM_INFLIGHT_FRAMES]; /* index into _sg_mtl_pool */ + } mtl; +} _sg_mtl_buffer_t; +typedef _sg_mtl_buffer_t _sg_buffer_t; + +typedef struct { + _sg_slot_t slot; + _sg_image_common_t cmn; + struct { + int tex[SG_NUM_INFLIGHT_FRAMES]; + int depth_tex; + int msaa_tex; + int sampler_state; + } mtl; +} _sg_mtl_image_t; +typedef _sg_mtl_image_t _sg_image_t; + +typedef struct { + int mtl_lib; + int mtl_func; +} _sg_mtl_shader_stage_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_common_t cmn; + struct { + _sg_mtl_shader_stage_t stage[SG_NUM_SHADER_STAGES]; + } mtl; +} _sg_mtl_shader_t; +typedef _sg_mtl_shader_t _sg_shader_t; + +typedef struct { + _sg_slot_t slot; + _sg_pipeline_common_t cmn; + _sg_shader_t* shader; + struct { + MTLPrimitiveType prim_type; + int index_size; + MTLIndexType index_type; + MTLCullMode cull_mode; + MTLWinding winding; + uint32_t stencil_ref; + int rps; + int dss; + } mtl; +} _sg_mtl_pipeline_t; +typedef _sg_mtl_pipeline_t _sg_pipeline_t; + +typedef struct { + _sg_image_t* image; +} _sg_mtl_attachment_t; + +typedef struct { + _sg_slot_t slot; + _sg_pass_common_t cmn; + struct { + _sg_mtl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_mtl_attachment_t ds_att; + } mtl; +} _sg_mtl_pass_t; +typedef _sg_mtl_pass_t _sg_pass_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; + +typedef struct { + _sg_slot_t slot; +} _sg_mtl_context_t; +typedef _sg_mtl_context_t _sg_context_t; + +/* resouce binding state cache */ +typedef struct { + const _sg_pipeline_t* cur_pipeline; + sg_pipeline cur_pipeline_id; + const _sg_buffer_t* cur_indexbuffer; + int cur_indexbuffer_offset; + sg_buffer cur_indexbuffer_id; + const _sg_buffer_t* cur_vertexbuffers[SG_MAX_SHADERSTAGE_BUFFERS]; + int cur_vertexbuffer_offsets[SG_MAX_SHADERSTAGE_BUFFERS]; + sg_buffer cur_vertexbuffer_ids[SG_MAX_SHADERSTAGE_BUFFERS]; + const _sg_image_t* cur_vs_images[SG_MAX_SHADERSTAGE_IMAGES]; + sg_image cur_vs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; + const _sg_image_t* cur_fs_images[SG_MAX_SHADERSTAGE_IMAGES]; + sg_image cur_fs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; +} _sg_mtl_state_cache_t; + +typedef struct { + bool valid; + const void*(*renderpass_descriptor_cb)(void); + const void*(*renderpass_descriptor_userdata_cb)(void*); + const void*(*drawable_cb)(void); + const void*(*drawable_userdata_cb)(void*); + void* user_data; + uint32_t frame_index; + uint32_t cur_frame_rotate_index; + int ub_size; + int cur_ub_offset; + uint8_t* cur_ub_base_ptr; + bool in_pass; + bool pass_valid; + int cur_width; + int cur_height; + _sg_mtl_state_cache_t state_cache; + _sg_sampler_cache_t sampler_cache; + _sg_mtl_idpool_t idpool; + dispatch_semaphore_t sem; + id device; + id cmd_queue; + id cmd_buffer; + id cmd_encoder; + id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; +} _sg_mtl_backend_t; + +/*=== WGPU BACKEND DECLARATIONS ==============================================*/ +#elif defined(SOKOL_WGPU) + +#define _SG_WGPU_STAGING_ALIGN (256) +#define _SG_WGPU_STAGING_PIPELINE_SIZE (8) +#define _SG_WGPU_ROWPITCH_ALIGN (256) +#define _SG_WGPU_MAX_SHADERSTAGE_IMAGES (8) +#define _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE (1<<16) + +typedef struct { + _sg_slot_t slot; + _sg_buffer_common_t cmn; + struct { + WGPUBuffer buf; + } wgpu; +} _sg_wgpu_buffer_t; +typedef _sg_wgpu_buffer_t _sg_buffer_t; + +typedef struct { + _sg_slot_t slot; + _sg_image_common_t cmn; + struct { + WGPUTexture tex; + WGPUTextureView tex_view; + WGPUTexture msaa_tex; + WGPUSampler sampler; + } wgpu; +} _sg_wgpu_image_t; +typedef _sg_wgpu_image_t _sg_image_t; + +typedef struct { + WGPUShaderModule module; + WGPUBindGroupLayout bind_group_layout; + _sg_str_t entry; +} _sg_wgpu_shader_stage_t; + +typedef struct { + _sg_slot_t slot; + _sg_shader_common_t cmn; + struct { + _sg_wgpu_shader_stage_t stage[SG_NUM_SHADER_STAGES]; + } wgpu; +} _sg_wgpu_shader_t; +typedef _sg_wgpu_shader_t _sg_shader_t; + +typedef struct { + _sg_slot_t slot; + _sg_pipeline_common_t cmn; + _sg_shader_t* shader; + struct { + WGPURenderPipeline pip; + uint32_t stencil_ref; + } wgpu; +} _sg_wgpu_pipeline_t; +typedef _sg_wgpu_pipeline_t _sg_pipeline_t; + +typedef struct { + _sg_image_t* image; + WGPUTextureView render_tex_view; + WGPUTextureView resolve_tex_view; +} _sg_wgpu_attachment_t; + +typedef struct { + _sg_slot_t slot; + _sg_pass_common_t cmn; + struct { + _sg_wgpu_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_wgpu_attachment_t ds_att; + } wgpu; +} _sg_wgpu_pass_t; +typedef _sg_wgpu_pass_t _sg_pass_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; + +typedef struct { + _sg_slot_t slot; +} _sg_wgpu_context_t; +typedef _sg_wgpu_context_t _sg_context_t; + +/* a pool of per-frame uniform buffers */ +typedef struct { + WGPUBindGroupLayout bindgroup_layout; + uint32_t num_bytes; + uint32_t offset; /* current offset into current frame's mapped uniform buffer */ + uint32_t bind_offsets[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; + WGPUBuffer buf; /* the GPU-side uniform buffer */ + WGPUBindGroup bindgroup; + struct { + int num; + int cur; + WGPUBuffer buf[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* CPU-side staging buffers */ + uint8_t* ptr[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* if != 0, staging buffer currently mapped */ + } stage; +} _sg_wgpu_ubpool_t; + +/* ...a similar pool (like uniform buffer pool) of dynamic-resource staging buffers */ +typedef struct { + uint32_t num_bytes; + uint32_t offset; /* current offset into current frame's staging buffer */ + int num; /* number of staging buffers */ + int cur; /* this frame's staging buffer */ + WGPUBuffer buf[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* CPU-side staging buffers */ + uint8_t* ptr[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* if != 0, staging buffer currently mapped */ +} _sg_wgpu_stagingpool_t; + +/* the WGPU backend state */ +typedef struct { + bool valid; + bool in_pass; + bool draw_indexed; + int cur_width; + int cur_height; + WGPUDevice dev; + WGPUTextureView (*render_view_cb)(void); + WGPUTextureView (*render_view_userdata_cb)(void*); + WGPUTextureView (*resolve_view_cb)(void); + WGPUTextureView (*resolve_view_userdata_cb)(void*); + WGPUTextureView (*depth_stencil_view_cb)(void); + WGPUTextureView (*depth_stencil_view_userdata_cb)(void*); + void* user_data; + WGPUQueue queue; + WGPUCommandEncoder render_cmd_enc; + WGPUCommandEncoder staging_cmd_enc; + WGPURenderPassEncoder pass_enc; + WGPUBindGroup empty_bind_group; + const _sg_pipeline_t* cur_pipeline; + sg_pipeline cur_pipeline_id; + _sg_sampler_cache_t sampler_cache; + _sg_wgpu_ubpool_t ub; + _sg_wgpu_stagingpool_t staging; +} _sg_wgpu_backend_t; +#endif + +/*=== RESOURCE POOL DECLARATIONS =============================================*/ + +/* this *MUST* remain 0 */ +#define _SG_INVALID_SLOT_INDEX (0) + +typedef struct { + int size; + int queue_top; + uint32_t* gen_ctrs; + int* free_queue; +} _sg_pool_t; + +typedef struct { + _sg_pool_t buffer_pool; + _sg_pool_t image_pool; + _sg_pool_t shader_pool; + _sg_pool_t pipeline_pool; + _sg_pool_t pass_pool; + _sg_pool_t context_pool; + _sg_buffer_t* buffers; + _sg_image_t* images; + _sg_shader_t* shaders; + _sg_pipeline_t* pipelines; + _sg_pass_t* passes; + _sg_context_t* contexts; +} _sg_pools_t; + +/*=== VALIDATION LAYER DECLARATIONS ==========================================*/ +typedef enum { + /* special case 'validation was successful' */ + _SG_VALIDATE_SUCCESS, + + /* buffer creation */ + _SG_VALIDATE_BUFFERDESC_CANARY, + _SG_VALIDATE_BUFFERDESC_SIZE, + _SG_VALIDATE_BUFFERDESC_DATA, + _SG_VALIDATE_BUFFERDESC_DATA_SIZE, + _SG_VALIDATE_BUFFERDESC_NO_DATA, + + /* image data (for image creation and updating) */ + _SG_VALIDATE_IMAGEDATA_NODATA, + _SG_VALIDATE_IMAGEDATA_DATA_SIZE, + + /* image creation */ + _SG_VALIDATE_IMAGEDESC_CANARY, + _SG_VALIDATE_IMAGEDESC_WIDTH, + _SG_VALIDATE_IMAGEDESC_HEIGHT, + _SG_VALIDATE_IMAGEDESC_RT_PIXELFORMAT, + _SG_VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT, + _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT, + _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT, + _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE, + _SG_VALIDATE_IMAGEDESC_RT_NO_DATA, + _SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA, + _SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, + _SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, + + /* shader creation */ + _SG_VALIDATE_SHADERDESC_CANARY, + _SG_VALIDATE_SHADERDESC_SOURCE, + _SG_VALIDATE_SHADERDESC_BYTECODE, + _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE, + _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE, + _SG_VALIDATE_SHADERDESC_NO_CONT_UBS, + _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS, + _SG_VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS, + _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS, + _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME, + _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH, + _SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT, + _SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE, + _SG_VALIDATE_SHADERDESC_IMG_NAME, + _SG_VALIDATE_SHADERDESC_ATTR_NAMES, + _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS, + _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG, + + /* pipeline creation */ + _SG_VALIDATE_PIPELINEDESC_CANARY, + _SG_VALIDATE_PIPELINEDESC_SHADER, + _SG_VALIDATE_PIPELINEDESC_NO_ATTRS, + _SG_VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4, + _SG_VALIDATE_PIPELINEDESC_ATTR_NAME, + _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS, + + /* pass creation */ + _SG_VALIDATE_PASSDESC_CANARY, + _SG_VALIDATE_PASSDESC_NO_COLOR_ATTS, + _SG_VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS, + _SG_VALIDATE_PASSDESC_IMAGE, + _SG_VALIDATE_PASSDESC_MIPLEVEL, + _SG_VALIDATE_PASSDESC_FACE, + _SG_VALIDATE_PASSDESC_LAYER, + _SG_VALIDATE_PASSDESC_SLICE, + _SG_VALIDATE_PASSDESC_IMAGE_NO_RT, + _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT, + _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT, + _SG_VALIDATE_PASSDESC_IMAGE_SIZES, + _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS, + + /* sg_begin_pass validation */ + _SG_VALIDATE_BEGINPASS_PASS, + _SG_VALIDATE_BEGINPASS_IMAGE, + + /* sg_apply_pipeline validation */ + _SG_VALIDATE_APIP_PIPELINE_VALID_ID, + _SG_VALIDATE_APIP_PIPELINE_EXISTS, + _SG_VALIDATE_APIP_PIPELINE_VALID, + _SG_VALIDATE_APIP_SHADER_EXISTS, + _SG_VALIDATE_APIP_SHADER_VALID, + _SG_VALIDATE_APIP_ATT_COUNT, + _SG_VALIDATE_APIP_COLOR_FORMAT, + _SG_VALIDATE_APIP_DEPTH_FORMAT, + _SG_VALIDATE_APIP_SAMPLE_COUNT, + + /* sg_apply_bindings validation */ + _SG_VALIDATE_ABND_PIPELINE, + _SG_VALIDATE_ABND_PIPELINE_EXISTS, + _SG_VALIDATE_ABND_PIPELINE_VALID, + _SG_VALIDATE_ABND_VBS, + _SG_VALIDATE_ABND_VB_EXISTS, + _SG_VALIDATE_ABND_VB_TYPE, + _SG_VALIDATE_ABND_VB_OVERFLOW, + _SG_VALIDATE_ABND_NO_IB, + _SG_VALIDATE_ABND_IB, + _SG_VALIDATE_ABND_IB_EXISTS, + _SG_VALIDATE_ABND_IB_TYPE, + _SG_VALIDATE_ABND_IB_OVERFLOW, + _SG_VALIDATE_ABND_VS_IMGS, + _SG_VALIDATE_ABND_VS_IMG_EXISTS, + _SG_VALIDATE_ABND_VS_IMG_TYPES, + _SG_VALIDATE_ABND_FS_IMGS, + _SG_VALIDATE_ABND_FS_IMG_EXISTS, + _SG_VALIDATE_ABND_FS_IMG_TYPES, + + /* sg_apply_uniforms validation */ + _SG_VALIDATE_AUB_NO_PIPELINE, + _SG_VALIDATE_AUB_NO_UB_AT_SLOT, + _SG_VALIDATE_AUB_SIZE, + + /* sg_update_buffer validation */ + _SG_VALIDATE_UPDATEBUF_USAGE, + _SG_VALIDATE_UPDATEBUF_SIZE, + _SG_VALIDATE_UPDATEBUF_ONCE, + _SG_VALIDATE_UPDATEBUF_APPEND, + + /* sg_append_buffer validation */ + _SG_VALIDATE_APPENDBUF_USAGE, + _SG_VALIDATE_APPENDBUF_SIZE, + _SG_VALIDATE_APPENDBUF_UPDATE, + + /* sg_update_image validation */ + _SG_VALIDATE_UPDIMG_USAGE, + _SG_VALIDATE_UPDIMG_NOTENOUGHDATA, + _SG_VALIDATE_UPDIMG_ONCE +} _sg_validate_error_t; + +/*=== GENERIC BACKEND STATE ==================================================*/ + +typedef struct { + bool valid; + sg_desc desc; /* original desc with default values patched in */ + uint32_t frame_index; + sg_context active_context; + sg_pass cur_pass; + sg_pipeline cur_pipeline; + bool pass_valid; + bool bindings_valid; + bool next_draw_valid; + #if defined(SOKOL_DEBUG) + _sg_validate_error_t validate_error; + #endif + _sg_pools_t pools; + sg_backend backend; + sg_features features; + sg_limits limits; + sg_pixelformat_info formats[_SG_PIXELFORMAT_NUM]; + #if defined(_SOKOL_ANY_GL) + _sg_gl_backend_t gl; + #elif defined(SOKOL_METAL) + _sg_mtl_backend_t mtl; + #elif defined(SOKOL_D3D11) + _sg_d3d11_backend_t d3d11; + #elif defined(SOKOL_WGPU) + _sg_wgpu_backend_t wgpu; + #endif + #if defined(SOKOL_TRACE_HOOKS) + sg_trace_hooks hooks; + #endif +} _sg_state_t; +static _sg_state_t _sg; + +/*-- helper functions --------------------------------------------------------*/ + +_SOKOL_PRIVATE bool _sg_strempty(const _sg_str_t* str) { + return 0 == str->buf[0]; +} + +_SOKOL_PRIVATE const char* _sg_strptr(const _sg_str_t* str) { + return &str->buf[0]; +} + +_SOKOL_PRIVATE void _sg_strcpy(_sg_str_t* dst, const char* src) { + SOKOL_ASSERT(dst); + if (src) { + #if defined(_MSC_VER) + strncpy_s(dst->buf, _SG_STRING_SIZE, src, (_SG_STRING_SIZE-1)); + #else + strncpy(dst->buf, src, _SG_STRING_SIZE); + #endif + dst->buf[_SG_STRING_SIZE-1] = 0; + } + else { + memset(dst->buf, 0, _SG_STRING_SIZE); + } +} + +_SOKOL_PRIVATE uint32_t _sg_align_u32(uint32_t val, uint32_t align) { + SOKOL_ASSERT((align > 0) && ((align & (align - 1)) == 0)); + return (val + (align - 1)) & ~(align - 1); +} + +/* return byte size of a vertex format */ +_SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_FLOAT: return 4; + case SG_VERTEXFORMAT_FLOAT2: return 8; + case SG_VERTEXFORMAT_FLOAT3: return 12; + case SG_VERTEXFORMAT_FLOAT4: return 16; + case SG_VERTEXFORMAT_BYTE4: return 4; + case SG_VERTEXFORMAT_BYTE4N: return 4; + case SG_VERTEXFORMAT_UBYTE4: return 4; + case SG_VERTEXFORMAT_UBYTE4N: return 4; + case SG_VERTEXFORMAT_SHORT2: return 4; + case SG_VERTEXFORMAT_SHORT2N: return 4; + case SG_VERTEXFORMAT_USHORT2N: return 4; + case SG_VERTEXFORMAT_SHORT4: return 8; + case SG_VERTEXFORMAT_SHORT4N: return 8; + case SG_VERTEXFORMAT_USHORT4N: return 8; + case SG_VERTEXFORMAT_UINT10_N2: return 4; + case SG_VERTEXFORMAT_INVALID: return 0; + default: + SOKOL_UNREACHABLE; + return -1; + } +} + +_SOKOL_PRIVATE uint32_t _sg_uniform_alignment(sg_uniform_type type, int array_count, sg_uniform_layout ub_layout) { + if (ub_layout == SG_UNIFORMLAYOUT_NATIVE) { + return 1; + } + else { + SOKOL_ASSERT(array_count > 0); + if (array_count == 1) { + switch (type) { + case SG_UNIFORMTYPE_FLOAT: + case SG_UNIFORMTYPE_INT: + return 4; + case SG_UNIFORMTYPE_FLOAT2: + case SG_UNIFORMTYPE_INT2: + return 8; + case SG_UNIFORMTYPE_FLOAT3: + case SG_UNIFORMTYPE_FLOAT4: + case SG_UNIFORMTYPE_INT3: + case SG_UNIFORMTYPE_INT4: + return 16; + case SG_UNIFORMTYPE_MAT4: + return 16; + default: + SOKOL_UNREACHABLE; + return 1; + } + } + else { + return 16; + } + } +} + +_SOKOL_PRIVATE uint32_t _sg_uniform_size(sg_uniform_type type, int array_count, sg_uniform_layout ub_layout) { + SOKOL_ASSERT(array_count > 0); + if (array_count == 1) { + switch (type) { + case SG_UNIFORMTYPE_FLOAT: + case SG_UNIFORMTYPE_INT: + return 4; + case SG_UNIFORMTYPE_FLOAT2: + case SG_UNIFORMTYPE_INT2: + return 8; + case SG_UNIFORMTYPE_FLOAT3: + case SG_UNIFORMTYPE_INT3: + return 12; + case SG_UNIFORMTYPE_FLOAT4: + case SG_UNIFORMTYPE_INT4: + return 16; + case SG_UNIFORMTYPE_MAT4: + return 64; + default: + SOKOL_UNREACHABLE; + return 0; + } + } + else { + if (ub_layout == SG_UNIFORMLAYOUT_NATIVE) { + switch (type) { + case SG_UNIFORMTYPE_FLOAT: + case SG_UNIFORMTYPE_INT: + return 4 * (uint32_t)array_count; + case SG_UNIFORMTYPE_FLOAT2: + case SG_UNIFORMTYPE_INT2: + return 8 * (uint32_t)array_count; + case SG_UNIFORMTYPE_FLOAT3: + case SG_UNIFORMTYPE_INT3: + return 12 * (uint32_t)array_count; + case SG_UNIFORMTYPE_FLOAT4: + case SG_UNIFORMTYPE_INT4: + return 16 * (uint32_t)array_count; + case SG_UNIFORMTYPE_MAT4: + return 64 * (uint32_t)array_count; + default: + SOKOL_UNREACHABLE; + return 0; + } + } + else { + switch (type) { + case SG_UNIFORMTYPE_FLOAT: + case SG_UNIFORMTYPE_FLOAT2: + case SG_UNIFORMTYPE_FLOAT3: + case SG_UNIFORMTYPE_FLOAT4: + case SG_UNIFORMTYPE_INT: + case SG_UNIFORMTYPE_INT2: + case SG_UNIFORMTYPE_INT3: + case SG_UNIFORMTYPE_INT4: + return 16 * (uint32_t)array_count; + case SG_UNIFORMTYPE_MAT4: + return 64 * (uint32_t)array_count; + default: + SOKOL_UNREACHABLE; + return 0; + } + } + } +} + +/* return true if pixel format is a compressed format */ +_SOKOL_PRIVATE bool _sg_is_compressed_pixel_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_BC1_RGBA: + case SG_PIXELFORMAT_BC2_RGBA: + case SG_PIXELFORMAT_BC3_RGBA: + case SG_PIXELFORMAT_BC4_R: + case SG_PIXELFORMAT_BC4_RSN: + case SG_PIXELFORMAT_BC5_RG: + case SG_PIXELFORMAT_BC5_RGSN: + case SG_PIXELFORMAT_BC6H_RGBF: + case SG_PIXELFORMAT_BC6H_RGBUF: + case SG_PIXELFORMAT_BC7_RGBA: + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + case SG_PIXELFORMAT_ETC2_RGB8: + case SG_PIXELFORMAT_ETC2_RGB8A1: + case SG_PIXELFORMAT_ETC2_RGBA8: + case SG_PIXELFORMAT_ETC2_RG11: + case SG_PIXELFORMAT_ETC2_RG11SN: + return true; + default: + return false; + } +} + +/* return true if pixel format is a valid render target format */ +_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_color_format(sg_pixel_format fmt) { + const int fmt_index = (int) fmt; + SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM)); + return _sg.formats[fmt_index].render && !_sg.formats[fmt_index].depth; +} + +/* return true if pixel format is a valid depth format */ +_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_depth_format(sg_pixel_format fmt) { + const int fmt_index = (int) fmt; + SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM)); + return _sg.formats[fmt_index].render && _sg.formats[fmt_index].depth; +} + +/* return true if pixel format is a depth-stencil format */ +_SOKOL_PRIVATE bool _sg_is_depth_stencil_format(sg_pixel_format fmt) { + return (SG_PIXELFORMAT_DEPTH_STENCIL == fmt); +} + +/* return the bytes-per-pixel for a pixel format */ +_SOKOL_PRIVATE int _sg_pixelformat_bytesize(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_R8: + case SG_PIXELFORMAT_R8SN: + case SG_PIXELFORMAT_R8UI: + case SG_PIXELFORMAT_R8SI: + return 1; + + case SG_PIXELFORMAT_R16: + case SG_PIXELFORMAT_R16SN: + case SG_PIXELFORMAT_R16UI: + case SG_PIXELFORMAT_R16SI: + case SG_PIXELFORMAT_R16F: + case SG_PIXELFORMAT_RG8: + case SG_PIXELFORMAT_RG8SN: + case SG_PIXELFORMAT_RG8UI: + case SG_PIXELFORMAT_RG8SI: + return 2; + + case SG_PIXELFORMAT_R32UI: + case SG_PIXELFORMAT_R32SI: + case SG_PIXELFORMAT_R32F: + case SG_PIXELFORMAT_RG16: + case SG_PIXELFORMAT_RG16SN: + case SG_PIXELFORMAT_RG16UI: + case SG_PIXELFORMAT_RG16SI: + case SG_PIXELFORMAT_RG16F: + case SG_PIXELFORMAT_RGBA8: + case SG_PIXELFORMAT_RGBA8SN: + case SG_PIXELFORMAT_RGBA8UI: + case SG_PIXELFORMAT_RGBA8SI: + case SG_PIXELFORMAT_BGRA8: + case SG_PIXELFORMAT_RGB10A2: + case SG_PIXELFORMAT_RG11B10F: + return 4; + + case SG_PIXELFORMAT_RG32UI: + case SG_PIXELFORMAT_RG32SI: + case SG_PIXELFORMAT_RG32F: + case SG_PIXELFORMAT_RGBA16: + case SG_PIXELFORMAT_RGBA16SN: + case SG_PIXELFORMAT_RGBA16UI: + case SG_PIXELFORMAT_RGBA16SI: + case SG_PIXELFORMAT_RGBA16F: + return 8; + + case SG_PIXELFORMAT_RGBA32UI: + case SG_PIXELFORMAT_RGBA32SI: + case SG_PIXELFORMAT_RGBA32F: + return 16; + + default: + SOKOL_UNREACHABLE; + return 0; + } +} + +_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) { + return (val+(round_to-1)) & ~(round_to-1); +} + +/* return row pitch for an image + + see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp + + For the special PVRTC pitch computation, see: + GL extension requirement (https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt) + + Quote: + + 6) How is the imageSize argument calculated for the CompressedTexImage2D + and CompressedTexSubImage2D functions. + + Resolution: For PVRTC 4BPP formats the imageSize is calculated as: + ( max(width, 8) * max(height, 8) * 4 + 7) / 8 + For PVRTC 2BPP formats the imageSize is calculated as: + ( max(width, 16) * max(height, 8) * 2 + 7) / 8 +*/ +_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) { + int pitch; + switch (fmt) { + case SG_PIXELFORMAT_BC1_RGBA: + case SG_PIXELFORMAT_BC4_R: + case SG_PIXELFORMAT_BC4_RSN: + case SG_PIXELFORMAT_ETC2_RGB8: + case SG_PIXELFORMAT_ETC2_RGB8A1: + pitch = ((width + 3) / 4) * 8; + pitch = pitch < 8 ? 8 : pitch; + break; + case SG_PIXELFORMAT_BC2_RGBA: + case SG_PIXELFORMAT_BC3_RGBA: + case SG_PIXELFORMAT_BC5_RG: + case SG_PIXELFORMAT_BC5_RGSN: + case SG_PIXELFORMAT_BC6H_RGBF: + case SG_PIXELFORMAT_BC6H_RGBUF: + case SG_PIXELFORMAT_BC7_RGBA: + case SG_PIXELFORMAT_ETC2_RGBA8: + case SG_PIXELFORMAT_ETC2_RG11: + case SG_PIXELFORMAT_ETC2_RG11SN: + pitch = ((width + 3) / 4) * 16; + pitch = pitch < 16 ? 16 : pitch; + break; + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + pitch = (_sg_max(width, 8) * 4 + 7) / 8; + break; + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + pitch = (_sg_max(width, 16) * 2 + 7) / 8; + break; + default: + pitch = width * _sg_pixelformat_bytesize(fmt); + break; + } + pitch = _sg_roundup(pitch, row_align); + return pitch; +} + +/* compute the number of rows in a surface depending on pixel format */ +_SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) { + int num_rows; + switch (fmt) { + case SG_PIXELFORMAT_BC1_RGBA: + case SG_PIXELFORMAT_BC4_R: + case SG_PIXELFORMAT_BC4_RSN: + case SG_PIXELFORMAT_ETC2_RGB8: + case SG_PIXELFORMAT_ETC2_RGB8A1: + case SG_PIXELFORMAT_ETC2_RGBA8: + case SG_PIXELFORMAT_ETC2_RG11: + case SG_PIXELFORMAT_ETC2_RG11SN: + case SG_PIXELFORMAT_BC2_RGBA: + case SG_PIXELFORMAT_BC3_RGBA: + case SG_PIXELFORMAT_BC5_RG: + case SG_PIXELFORMAT_BC5_RGSN: + case SG_PIXELFORMAT_BC6H_RGBF: + case SG_PIXELFORMAT_BC6H_RGBUF: + case SG_PIXELFORMAT_BC7_RGBA: + num_rows = ((height + 3) / 4); + break; + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + /* NOTE: this is most likely not correct because it ignores any + PVCRTC block size, but multiplied with _sg_row_pitch() + it gives the correct surface pitch. + + See: https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt + */ + num_rows = ((_sg_max(height, 8) + 7) / 8) * 8; + break; + default: + num_rows = height; + break; + } + if (num_rows < 1) { + num_rows = 1; + } + return num_rows; +} + +/* return pitch of a 2D subimage / texture slice + see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp +*/ +_SOKOL_PRIVATE int _sg_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align) { + int num_rows = _sg_num_rows(fmt, height); + return num_rows * _sg_row_pitch(fmt, width, row_align); +} + +/* capability table pixel format helper functions */ +_SOKOL_PRIVATE void _sg_pixelformat_all(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->filter = true; + pfi->blend = true; + pfi->render = true; + pfi->msaa = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_s(sg_pixelformat_info* pfi) { + pfi->sample = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_sf(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->filter = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_sr(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->render = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_srmd(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->render = true; + pfi->msaa = true; + pfi->depth = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_srm(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->render = true; + pfi->msaa = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_sfrm(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->filter = true; + pfi->render = true; + pfi->msaa = true; +} +_SOKOL_PRIVATE void _sg_pixelformat_sbrm(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->blend = true; + pfi->render = true; + pfi->msaa = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_sbr(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->blend = true; + pfi->render = true; +} + +_SOKOL_PRIVATE void _sg_pixelformat_sfbr(sg_pixelformat_info* pfi) { + pfi->sample = true; + pfi->filter = true; + pfi->blend = true; + pfi->render = true; +} + +/* resolve pass action defaults into a new pass action struct */ +_SOKOL_PRIVATE void _sg_resolve_default_pass_action(const sg_pass_action* from, sg_pass_action* to) { + SOKOL_ASSERT(from && to); + *to = *from; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (to->colors[i].action == _SG_ACTION_DEFAULT) { + to->colors[i].action = SG_ACTION_CLEAR; + to->colors[i].value.r = SG_DEFAULT_CLEAR_RED; + to->colors[i].value.g = SG_DEFAULT_CLEAR_GREEN; + to->colors[i].value.b = SG_DEFAULT_CLEAR_BLUE; + to->colors[i].value.a = SG_DEFAULT_CLEAR_ALPHA; + } + } + if (to->depth.action == _SG_ACTION_DEFAULT) { + to->depth.action = SG_ACTION_CLEAR; + to->depth.value = SG_DEFAULT_CLEAR_DEPTH; + } + if (to->stencil.action == _SG_ACTION_DEFAULT) { + to->stencil.action = SG_ACTION_CLEAR; + to->stencil.value = SG_DEFAULT_CLEAR_STENCIL; + } +} + +/*== DUMMY BACKEND IMPL ======================================================*/ +#if defined(SOKOL_DUMMY_BACKEND) + +_SOKOL_PRIVATE void _sg_dummy_setup_backend(const sg_desc* desc) { + SOKOL_ASSERT(desc); + _SOKOL_UNUSED(desc); + _sg.backend = SG_BACKEND_DUMMY; + for (int i = SG_PIXELFORMAT_R8; i < SG_PIXELFORMAT_BC1_RGBA; i++) { + _sg.formats[i].sample = true; + _sg.formats[i].filter = true; + _sg.formats[i].render = true; + _sg.formats[i].blend = true; + _sg.formats[i].msaa = true; + } + _sg.formats[SG_PIXELFORMAT_DEPTH].depth = true; + _sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL].depth = true; +} + +_SOKOL_PRIVATE void _sg_dummy_discard_backend(void) { + /* empty */ +} + +_SOKOL_PRIVATE void _sg_dummy_reset_state_cache(void) { + /* empty*/ +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); +} + +_SOKOL_PRIVATE void _sg_dummy_activate_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf && desc); + _sg_buffer_common_init(&buf->cmn, desc); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + _SOKOL_UNUSED(buf); +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + _sg_image_common_init(&img->cmn, desc); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + _SOKOL_UNUSED(img); +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + _sg_shader_common_init(&shd->cmn, desc); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + _SOKOL_UNUSED(shd); +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && desc); + pip->shader = shd; + _sg_pipeline_common_init(&pip->cmn, desc); + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + _SOKOL_UNUSED(pip); +} + +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass && desc); + SOKOL_ASSERT(att_images && att_images[0]); + + _sg_pass_common_init(&pass->cmn, desc); + + const sg_pass_attachment_desc* att_desc; + for (int i = 0; i < pass->cmn.num_color_atts; i++) { + att_desc = &desc->color_attachments[i]; + SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); + SOKOL_ASSERT(0 == pass->dmy.color_atts[i].image); + SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_images[i]->cmn.pixel_format)); + pass->dmy.color_atts[i].image = att_images[i]; + } + + SOKOL_ASSERT(0 == pass->dmy.ds_att.image); + att_desc = &desc->depth_stencil_attachment; + if (att_desc->image.id != SG_INVALID_ID) { + const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; + SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format)); + pass->dmy.ds_att.image = att_images[ds_img_index]; + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_dummy_destroy_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + _SOKOL_UNUSED(pass); +} + +_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_color_image(const _sg_pass_t* pass, int index) { + SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + /* NOTE: may return null */ + return pass->dmy.color_atts[index].image; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_ds_image(const _sg_pass_t* pass) { + /* NOTE: may return null */ + SOKOL_ASSERT(pass); + return pass->dmy.ds_att.image; +} + +_SOKOL_PRIVATE void _sg_dummy_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + SOKOL_ASSERT(action); + _SOKOL_UNUSED(pass); + _SOKOL_UNUSED(action); + _SOKOL_UNUSED(w); + _SOKOL_UNUSED(h); +} + +_SOKOL_PRIVATE void _sg_dummy_end_pass(void) { + /* empty */ +} + +_SOKOL_PRIVATE void _sg_dummy_commit(void) { + /* empty */ +} + +_SOKOL_PRIVATE void _sg_dummy_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + _SOKOL_UNUSED(x); + _SOKOL_UNUSED(y); + _SOKOL_UNUSED(w); + _SOKOL_UNUSED(h); + _SOKOL_UNUSED(origin_top_left); +} + +_SOKOL_PRIVATE void _sg_dummy_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + _SOKOL_UNUSED(x); + _SOKOL_UNUSED(y); + _SOKOL_UNUSED(w); + _SOKOL_UNUSED(h); + _SOKOL_UNUSED(origin_top_left); +} + +_SOKOL_PRIVATE void _sg_dummy_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + _SOKOL_UNUSED(pip); +} + +_SOKOL_PRIVATE void _sg_dummy_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + SOKOL_ASSERT(pip); + SOKOL_ASSERT(vbs && vb_offsets); + SOKOL_ASSERT(vs_imgs); + SOKOL_ASSERT(fs_imgs); + _SOKOL_UNUSED(pip); + _SOKOL_UNUSED(vbs); _SOKOL_UNUSED(vb_offsets); _SOKOL_UNUSED(num_vbs); + _SOKOL_UNUSED(ib); _SOKOL_UNUSED(ib_offset); + _SOKOL_UNUSED(vs_imgs); _SOKOL_UNUSED(num_vs_imgs); + _SOKOL_UNUSED(fs_imgs); _SOKOL_UNUSED(num_fs_imgs); +} + +_SOKOL_PRIVATE void _sg_dummy_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + _SOKOL_UNUSED(stage_index); + _SOKOL_UNUSED(ub_index); + _SOKOL_UNUSED(data); +} + +_SOKOL_PRIVATE void _sg_dummy_draw(int base_element, int num_elements, int num_instances) { + _SOKOL_UNUSED(base_element); + _SOKOL_UNUSED(num_elements); + _SOKOL_UNUSED(num_instances); +} + +_SOKOL_PRIVATE void _sg_dummy_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + _SOKOL_UNUSED(data); + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } +} + +_SOKOL_PRIVATE int _sg_dummy_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + _SOKOL_UNUSED(data); + if (new_frame) { + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } + } + /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */ + return _sg_roundup((int)data->size, 4); +} + +_SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + _SOKOL_UNUSED(data); + if (++img->cmn.active_slot >= img->cmn.num_slots) { + img->cmn.active_slot = 0; + } +} + +/*== GL BACKEND ==============================================================*/ +#elif defined(_SOKOL_ANY_GL) + +/*=== OPTIONAL GL LOADER FOR WIN32 ===========================================*/ +#if defined(_SOKOL_USE_WIN32_GL_LOADER) + +// X Macro list of GL function names and signatures +#define _SG_GL_FUNCS \ + _SG_XMACRO(glBindVertexArray, void, (GLuint array)) \ + _SG_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \ + _SG_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \ + _SG_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \ + _SG_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \ + _SG_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \ + _SG_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \ + _SG_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \ + _SG_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \ + _SG_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \ + _SG_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \ + _SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUniform1iv, void, (GLint location, GLsizei count, const GLint * value)) \ + _SG_XMACRO(glUniform2iv, void, (GLint location, GLsizei count, const GLint * value)) \ + _SG_XMACRO(glUniform3iv, void, (GLint location, GLsizei count, const GLint * value)) \ + _SG_XMACRO(glUniform4iv, void, (GLint location, GLsizei count, const GLint * value)) \ + _SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \ + _SG_XMACRO(glUseProgram, void, (GLuint program)) \ + _SG_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \ + _SG_XMACRO(glLinkProgram, void, (GLuint program)) \ + _SG_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \ + _SG_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \ + _SG_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ + _SG_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \ + _SG_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \ + _SG_XMACRO(glDeleteShader, void, (GLuint shader)) \ + _SG_XMACRO(glDeleteProgram, void, (GLuint program)) \ + _SG_XMACRO(glCompileShader, void, (GLuint shader)) \ + _SG_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \ + _SG_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \ + _SG_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \ + _SG_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \ + _SG_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \ + _SG_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \ + _SG_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \ + _SG_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \ + _SG_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \ + _SG_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \ + _SG_XMACRO(glActiveTexture, void, (GLenum texture)) \ + _SG_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \ + _SG_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \ + _SG_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \ + _SG_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \ + _SG_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \ + _SG_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \ + _SG_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \ + _SG_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \ + _SG_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glCreateShader, GLuint, (GLenum type)) \ + _SG_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glClearDepth, void, (GLdouble depth)) \ + _SG_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \ + _SG_XMACRO(glCreateProgram, GLuint, (void)) \ + _SG_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \ + _SG_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \ + _SG_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \ + _SG_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \ + _SG_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \ + _SG_XMACRO(glDisable, void, (GLenum cap)) \ + _SG_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ + _SG_XMACRO(glColorMaski, void, (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ + _SG_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \ + _SG_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \ + _SG_XMACRO(glDepthMask, void, (GLboolean flag)) \ + _SG_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \ + _SG_XMACRO(glClearStencil, void, (GLint s)) \ + _SG_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \ + _SG_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \ + _SG_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \ + _SG_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \ + _SG_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \ + _SG_XMACRO(glEnable, void, (GLenum cap)) \ + _SG_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \ + _SG_XMACRO(glStencilMask, void, (GLuint mask)) \ + _SG_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \ + _SG_XMACRO(glGetError, GLenum, (void)) \ + _SG_XMACRO(glClearColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ + _SG_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ + _SG_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \ + _SG_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, GLfloat* params)) \ + _SG_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ + _SG_XMACRO(glDepthFunc, void, (GLenum func)) \ + _SG_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \ + _SG_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \ + _SG_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \ + _SG_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \ + _SG_XMACRO(glReadBuffer, void, (GLenum src)) \ + _SG_XMACRO(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data)) \ + _SG_XMACRO(glClear, void, (GLbitfield mask)) \ + _SG_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \ + _SG_XMACRO(glFrontFace, void, (GLenum mode)) \ + _SG_XMACRO(glCullFace, void, (GLenum mode)) + +// generate GL function pointer typedefs +#define _SG_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args; +_SG_GL_FUNCS +#undef _SG_XMACRO + +// generate GL function pointers +#define _SG_XMACRO(name, ret, args) static PFN_ ## name name; +_SG_GL_FUNCS +#undef _SG_XMACRO + +// helper function to lookup GL functions in GL DLL +typedef PROC (WINAPI * _sg_wglGetProcAddress)(LPCSTR); +_SOKOL_PRIVATE void* _sg_gl_getprocaddr(const char* name, _sg_wglGetProcAddress wgl_getprocaddress) { + void* proc_addr = (void*) wgl_getprocaddress(name); + if (0 == proc_addr) { + proc_addr = (void*) GetProcAddress(_sg.gl.opengl32_dll, name); + } + SOKOL_ASSERT(proc_addr); + return proc_addr; +} + +// populate GL function pointers +_SOKOL_PRIVATE void _sg_gl_load_opengl(void) { + SOKOL_ASSERT(0 == _sg.gl.opengl32_dll); + _sg.gl.opengl32_dll = LoadLibraryA("opengl32.dll"); + SOKOL_ASSERT(_sg.gl.opengl32_dll); + _sg_wglGetProcAddress wgl_getprocaddress = (_sg_wglGetProcAddress) GetProcAddress(_sg.gl.opengl32_dll, "wglGetProcAddress"); + SOKOL_ASSERT(wgl_getprocaddress); + #define _SG_XMACRO(name, ret, args) name = (PFN_ ## name) _sg_gl_getprocaddr(#name, wgl_getprocaddress); + _SG_GL_FUNCS + #undef _SG_XMACRO +} + +_SOKOL_PRIVATE void _sg_gl_unload_opengl(void) { + SOKOL_ASSERT(_sg.gl.opengl32_dll); + FreeLibrary(_sg.gl.opengl32_dll); + _sg.gl.opengl32_dll = 0; +} +#endif // _SOKOL_USE_WIN32_GL_LOADER + +/*-- type translation --------------------------------------------------------*/ +_SOKOL_PRIVATE GLenum _sg_gl_buffer_target(sg_buffer_type t) { + switch (t) { + case SG_BUFFERTYPE_VERTEXBUFFER: return GL_ARRAY_BUFFER; + case SG_BUFFERTYPE_INDEXBUFFER: return GL_ELEMENT_ARRAY_BUFFER; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_texture_target(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return GL_TEXTURE_2D; + case SG_IMAGETYPE_CUBE: return GL_TEXTURE_CUBE_MAP; + #if !defined(SOKOL_GLES2) + case SG_IMAGETYPE_3D: return GL_TEXTURE_3D; + case SG_IMAGETYPE_ARRAY: return GL_TEXTURE_2D_ARRAY; + #endif + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_usage(sg_usage u) { + switch (u) { + case SG_USAGE_IMMUTABLE: return GL_STATIC_DRAW; + case SG_USAGE_DYNAMIC: return GL_DYNAMIC_DRAW; + case SG_USAGE_STREAM: return GL_STREAM_DRAW; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_shader_stage(sg_shader_stage stage) { + switch (stage) { + case SG_SHADERSTAGE_VS: return GL_VERTEX_SHADER; + case SG_SHADERSTAGE_FS: return GL_FRAGMENT_SHADER; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLint _sg_gl_vertexformat_size(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_FLOAT: return 1; + case SG_VERTEXFORMAT_FLOAT2: return 2; + case SG_VERTEXFORMAT_FLOAT3: return 3; + case SG_VERTEXFORMAT_FLOAT4: return 4; + case SG_VERTEXFORMAT_BYTE4: return 4; + case SG_VERTEXFORMAT_BYTE4N: return 4; + case SG_VERTEXFORMAT_UBYTE4: return 4; + case SG_VERTEXFORMAT_UBYTE4N: return 4; + case SG_VERTEXFORMAT_SHORT2: return 2; + case SG_VERTEXFORMAT_SHORT2N: return 2; + case SG_VERTEXFORMAT_USHORT2N: return 2; + case SG_VERTEXFORMAT_SHORT4: return 4; + case SG_VERTEXFORMAT_SHORT4N: return 4; + case SG_VERTEXFORMAT_USHORT4N: return 4; + case SG_VERTEXFORMAT_UINT10_N2: return 4; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_vertexformat_type(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_FLOAT: + case SG_VERTEXFORMAT_FLOAT2: + case SG_VERTEXFORMAT_FLOAT3: + case SG_VERTEXFORMAT_FLOAT4: + return GL_FLOAT; + case SG_VERTEXFORMAT_BYTE4: + case SG_VERTEXFORMAT_BYTE4N: + return GL_BYTE; + case SG_VERTEXFORMAT_UBYTE4: + case SG_VERTEXFORMAT_UBYTE4N: + return GL_UNSIGNED_BYTE; + case SG_VERTEXFORMAT_SHORT2: + case SG_VERTEXFORMAT_SHORT2N: + case SG_VERTEXFORMAT_SHORT4: + case SG_VERTEXFORMAT_SHORT4N: + return GL_SHORT; + case SG_VERTEXFORMAT_USHORT2N: + case SG_VERTEXFORMAT_USHORT4N: + return GL_UNSIGNED_SHORT; + case SG_VERTEXFORMAT_UINT10_N2: + return GL_UNSIGNED_INT_2_10_10_10_REV; + default: + SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLboolean _sg_gl_vertexformat_normalized(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_BYTE4N: + case SG_VERTEXFORMAT_UBYTE4N: + case SG_VERTEXFORMAT_SHORT2N: + case SG_VERTEXFORMAT_USHORT2N: + case SG_VERTEXFORMAT_SHORT4N: + case SG_VERTEXFORMAT_USHORT4N: + case SG_VERTEXFORMAT_UINT10_N2: + return GL_TRUE; + default: + return GL_FALSE; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_primitive_type(sg_primitive_type t) { + switch (t) { + case SG_PRIMITIVETYPE_POINTS: return GL_POINTS; + case SG_PRIMITIVETYPE_LINES: return GL_LINES; + case SG_PRIMITIVETYPE_LINE_STRIP: return GL_LINE_STRIP; + case SG_PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES; + case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_index_type(sg_index_type t) { + switch (t) { + case SG_INDEXTYPE_NONE: return 0; + case SG_INDEXTYPE_UINT16: return GL_UNSIGNED_SHORT; + case SG_INDEXTYPE_UINT32: return GL_UNSIGNED_INT; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_compare_func(sg_compare_func cmp) { + switch (cmp) { + case SG_COMPAREFUNC_NEVER: return GL_NEVER; + case SG_COMPAREFUNC_LESS: return GL_LESS; + case SG_COMPAREFUNC_EQUAL: return GL_EQUAL; + case SG_COMPAREFUNC_LESS_EQUAL: return GL_LEQUAL; + case SG_COMPAREFUNC_GREATER: return GL_GREATER; + case SG_COMPAREFUNC_NOT_EQUAL: return GL_NOTEQUAL; + case SG_COMPAREFUNC_GREATER_EQUAL: return GL_GEQUAL; + case SG_COMPAREFUNC_ALWAYS: return GL_ALWAYS; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_stencil_op(sg_stencil_op op) { + switch (op) { + case SG_STENCILOP_KEEP: return GL_KEEP; + case SG_STENCILOP_ZERO: return GL_ZERO; + case SG_STENCILOP_REPLACE: return GL_REPLACE; + case SG_STENCILOP_INCR_CLAMP: return GL_INCR; + case SG_STENCILOP_DECR_CLAMP: return GL_DECR; + case SG_STENCILOP_INVERT: return GL_INVERT; + case SG_STENCILOP_INCR_WRAP: return GL_INCR_WRAP; + case SG_STENCILOP_DECR_WRAP: return GL_DECR_WRAP; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_blend_factor(sg_blend_factor f) { + switch (f) { + case SG_BLENDFACTOR_ZERO: return GL_ZERO; + case SG_BLENDFACTOR_ONE: return GL_ONE; + case SG_BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; + case SG_BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; + case SG_BLENDFACTOR_DST_COLOR: return GL_DST_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; + case SG_BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return GL_SRC_ALPHA_SATURATE; + case SG_BLENDFACTOR_BLEND_COLOR: return GL_CONSTANT_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; + case SG_BLENDFACTOR_BLEND_ALPHA: return GL_CONSTANT_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_blend_op(sg_blend_op op) { + switch (op) { + case SG_BLENDOP_ADD: return GL_FUNC_ADD; + case SG_BLENDOP_SUBTRACT: return GL_FUNC_SUBTRACT; + case SG_BLENDOP_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_filter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: return GL_NEAREST; + case SG_FILTER_LINEAR: return GL_LINEAR; + case SG_FILTER_NEAREST_MIPMAP_NEAREST: return GL_NEAREST_MIPMAP_NEAREST; + case SG_FILTER_NEAREST_MIPMAP_LINEAR: return GL_NEAREST_MIPMAP_LINEAR; + case SG_FILTER_LINEAR_MIPMAP_NEAREST: return GL_LINEAR_MIPMAP_NEAREST; + case SG_FILTER_LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_wrap(sg_wrap w) { + switch (w) { + case SG_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; + #if defined(SOKOL_GLCORE33) + case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; + #else + case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_EDGE; + #endif + case SG_WRAP_REPEAT: return GL_REPEAT; + case SG_WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_teximage_type(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_R8: + case SG_PIXELFORMAT_R8UI: + case SG_PIXELFORMAT_RG8: + case SG_PIXELFORMAT_RG8UI: + case SG_PIXELFORMAT_RGBA8: + case SG_PIXELFORMAT_RGBA8UI: + case SG_PIXELFORMAT_BGRA8: + return GL_UNSIGNED_BYTE; + case SG_PIXELFORMAT_R8SN: + case SG_PIXELFORMAT_R8SI: + case SG_PIXELFORMAT_RG8SN: + case SG_PIXELFORMAT_RG8SI: + case SG_PIXELFORMAT_RGBA8SN: + case SG_PIXELFORMAT_RGBA8SI: + return GL_BYTE; + case SG_PIXELFORMAT_R16: + case SG_PIXELFORMAT_R16UI: + case SG_PIXELFORMAT_RG16: + case SG_PIXELFORMAT_RG16UI: + case SG_PIXELFORMAT_RGBA16: + case SG_PIXELFORMAT_RGBA16UI: + return GL_UNSIGNED_SHORT; + case SG_PIXELFORMAT_R16SN: + case SG_PIXELFORMAT_R16SI: + case SG_PIXELFORMAT_RG16SN: + case SG_PIXELFORMAT_RG16SI: + case SG_PIXELFORMAT_RGBA16SN: + case SG_PIXELFORMAT_RGBA16SI: + return GL_SHORT; + case SG_PIXELFORMAT_R16F: + case SG_PIXELFORMAT_RG16F: + case SG_PIXELFORMAT_RGBA16F: + return GL_HALF_FLOAT; + case SG_PIXELFORMAT_R32UI: + case SG_PIXELFORMAT_RG32UI: + case SG_PIXELFORMAT_RGBA32UI: + return GL_UNSIGNED_INT; + case SG_PIXELFORMAT_R32SI: + case SG_PIXELFORMAT_RG32SI: + case SG_PIXELFORMAT_RGBA32SI: + return GL_INT; + case SG_PIXELFORMAT_R32F: + case SG_PIXELFORMAT_RG32F: + case SG_PIXELFORMAT_RGBA32F: + return GL_FLOAT; + #if !defined(SOKOL_GLES2) + case SG_PIXELFORMAT_RGB10A2: + return GL_UNSIGNED_INT_2_10_10_10_REV; + case SG_PIXELFORMAT_RG11B10F: + return GL_UNSIGNED_INT_10F_11F_11F_REV; + #endif + case SG_PIXELFORMAT_DEPTH: + return GL_UNSIGNED_SHORT; + case SG_PIXELFORMAT_DEPTH_STENCIL: + return GL_UNSIGNED_INT_24_8; + default: + SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_teximage_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_R8: + case SG_PIXELFORMAT_R8SN: + case SG_PIXELFORMAT_R16: + case SG_PIXELFORMAT_R16SN: + case SG_PIXELFORMAT_R16F: + case SG_PIXELFORMAT_R32F: + #if defined(SOKOL_GLES2) + return GL_LUMINANCE; + #else + if (_sg.gl.gles2) { + return GL_LUMINANCE; + } + else { + return GL_RED; + } + #endif + #if !defined(SOKOL_GLES2) + case SG_PIXELFORMAT_R8UI: + case SG_PIXELFORMAT_R8SI: + case SG_PIXELFORMAT_R16UI: + case SG_PIXELFORMAT_R16SI: + case SG_PIXELFORMAT_R32UI: + case SG_PIXELFORMAT_R32SI: + return GL_RED_INTEGER; + case SG_PIXELFORMAT_RG8: + case SG_PIXELFORMAT_RG8SN: + case SG_PIXELFORMAT_RG16: + case SG_PIXELFORMAT_RG16SN: + case SG_PIXELFORMAT_RG16F: + case SG_PIXELFORMAT_RG32F: + return GL_RG; + case SG_PIXELFORMAT_RG8UI: + case SG_PIXELFORMAT_RG8SI: + case SG_PIXELFORMAT_RG16UI: + case SG_PIXELFORMAT_RG16SI: + case SG_PIXELFORMAT_RG32UI: + case SG_PIXELFORMAT_RG32SI: + return GL_RG_INTEGER; + #endif + case SG_PIXELFORMAT_RGBA8: + case SG_PIXELFORMAT_RGBA8SN: + case SG_PIXELFORMAT_RGBA16: + case SG_PIXELFORMAT_RGBA16SN: + case SG_PIXELFORMAT_RGBA16F: + case SG_PIXELFORMAT_RGBA32F: + case SG_PIXELFORMAT_RGB10A2: + return GL_RGBA; + #if !defined(SOKOL_GLES2) + case SG_PIXELFORMAT_RGBA8UI: + case SG_PIXELFORMAT_RGBA8SI: + case SG_PIXELFORMAT_RGBA16UI: + case SG_PIXELFORMAT_RGBA16SI: + case SG_PIXELFORMAT_RGBA32UI: + case SG_PIXELFORMAT_RGBA32SI: + return GL_RGBA_INTEGER; + #endif + case SG_PIXELFORMAT_RG11B10F: + return GL_RGB; + case SG_PIXELFORMAT_DEPTH: + return GL_DEPTH_COMPONENT; + case SG_PIXELFORMAT_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case SG_PIXELFORMAT_BC1_RGBA: + return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case SG_PIXELFORMAT_BC2_RGBA: + return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case SG_PIXELFORMAT_BC3_RGBA: + return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case SG_PIXELFORMAT_BC4_R: + return GL_COMPRESSED_RED_RGTC1; + case SG_PIXELFORMAT_BC4_RSN: + return GL_COMPRESSED_SIGNED_RED_RGTC1; + case SG_PIXELFORMAT_BC5_RG: + return GL_COMPRESSED_RED_GREEN_RGTC2; + case SG_PIXELFORMAT_BC5_RGSN: + return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2; + case SG_PIXELFORMAT_BC6H_RGBF: + return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB; + case SG_PIXELFORMAT_BC6H_RGBUF: + return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; + case SG_PIXELFORMAT_BC7_RGBA: + return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + case SG_PIXELFORMAT_ETC2_RGB8: + return GL_COMPRESSED_RGB8_ETC2; + case SG_PIXELFORMAT_ETC2_RGB8A1: + return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case SG_PIXELFORMAT_ETC2_RGBA8: + return GL_COMPRESSED_RGBA8_ETC2_EAC; + case SG_PIXELFORMAT_ETC2_RG11: + return GL_COMPRESSED_RG11_EAC; + case SG_PIXELFORMAT_ETC2_RG11SN: + return GL_COMPRESSED_SIGNED_RG11_EAC; + default: + SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_teximage_internal_format(sg_pixel_format fmt) { + #if defined(SOKOL_GLES2) + return _sg_gl_teximage_format(fmt); + #else + if (_sg.gl.gles2) { + return _sg_gl_teximage_format(fmt); + } + else { + switch (fmt) { + case SG_PIXELFORMAT_R8: return GL_R8; + case SG_PIXELFORMAT_R8SN: return GL_R8_SNORM; + case SG_PIXELFORMAT_R8UI: return GL_R8UI; + case SG_PIXELFORMAT_R8SI: return GL_R8I; + #if !defined(SOKOL_GLES3) + case SG_PIXELFORMAT_R16: return GL_R16; + case SG_PIXELFORMAT_R16SN: return GL_R16_SNORM; + #endif + case SG_PIXELFORMAT_R16UI: return GL_R16UI; + case SG_PIXELFORMAT_R16SI: return GL_R16I; + case SG_PIXELFORMAT_R16F: return GL_R16F; + case SG_PIXELFORMAT_RG8: return GL_RG8; + case SG_PIXELFORMAT_RG8SN: return GL_RG8_SNORM; + case SG_PIXELFORMAT_RG8UI: return GL_RG8UI; + case SG_PIXELFORMAT_RG8SI: return GL_RG8I; + case SG_PIXELFORMAT_R32UI: return GL_R32UI; + case SG_PIXELFORMAT_R32SI: return GL_R32I; + case SG_PIXELFORMAT_R32F: return GL_R32F; + #if !defined(SOKOL_GLES3) + case SG_PIXELFORMAT_RG16: return GL_RG16; + case SG_PIXELFORMAT_RG16SN: return GL_RG16_SNORM; + #endif + case SG_PIXELFORMAT_RG16UI: return GL_RG16UI; + case SG_PIXELFORMAT_RG16SI: return GL_RG16I; + case SG_PIXELFORMAT_RG16F: return GL_RG16F; + case SG_PIXELFORMAT_RGBA8: return GL_RGBA8; + case SG_PIXELFORMAT_RGBA8SN: return GL_RGBA8_SNORM; + case SG_PIXELFORMAT_RGBA8UI: return GL_RGBA8UI; + case SG_PIXELFORMAT_RGBA8SI: return GL_RGBA8I; + case SG_PIXELFORMAT_RGB10A2: return GL_RGB10_A2; + case SG_PIXELFORMAT_RG11B10F: return GL_R11F_G11F_B10F; + case SG_PIXELFORMAT_RG32UI: return GL_RG32UI; + case SG_PIXELFORMAT_RG32SI: return GL_RG32I; + case SG_PIXELFORMAT_RG32F: return GL_RG32F; + #if !defined(SOKOL_GLES3) + case SG_PIXELFORMAT_RGBA16: return GL_RGBA16; + case SG_PIXELFORMAT_RGBA16SN: return GL_RGBA16_SNORM; + #endif + case SG_PIXELFORMAT_RGBA16UI: return GL_RGBA16UI; + case SG_PIXELFORMAT_RGBA16SI: return GL_RGBA16I; + case SG_PIXELFORMAT_RGBA16F: return GL_RGBA16F; + case SG_PIXELFORMAT_RGBA32UI: return GL_RGBA32UI; + case SG_PIXELFORMAT_RGBA32SI: return GL_RGBA32I; + case SG_PIXELFORMAT_RGBA32F: return GL_RGBA32F; + case SG_PIXELFORMAT_DEPTH: return GL_DEPTH_COMPONENT16; + case SG_PIXELFORMAT_DEPTH_STENCIL: return GL_DEPTH24_STENCIL8; + case SG_PIXELFORMAT_BC1_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case SG_PIXELFORMAT_BC2_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case SG_PIXELFORMAT_BC3_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case SG_PIXELFORMAT_BC4_R: return GL_COMPRESSED_RED_RGTC1; + case SG_PIXELFORMAT_BC4_RSN: return GL_COMPRESSED_SIGNED_RED_RGTC1; + case SG_PIXELFORMAT_BC5_RG: return GL_COMPRESSED_RED_GREEN_RGTC2; + case SG_PIXELFORMAT_BC5_RGSN: return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2; + case SG_PIXELFORMAT_BC6H_RGBF: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB; + case SG_PIXELFORMAT_BC6H_RGBUF: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; + case SG_PIXELFORMAT_BC7_RGBA: return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + case SG_PIXELFORMAT_ETC2_RGB8: return GL_COMPRESSED_RGB8_ETC2; + case SG_PIXELFORMAT_ETC2_RGB8A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case SG_PIXELFORMAT_ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC; + case SG_PIXELFORMAT_ETC2_RG11: return GL_COMPRESSED_RG11_EAC; + case SG_PIXELFORMAT_ETC2_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; + default: SOKOL_UNREACHABLE; return 0; + } + } + #endif +} + +_SOKOL_PRIVATE GLenum _sg_gl_cubeface_target(int face_index) { + switch (face_index) { + case 0: return GL_TEXTURE_CUBE_MAP_POSITIVE_X; + case 1: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + case 2: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + case 3: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + case 4: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + case 5: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE GLenum _sg_gl_depth_attachment_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_DEPTH: return GL_DEPTH_COMPONENT16; + case SG_PIXELFORMAT_DEPTH_STENCIL: return GL_DEPTH24_STENCIL8; + default: SOKOL_UNREACHABLE; return 0; + } +} + +/* see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml */ +_SOKOL_PRIVATE void _sg_gl_init_pixelformats(bool has_bgra) { + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); + } + else { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8]); + } + #else + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8]); + #endif + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]); + #if !defined(SOKOL_GLES3) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); + #if !defined(SOKOL_GLES3) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]); + } + #endif + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); + } + #endif + if (has_bgra) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); + } + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + #if !defined(SOKOL_GLES3) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + } + #endif + // FIXME: WEBGL_depth_texture extension? + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); +} + +/* FIXME: OES_half_float_blend */ +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_half_float(bool has_colorbuffer_half_float, bool has_texture_half_float_linear) { + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + if (has_texture_half_float_linear) { + if (has_colorbuffer_half_float) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + else { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + } + else { + if (has_colorbuffer_half_float) { + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + else { + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + } + } + else { + #endif + /* GLES2 can only render to RGBA, and there's no RG format */ + if (has_texture_half_float_linear) { + if (has_colorbuffer_half_float) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + else { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R16F]); + } + else { + if (has_colorbuffer_half_float) { + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + else { + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + } + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R16F]); + } + #if !defined(SOKOL_GLES2) + } + #endif +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_float(bool has_colorbuffer_float, bool has_texture_float_linear, bool has_float_blend) { + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + if (has_texture_float_linear) { + if (has_colorbuffer_float) { + if (has_float_blend) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + else { + _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + } + else { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + } + else { + if (has_colorbuffer_float) { + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + else { + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + } + } + else { + #endif + /* GLES2 can only render to RGBA, and there's no RG format */ + if (has_texture_float_linear) { + if (has_colorbuffer_float) { + if (has_float_blend) { + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + else { + _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + } + else { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R32F]); + } + else { + if (has_colorbuffer_float) { + _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + else { + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } + _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R32F]); + } + #if !defined(SOKOL_GLES2) + } + #endif +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_s3tc(void) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_rgtc(void) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_bptc(void) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_pvrtc(void) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_2BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_4BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_2BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_4BPP]); +} + +_SOKOL_PRIVATE void _sg_gl_init_pixelformats_etc2(void) { + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]); +} + +_SOKOL_PRIVATE void _sg_gl_init_limits(void) { + _SG_GL_CHECK_ERROR(); + GLint gl_int; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.limits.max_image_size_2d = gl_int; + _sg.limits.max_image_size_array = gl_int; + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.limits.max_image_size_cube = gl_int; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &gl_int); + _SG_GL_CHECK_ERROR(); + if (gl_int > SG_MAX_VERTEX_ATTRIBUTES) { + gl_int = SG_MAX_VERTEX_ATTRIBUTES; + } + _sg.limits.max_vertex_attrs = gl_int; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.limits.gl_max_vertex_uniform_vectors = gl_int; + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.limits.max_image_size_3d = gl_int; + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.limits.max_image_array_layers = gl_int; + } + #endif + if (_sg.gl.ext_anisotropic) { + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.gl.max_anisotropy = gl_int; + } + else { + _sg.gl.max_anisotropy = 1; + } + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gl_int); + _SG_GL_CHECK_ERROR(); + _sg.gl.max_combined_texture_image_units = gl_int; +} + +#if defined(SOKOL_GLCORE33) +_SOKOL_PRIVATE void _sg_gl_init_caps_glcore33(void) { + _sg.backend = SG_BACKEND_GLCORE33; + + _sg.features.origin_top_left = false; + _sg.features.instancing = true; + _sg.features.multiple_render_targets = true; + _sg.features.msaa_render_targets = true; + _sg.features.imagetype_3d = true; + _sg.features.imagetype_array = true; + _sg.features.image_clamp_to_border = true; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = true; + + /* scan extensions */ + bool has_s3tc = false; /* BC1..BC3 */ + bool has_rgtc = false; /* BC4 and BC5 */ + bool has_bptc = false; /* BC6H and BC7 */ + bool has_pvrtc = false; + bool has_etc2 = false; + GLint num_ext = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); + for (int i = 0; i < num_ext; i++) { + const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); + if (ext) { + if (strstr(ext, "_texture_compression_s3tc")) { + has_s3tc = true; + } + else if (strstr(ext, "_texture_compression_rgtc")) { + has_rgtc = true; + } + else if (strstr(ext, "_texture_compression_bptc")) { + has_bptc = true; + } + else if (strstr(ext, "_texture_compression_pvrtc")) { + has_pvrtc = true; + } + else if (strstr(ext, "_ES3_compatibility")) { + has_etc2 = true; + } + else if (strstr(ext, "_texture_filter_anisotropic")) { + _sg.gl.ext_anisotropic = true; + } + } + } + + /* limits */ + _sg_gl_init_limits(); + + /* pixel formats */ + const bool has_bgra = false; /* not a bug */ + const bool has_colorbuffer_float = true; + const bool has_colorbuffer_half_float = true; + const bool has_texture_float_linear = true; /* FIXME??? */ + const bool has_texture_half_float_linear = true; + const bool has_float_blend = true; + _sg_gl_init_pixelformats(has_bgra); + _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend); + _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear); + if (has_s3tc) { + _sg_gl_init_pixelformats_s3tc(); + } + if (has_rgtc) { + _sg_gl_init_pixelformats_rgtc(); + } + if (has_bptc) { + _sg_gl_init_pixelformats_bptc(); + } + if (has_pvrtc) { + _sg_gl_init_pixelformats_pvrtc(); + } + if (has_etc2) { + _sg_gl_init_pixelformats_etc2(); + } +} +#endif + +#if defined(SOKOL_GLES3) +_SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { + _sg.backend = SG_BACKEND_GLES3; + + _sg.features.origin_top_left = false; + _sg.features.instancing = true; + _sg.features.multiple_render_targets = true; + _sg.features.msaa_render_targets = true; + _sg.features.imagetype_3d = true; + _sg.features.imagetype_array = true; + _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = false; + + bool has_s3tc = false; /* BC1..BC3 */ + bool has_rgtc = false; /* BC4 and BC5 */ + bool has_bptc = false; /* BC6H and BC7 */ + bool has_pvrtc = false; + #if defined(__EMSCRIPTEN__) + bool has_etc2 = false; + #else + bool has_etc2 = true; + #endif + bool has_colorbuffer_float = false; + bool has_colorbuffer_half_float = false; + bool has_texture_float_linear = false; + bool has_float_blend = false; + GLint num_ext = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); + for (int i = 0; i < num_ext; i++) { + const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); + if (ext) { + if (strstr(ext, "_texture_compression_s3tc")) { + has_s3tc = true; + } + else if (strstr(ext, "_compressed_texture_s3tc")) { + has_s3tc = true; + } + else if (strstr(ext, "_texture_compression_rgtc")) { + has_rgtc = true; + } + else if (strstr(ext, "_texture_compression_bptc")) { + has_bptc = true; + } + else if (strstr(ext, "_texture_compression_pvrtc")) { + has_pvrtc = true; + } + else if (strstr(ext, "_compressed_texture_pvrtc")) { + has_pvrtc = true; + } + else if (strstr(ext, "_compressed_texture_etc")) { + has_etc2 = true; + } + else if (strstr(ext, "_color_buffer_float")) { + has_colorbuffer_float = true; + } + else if (strstr(ext, "_color_buffer_half_float")) { + has_colorbuffer_half_float = true; + } + else if (strstr(ext, "_texture_float_linear")) { + has_texture_float_linear = true; + } + else if (strstr(ext, "_float_blend")) { + has_float_blend = true; + } + else if (strstr(ext, "_texture_filter_anisotropic")) { + _sg.gl.ext_anisotropic = true; + } + } + } + + /* on WebGL2, color_buffer_float also includes 16-bit formats + see: https://developer.mozilla.org/en-US/docs/Web/API/EXT_color_buffer_float + */ + #if defined(__EMSCRIPTEN__) + has_colorbuffer_half_float = has_colorbuffer_float; + #endif + + /* limits */ + _sg_gl_init_limits(); + + /* pixel formats */ + const bool has_texture_half_float_linear = true; + const bool has_bgra = false; /* not a bug */ + _sg_gl_init_pixelformats(has_bgra); + _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend); + _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear); + if (has_s3tc) { + _sg_gl_init_pixelformats_s3tc(); + } + if (has_rgtc) { + _sg_gl_init_pixelformats_rgtc(); + } + if (has_bptc) { + _sg_gl_init_pixelformats_bptc(); + } + if (has_pvrtc) { + _sg_gl_init_pixelformats_pvrtc(); + } + if (has_etc2) { + _sg_gl_init_pixelformats_etc2(); + } +} +#endif + +#if defined(SOKOL_GLES3) || defined(SOKOL_GLES2) +_SOKOL_PRIVATE void _sg_gl_init_caps_gles2(void) { + _sg.backend = SG_BACKEND_GLES2; + + bool has_s3tc = false; /* BC1..BC3 */ + bool has_rgtc = false; /* BC4 and BC5 */ + bool has_bptc = false; /* BC6H and BC7 */ + bool has_pvrtc = false; + bool has_etc2 = false; + bool has_texture_float = false; + bool has_texture_float_linear = false; + bool has_colorbuffer_float = false; + bool has_float_blend = false; + bool has_instancing = false; + const char* ext = (const char*) glGetString(GL_EXTENSIONS); + if (ext) { + has_s3tc = strstr(ext, "_texture_compression_s3tc") || strstr(ext, "_compressed_texture_s3tc"); + has_rgtc = strstr(ext, "_texture_compression_rgtc"); + has_bptc = strstr(ext, "_texture_compression_bptc"); + has_pvrtc = strstr(ext, "_texture_compression_pvrtc") || strstr(ext, "_compressed_texture_pvrtc"); + has_etc2 = strstr(ext, "_compressed_texture_etc"); + has_texture_float = strstr(ext, "_texture_float"); + has_texture_float_linear = strstr(ext, "_texture_float_linear"); + has_colorbuffer_float = strstr(ext, "_color_buffer_float"); + has_float_blend = strstr(ext, "_float_blend"); + /* don't bother with half_float support on WebGL1 + has_texture_half_float = strstr(ext, "_texture_half_float"); + has_texture_half_float_linear = strstr(ext, "_texture_half_float_linear"); + has_colorbuffer_half_float = strstr(ext, "_color_buffer_half_float"); + */ + has_instancing = strstr(ext, "_instanced_arrays"); + _sg.gl.ext_anisotropic = strstr(ext, "ext_anisotropic"); + } + + _sg.features.origin_top_left = false; + #if defined(_SOKOL_GL_INSTANCING_ENABLED) + _sg.features.instancing = has_instancing; + #endif + _sg.features.multiple_render_targets = false; + _sg.features.msaa_render_targets = false; + _sg.features.imagetype_3d = false; + _sg.features.imagetype_array = false; + _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = false; + + /* limits */ + _sg_gl_init_limits(); + + /* pixel formats */ + const bool has_bgra = false; /* not a bug */ + const bool has_texture_half_float = false; + const bool has_texture_half_float_linear = false; + const bool has_colorbuffer_half_float = false; + _sg_gl_init_pixelformats(has_bgra); + if (has_texture_float) { + _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend); + } + if (has_texture_half_float) { + _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear); + } + if (has_s3tc) { + _sg_gl_init_pixelformats_s3tc(); + } + if (has_rgtc) { + _sg_gl_init_pixelformats_rgtc(); + } + if (has_bptc) { + _sg_gl_init_pixelformats_bptc(); + } + if (has_pvrtc) { + _sg_gl_init_pixelformats_pvrtc(); + } + if (has_etc2) { + _sg_gl_init_pixelformats_etc2(); + } + /* GLES2 doesn't allow multi-sampled render targets at all */ + for (int i = 0; i < _SG_PIXELFORMAT_NUM; i++) { + _sg.formats[i].msaa = false; + } +} +#endif + +/*-- state cache implementation ----------------------------------------------*/ +_SOKOL_PRIVATE void _sg_gl_cache_clear_buffer_bindings(bool force) { + if (force || (_sg.gl.cache.vertex_buffer != 0)) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + _sg.gl.cache.vertex_buffer = 0; + } + if (force || (_sg.gl.cache.index_buffer != 0)) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + _sg.gl.cache.index_buffer = 0; + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_bind_buffer(GLenum target, GLuint buffer) { + SOKOL_ASSERT((GL_ARRAY_BUFFER == target) || (GL_ELEMENT_ARRAY_BUFFER == target)); + if (target == GL_ARRAY_BUFFER) { + if (_sg.gl.cache.vertex_buffer != buffer) { + _sg.gl.cache.vertex_buffer = buffer; + glBindBuffer(target, buffer); + } + } + else { + if (_sg.gl.cache.index_buffer != buffer) { + _sg.gl.cache.index_buffer = buffer; + glBindBuffer(target, buffer); + } + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_store_buffer_binding(GLenum target) { + if (target == GL_ARRAY_BUFFER) { + _sg.gl.cache.stored_vertex_buffer = _sg.gl.cache.vertex_buffer; + } + else { + _sg.gl.cache.stored_index_buffer = _sg.gl.cache.index_buffer; + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_restore_buffer_binding(GLenum target) { + if (target == GL_ARRAY_BUFFER) { + if (_sg.gl.cache.stored_vertex_buffer != 0) { + /* we only care restoring valid ids */ + _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_vertex_buffer); + _sg.gl.cache.stored_vertex_buffer = 0; + } + } + else { + if (_sg.gl.cache.stored_index_buffer != 0) { + /* we only care restoring valid ids */ + _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_index_buffer); + _sg.gl.cache.stored_index_buffer = 0; + } + } +} + +/* called when from _sg_gl_destroy_buffer() */ +_SOKOL_PRIVATE void _sg_gl_cache_invalidate_buffer(GLuint buf) { + if (buf == _sg.gl.cache.vertex_buffer) { + _sg.gl.cache.vertex_buffer = 0; + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + if (buf == _sg.gl.cache.index_buffer) { + _sg.gl.cache.index_buffer = 0; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + if (buf == _sg.gl.cache.stored_vertex_buffer) { + _sg.gl.cache.stored_vertex_buffer = 0; + } + if (buf == _sg.gl.cache.stored_index_buffer) { + _sg.gl.cache.stored_index_buffer = 0; + } + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + if (buf == _sg.gl.cache.attrs[i].gl_vbuf) { + _sg.gl.cache.attrs[i].gl_vbuf = 0; + } + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_active_texture(GLenum texture) { + if (_sg.gl.cache.cur_active_texture != texture) { + _sg.gl.cache.cur_active_texture = texture; + glActiveTexture(texture); + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_clear_texture_bindings(bool force) { + for (int i = 0; (i < SG_MAX_SHADERSTAGE_IMAGES) && (i < _sg.gl.max_combined_texture_image_units); i++) { + if (force || (_sg.gl.cache.textures[i].texture != 0)) { + GLenum gl_texture_slot = (GLenum) (GL_TEXTURE0 + i); + glActiveTexture(gl_texture_slot); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glBindTexture(GL_TEXTURE_3D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + } + #endif + _sg.gl.cache.textures[i].target = 0; + _sg.gl.cache.textures[i].texture = 0; + _sg.gl.cache.cur_active_texture = gl_texture_slot; + } + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_bind_texture(int slot_index, GLenum target, GLuint texture) { + /* it's valid to call this function with target=0 and/or texture=0 + target=0 will unbind the previous binding, texture=0 will clear + the new binding + */ + SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES); + if (slot_index >= _sg.gl.max_combined_texture_image_units) { + return; + } + _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[slot_index]; + if ((slot->target != target) || (slot->texture != texture)) { + _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + slot_index)); + /* if the target has changed, clear the previous binding on that target */ + if ((target != slot->target) && (slot->target != 0)) { + glBindTexture(slot->target, 0); + } + /* apply new binding (texture can be 0 to unbind) */ + if (target != 0) { + glBindTexture(target, texture); + } + slot->target = target; + slot->texture = texture; + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_store_texture_binding(int slot_index) { + SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES); + _sg.gl.cache.stored_texture = _sg.gl.cache.textures[slot_index]; +} + +_SOKOL_PRIVATE void _sg_gl_cache_restore_texture_binding(int slot_index) { + SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES); + _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.stored_texture; + if (slot->texture != 0) { + /* we only care restoring valid ids */ + SOKOL_ASSERT(slot->target != 0); + _sg_gl_cache_bind_texture(slot_index, slot->target, slot->texture); + slot->target = 0; + slot->texture = 0; + } +} + +/* called from _sg_gl_destroy_texture() */ +_SOKOL_PRIVATE void _sg_gl_cache_invalidate_texture(GLuint tex) { + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { + _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[i]; + if (tex == slot->texture) { + _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + i)); + glBindTexture(slot->target, 0); + slot->target = 0; + slot->texture = 0; + } + } + if (tex == _sg.gl.cache.stored_texture.texture) { + _sg.gl.cache.stored_texture.target = 0; + _sg.gl.cache.stored_texture.texture = 0; + } +} + +/* called from _sg_gl_destroy_shader() */ +_SOKOL_PRIVATE void _sg_gl_cache_invalidate_program(GLuint prog) { + if (prog == _sg.gl.cache.prog) { + _sg.gl.cache.prog = 0; + glUseProgram(0); + } +} + +/* called from _sg_gl_destroy_pipeline() */ +_SOKOL_PRIVATE void _sg_gl_cache_invalidate_pipeline(_sg_pipeline_t* pip) { + if (pip == _sg.gl.cache.cur_pipeline) { + _sg.gl.cache.cur_pipeline = 0; + _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID; + } +} + +_SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { + if (_sg.gl.cur_context) { + _SG_GL_CHECK_ERROR(); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glBindVertexArray(_sg.gl.cur_context->vao); + _SG_GL_CHECK_ERROR(); + } + #endif + memset(&_sg.gl.cache, 0, sizeof(_sg.gl.cache)); + _sg_gl_cache_clear_buffer_bindings(true); + _SG_GL_CHECK_ERROR(); + _sg_gl_cache_clear_texture_bindings(true); + _SG_GL_CHECK_ERROR(); + for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { + _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; + attr->vb_index = -1; + attr->divisor = -1; + glDisableVertexAttribArray((GLuint)i); + _SG_GL_CHECK_ERROR(); + } + _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; + + /* shader program */ + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); + _SG_GL_CHECK_ERROR(); + + /* depth and stencil state */ + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + glDisable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0); + + /* blend state */ + _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; + _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; + glDisable(GL_BLEND); + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* standalone state */ + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; + _sg.gl.cache.face_winding = SG_FACEWINDING_CW; + _sg.gl.cache.sample_count = 1; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); + glFrontFace(GL_CW); + glCullFace(GL_BACK); + glEnable(GL_SCISSOR_TEST); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + glEnable(GL_DITHER); + glDisable(GL_POLYGON_OFFSET_FILL); + #if defined(SOKOL_GLCORE33) + glEnable(GL_MULTISAMPLE); + glEnable(GL_PROGRAM_POINT_SIZE); + #endif + } +} + +_SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { + /* assumes that _sg.gl is already zero-initialized */ + _sg.gl.valid = true; + #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + _sg.gl.gles2 = desc->context.gl.force_gles2; + #else + _SOKOL_UNUSED(desc); + _sg.gl.gles2 = false; + #endif + + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + _sg_gl_load_opengl(); + #endif + + /* clear initial GL error state */ + #if defined(SOKOL_DEBUG) + while (glGetError() != GL_NO_ERROR); + #endif + #if defined(SOKOL_GLCORE33) + _sg_gl_init_caps_glcore33(); + #elif defined(SOKOL_GLES3) + if (_sg.gl.gles2) { + _sg_gl_init_caps_gles2(); + } + else { + _sg_gl_init_caps_gles3(); + } + #else + _sg_gl_init_caps_gles2(); + #endif +} + +_SOKOL_PRIVATE void _sg_gl_discard_backend(void) { + SOKOL_ASSERT(_sg.gl.valid); + _sg.gl.valid = false; + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + _sg_gl_unload_opengl(); + #endif +} + +_SOKOL_PRIVATE void _sg_gl_activate_context(_sg_context_t* ctx) { + SOKOL_ASSERT(_sg.gl.valid); + /* NOTE: ctx can be 0 to unset the current context */ + _sg.gl.cur_context = ctx; + _sg_gl_reset_state_cache(); +} + +/*-- GL backend resource creation and destruction ----------------------------*/ +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + SOKOL_ASSERT(0 == ctx->default_framebuffer); + _SG_GL_CHECK_ERROR(); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer); + _SG_GL_CHECK_ERROR(); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + SOKOL_ASSERT(0 == ctx->vao); + glGenVertexArrays(1, &ctx->vao); + glBindVertexArray(ctx->vao); + _SG_GL_CHECK_ERROR(); + } + #endif + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + if (ctx->vao) { + glDeleteVertexArrays(1, &ctx->vao); + } + _SG_GL_CHECK_ERROR(); + } + #else + _SOKOL_UNUSED(ctx); + #endif +} + +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf && desc); + _SG_GL_CHECK_ERROR(); + _sg_buffer_common_init(&buf->cmn, desc); + buf->gl.ext_buffers = (0 != desc->gl_buffers[0]); + GLenum gl_target = _sg_gl_buffer_target(buf->cmn.type); + GLenum gl_usage = _sg_gl_usage(buf->cmn.usage); + for (int slot = 0; slot < buf->cmn.num_slots; slot++) { + GLuint gl_buf = 0; + if (buf->gl.ext_buffers) { + SOKOL_ASSERT(desc->gl_buffers[slot]); + gl_buf = desc->gl_buffers[slot]; + } + else { + glGenBuffers(1, &gl_buf); + SOKOL_ASSERT(gl_buf); + _sg_gl_cache_store_buffer_binding(gl_target); + _sg_gl_cache_bind_buffer(gl_target, gl_buf); + glBufferData(gl_target, buf->cmn.size, 0, gl_usage); + if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { + SOKOL_ASSERT(desc->data.ptr); + glBufferSubData(gl_target, 0, buf->cmn.size, desc->data.ptr); + } + _sg_gl_cache_restore_buffer_binding(gl_target); + } + buf->gl.buf[slot] = gl_buf; + } + _SG_GL_CHECK_ERROR(); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + _SG_GL_CHECK_ERROR(); + for (int slot = 0; slot < buf->cmn.num_slots; slot++) { + if (buf->gl.buf[slot]) { + _sg_gl_cache_invalidate_buffer(buf->gl.buf[slot]); + if (!buf->gl.ext_buffers) { + glDeleteBuffers(1, &buf->gl.buf[slot]); + } + } + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE bool _sg_gl_supported_texture_format(sg_pixel_format fmt) { + const int fmt_index = (int) fmt; + SOKOL_ASSERT((fmt_index > SG_PIXELFORMAT_NONE) && (fmt_index < _SG_PIXELFORMAT_NUM)); + return _sg.formats[fmt_index].sample; +} + +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + _SG_GL_CHECK_ERROR(); + _sg_image_common_init(&img->cmn, desc); + img->gl.ext_textures = (0 != desc->gl_textures[0]); + + /* check if texture format is support */ + if (!_sg_gl_supported_texture_format(img->cmn.pixel_format)) { + SOKOL_LOG("texture format not supported by GL context\n"); + return SG_RESOURCESTATE_FAILED; + } + /* check for optional texture types */ + if ((img->cmn.type == SG_IMAGETYPE_3D) && !_sg.features.imagetype_3d) { + SOKOL_LOG("3D textures not supported by GL context\n"); + return SG_RESOURCESTATE_FAILED; + } + if ((img->cmn.type == SG_IMAGETYPE_ARRAY) && !_sg.features.imagetype_array) { + SOKOL_LOG("array textures not supported by GL context\n"); + return SG_RESOURCESTATE_FAILED; + } + + #if !defined(SOKOL_GLES2) + bool msaa = false; + if (!_sg.gl.gles2) { + msaa = (img->cmn.sample_count > 1) && (_sg.features.msaa_render_targets); + } + #endif + + if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) { + /* special case depth-stencil-buffer? */ + SOKOL_ASSERT((img->cmn.usage == SG_USAGE_IMMUTABLE) && (img->cmn.num_slots == 1)); + SOKOL_ASSERT(!img->gl.ext_textures); /* cannot provide external texture for depth images */ + glGenRenderbuffers(1, &img->gl.depth_render_buffer); + glBindRenderbuffer(GL_RENDERBUFFER, img->gl.depth_render_buffer); + GLenum gl_depth_format = _sg_gl_depth_attachment_format(img->cmn.pixel_format); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2 && msaa) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, img->cmn.sample_count, gl_depth_format, img->cmn.width, img->cmn.height); + } + else + #endif + { + glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format, img->cmn.width, img->cmn.height); + } + } + else { + /* regular color texture */ + img->gl.target = _sg_gl_texture_target(img->cmn.type); + const GLenum gl_internal_format = _sg_gl_teximage_internal_format(img->cmn.pixel_format); + + /* if this is a MSAA render target, need to create a separate render buffer */ + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2 && img->cmn.render_target && msaa) { + glGenRenderbuffers(1, &img->gl.msaa_render_buffer); + glBindRenderbuffer(GL_RENDERBUFFER, img->gl.msaa_render_buffer); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, img->cmn.sample_count, gl_internal_format, img->cmn.width, img->cmn.height); + } + #endif + + if (img->gl.ext_textures) { + /* inject externally GL textures */ + for (int slot = 0; slot < img->cmn.num_slots; slot++) { + SOKOL_ASSERT(desc->gl_textures[slot]); + img->gl.tex[slot] = desc->gl_textures[slot]; + } + if (desc->gl_texture_target) { + img->gl.target = (GLenum)desc->gl_texture_target; + } + } + else { + /* create our own GL texture(s) */ + const GLenum gl_format = _sg_gl_teximage_format(img->cmn.pixel_format); + const bool is_compressed = _sg_is_compressed_pixel_format(img->cmn.pixel_format); + for (int slot = 0; slot < img->cmn.num_slots; slot++) { + glGenTextures(1, &img->gl.tex[slot]); + SOKOL_ASSERT(img->gl.tex[slot]); + _sg_gl_cache_store_texture_binding(0); + _sg_gl_cache_bind_texture(0, img->gl.target, img->gl.tex[slot]); + GLenum gl_min_filter = _sg_gl_filter(img->cmn.min_filter); + GLenum gl_mag_filter = _sg_gl_filter(img->cmn.mag_filter); + glTexParameteri(img->gl.target, GL_TEXTURE_MIN_FILTER, (GLint)gl_min_filter); + glTexParameteri(img->gl.target, GL_TEXTURE_MAG_FILTER, (GLint)gl_mag_filter); + if (_sg.gl.ext_anisotropic && (img->cmn.max_anisotropy > 1)) { + GLint max_aniso = (GLint) img->cmn.max_anisotropy; + if (max_aniso > _sg.gl.max_anisotropy) { + max_aniso = _sg.gl.max_anisotropy; + } + glTexParameteri(img->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); + } + if (img->cmn.type == SG_IMAGETYPE_CUBE) { + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else { + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, (GLint)_sg_gl_wrap(img->cmn.wrap_u)); + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, (GLint)_sg_gl_wrap(img->cmn.wrap_v)); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2 && (img->cmn.type == SG_IMAGETYPE_3D)) { + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_R, (GLint)_sg_gl_wrap(img->cmn.wrap_w)); + } + #endif + #if defined(SOKOL_GLCORE33) + float border[4]; + switch (img->cmn.border_color) { + case SG_BORDERCOLOR_TRANSPARENT_BLACK: + border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 0.0f; + break; + case SG_BORDERCOLOR_OPAQUE_WHITE: + border[0] = 1.0f; border[1] = 1.0f; border[2] = 1.0f; border[3] = 1.0f; + break; + default: + border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 1.0f; + break; + } + glTexParameterfv(img->gl.target, GL_TEXTURE_BORDER_COLOR, border); + #endif + } + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + /* GL spec has strange defaults for mipmap min/max lod: -1000 to +1000 */ + const float min_lod = _sg_clamp(desc->min_lod, 0.0f, 1000.0f); + const float max_lod = _sg_clamp(desc->max_lod, 0.0f, 1000.0f); + glTexParameterf(img->gl.target, GL_TEXTURE_MIN_LOD, min_lod); + glTexParameterf(img->gl.target, GL_TEXTURE_MAX_LOD, max_lod); + } + #endif + const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; + int data_index = 0; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, data_index++) { + GLenum gl_img_target = img->gl.target; + if (SG_IMAGETYPE_CUBE == img->cmn.type) { + gl_img_target = _sg_gl_cubeface_target(face_index); + } + const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr; + int mip_width = img->cmn.width >> mip_index; + if (mip_width == 0) { + mip_width = 1; + } + int mip_height = img->cmn.height >> mip_index; + if (mip_height == 0) { + mip_height = 1; + } + if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { + if (is_compressed) { + const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; + glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format, + mip_width, mip_height, 0, data_size, data_ptr); + } + else { + const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); + glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format, + mip_width, mip_height, 0, gl_format, gl_type, data_ptr); + } + } + #if !defined(SOKOL_GLES2) + else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) { + int mip_depth = img->cmn.num_slices; + if (SG_IMAGETYPE_3D == img->cmn.type) { + mip_depth >>= mip_index; + } + if (mip_depth == 0) { + mip_depth = 1; + } + if (is_compressed) { + const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; + glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format, + mip_width, mip_height, mip_depth, 0, data_size, data_ptr); + } + else { + const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); + glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format, + mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr); + } + } + #endif + } + } + _sg_gl_cache_restore_texture_binding(0); + } + } + } + _SG_GL_CHECK_ERROR(); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + _SG_GL_CHECK_ERROR(); + for (int slot = 0; slot < img->cmn.num_slots; slot++) { + if (img->gl.tex[slot]) { + _sg_gl_cache_invalidate_texture(img->gl.tex[slot]); + if (!img->gl.ext_textures) { + glDeleteTextures(1, &img->gl.tex[slot]); + } + } + } + if (img->gl.depth_render_buffer) { + glDeleteRenderbuffers(1, &img->gl.depth_render_buffer); + } + if (img->gl.msaa_render_buffer) { + glDeleteRenderbuffers(1, &img->gl.msaa_render_buffer); + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE GLuint _sg_gl_compile_shader(sg_shader_stage stage, const char* src) { + SOKOL_ASSERT(src); + _SG_GL_CHECK_ERROR(); + GLuint gl_shd = glCreateShader(_sg_gl_shader_stage(stage)); + glShaderSource(gl_shd, 1, &src, 0); + glCompileShader(gl_shd); + GLint compile_status = 0; + glGetShaderiv(gl_shd, GL_COMPILE_STATUS, &compile_status); + if (!compile_status) { + /* compilation failed, log error and delete shader */ + GLint log_len = 0; + glGetShaderiv(gl_shd, GL_INFO_LOG_LENGTH, &log_len); + if (log_len > 0) { + GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len); + glGetShaderInfoLog(gl_shd, log_len, &log_len, log_buf); + SOKOL_LOG(log_buf); + SOKOL_FREE(log_buf); + } + glDeleteShader(gl_shd); + gl_shd = 0; + } + _SG_GL_CHECK_ERROR(); + return gl_shd; +} + +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + SOKOL_ASSERT(!shd->gl.prog); + _SG_GL_CHECK_ERROR(); + + _sg_shader_common_init(&shd->cmn, desc); + + /* copy vertex attribute names over, these are required for GLES2, and optional for GLES3 and GL3.x */ + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + _sg_strcpy(&shd->gl.attrs[i].name, desc->attrs[i].name); + } + + GLuint gl_vs = _sg_gl_compile_shader(SG_SHADERSTAGE_VS, desc->vs.source); + GLuint gl_fs = _sg_gl_compile_shader(SG_SHADERSTAGE_FS, desc->fs.source); + if (!(gl_vs && gl_fs)) { + return SG_RESOURCESTATE_FAILED; + } + GLuint gl_prog = glCreateProgram(); + glAttachShader(gl_prog, gl_vs); + glAttachShader(gl_prog, gl_fs); + glLinkProgram(gl_prog); + glDeleteShader(gl_vs); + glDeleteShader(gl_fs); + _SG_GL_CHECK_ERROR(); + + GLint link_status; + glGetProgramiv(gl_prog, GL_LINK_STATUS, &link_status); + if (!link_status) { + GLint log_len = 0; + glGetProgramiv(gl_prog, GL_INFO_LOG_LENGTH, &log_len); + if (log_len > 0) { + GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len); + glGetProgramInfoLog(gl_prog, log_len, &log_len, log_buf); + SOKOL_LOG(log_buf); + SOKOL_FREE(log_buf); + } + glDeleteProgram(gl_prog); + return SG_RESOURCESTATE_FAILED; + } + shd->gl.prog = gl_prog; + + /* resolve uniforms */ + _SG_GL_CHECK_ERROR(); + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs; + _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index]; + for (int ub_index = 0; ub_index < shd->cmn.stage[stage_index].num_uniform_blocks; ub_index++) { + const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; + SOKOL_ASSERT(ub_desc->size > 0); + _sg_gl_uniform_block_t* ub = &gl_stage->uniform_blocks[ub_index]; + SOKOL_ASSERT(ub->num_uniforms == 0); + uint32_t cur_uniform_offset = 0; + for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { + const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; + if (u_desc->type == SG_UNIFORMTYPE_INVALID) { + break; + } + const uint32_t u_align = _sg_uniform_alignment(u_desc->type, u_desc->array_count, ub_desc->layout); + const uint32_t u_size = _sg_uniform_size(u_desc->type, u_desc->array_count, ub_desc->layout); + cur_uniform_offset = _sg_align_u32(cur_uniform_offset, u_align); + _sg_gl_uniform_t* u = &ub->uniforms[u_index]; + u->type = u_desc->type; + u->count = (uint16_t) u_desc->array_count; + u->offset = (uint16_t) cur_uniform_offset; + cur_uniform_offset += u_size; + if (u_desc->name) { + u->gl_loc = glGetUniformLocation(gl_prog, u_desc->name); + } + else { + u->gl_loc = u_index; + } + ub->num_uniforms++; + } + if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { + cur_uniform_offset = _sg_align_u32(cur_uniform_offset, 16); + } + SOKOL_ASSERT(ub_desc->size == (size_t)cur_uniform_offset); + _SOKOL_UNUSED(cur_uniform_offset); + } + } + + /* resolve image locations */ + _SG_GL_CHECK_ERROR(); + GLuint cur_prog = 0; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&cur_prog); + glUseProgram(gl_prog); + int gl_tex_slot = 0; + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs; + _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index]; + for (int img_index = 0; img_index < shd->cmn.stage[stage_index].num_images; img_index++) { + const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; + SOKOL_ASSERT(img_desc->image_type != _SG_IMAGETYPE_DEFAULT); + _sg_gl_shader_image_t* gl_img = &gl_stage->images[img_index]; + GLint gl_loc = img_index; + if (img_desc->name) { + gl_loc = glGetUniformLocation(gl_prog, img_desc->name); + } + if (gl_loc != -1) { + gl_img->gl_tex_slot = gl_tex_slot++; + glUniform1i(gl_loc, gl_img->gl_tex_slot); + } + else { + gl_img->gl_tex_slot = -1; + } + } + } + /* it's legal to call glUseProgram with 0 */ + glUseProgram(cur_prog); + _SG_GL_CHECK_ERROR(); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + _SG_GL_CHECK_ERROR(); + if (shd->gl.prog) { + _sg_gl_cache_invalidate_program(shd->gl.prog); + glDeleteProgram(shd->gl.prog); + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && shd && desc); + SOKOL_ASSERT(!pip->shader && pip->cmn.shader_id.id == SG_INVALID_ID); + SOKOL_ASSERT(desc->shader.id == shd->slot.id); + SOKOL_ASSERT(shd->gl.prog); + pip->shader = shd; + _sg_pipeline_common_init(&pip->cmn, desc); + pip->gl.primitive_type = desc->primitive_type; + pip->gl.depth = desc->depth; + pip->gl.stencil = desc->stencil; + // FIXME: blend color and write mask per draw-buffer-attachment (requires GL4) + pip->gl.blend = desc->colors[0].blend; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + pip->gl.color_write_mask[i] = desc->colors[i].write_mask; + } + pip->gl.cull_mode = desc->cull_mode; + pip->gl.face_winding = desc->face_winding; + pip->gl.sample_count = desc->sample_count; + pip->gl.alpha_to_coverage_enabled = desc->alpha_to_coverage_enabled; + + /* resolve vertex attributes */ + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + pip->gl.attrs[attr_index].vb_index = -1; + } + for (int attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) { + const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[a_desc->buffer_index]; + const sg_vertex_step step_func = l_desc->step_func; + const int step_rate = l_desc->step_rate; + GLint attr_loc = attr_index; + if (!_sg_strempty(&shd->gl.attrs[attr_index].name)) { + attr_loc = glGetAttribLocation(pip->shader->gl.prog, _sg_strptr(&shd->gl.attrs[attr_index].name)); + } + SOKOL_ASSERT(attr_loc < (GLint)_sg.limits.max_vertex_attrs); + if (attr_loc != -1) { + _sg_gl_attr_t* gl_attr = &pip->gl.attrs[attr_loc]; + SOKOL_ASSERT(gl_attr->vb_index == -1); + gl_attr->vb_index = (int8_t) a_desc->buffer_index; + if (step_func == SG_VERTEXSTEP_PER_VERTEX) { + gl_attr->divisor = 0; + } + else { + gl_attr->divisor = (int8_t) step_rate; + pip->cmn.use_instanced_draw = true; + } + SOKOL_ASSERT(l_desc->stride > 0); + gl_attr->stride = (uint8_t) l_desc->stride; + gl_attr->offset = a_desc->offset; + gl_attr->size = (uint8_t) _sg_gl_vertexformat_size(a_desc->format); + gl_attr->type = _sg_gl_vertexformat_type(a_desc->format); + gl_attr->normalized = _sg_gl_vertexformat_normalized(a_desc->format); + pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; + } + else { + SOKOL_LOG("Vertex attribute not found in shader: "); + SOKOL_LOG(_sg_strptr(&shd->gl.attrs[attr_index].name)); + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + _sg_gl_cache_invalidate_pipeline(pip); +} + +/* + _sg_create_pass + + att_imgs must point to a _sg_image* att_imgs[SG_MAX_COLOR_ATTACHMENTS+1] array, + first entries are the color attachment images (or nullptr), last entry + is the depth-stencil image (or nullptr). +*/ +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass && att_images && desc); + SOKOL_ASSERT(att_images && att_images[0]); + _SG_GL_CHECK_ERROR(); + + _sg_pass_common_init(&pass->cmn, desc); + + /* copy image pointers */ + const sg_pass_attachment_desc* att_desc; + for (int i = 0; i < pass->cmn.num_color_atts; i++) { + att_desc = &desc->color_attachments[i]; + SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); + SOKOL_ASSERT(0 == pass->gl.color_atts[i].image); + SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_images[i]->cmn.pixel_format)); + pass->gl.color_atts[i].image = att_images[i]; + } + SOKOL_ASSERT(0 == pass->gl.ds_att.image); + att_desc = &desc->depth_stencil_attachment; + if (att_desc->image.id != SG_INVALID_ID) { + const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; + SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format)); + pass->gl.ds_att.image = att_images[ds_img_index]; + } + + /* store current framebuffer binding (restored at end of function) */ + GLuint gl_orig_fb; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&gl_orig_fb); + + /* create a framebuffer object */ + glGenFramebuffers(1, &pass->gl.fb); + glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb); + + /* attach msaa render buffer or textures */ + const bool is_msaa = (0 != att_images[0]->gl.msaa_render_buffer); + if (is_msaa) { + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + const _sg_image_t* att_img = pass->gl.color_atts[i].image; + if (att_img) { + const GLuint gl_render_buffer = att_img->gl.msaa_render_buffer; + SOKOL_ASSERT(gl_render_buffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), GL_RENDERBUFFER, gl_render_buffer); + } + } + } + else { + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + const _sg_image_t* att_img = pass->gl.color_atts[i].image; + const int mip_level = pass->cmn.color_atts[i].mip_level; + const int slice = pass->cmn.color_atts[i].slice; + if (att_img) { + const GLuint gl_tex = att_img->gl.tex[0]; + SOKOL_ASSERT(gl_tex); + const GLenum gl_att = (GLenum)(GL_COLOR_ATTACHMENT0 + i); + switch (att_img->cmn.type) { + case SG_IMAGETYPE_2D: + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, GL_TEXTURE_2D, gl_tex, mip_level); + break; + case SG_IMAGETYPE_CUBE: + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, _sg_gl_cubeface_target(slice), gl_tex, mip_level); + break; + default: + /* 3D- or array-texture */ + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_att, gl_tex, mip_level, slice); + } + #endif + break; + } + } + } + } + + /* attach depth-stencil buffer to framebuffer */ + if (pass->gl.ds_att.image) { + const GLuint gl_render_buffer = pass->gl.ds_att.image->gl.depth_render_buffer; + SOKOL_ASSERT(gl_render_buffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer); + if (_sg_is_depth_stencil_format(pass->gl.ds_att.image->cmn.pixel_format)) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer); + } + } + + /* check if framebuffer is complete */ + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SOKOL_LOG("Framebuffer completeness check failed!\n"); + return SG_RESOURCESTATE_FAILED; + } + + /* setup color attachments for the framebuffer */ + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + GLenum att[SG_MAX_COLOR_ATTACHMENTS] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3 + }; + glDrawBuffers(pass->cmn.num_color_atts, att); + } + #endif + + /* create MSAA resolve framebuffers if necessary */ + if (is_msaa) { + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg_gl_attachment_t* gl_att = &pass->gl.color_atts[i]; + _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + if (gl_att->image) { + SOKOL_ASSERT(0 == gl_att->gl_msaa_resolve_buffer); + glGenFramebuffers(1, &gl_att->gl_msaa_resolve_buffer); + glBindFramebuffer(GL_FRAMEBUFFER, gl_att->gl_msaa_resolve_buffer); + const GLuint gl_tex = gl_att->image->gl.tex[0]; + SOKOL_ASSERT(gl_tex); + switch (gl_att->image->cmn.type) { + case SG_IMAGETYPE_2D: + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, gl_tex, cmn_att->mip_level); + break; + case SG_IMAGETYPE_CUBE: + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + _sg_gl_cubeface_target(cmn_att->slice), gl_tex, cmn_att->mip_level); + break; + default: + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl_tex, cmn_att->mip_level, cmn_att->slice); + } + #endif + break; + } + /* check if framebuffer is complete */ + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SOKOL_LOG("Framebuffer completeness check failed (msaa resolve buffer)!\n"); + return SG_RESOURCESTATE_FAILED; + } + /* setup color attachments for the framebuffer */ + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + const GLenum gl_draw_bufs = GL_COLOR_ATTACHMENT0; + glDrawBuffers(1, &gl_draw_bufs); + } + #endif + } + } + } + + /* restore original framebuffer binding */ + glBindFramebuffer(GL_FRAMEBUFFER, gl_orig_fb); + _SG_GL_CHECK_ERROR(); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_gl_destroy_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + SOKOL_ASSERT(pass != _sg.gl.cur_pass); + _SG_GL_CHECK_ERROR(); + if (0 != pass->gl.fb) { + glDeleteFramebuffers(1, &pass->gl.fb); + } + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (pass->gl.color_atts[i].gl_msaa_resolve_buffer) { + glDeleteFramebuffers(1, &pass->gl.color_atts[i].gl_msaa_resolve_buffer); + } + } + if (pass->gl.ds_att.gl_msaa_resolve_buffer) { + glDeleteFramebuffers(1, &pass->gl.ds_att.gl_msaa_resolve_buffer); + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_color_image(const _sg_pass_t* pass, int index) { + SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + /* NOTE: may return null */ + return pass->gl.color_atts[index].image; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_ds_image(const _sg_pass_t* pass) { + /* NOTE: may return null */ + SOKOL_ASSERT(pass); + return pass->gl.ds_att.image; +} + +_SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + /* FIXME: what if a texture used as render target is still bound, should we + unbind all currently bound textures in begin pass? */ + SOKOL_ASSERT(action); + SOKOL_ASSERT(!_sg.gl.in_pass); + _SG_GL_CHECK_ERROR(); + _sg.gl.in_pass = true; + _sg.gl.cur_pass = pass; /* can be 0 */ + if (pass) { + _sg.gl.cur_pass_id.id = pass->slot.id; + } + else { + _sg.gl.cur_pass_id.id = SG_INVALID_ID; + } + _sg.gl.cur_pass_width = w; + _sg.gl.cur_pass_height = h; + + /* number of color attachments */ + const int num_color_atts = pass ? pass->cmn.num_color_atts : 1; + + /* bind the render pass framebuffer */ + if (pass) { + /* offscreen pass */ + SOKOL_ASSERT(pass->gl.fb); + glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb); + } + else { + /* default pass */ + SOKOL_ASSERT(_sg.gl.cur_context); + glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); + } + glViewport(0, 0, w, h); + glScissor(0, 0, w, h); + + /* clear color and depth-stencil attachments if needed */ + bool clear_color = false; + for (int i = 0; i < num_color_atts; i++) { + if (SG_ACTION_CLEAR == action->colors[i].action) { + clear_color = true; + break; + } + } + const bool clear_depth = (action->depth.action == SG_ACTION_CLEAR); + const bool clear_stencil = (action->stencil.action == SG_ACTION_CLEAR); + + bool need_pip_cache_flush = false; + if (clear_color) { + bool need_color_mask_flush = false; + // NOTE: not a bug to iterate over all possible color attachments + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (SG_COLORMASK_RGBA != _sg.gl.cache.color_write_mask[i]) { + need_pip_cache_flush = true; + need_color_mask_flush = true; + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + } + if (need_color_mask_flush) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + } + if (clear_depth) { + if (!_sg.gl.cache.depth.write_enabled) { + need_pip_cache_flush = true; + _sg.gl.cache.depth.write_enabled = true; + glDepthMask(GL_TRUE); + } + if (_sg.gl.cache.depth.compare != SG_COMPAREFUNC_ALWAYS) { + need_pip_cache_flush = true; + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; + glDepthFunc(GL_ALWAYS); + } + } + if (clear_stencil) { + if (_sg.gl.cache.stencil.write_mask != 0xFF) { + need_pip_cache_flush = true; + _sg.gl.cache.stencil.write_mask = 0xFF; + glStencilMask(0xFF); + } + } + if (need_pip_cache_flush) { + /* we messed with the state cache directly, need to clear cached + pipeline to force re-evaluation in next sg_apply_pipeline() */ + _sg.gl.cache.cur_pipeline = 0; + _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID; + } + bool use_mrt_clear = (0 != pass); + #if defined(SOKOL_GLES2) + use_mrt_clear = false; + #else + if (_sg.gl.gles2) { + use_mrt_clear = false; + } + #endif + if (!use_mrt_clear) { + GLbitfield clear_mask = 0; + if (clear_color) { + clear_mask |= GL_COLOR_BUFFER_BIT; + const sg_color c = action->colors[0].value; + glClearColor(c.r, c.g, c.b, c.a); + } + if (clear_depth) { + clear_mask |= GL_DEPTH_BUFFER_BIT; + #ifdef SOKOL_GLCORE33 + glClearDepth(action->depth.value); + #else + glClearDepthf(action->depth.value); + #endif + } + if (clear_stencil) { + clear_mask |= GL_STENCIL_BUFFER_BIT; + glClearStencil(action->stencil.value); + } + if (0 != clear_mask) { + glClear(clear_mask); + } + } + #if !defined SOKOL_GLES2 + else { + SOKOL_ASSERT(pass); + for (int i = 0; i < num_color_atts; i++) { + if (action->colors[i].action == SG_ACTION_CLEAR) { + glClearBufferfv(GL_COLOR, i, &action->colors[i].value.r); + } + } + if (pass->gl.ds_att.image) { + if (clear_depth && clear_stencil) { + glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.value, action->stencil.value); + } + else if (clear_depth) { + glClearBufferfv(GL_DEPTH, 0, &action->depth.value); + } + else if (clear_stencil) { + GLint val = (GLint) action->stencil.value; + glClearBufferiv(GL_STENCIL, 0, &val); + } + } + } + #endif + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE void _sg_gl_end_pass(void) { + SOKOL_ASSERT(_sg.gl.in_pass); + _SG_GL_CHECK_ERROR(); + + /* if this was an offscreen pass, and MSAA rendering was used, need + to resolve into the pass images */ + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2 && _sg.gl.cur_pass) { + /* check if the pass object is still valid */ + const _sg_pass_t* pass = _sg.gl.cur_pass; + SOKOL_ASSERT(pass->slot.id == _sg.gl.cur_pass_id.id); + bool is_msaa = (0 != _sg.gl.cur_pass->gl.color_atts[0].gl_msaa_resolve_buffer); + if (is_msaa) { + SOKOL_ASSERT(pass->gl.fb); + glBindFramebuffer(GL_READ_FRAMEBUFFER, pass->gl.fb); + SOKOL_ASSERT(pass->gl.color_atts[0].image); + const int w = pass->gl.color_atts[0].image->cmn.width; + const int h = pass->gl.color_atts[0].image->cmn.height; + for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) { + const _sg_gl_attachment_t* gl_att = &pass->gl.color_atts[att_index]; + if (gl_att->image) { + SOKOL_ASSERT(gl_att->gl_msaa_resolve_buffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gl_att->gl_msaa_resolve_buffer); + glReadBuffer((GLenum)(GL_COLOR_ATTACHMENT0 + att_index)); + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + else { + break; + } + } + } + } + #endif + _sg.gl.cur_pass = 0; + _sg.gl.cur_pass_id.id = SG_INVALID_ID; + _sg.gl.cur_pass_width = 0; + _sg.gl.cur_pass_height = 0; + + SOKOL_ASSERT(_sg.gl.cur_context); + glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); + _sg.gl.in_pass = false; + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE void _sg_gl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.gl.in_pass); + y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y; + glViewport(x, y, w, h); +} + +_SOKOL_PRIVATE void _sg_gl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.gl.in_pass); + y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y; + glScissor(x, y, w, h); +} + +_SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); + _SG_GL_CHECK_ERROR(); + if ((_sg.gl.cache.cur_pipeline != pip) || (_sg.gl.cache.cur_pipeline_id.id != pip->slot.id)) { + _sg.gl.cache.cur_pipeline = pip; + _sg.gl.cache.cur_pipeline_id.id = pip->slot.id; + _sg.gl.cache.cur_primitive_type = _sg_gl_primitive_type(pip->gl.primitive_type); + _sg.gl.cache.cur_index_type = _sg_gl_index_type(pip->cmn.index_type); + + /* update depth state */ + { + const sg_depth_state* state_ds = &pip->gl.depth; + sg_depth_state* cache_ds = &_sg.gl.cache.depth; + if (state_ds->compare != cache_ds->compare) { + cache_ds->compare = state_ds->compare; + glDepthFunc(_sg_gl_compare_func(state_ds->compare)); + } + if (state_ds->write_enabled != cache_ds->write_enabled) { + cache_ds->write_enabled = state_ds->write_enabled; + glDepthMask(state_ds->write_enabled); + } + if (!_sg_fequal(state_ds->bias, cache_ds->bias, 0.000001f) || + !_sg_fequal(state_ds->bias_slope_scale, cache_ds->bias_slope_scale, 0.000001f)) + { + /* according to ANGLE's D3D11 backend: + D3D11 SlopeScaledDepthBias ==> GL polygonOffsetFactor + D3D11 DepthBias ==> GL polygonOffsetUnits + DepthBiasClamp has no meaning on GL + */ + cache_ds->bias = state_ds->bias; + cache_ds->bias_slope_scale = state_ds->bias_slope_scale; + glPolygonOffset(state_ds->bias_slope_scale, state_ds->bias); + bool po_enabled = true; + if (_sg_fequal(state_ds->bias, 0.0f, 0.000001f) && + _sg_fequal(state_ds->bias_slope_scale, 0.0f, 0.000001f)) + { + po_enabled = false; + } + if (po_enabled != _sg.gl.cache.polygon_offset_enabled) { + _sg.gl.cache.polygon_offset_enabled = po_enabled; + if (po_enabled) { + glEnable(GL_POLYGON_OFFSET_FILL); + } + else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + } + } + } + + /* update stencil state */ + { + const sg_stencil_state* state_ss = &pip->gl.stencil; + sg_stencil_state* cache_ss = &_sg.gl.cache.stencil; + if (state_ss->enabled != cache_ss->enabled) { + cache_ss->enabled = state_ss->enabled; + if (state_ss->enabled) { + glEnable(GL_STENCIL_TEST); + } + else { + glDisable(GL_STENCIL_TEST); + } + } + if (state_ss->write_mask != cache_ss->write_mask) { + cache_ss->write_mask = state_ss->write_mask; + glStencilMask(state_ss->write_mask); + } + for (int i = 0; i < 2; i++) { + const sg_stencil_face_state* state_sfs = (i==0)? &state_ss->front : &state_ss->back; + sg_stencil_face_state* cache_sfs = (i==0)? &cache_ss->front : &cache_ss->back; + GLenum gl_face = (i==0)? GL_FRONT : GL_BACK; + if ((state_sfs->compare != cache_sfs->compare) || + (state_ss->read_mask != cache_ss->read_mask) || + (state_ss->ref != cache_ss->ref)) + { + cache_sfs->compare = state_sfs->compare; + glStencilFuncSeparate(gl_face, + _sg_gl_compare_func(state_sfs->compare), + state_ss->ref, + state_ss->read_mask); + } + if ((state_sfs->fail_op != cache_sfs->fail_op) || + (state_sfs->depth_fail_op != cache_sfs->depth_fail_op) || + (state_sfs->pass_op != cache_sfs->pass_op)) + { + cache_sfs->fail_op = state_sfs->fail_op; + cache_sfs->depth_fail_op = state_sfs->depth_fail_op; + cache_sfs->pass_op = state_sfs->pass_op; + glStencilOpSeparate(gl_face, + _sg_gl_stencil_op(state_sfs->fail_op), + _sg_gl_stencil_op(state_sfs->depth_fail_op), + _sg_gl_stencil_op(state_sfs->pass_op)); + } + } + cache_ss->read_mask = state_ss->read_mask; + cache_ss->ref = state_ss->ref; + } + + /* update blend state + FIXME: separate blend state per color attachment not support, needs GL4 + */ + { + const sg_blend_state* state_bs = &pip->gl.blend; + sg_blend_state* cache_bs = &_sg.gl.cache.blend; + if (state_bs->enabled != cache_bs->enabled) { + cache_bs->enabled = state_bs->enabled; + if (state_bs->enabled) { + glEnable(GL_BLEND); + } + else { + glDisable(GL_BLEND); + } + } + if ((state_bs->src_factor_rgb != cache_bs->src_factor_rgb) || + (state_bs->dst_factor_rgb != cache_bs->dst_factor_rgb) || + (state_bs->src_factor_alpha != cache_bs->src_factor_alpha) || + (state_bs->dst_factor_alpha != cache_bs->dst_factor_alpha)) + { + cache_bs->src_factor_rgb = state_bs->src_factor_rgb; + cache_bs->dst_factor_rgb = state_bs->dst_factor_rgb; + cache_bs->src_factor_alpha = state_bs->src_factor_alpha; + cache_bs->dst_factor_alpha = state_bs->dst_factor_alpha; + glBlendFuncSeparate(_sg_gl_blend_factor(state_bs->src_factor_rgb), + _sg_gl_blend_factor(state_bs->dst_factor_rgb), + _sg_gl_blend_factor(state_bs->src_factor_alpha), + _sg_gl_blend_factor(state_bs->dst_factor_alpha)); + } + if ((state_bs->op_rgb != cache_bs->op_rgb) || (state_bs->op_alpha != cache_bs->op_alpha)) { + cache_bs->op_rgb = state_bs->op_rgb; + cache_bs->op_alpha = state_bs->op_alpha; + glBlendEquationSeparate(_sg_gl_blend_op(state_bs->op_rgb), _sg_gl_blend_op(state_bs->op_alpha)); + } + } + + /* standalone state */ + for (GLuint i = 0; i < (GLuint)pip->cmn.color_attachment_count; i++) { + if (pip->gl.color_write_mask[i] != _sg.gl.cache.color_write_mask[i]) { + const sg_color_mask cm = pip->gl.color_write_mask[i]; + _sg.gl.cache.color_write_mask[i] = cm; + #ifdef SOKOL_GLCORE33 + glColorMaski(i, + (cm & SG_COLORMASK_R) != 0, + (cm & SG_COLORMASK_G) != 0, + (cm & SG_COLORMASK_B) != 0, + (cm & SG_COLORMASK_A) != 0); + #else + if (0 == i) { + glColorMask((cm & SG_COLORMASK_R) != 0, + (cm & SG_COLORMASK_G) != 0, + (cm & SG_COLORMASK_B) != 0, + (cm & SG_COLORMASK_A) != 0); + } + #endif + } + } + + if (!_sg_fequal(pip->cmn.blend_color.r, _sg.gl.cache.blend_color.r, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.g, _sg.gl.cache.blend_color.g, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.b, _sg.gl.cache.blend_color.b, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.a, _sg.gl.cache.blend_color.a, 0.0001f)) + { + sg_color c = pip->cmn.blend_color; + _sg.gl.cache.blend_color = c; + glBlendColor(c.r, c.g, c.b, c.a); + } + if (pip->gl.cull_mode != _sg.gl.cache.cull_mode) { + _sg.gl.cache.cull_mode = pip->gl.cull_mode; + if (SG_CULLMODE_NONE == pip->gl.cull_mode) { + glDisable(GL_CULL_FACE); + } + else { + glEnable(GL_CULL_FACE); + GLenum gl_mode = (SG_CULLMODE_FRONT == pip->gl.cull_mode) ? GL_FRONT : GL_BACK; + glCullFace(gl_mode); + } + } + if (pip->gl.face_winding != _sg.gl.cache.face_winding) { + _sg.gl.cache.face_winding = pip->gl.face_winding; + GLenum gl_winding = (SG_FACEWINDING_CW == pip->gl.face_winding) ? GL_CW : GL_CCW; + glFrontFace(gl_winding); + } + if (pip->gl.alpha_to_coverage_enabled != _sg.gl.cache.alpha_to_coverage_enabled) { + _sg.gl.cache.alpha_to_coverage_enabled = pip->gl.alpha_to_coverage_enabled; + if (pip->gl.alpha_to_coverage_enabled) { + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + else { + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + } + #ifdef SOKOL_GLCORE33 + if (pip->gl.sample_count != _sg.gl.cache.sample_count) { + _sg.gl.cache.sample_count = pip->gl.sample_count; + if (pip->gl.sample_count > 1) { + glEnable(GL_MULTISAMPLE); + } + else { + glDisable(GL_MULTISAMPLE); + } + } + #endif + + /* bind shader program */ + if (pip->shader->gl.prog != _sg.gl.cache.prog) { + _sg.gl.cache.prog = pip->shader->gl.prog; + glUseProgram(pip->shader->gl.prog); + } + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE void _sg_gl_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + SOKOL_ASSERT(pip); + _SOKOL_UNUSED(num_fs_imgs); + _SOKOL_UNUSED(num_vs_imgs); + _SOKOL_UNUSED(num_vbs); + _SG_GL_CHECK_ERROR(); + + /* bind textures */ + _SG_GL_CHECK_ERROR(); + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[stage_index]; + const _sg_gl_shader_stage_t* gl_stage = &pip->shader->gl.stage[stage_index]; + _sg_image_t** imgs = (stage_index == SG_SHADERSTAGE_VS)? vs_imgs : fs_imgs; + SOKOL_ASSERT(((stage_index == SG_SHADERSTAGE_VS)? num_vs_imgs : num_fs_imgs) == stage->num_images); + for (int img_index = 0; img_index < stage->num_images; img_index++) { + const _sg_gl_shader_image_t* gl_shd_img = &gl_stage->images[img_index]; + if (gl_shd_img->gl_tex_slot != -1) { + _sg_image_t* img = imgs[img_index]; + const GLuint gl_tex = img->gl.tex[img->cmn.active_slot]; + SOKOL_ASSERT(img && img->gl.target); + SOKOL_ASSERT((gl_shd_img->gl_tex_slot != -1) && gl_tex); + _sg_gl_cache_bind_texture(gl_shd_img->gl_tex_slot, img->gl.target, gl_tex); + } + } + } + _SG_GL_CHECK_ERROR(); + + /* index buffer (can be 0) */ + const GLuint gl_ib = ib ? ib->gl.buf[ib->cmn.active_slot] : 0; + _sg_gl_cache_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, gl_ib); + _sg.gl.cache.cur_ib_offset = ib_offset; + + /* vertex attributes */ + for (GLuint attr_index = 0; attr_index < (GLuint)_sg.limits.max_vertex_attrs; attr_index++) { + _sg_gl_attr_t* attr = &pip->gl.attrs[attr_index]; + _sg_gl_cache_attr_t* cache_attr = &_sg.gl.cache.attrs[attr_index]; + bool cache_attr_dirty = false; + int vb_offset = 0; + GLuint gl_vb = 0; + if (attr->vb_index >= 0) { + /* attribute is enabled */ + SOKOL_ASSERT(attr->vb_index < num_vbs); + _sg_buffer_t* vb = vbs[attr->vb_index]; + SOKOL_ASSERT(vb); + gl_vb = vb->gl.buf[vb->cmn.active_slot]; + vb_offset = vb_offsets[attr->vb_index] + attr->offset; + if ((gl_vb != cache_attr->gl_vbuf) || + (attr->size != cache_attr->gl_attr.size) || + (attr->type != cache_attr->gl_attr.type) || + (attr->normalized != cache_attr->gl_attr.normalized) || + (attr->stride != cache_attr->gl_attr.stride) || + (vb_offset != cache_attr->gl_attr.offset) || + (cache_attr->gl_attr.divisor != attr->divisor)) + { + _sg_gl_cache_bind_buffer(GL_ARRAY_BUFFER, gl_vb); + glVertexAttribPointer(attr_index, attr->size, attr->type, + attr->normalized, attr->stride, + (const GLvoid*)(GLintptr)vb_offset); + #if defined(_SOKOL_GL_INSTANCING_ENABLED) + if (_sg.features.instancing) { + glVertexAttribDivisor(attr_index, (GLuint)attr->divisor); + } + #endif + cache_attr_dirty = true; + } + if (cache_attr->gl_attr.vb_index == -1) { + glEnableVertexAttribArray(attr_index); + cache_attr_dirty = true; + } + } + else { + /* attribute is disabled */ + if (cache_attr->gl_attr.vb_index != -1) { + glDisableVertexAttribArray(attr_index); + cache_attr_dirty = true; + } + } + if (cache_attr_dirty) { + cache_attr->gl_attr = *attr; + cache_attr->gl_attr.offset = vb_offset; + cache_attr->gl_vbuf = gl_vb; + } + } + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->slot.id == _sg.gl.cache.cur_pipeline_id.id); + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->slot.id == _sg.gl.cache.cur_pipeline->cmn.shader_id.id); + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks > ub_index); + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size == data->size); + const _sg_gl_shader_stage_t* gl_stage = &_sg.gl.cache.cur_pipeline->shader->gl.stage[stage_index]; + const _sg_gl_uniform_block_t* gl_ub = &gl_stage->uniform_blocks[ub_index]; + for (int u_index = 0; u_index < gl_ub->num_uniforms; u_index++) { + const _sg_gl_uniform_t* u = &gl_ub->uniforms[u_index]; + SOKOL_ASSERT(u->type != SG_UNIFORMTYPE_INVALID); + if (u->gl_loc == -1) { + continue; + } + GLfloat* fptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset); + GLint* iptr = (GLint*) (((uint8_t*)data->ptr) + u->offset); + switch (u->type) { + case SG_UNIFORMTYPE_INVALID: + break; + case SG_UNIFORMTYPE_FLOAT: + glUniform1fv(u->gl_loc, u->count, fptr); + break; + case SG_UNIFORMTYPE_FLOAT2: + glUniform2fv(u->gl_loc, u->count, fptr); + break; + case SG_UNIFORMTYPE_FLOAT3: + glUniform3fv(u->gl_loc, u->count, fptr); + break; + case SG_UNIFORMTYPE_FLOAT4: + glUniform4fv(u->gl_loc, u->count, fptr); + break; + case SG_UNIFORMTYPE_INT: + glUniform1iv(u->gl_loc, u->count, iptr); + break; + case SG_UNIFORMTYPE_INT2: + glUniform2iv(u->gl_loc, u->count, iptr); + break; + case SG_UNIFORMTYPE_INT3: + glUniform3iv(u->gl_loc, u->count, iptr); + break; + case SG_UNIFORMTYPE_INT4: + glUniform4iv(u->gl_loc, u->count, iptr); + break; + case SG_UNIFORMTYPE_MAT4: + glUniformMatrix4fv(u->gl_loc, u->count, GL_FALSE, fptr); + break; + default: + SOKOL_UNREACHABLE; + break; + } + } +} + +_SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_instances) { + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); + const GLenum i_type = _sg.gl.cache.cur_index_type; + const GLenum p_type = _sg.gl.cache.cur_primitive_type; + if (0 != i_type) { + /* indexed rendering */ + const int i_size = (i_type == GL_UNSIGNED_SHORT) ? 2 : 4; + const int ib_offset = _sg.gl.cache.cur_ib_offset; + const GLvoid* indices = (const GLvoid*)(GLintptr)(base_element*i_size+ib_offset); + if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) { + if (_sg.features.instancing) { + glDrawElementsInstanced(p_type, num_elements, i_type, indices, num_instances); + } + } + else { + glDrawElements(p_type, num_elements, i_type, indices); + } + } + else { + /* non-indexed rendering */ + if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) { + if (_sg.features.instancing) { + glDrawArraysInstanced(p_type, base_element, num_elements, num_instances); + } + } + else { + glDrawArrays(p_type, base_element, num_elements); + } + } +} + +_SOKOL_PRIVATE void _sg_gl_commit(void) { + SOKOL_ASSERT(!_sg.gl.in_pass); + /* "soft" clear bindings (only those that are actually bound) */ + _sg_gl_cache_clear_buffer_bindings(false); + _sg_gl_cache_clear_texture_bindings(false); +} + +_SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + /* only one update per buffer per frame allowed */ + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } + GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type); + SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); + GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot]; + SOKOL_ASSERT(gl_buf); + _SG_GL_CHECK_ERROR(); + _sg_gl_cache_store_buffer_binding(gl_tgt); + _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); + glBufferSubData(gl_tgt, 0, (GLsizeiptr)data->size, data->ptr); + _sg_gl_cache_restore_buffer_binding(gl_tgt); + _SG_GL_CHECK_ERROR(); +} + +_SOKOL_PRIVATE int _sg_gl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + if (new_frame) { + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } + } + GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type); + SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); + GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot]; + SOKOL_ASSERT(gl_buf); + _SG_GL_CHECK_ERROR(); + _sg_gl_cache_store_buffer_binding(gl_tgt); + _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); + glBufferSubData(gl_tgt, buf->cmn.append_pos, (GLsizeiptr)data->size, data->ptr); + _sg_gl_cache_restore_buffer_binding(gl_tgt); + _SG_GL_CHECK_ERROR(); + /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */ + return _sg_roundup((int)data->size, 4); +} + +_SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + /* only one update per image per frame allowed */ + if (++img->cmn.active_slot >= img->cmn.num_slots) { + img->cmn.active_slot = 0; + } + SOKOL_ASSERT(img->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES); + SOKOL_ASSERT(0 != img->gl.tex[img->cmn.active_slot]); + _sg_gl_cache_store_texture_binding(0); + _sg_gl_cache_bind_texture(0, img->gl.target, img->gl.tex[img->cmn.active_slot]); + const GLenum gl_img_format = _sg_gl_teximage_format(img->cmn.pixel_format); + const GLenum gl_img_type = _sg_gl_teximage_type(img->cmn.pixel_format); + const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; + const int num_mips = img->cmn.num_mipmaps; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int mip_index = 0; mip_index < num_mips; mip_index++) { + GLenum gl_img_target = img->gl.target; + if (SG_IMAGETYPE_CUBE == img->cmn.type) { + gl_img_target = _sg_gl_cubeface_target(face_index); + } + const GLvoid* data_ptr = data->subimage[face_index][mip_index].ptr; + int mip_width = img->cmn.width >> mip_index; + if (mip_width == 0) { + mip_width = 1; + } + int mip_height = img->cmn.height >> mip_index; + if (mip_height == 0) { + mip_height = 1; + } + if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { + glTexSubImage2D(gl_img_target, mip_index, + 0, 0, + mip_width, mip_height, + gl_img_format, gl_img_type, + data_ptr); + } + #if !defined(SOKOL_GLES2) + else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) { + int mip_depth = img->cmn.num_slices >> mip_index; + if (mip_depth == 0) { + mip_depth = 1; + } + glTexSubImage3D(gl_img_target, mip_index, + 0, 0, 0, + mip_width, mip_height, mip_depth, + gl_img_format, gl_img_type, + data_ptr); + + } + #endif + } + } + _sg_gl_cache_restore_texture_binding(0); +} + +/*== D3D11 BACKEND IMPLEMENTATION ============================================*/ +#elif defined(SOKOL_D3D11) + +#if defined(__cplusplus) +#define _sg_d3d11_AddRef(self) (self)->AddRef() +#else +#define _sg_d3d11_AddRef(self) (self)->lpVtbl->AddRef(self) +#endif + +#if defined(__cplusplus) +#define _sg_d3d11_Release(self) (self)->Release() +#else +#define _sg_d3d11_Release(self) (self)->lpVtbl->Release(self) +#endif + +/*-- D3D11 C/C++ wrappers ----------------------------------------------------*/ +static inline HRESULT _sg_d3d11_CheckFormatSupport(ID3D11Device* self, DXGI_FORMAT Format, UINT* pFormatSupport) { + #if defined(__cplusplus) + return self->CheckFormatSupport(Format, pFormatSupport); + #else + return self->lpVtbl->CheckFormatSupport(self, Format, pFormatSupport); + #endif +} + +static inline void _sg_d3d11_OMSetRenderTargets(ID3D11DeviceContext* self, UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) { + #if defined(__cplusplus) + self->OMSetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView); + #else + self->lpVtbl->OMSetRenderTargets(self, NumViews, ppRenderTargetViews, pDepthStencilView); + #endif +} + +static inline void _sg_d3d11_RSSetState(ID3D11DeviceContext* self, ID3D11RasterizerState* pRasterizerState) { + #if defined(__cplusplus) + self->RSSetState(pRasterizerState); + #else + self->lpVtbl->RSSetState(self, pRasterizerState); + #endif +} + +static inline void _sg_d3d11_OMSetDepthStencilState(ID3D11DeviceContext* self, ID3D11DepthStencilState* pDepthStencilState, UINT StencilRef) { + #if defined(__cplusplus) + self->OMSetDepthStencilState(pDepthStencilState, StencilRef); + #else + self->lpVtbl->OMSetDepthStencilState(self, pDepthStencilState, StencilRef); + #endif +} + +static inline void _sg_d3d11_OMSetBlendState(ID3D11DeviceContext* self, ID3D11BlendState* pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) { + #if defined(__cplusplus) + self->OMSetBlendState(pBlendState, BlendFactor, SampleMask); + #else + self->lpVtbl->OMSetBlendState(self, pBlendState, BlendFactor, SampleMask); + #endif +} + +static inline void _sg_d3d11_IASetVertexBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppVertexBuffers, const UINT* pStrides, const UINT* pOffsets) { + #if defined(__cplusplus) + self->IASetVertexBuffers(StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); + #else + self->lpVtbl->IASetVertexBuffers(self, StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); + #endif +} + +static inline void _sg_d3d11_IASetIndexBuffer(ID3D11DeviceContext* self, ID3D11Buffer* pIndexBuffer, DXGI_FORMAT Format, UINT Offset) { + #if defined(__cplusplus) + self->IASetIndexBuffer(pIndexBuffer, Format, Offset); + #else + self->lpVtbl->IASetIndexBuffer(self, pIndexBuffer, Format, Offset); + #endif +} + +static inline void _sg_d3d11_IASetInputLayout(ID3D11DeviceContext* self, ID3D11InputLayout* pInputLayout) { + #if defined(__cplusplus) + self->IASetInputLayout(pInputLayout); + #else + self->lpVtbl->IASetInputLayout(self, pInputLayout); + #endif +} + +static inline void _sg_d3d11_VSSetShader(ID3D11DeviceContext* self, ID3D11VertexShader* pVertexShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { + #if defined(__cplusplus) + self->VSSetShader(pVertexShader, ppClassInstances, NumClassInstances); + #else + self->lpVtbl->VSSetShader(self, pVertexShader, ppClassInstances, NumClassInstances); + #endif +} + +static inline void _sg_d3d11_PSSetShader(ID3D11DeviceContext* self, ID3D11PixelShader* pPixelShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { + #if defined(__cplusplus) + self->PSSetShader(pPixelShader, ppClassInstances, NumClassInstances); + #else + self->lpVtbl->PSSetShader(self, pPixelShader, ppClassInstances, NumClassInstances); + #endif +} + +static inline void _sg_d3d11_VSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { + #if defined(__cplusplus) + self->VSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + #else + self->lpVtbl->VSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers); + #endif +} + +static inline void _sg_d3d11_PSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { + #if defined(__cplusplus) + self->PSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers); + #else + self->lpVtbl->PSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers); + #endif +} + +static inline void _sg_d3d11_VSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { + #if defined(__cplusplus) + self->VSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + #else + self->lpVtbl->VSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews); + #endif +} + +static inline void _sg_d3d11_PSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { + #if defined(__cplusplus) + self->PSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews); + #else + self->lpVtbl->PSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews); + #endif +} + +static inline void _sg_d3d11_VSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { + #if defined(__cplusplus) + self->VSSetSamplers(StartSlot, NumSamplers, ppSamplers); + #else + self->lpVtbl->VSSetSamplers(self, StartSlot, NumSamplers, ppSamplers); + #endif +} + +static inline void _sg_d3d11_PSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { + #if defined(__cplusplus) + self->PSSetSamplers(StartSlot, NumSamplers, ppSamplers); + #else + self->lpVtbl->PSSetSamplers(self, StartSlot, NumSamplers, ppSamplers); + #endif +} + +static inline HRESULT _sg_d3d11_CreateBuffer(ID3D11Device* self, const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) { + #if defined(__cplusplus) + return self->CreateBuffer(pDesc, pInitialData, ppBuffer); + #else + return self->lpVtbl->CreateBuffer(self, pDesc, pInitialData, ppBuffer); + #endif +} + +static inline HRESULT _sg_d3d11_CreateTexture2D(ID3D11Device* self, const D3D11_TEXTURE2D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture2D** ppTexture2D) { + #if defined(__cplusplus) + return self->CreateTexture2D(pDesc, pInitialData, ppTexture2D); + #else + return self->lpVtbl->CreateTexture2D(self, pDesc, pInitialData, ppTexture2D); + #endif +} + +static inline HRESULT _sg_d3d11_CreateShaderResourceView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRView) { + #if defined(__cplusplus) + return self->CreateShaderResourceView(pResource, pDesc, ppSRView); + #else + return self->lpVtbl->CreateShaderResourceView(self, pResource, pDesc, ppSRView); + #endif +} + +static inline void _sg_d3d11_GetResource(ID3D11View* self, ID3D11Resource** ppResource) { + #if defined(__cplusplus) + self->GetResource(ppResource); + #else + self->lpVtbl->GetResource(self, ppResource); + #endif +} + +static inline HRESULT _sg_d3d11_CreateTexture3D(ID3D11Device* self, const D3D11_TEXTURE3D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture3D** ppTexture3D) { + #if defined(__cplusplus) + return self->CreateTexture3D(pDesc, pInitialData, ppTexture3D); + #else + return self->lpVtbl->CreateTexture3D(self, pDesc, pInitialData, ppTexture3D); + #endif +} + +static inline HRESULT _sg_d3d11_CreateSamplerState(ID3D11Device* self, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) { + #if defined(__cplusplus) + return self->CreateSamplerState(pSamplerDesc, ppSamplerState); + #else + return self->lpVtbl->CreateSamplerState(self, pSamplerDesc, ppSamplerState); + #endif +} + +static inline LPVOID _sg_d3d11_GetBufferPointer(ID3D10Blob* self) { + #if defined(__cplusplus) + return self->GetBufferPointer(); + #else + return self->lpVtbl->GetBufferPointer(self); + #endif +} + +static inline SIZE_T _sg_d3d11_GetBufferSize(ID3D10Blob* self) { + #if defined(__cplusplus) + return self->GetBufferSize(); + #else + return self->lpVtbl->GetBufferSize(self); + #endif +} + +static inline HRESULT _sg_d3d11_CreateVertexShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11VertexShader** ppVertexShader) { + #if defined(__cplusplus) + return self->CreateVertexShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader); + #else + return self->lpVtbl->CreateVertexShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader); + #endif +} + +static inline HRESULT _sg_d3d11_CreatePixelShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11PixelShader** ppPixelShader) { + #if defined(__cplusplus) + return self->CreatePixelShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader); + #else + return self->lpVtbl->CreatePixelShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader); + #endif +} + +static inline HRESULT _sg_d3d11_CreateInputLayout(ID3D11Device* self, const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, const void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout **ppInputLayout) { + #if defined(__cplusplus) + return self->CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); + #else + return self->lpVtbl->CreateInputLayout(self, pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout); + #endif +} + +static inline HRESULT _sg_d3d11_CreateRasterizerState(ID3D11Device* self, const D3D11_RASTERIZER_DESC* pRasterizerDesc, ID3D11RasterizerState** ppRasterizerState) { + #if defined(__cplusplus) + return self->CreateRasterizerState(pRasterizerDesc, ppRasterizerState); + #else + return self->lpVtbl->CreateRasterizerState(self, pRasterizerDesc, ppRasterizerState); + #endif +} + +static inline HRESULT _sg_d3d11_CreateDepthStencilState(ID3D11Device* self, const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc, ID3D11DepthStencilState** ppDepthStencilState) { + #if defined(__cplusplus) + return self->CreateDepthStencilState(pDepthStencilDesc, ppDepthStencilState); + #else + return self->lpVtbl->CreateDepthStencilState(self, pDepthStencilDesc, ppDepthStencilState); + #endif +} + +static inline HRESULT _sg_d3d11_CreateBlendState(ID3D11Device* self, const D3D11_BLEND_DESC* pBlendStateDesc, ID3D11BlendState** ppBlendState) { + #if defined(__cplusplus) + return self->CreateBlendState(pBlendStateDesc, ppBlendState); + #else + return self->lpVtbl->CreateBlendState(self, pBlendStateDesc, ppBlendState); + #endif +} + +static inline HRESULT _sg_d3d11_CreateRenderTargetView(ID3D11Device* self, ID3D11Resource *pResource, const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, ID3D11RenderTargetView** ppRTView) { + #if defined(__cplusplus) + return self->CreateRenderTargetView(pResource, pDesc, ppRTView); + #else + return self->lpVtbl->CreateRenderTargetView(self, pResource, pDesc, ppRTView); + #endif +} + +static inline HRESULT _sg_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, ID3D11DepthStencilView** ppDepthStencilView) { + #if defined(__cplusplus) + return self->CreateDepthStencilView(pResource, pDesc, ppDepthStencilView); + #else + return self->lpVtbl->CreateDepthStencilView(self, pResource, pDesc, ppDepthStencilView); + #endif +} + +static inline void _sg_d3d11_RSSetViewports(ID3D11DeviceContext* self, UINT NumViewports, const D3D11_VIEWPORT* pViewports) { + #if defined(__cplusplus) + self->RSSetViewports(NumViewports, pViewports); + #else + self->lpVtbl->RSSetViewports(self, NumViewports, pViewports); + #endif +} + +static inline void _sg_d3d11_RSSetScissorRects(ID3D11DeviceContext* self, UINT NumRects, const D3D11_RECT* pRects) { + #if defined(__cplusplus) + self->RSSetScissorRects(NumRects, pRects); + #else + self->lpVtbl->RSSetScissorRects(self, NumRects, pRects); + #endif +} + +static inline void _sg_d3d11_ClearRenderTargetView(ID3D11DeviceContext* self, ID3D11RenderTargetView* pRenderTargetView, const FLOAT ColorRGBA[4]) { + #if defined(__cplusplus) + self->ClearRenderTargetView(pRenderTargetView, ColorRGBA); + #else + self->lpVtbl->ClearRenderTargetView(self, pRenderTargetView, ColorRGBA); + #endif +} + +static inline void _sg_d3d11_ClearDepthStencilView(ID3D11DeviceContext* self, ID3D11DepthStencilView* pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) { + #if defined(__cplusplus) + self->ClearDepthStencilView(pDepthStencilView, ClearFlags, Depth, Stencil); + #else + self->lpVtbl->ClearDepthStencilView(self, pDepthStencilView, ClearFlags, Depth, Stencil); + #endif +} + +static inline void _sg_d3d11_ResolveSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, ID3D11Resource* pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { + #if defined(__cplusplus) + self->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + #else + self->lpVtbl->ResolveSubresource(self, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + #endif +} + +static inline void _sg_d3d11_IASetPrimitiveTopology(ID3D11DeviceContext* self, D3D11_PRIMITIVE_TOPOLOGY Topology) { + #if defined(__cplusplus) + self->IASetPrimitiveTopology(Topology); + #else + self->lpVtbl->IASetPrimitiveTopology(self, Topology); + #endif +} + +static inline void _sg_d3d11_UpdateSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) { + #if defined(__cplusplus) + self->UpdateSubresource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); + #else + self->lpVtbl->UpdateSubresource(self, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); + #endif +} + +static inline void _sg_d3d11_DrawIndexed(ID3D11DeviceContext* self, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) { + #if defined(__cplusplus) + self->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); + #else + self->lpVtbl->DrawIndexed(self, IndexCount, StartIndexLocation, BaseVertexLocation); + #endif +} + +static inline void _sg_d3d11_DrawIndexedInstanced(ID3D11DeviceContext* self, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) { + #if defined(__cplusplus) + self->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + #else + self->lpVtbl->DrawIndexedInstanced(self, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + #endif +} + +static inline void _sg_d3d11_Draw(ID3D11DeviceContext* self, UINT VertexCount, UINT StartVertexLocation) { + #if defined(__cplusplus) + self->Draw(VertexCount, StartVertexLocation); + #else + self->lpVtbl->Draw(self, VertexCount, StartVertexLocation); + #endif +} + +static inline void _sg_d3d11_DrawInstanced(ID3D11DeviceContext* self, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) { + #if defined(__cplusplus) + self->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + #else + self->lpVtbl->DrawInstanced(self, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + #endif +} + +static inline HRESULT _sg_d3d11_Map(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + #if defined(__cplusplus) + return self->Map(pResource, Subresource, MapType, MapFlags, pMappedResource); + #else + return self->lpVtbl->Map(self, pResource, Subresource, MapType, MapFlags, pMappedResource); + #endif +} + +static inline void _sg_d3d11_Unmap(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource) { + #if defined(__cplusplus) + self->Unmap(pResource, Subresource); + #else + self->lpVtbl->Unmap(self, pResource, Subresource); + #endif +} + +static inline void _sg_d3d11_ClearState(ID3D11DeviceContext* self) { + #if defined(__cplusplus) + self->ClearState(); + #else + self->lpVtbl->ClearState(self); + #endif +} + +/*-- enum translation functions ----------------------------------------------*/ +_SOKOL_PRIVATE D3D11_USAGE _sg_d3d11_usage(sg_usage usg) { + switch (usg) { + case SG_USAGE_IMMUTABLE: + return D3D11_USAGE_IMMUTABLE; + case SG_USAGE_DYNAMIC: + case SG_USAGE_STREAM: + return D3D11_USAGE_DYNAMIC; + default: + SOKOL_UNREACHABLE; + return (D3D11_USAGE) 0; + } +} + +_SOKOL_PRIVATE UINT _sg_d3d11_cpu_access_flags(sg_usage usg) { + switch (usg) { + case SG_USAGE_IMMUTABLE: + return 0; + case SG_USAGE_DYNAMIC: + case SG_USAGE_STREAM: + return D3D11_CPU_ACCESS_WRITE; + default: + SOKOL_UNREACHABLE; + return 0; + } +} + +_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_pixel_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_R8: return DXGI_FORMAT_R8_UNORM; + case SG_PIXELFORMAT_R8SN: return DXGI_FORMAT_R8_SNORM; + case SG_PIXELFORMAT_R8UI: return DXGI_FORMAT_R8_UINT; + case SG_PIXELFORMAT_R8SI: return DXGI_FORMAT_R8_SINT; + case SG_PIXELFORMAT_R16: return DXGI_FORMAT_R16_UNORM; + case SG_PIXELFORMAT_R16SN: return DXGI_FORMAT_R16_SNORM; + case SG_PIXELFORMAT_R16UI: return DXGI_FORMAT_R16_UINT; + case SG_PIXELFORMAT_R16SI: return DXGI_FORMAT_R16_SINT; + case SG_PIXELFORMAT_R16F: return DXGI_FORMAT_R16_FLOAT; + case SG_PIXELFORMAT_RG8: return DXGI_FORMAT_R8G8_UNORM; + case SG_PIXELFORMAT_RG8SN: return DXGI_FORMAT_R8G8_SNORM; + case SG_PIXELFORMAT_RG8UI: return DXGI_FORMAT_R8G8_UINT; + case SG_PIXELFORMAT_RG8SI: return DXGI_FORMAT_R8G8_SINT; + case SG_PIXELFORMAT_R32UI: return DXGI_FORMAT_R32_UINT; + case SG_PIXELFORMAT_R32SI: return DXGI_FORMAT_R32_SINT; + case SG_PIXELFORMAT_R32F: return DXGI_FORMAT_R32_FLOAT; + case SG_PIXELFORMAT_RG16: return DXGI_FORMAT_R16G16_UNORM; + case SG_PIXELFORMAT_RG16SN: return DXGI_FORMAT_R16G16_SNORM; + case SG_PIXELFORMAT_RG16UI: return DXGI_FORMAT_R16G16_UINT; + case SG_PIXELFORMAT_RG16SI: return DXGI_FORMAT_R16G16_SINT; + case SG_PIXELFORMAT_RG16F: return DXGI_FORMAT_R16G16_FLOAT; + case SG_PIXELFORMAT_RGBA8: return DXGI_FORMAT_R8G8B8A8_UNORM; + case SG_PIXELFORMAT_RGBA8SN: return DXGI_FORMAT_R8G8B8A8_SNORM; + case SG_PIXELFORMAT_RGBA8UI: return DXGI_FORMAT_R8G8B8A8_UINT; + case SG_PIXELFORMAT_RGBA8SI: return DXGI_FORMAT_R8G8B8A8_SINT; + case SG_PIXELFORMAT_BGRA8: return DXGI_FORMAT_B8G8R8A8_UNORM; + case SG_PIXELFORMAT_RGB10A2: return DXGI_FORMAT_R10G10B10A2_UNORM; + case SG_PIXELFORMAT_RG11B10F: return DXGI_FORMAT_R11G11B10_FLOAT; + case SG_PIXELFORMAT_RG32UI: return DXGI_FORMAT_R32G32_UINT; + case SG_PIXELFORMAT_RG32SI: return DXGI_FORMAT_R32G32_SINT; + case SG_PIXELFORMAT_RG32F: return DXGI_FORMAT_R32G32_FLOAT; + case SG_PIXELFORMAT_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM; + case SG_PIXELFORMAT_RGBA16SN: return DXGI_FORMAT_R16G16B16A16_SNORM; + case SG_PIXELFORMAT_RGBA16UI: return DXGI_FORMAT_R16G16B16A16_UINT; + case SG_PIXELFORMAT_RGBA16SI: return DXGI_FORMAT_R16G16B16A16_SINT; + case SG_PIXELFORMAT_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case SG_PIXELFORMAT_RGBA32UI: return DXGI_FORMAT_R32G32B32A32_UINT; + case SG_PIXELFORMAT_RGBA32SI: return DXGI_FORMAT_R32G32B32A32_SINT; + case SG_PIXELFORMAT_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case SG_PIXELFORMAT_DEPTH: return DXGI_FORMAT_D32_FLOAT; + case SG_PIXELFORMAT_DEPTH_STENCIL: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case SG_PIXELFORMAT_BC1_RGBA: return DXGI_FORMAT_BC1_UNORM; + case SG_PIXELFORMAT_BC2_RGBA: return DXGI_FORMAT_BC2_UNORM; + case SG_PIXELFORMAT_BC3_RGBA: return DXGI_FORMAT_BC3_UNORM; + case SG_PIXELFORMAT_BC4_R: return DXGI_FORMAT_BC4_UNORM; + case SG_PIXELFORMAT_BC4_RSN: return DXGI_FORMAT_BC4_SNORM; + case SG_PIXELFORMAT_BC5_RG: return DXGI_FORMAT_BC5_UNORM; + case SG_PIXELFORMAT_BC5_RGSN: return DXGI_FORMAT_BC5_SNORM; + case SG_PIXELFORMAT_BC6H_RGBF: return DXGI_FORMAT_BC6H_SF16; + case SG_PIXELFORMAT_BC6H_RGBUF: return DXGI_FORMAT_BC6H_UF16; + case SG_PIXELFORMAT_BC7_RGBA: return DXGI_FORMAT_BC7_UNORM; + default: return DXGI_FORMAT_UNKNOWN; + }; +} + +_SOKOL_PRIVATE D3D11_PRIMITIVE_TOPOLOGY _sg_d3d11_primitive_topology(sg_primitive_type prim_type) { + switch (prim_type) { + case SG_PRIMITIVETYPE_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + case SG_PRIMITIVETYPE_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + case SG_PRIMITIVETYPE_LINE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; + case SG_PRIMITIVETYPE_TRIANGLES: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + default: SOKOL_UNREACHABLE; return (D3D11_PRIMITIVE_TOPOLOGY) 0; + } +} + +_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_index_format(sg_index_type index_type) { + switch (index_type) { + case SG_INDEXTYPE_NONE: return DXGI_FORMAT_UNKNOWN; + case SG_INDEXTYPE_UINT16: return DXGI_FORMAT_R16_UINT; + case SG_INDEXTYPE_UINT32: return DXGI_FORMAT_R32_UINT; + default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0; + } +} + +_SOKOL_PRIVATE D3D11_FILTER _sg_d3d11_filter(sg_filter min_f, sg_filter mag_f, uint32_t max_anisotropy) { + if (max_anisotropy > 1) { + return D3D11_FILTER_ANISOTROPIC; + } + else if (mag_f == SG_FILTER_NEAREST) { + switch (min_f) { + case SG_FILTER_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + return D3D11_FILTER_MIN_MAG_MIP_POINT; + case SG_FILTER_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + default: + SOKOL_UNREACHABLE; break; + } + } + else if (mag_f == SG_FILTER_LINEAR) { + switch (min_f) { + case SG_FILTER_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + case SG_FILTER_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return D3D11_FILTER_MIN_MAG_MIP_LINEAR; + default: + SOKOL_UNREACHABLE; break; + } + } + /* invalid value for mag filter */ + SOKOL_UNREACHABLE; + return D3D11_FILTER_MIN_MAG_MIP_POINT; +} + +_SOKOL_PRIVATE D3D11_TEXTURE_ADDRESS_MODE _sg_d3d11_address_mode(sg_wrap m) { + switch (m) { + case SG_WRAP_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; + case SG_WRAP_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; + case SG_WRAP_CLAMP_TO_BORDER: return D3D11_TEXTURE_ADDRESS_BORDER; + case SG_WRAP_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; + default: SOKOL_UNREACHABLE; return (D3D11_TEXTURE_ADDRESS_MODE) 0; + } +} + +_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_vertex_format(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case SG_VERTEXFORMAT_FLOAT2: return DXGI_FORMAT_R32G32_FLOAT; + case SG_VERTEXFORMAT_FLOAT3: return DXGI_FORMAT_R32G32B32_FLOAT; + case SG_VERTEXFORMAT_FLOAT4: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case SG_VERTEXFORMAT_BYTE4: return DXGI_FORMAT_R8G8B8A8_SINT; + case SG_VERTEXFORMAT_BYTE4N: return DXGI_FORMAT_R8G8B8A8_SNORM; + case SG_VERTEXFORMAT_UBYTE4: return DXGI_FORMAT_R8G8B8A8_UINT; + case SG_VERTEXFORMAT_UBYTE4N: return DXGI_FORMAT_R8G8B8A8_UNORM; + case SG_VERTEXFORMAT_SHORT2: return DXGI_FORMAT_R16G16_SINT; + case SG_VERTEXFORMAT_SHORT2N: return DXGI_FORMAT_R16G16_SNORM; + case SG_VERTEXFORMAT_USHORT2N: return DXGI_FORMAT_R16G16_UNORM; + case SG_VERTEXFORMAT_SHORT4: return DXGI_FORMAT_R16G16B16A16_SINT; + case SG_VERTEXFORMAT_SHORT4N: return DXGI_FORMAT_R16G16B16A16_SNORM; + case SG_VERTEXFORMAT_USHORT4N: return DXGI_FORMAT_R16G16B16A16_UNORM; + case SG_VERTEXFORMAT_UINT10_N2: return DXGI_FORMAT_R10G10B10A2_UNORM; + default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0; + } +} + +_SOKOL_PRIVATE D3D11_INPUT_CLASSIFICATION _sg_d3d11_input_classification(sg_vertex_step step) { + switch (step) { + case SG_VERTEXSTEP_PER_VERTEX: return D3D11_INPUT_PER_VERTEX_DATA; + case SG_VERTEXSTEP_PER_INSTANCE: return D3D11_INPUT_PER_INSTANCE_DATA; + default: SOKOL_UNREACHABLE; return (D3D11_INPUT_CLASSIFICATION) 0; + } +} + +_SOKOL_PRIVATE D3D11_CULL_MODE _sg_d3d11_cull_mode(sg_cull_mode m) { + switch (m) { + case SG_CULLMODE_NONE: return D3D11_CULL_NONE; + case SG_CULLMODE_FRONT: return D3D11_CULL_FRONT; + case SG_CULLMODE_BACK: return D3D11_CULL_BACK; + default: SOKOL_UNREACHABLE; return (D3D11_CULL_MODE) 0; + } +} + +_SOKOL_PRIVATE D3D11_COMPARISON_FUNC _sg_d3d11_compare_func(sg_compare_func f) { + switch (f) { + case SG_COMPAREFUNC_NEVER: return D3D11_COMPARISON_NEVER; + case SG_COMPAREFUNC_LESS: return D3D11_COMPARISON_LESS; + case SG_COMPAREFUNC_EQUAL: return D3D11_COMPARISON_EQUAL; + case SG_COMPAREFUNC_LESS_EQUAL: return D3D11_COMPARISON_LESS_EQUAL; + case SG_COMPAREFUNC_GREATER: return D3D11_COMPARISON_GREATER; + case SG_COMPAREFUNC_NOT_EQUAL: return D3D11_COMPARISON_NOT_EQUAL; + case SG_COMPAREFUNC_GREATER_EQUAL: return D3D11_COMPARISON_GREATER_EQUAL; + case SG_COMPAREFUNC_ALWAYS: return D3D11_COMPARISON_ALWAYS; + default: SOKOL_UNREACHABLE; return (D3D11_COMPARISON_FUNC) 0; + } +} + +_SOKOL_PRIVATE D3D11_STENCIL_OP _sg_d3d11_stencil_op(sg_stencil_op op) { + switch (op) { + case SG_STENCILOP_KEEP: return D3D11_STENCIL_OP_KEEP; + case SG_STENCILOP_ZERO: return D3D11_STENCIL_OP_ZERO; + case SG_STENCILOP_REPLACE: return D3D11_STENCIL_OP_REPLACE; + case SG_STENCILOP_INCR_CLAMP: return D3D11_STENCIL_OP_INCR_SAT; + case SG_STENCILOP_DECR_CLAMP: return D3D11_STENCIL_OP_DECR_SAT; + case SG_STENCILOP_INVERT: return D3D11_STENCIL_OP_INVERT; + case SG_STENCILOP_INCR_WRAP: return D3D11_STENCIL_OP_INCR; + case SG_STENCILOP_DECR_WRAP: return D3D11_STENCIL_OP_DECR; + default: SOKOL_UNREACHABLE; return (D3D11_STENCIL_OP) 0; + } +} + +_SOKOL_PRIVATE D3D11_BLEND _sg_d3d11_blend_factor(sg_blend_factor f) { + switch (f) { + case SG_BLENDFACTOR_ZERO: return D3D11_BLEND_ZERO; + case SG_BLENDFACTOR_ONE: return D3D11_BLEND_ONE; + case SG_BLENDFACTOR_SRC_COLOR: return D3D11_BLEND_SRC_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return D3D11_BLEND_INV_SRC_COLOR; + case SG_BLENDFACTOR_SRC_ALPHA: return D3D11_BLEND_SRC_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return D3D11_BLEND_INV_SRC_ALPHA; + case SG_BLENDFACTOR_DST_COLOR: return D3D11_BLEND_DEST_COLOR; + case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return D3D11_BLEND_INV_DEST_COLOR; + case SG_BLENDFACTOR_DST_ALPHA: return D3D11_BLEND_DEST_ALPHA; + case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA; + case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return D3D11_BLEND_SRC_ALPHA_SAT; + case SG_BLENDFACTOR_BLEND_COLOR: return D3D11_BLEND_BLEND_FACTOR; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return D3D11_BLEND_INV_BLEND_FACTOR; + case SG_BLENDFACTOR_BLEND_ALPHA: return D3D11_BLEND_BLEND_FACTOR; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return D3D11_BLEND_INV_BLEND_FACTOR; + default: SOKOL_UNREACHABLE; return (D3D11_BLEND) 0; + } +} + +_SOKOL_PRIVATE D3D11_BLEND_OP _sg_d3d11_blend_op(sg_blend_op op) { + switch (op) { + case SG_BLENDOP_ADD: return D3D11_BLEND_OP_ADD; + case SG_BLENDOP_SUBTRACT: return D3D11_BLEND_OP_SUBTRACT; + case SG_BLENDOP_REVERSE_SUBTRACT: return D3D11_BLEND_OP_REV_SUBTRACT; + default: SOKOL_UNREACHABLE; return (D3D11_BLEND_OP) 0; + } +} + +_SOKOL_PRIVATE UINT8 _sg_d3d11_color_write_mask(sg_color_mask m) { + UINT8 res = 0; + if (m & SG_COLORMASK_R) { + res |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (m & SG_COLORMASK_G) { + res |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (m & SG_COLORMASK_B) { + res |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (m & SG_COLORMASK_A) { + res |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return res; +} + +/* see: https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-limits#resource-limits-for-feature-level-11-hardware */ +_SOKOL_PRIVATE void _sg_d3d11_init_caps(void) { + _sg.backend = SG_BACKEND_D3D11; + + _sg.features.instancing = true; + _sg.features.origin_top_left = true; + _sg.features.multiple_render_targets = true; + _sg.features.msaa_render_targets = true; + _sg.features.imagetype_3d = true; + _sg.features.imagetype_array = true; + _sg.features.image_clamp_to_border = true; + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; + + _sg.limits.max_image_size_2d = 16 * 1024; + _sg.limits.max_image_size_cube = 16 * 1024; + _sg.limits.max_image_size_3d = 2 * 1024; + _sg.limits.max_image_size_array = 16 * 1024; + _sg.limits.max_image_array_layers = 2 * 1024; + _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; + + /* see: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_format_support */ + for (int fmt = (SG_PIXELFORMAT_NONE+1); fmt < _SG_PIXELFORMAT_NUM; fmt++) { + UINT dxgi_fmt_caps = 0; + const DXGI_FORMAT dxgi_fmt = _sg_d3d11_pixel_format((sg_pixel_format)fmt); + if (dxgi_fmt != DXGI_FORMAT_UNKNOWN) { + HRESULT hr = _sg_d3d11_CheckFormatSupport(_sg.d3d11.dev, dxgi_fmt, &dxgi_fmt_caps); + SOKOL_ASSERT(SUCCEEDED(hr) || (E_FAIL == hr)); + if (!SUCCEEDED(hr)) { + dxgi_fmt_caps = 0; + } + } + sg_pixelformat_info* info = &_sg.formats[fmt]; + info->sample = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_TEXTURE2D); + info->filter = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE); + info->render = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + info->blend = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_BLENDABLE); + info->msaa = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET); + info->depth = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); + if (info->depth) { + info->render = true; + } + } +} + +_SOKOL_PRIVATE void _sg_d3d11_setup_backend(const sg_desc* desc) { + /* assume _sg.d3d11 already is zero-initialized */ + SOKOL_ASSERT(desc); + SOKOL_ASSERT(desc->context.d3d11.device); + SOKOL_ASSERT(desc->context.d3d11.device_context); + SOKOL_ASSERT(desc->context.d3d11.render_target_view_cb || desc->context.d3d11.render_target_view_userdata_cb); + SOKOL_ASSERT(desc->context.d3d11.depth_stencil_view_cb || desc->context.d3d11.depth_stencil_view_userdata_cb); + _sg.d3d11.valid = true; + _sg.d3d11.dev = (ID3D11Device*) desc->context.d3d11.device; + _sg.d3d11.ctx = (ID3D11DeviceContext*) desc->context.d3d11.device_context; + _sg.d3d11.rtv_cb = desc->context.d3d11.render_target_view_cb; + _sg.d3d11.rtv_userdata_cb = desc->context.d3d11.render_target_view_userdata_cb; + _sg.d3d11.dsv_cb = desc->context.d3d11.depth_stencil_view_cb; + _sg.d3d11.dsv_userdata_cb = desc->context.d3d11.depth_stencil_view_userdata_cb; + _sg.d3d11.user_data = desc->context.d3d11.user_data; + _sg_d3d11_init_caps(); +} + +_SOKOL_PRIVATE void _sg_d3d11_discard_backend(void) { + SOKOL_ASSERT(_sg.d3d11.valid); + _sg.d3d11.valid = false; +} + +_SOKOL_PRIVATE void _sg_d3d11_clear_state(void) { + /* clear all the device context state, so that resource refs don't keep stuck in the d3d device context */ + _sg_d3d11_ClearState(_sg.d3d11.ctx); +} + +_SOKOL_PRIVATE void _sg_d3d11_reset_state_cache(void) { + /* just clear the d3d11 device context state */ + _sg_d3d11_clear_state(); +} + +_SOKOL_PRIVATE void _sg_d3d11_activate_context(_sg_context_t* ctx) { + _SOKOL_UNUSED(ctx); + _sg_d3d11_clear_state(); +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + /* empty */ +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf && desc); + SOKOL_ASSERT(!buf->d3d11.buf); + _sg_buffer_common_init(&buf->cmn, desc); + const bool injected = (0 != desc->d3d11_buffer); + if (injected) { + buf->d3d11.buf = (ID3D11Buffer*) desc->d3d11_buffer; + _sg_d3d11_AddRef(buf->d3d11.buf); + } + else { + D3D11_BUFFER_DESC d3d11_desc; + memset(&d3d11_desc, 0, sizeof(d3d11_desc)); + d3d11_desc.ByteWidth = (UINT)buf->cmn.size; + d3d11_desc.Usage = _sg_d3d11_usage(buf->cmn.usage); + d3d11_desc.BindFlags = buf->cmn.type == SG_BUFFERTYPE_VERTEXBUFFER ? D3D11_BIND_VERTEX_BUFFER : D3D11_BIND_INDEX_BUFFER; + d3d11_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage); + D3D11_SUBRESOURCE_DATA* init_data_ptr = 0; + D3D11_SUBRESOURCE_DATA init_data; + memset(&init_data, 0, sizeof(init_data)); + if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { + SOKOL_ASSERT(desc->data.ptr); + init_data.pSysMem = desc->data.ptr; + init_data_ptr = &init_data; + } + HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf); + if (!(SUCCEEDED(hr) && buf->d3d11.buf)) { + SOKOL_LOG("failed to create D3D11 buffer\n"); + return SG_RESOURCESTATE_FAILED; + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + if (buf->d3d11.buf) { + _sg_d3d11_Release(buf->d3d11.buf); + } +} + +_SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_data* data) { + const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; + const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; + int subres_index = 0; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int slice_index = 0; slice_index < num_slices; slice_index++) { + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, subres_index++) { + SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS)); + D3D11_SUBRESOURCE_DATA* subres_data = &_sg.d3d11.subres_data[subres_index]; + const int mip_width = ((img->cmn.width>>mip_index)>0) ? img->cmn.width>>mip_index : 1; + const int mip_height = ((img->cmn.height>>mip_index)>0) ? img->cmn.height>>mip_index : 1; + const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); + const size_t slice_size = subimg_data->size / (size_t)num_slices; + const size_t slice_offset = slice_size * (size_t)slice_index; + const uint8_t* ptr = (const uint8_t*) subimg_data->ptr; + subres_data->pSysMem = ptr + slice_offset; + subres_data->SysMemPitch = (UINT)_sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + if (img->cmn.type == SG_IMAGETYPE_3D) { + /* FIXME? const int mip_depth = ((img->depth>>mip_index)>0) ? img->depth>>mip_index : 1; */ + subres_data->SysMemSlicePitch = (UINT)_sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); + } + else { + subres_data->SysMemSlicePitch = 0; + } + } + } + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + SOKOL_ASSERT(!img->d3d11.tex2d && !img->d3d11.tex3d && !img->d3d11.texds && !img->d3d11.texmsaa); + SOKOL_ASSERT(!img->d3d11.srv && !img->d3d11.smp); + HRESULT hr; + + _sg_image_common_init(&img->cmn, desc); + const bool injected = (0 != desc->d3d11_texture) || (0 != desc->d3d11_shader_resource_view); + const bool msaa = (img->cmn.sample_count > 1); + img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); + + /* special case depth-stencil buffer? */ + if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) { + /* create only a depth-texture */ + SOKOL_ASSERT(!injected); + if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { + SOKOL_LOG("trying to create a D3D11 depth-texture with unsupported pixel format\n"); + return SG_RESOURCESTATE_FAILED; + } + D3D11_TEXTURE2D_DESC d3d11_desc; + memset(&d3d11_desc, 0, sizeof(d3d11_desc)); + d3d11_desc.Width = (UINT)img->cmn.width; + d3d11_desc.Height = (UINT)img->cmn.height; + d3d11_desc.MipLevels = 1; + d3d11_desc.ArraySize = 1; + d3d11_desc.Format = img->d3d11.format; + d3d11_desc.Usage = D3D11_USAGE_DEFAULT; + d3d11_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + d3d11_desc.SampleDesc.Count = (UINT)img->cmn.sample_count; + d3d11_desc.SampleDesc.Quality = (UINT) (msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0); + hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_desc, NULL, &img->d3d11.texds); + if (!(SUCCEEDED(hr) && img->d3d11.texds)) { + SOKOL_LOG("failed to create D3D11 texture 2D\n"); + return SG_RESOURCESTATE_FAILED; + } + } + else { + /* create (or inject) color texture and shader-resource-view */ + + /* prepare initial content pointers */ + D3D11_SUBRESOURCE_DATA* init_data = 0; + if (!injected && (img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { + _sg_d3d11_fill_subres_data(img, &desc->data); + init_data = _sg.d3d11.subres_data; + } + if (img->cmn.type != SG_IMAGETYPE_3D) { + /* 2D-, cube- or array-texture */ + /* if this is an MSAA render target, the following texture will be the 'resolve-texture' */ + + /* first check for injected texture and/or resource view */ + if (injected) { + img->d3d11.tex2d = (ID3D11Texture2D*) desc->d3d11_texture; + img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; + if (img->d3d11.tex2d) { + _sg_d3d11_AddRef(img->d3d11.tex2d); + } + else { + /* if only a shader-resource-view was provided, but no texture, lookup + the texture from the shader-resource-view, this also bumps the refcount + */ + SOKOL_ASSERT(img->d3d11.srv); + _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex2d); + SOKOL_ASSERT(img->d3d11.tex2d); + } + if (img->d3d11.srv) { + _sg_d3d11_AddRef(img->d3d11.srv); + } + } + + /* if not injected, create texture */ + if (0 == img->d3d11.tex2d) { + D3D11_TEXTURE2D_DESC d3d11_tex_desc; + memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; + d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; + switch (img->cmn.type) { + case SG_IMAGETYPE_ARRAY: d3d11_tex_desc.ArraySize = (UINT)img->cmn.num_slices; break; + case SG_IMAGETYPE_CUBE: d3d11_tex_desc.ArraySize = 6; break; + default: d3d11_tex_desc.ArraySize = 1; break; + } + d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + d3d11_tex_desc.Format = img->d3d11.format; + if (img->cmn.render_target) { + d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; + if (!msaa) { + d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + } + d3d11_tex_desc.CPUAccessFlags = 0; + } + else { + d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); + d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); + } + if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { + /* trying to create a texture format that's not supported by D3D */ + SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + return SG_RESOURCESTATE_FAILED; + } + d3d11_tex_desc.SampleDesc.Count = 1; + d3d11_tex_desc.SampleDesc.Quality = 0; + d3d11_tex_desc.MiscFlags = (img->cmn.type == SG_IMAGETYPE_CUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; + + hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex2d); + if (!(SUCCEEDED(hr) && img->d3d11.tex2d)) { + SOKOL_LOG("failed to create D3D11 texture 2D\n"); + return SG_RESOURCESTATE_FAILED; + } + } + + /* ...and similar, if not injected, create shader-resource-view */ + if (0 == img->d3d11.srv) { + D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; + memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); + d3d11_srv_desc.Format = img->d3d11.format; + switch (img->cmn.type) { + case SG_IMAGETYPE_2D: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + d3d11_srv_desc.Texture2D.MipLevels = (UINT)img->cmn.num_mipmaps; + break; + case SG_IMAGETYPE_CUBE: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + d3d11_srv_desc.TextureCube.MipLevels = (UINT)img->cmn.num_mipmaps; + break; + case SG_IMAGETYPE_ARRAY: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + d3d11_srv_desc.Texture2DArray.MipLevels = (UINT)img->cmn.num_mipmaps; + d3d11_srv_desc.Texture2DArray.ArraySize = (UINT)img->cmn.num_slices; + break; + default: + SOKOL_UNREACHABLE; break; + } + hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv); + if (!(SUCCEEDED(hr) && img->d3d11.srv)) { + SOKOL_LOG("failed to create D3D11 resource view\n"); + return SG_RESOURCESTATE_FAILED; + } + } + } + else { + /* 3D texture - same procedure, first check if injected, than create non-injected */ + if (injected) { + img->d3d11.tex3d = (ID3D11Texture3D*) desc->d3d11_texture; + img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; + if (img->d3d11.tex3d) { + _sg_d3d11_AddRef(img->d3d11.tex3d); + } + else { + SOKOL_ASSERT(img->d3d11.srv); + _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex3d); + SOKOL_ASSERT(img->d3d11.tex3d); + } + if (img->d3d11.srv) { + _sg_d3d11_AddRef(img->d3d11.srv); + } + } + + if (0 == img->d3d11.tex3d) { + D3D11_TEXTURE3D_DESC d3d11_tex_desc; + memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; + d3d11_tex_desc.Depth = (UINT)img->cmn.num_slices; + d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; + d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + d3d11_tex_desc.Format = img->d3d11.format; + if (img->cmn.render_target) { + d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; + if (!msaa) { + d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + } + d3d11_tex_desc.CPUAccessFlags = 0; + } + else { + d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); + d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); + } + if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { + /* trying to create a texture format that's not supported by D3D */ + SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + return SG_RESOURCESTATE_FAILED; + } + hr = _sg_d3d11_CreateTexture3D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex3d); + if (!(SUCCEEDED(hr) && img->d3d11.tex3d)) { + SOKOL_LOG("failed to create D3D11 texture 3D\n"); + return SG_RESOURCESTATE_FAILED; + } + } + + if (0 == img->d3d11.srv) { + D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; + memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); + d3d11_srv_desc.Format = img->d3d11.format; + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + d3d11_srv_desc.Texture3D.MipLevels = (UINT)img->cmn.num_mipmaps; + hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex3d, &d3d11_srv_desc, &img->d3d11.srv); + if (!(SUCCEEDED(hr) && img->d3d11.srv)) { + SOKOL_LOG("failed to create D3D11 resource view\n"); + return SG_RESOURCESTATE_FAILED; + } + } + } + + /* also need to create a separate MSAA render target texture? */ + if (msaa) { + D3D11_TEXTURE2D_DESC d3d11_tex_desc; + memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; + d3d11_tex_desc.MipLevels = 1; + d3d11_tex_desc.ArraySize = 1; + d3d11_tex_desc.Format = img->d3d11.format; + d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; + d3d11_tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; + d3d11_tex_desc.CPUAccessFlags = 0; + d3d11_tex_desc.SampleDesc.Count = (UINT)img->cmn.sample_count; + d3d11_tex_desc.SampleDesc.Quality = (UINT)D3D11_STANDARD_MULTISAMPLE_PATTERN; + hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, NULL, &img->d3d11.texmsaa); + if (!(SUCCEEDED(hr) && img->d3d11.texmsaa)) { + SOKOL_LOG("failed to create D3D11 texture 2D\n"); + return SG_RESOURCESTATE_FAILED; + } + } + + /* sampler state object, note D3D11 implements an internal shared-pool for sampler objects */ + D3D11_SAMPLER_DESC d3d11_smp_desc; + memset(&d3d11_smp_desc, 0, sizeof(d3d11_smp_desc)); + d3d11_smp_desc.Filter = _sg_d3d11_filter(img->cmn.min_filter, img->cmn.mag_filter, img->cmn.max_anisotropy); + d3d11_smp_desc.AddressU = _sg_d3d11_address_mode(img->cmn.wrap_u); + d3d11_smp_desc.AddressV = _sg_d3d11_address_mode(img->cmn.wrap_v); + d3d11_smp_desc.AddressW = _sg_d3d11_address_mode(img->cmn.wrap_w); + switch (img->cmn.border_color) { + case SG_BORDERCOLOR_TRANSPARENT_BLACK: + /* all 0.0f */ + break; + case SG_BORDERCOLOR_OPAQUE_WHITE: + for (int i = 0; i < 4; i++) { + d3d11_smp_desc.BorderColor[i] = 1.0f; + } + break; + default: + /* opaque black */ + d3d11_smp_desc.BorderColor[3] = 1.0f; + break; + } + d3d11_smp_desc.MaxAnisotropy = img->cmn.max_anisotropy; + d3d11_smp_desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + d3d11_smp_desc.MinLOD = desc->min_lod; + d3d11_smp_desc.MaxLOD = desc->max_lod; + hr = _sg_d3d11_CreateSamplerState(_sg.d3d11.dev, &d3d11_smp_desc, &img->d3d11.smp); + if (!(SUCCEEDED(hr) && img->d3d11.smp)) { + SOKOL_LOG("failed to create D3D11 sampler state\n"); + return SG_RESOURCESTATE_FAILED; + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + if (img->d3d11.tex2d) { + _sg_d3d11_Release(img->d3d11.tex2d); + } + if (img->d3d11.tex3d) { + _sg_d3d11_Release(img->d3d11.tex3d); + } + if (img->d3d11.texds) { + _sg_d3d11_Release(img->d3d11.texds); + } + if (img->d3d11.texmsaa) { + _sg_d3d11_Release(img->d3d11.texmsaa); + } + if (img->d3d11.srv) { + _sg_d3d11_Release(img->d3d11.srv); + } + if (img->d3d11.smp) { + _sg_d3d11_Release(img->d3d11.smp); + } +} + +_SOKOL_PRIVATE bool _sg_d3d11_load_d3dcompiler_dll(void) { + /* on UWP, don't do anything (not tested) */ + #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) + return true; + #else + /* load DLL on demand */ + if ((0 == _sg.d3d11.d3dcompiler_dll) && !_sg.d3d11.d3dcompiler_dll_load_failed) { + _sg.d3d11.d3dcompiler_dll = LoadLibraryA("d3dcompiler_47.dll"); + if (0 == _sg.d3d11.d3dcompiler_dll) { + /* don't attempt to load missing DLL in the future */ + SOKOL_LOG("failed to load d3dcompiler_47.dll!\n"); + _sg.d3d11.d3dcompiler_dll_load_failed = true; + return false; + } + /* look up function pointers */ + _sg.d3d11.D3DCompile_func = (pD3DCompile)(void*) GetProcAddress(_sg.d3d11.d3dcompiler_dll, "D3DCompile"); + SOKOL_ASSERT(_sg.d3d11.D3DCompile_func); + } + return 0 != _sg.d3d11.d3dcompiler_dll; + #endif +} + +#if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +#define _sg_d3d11_D3DCompile D3DCompile +#else +#define _sg_d3d11_D3DCompile _sg.d3d11.D3DCompile_func +#endif + +_SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* stage_desc) { + if (!_sg_d3d11_load_d3dcompiler_dll()) { + return NULL; + } + SOKOL_ASSERT(stage_desc->d3d11_target); + ID3DBlob* output = NULL; + ID3DBlob* errors_or_warnings = NULL; + HRESULT hr = _sg_d3d11_D3DCompile( + stage_desc->source, /* pSrcData */ + strlen(stage_desc->source), /* SrcDataSize */ + NULL, /* pSourceName */ + NULL, /* pDefines */ + NULL, /* pInclude */ + stage_desc->entry ? stage_desc->entry : "main", /* pEntryPoint */ + stage_desc->d3d11_target, /* pTarget (vs_5_0 or ps_5_0) */ + D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR | D3DCOMPILE_OPTIMIZATION_LEVEL3, /* Flags1 */ + 0, /* Flags2 */ + &output, /* ppCode */ + &errors_or_warnings); /* ppErrorMsgs */ + if (errors_or_warnings) { + SOKOL_LOG((LPCSTR)_sg_d3d11_GetBufferPointer(errors_or_warnings)); + _sg_d3d11_Release(errors_or_warnings); errors_or_warnings = NULL; + } + if (FAILED(hr)) { + /* just in case, usually output is NULL here */ + if (output) { + _sg_d3d11_Release(output); + output = NULL; + } + } + return output; +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + SOKOL_ASSERT(!shd->d3d11.vs && !shd->d3d11.fs && !shd->d3d11.vs_blob); + HRESULT hr; + + _sg_shader_common_init(&shd->cmn, desc); + + /* copy vertex attribute semantic names and indices */ + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + _sg_strcpy(&shd->d3d11.attrs[i].sem_name, desc->attrs[i].sem_name); + shd->d3d11.attrs[i].sem_index = desc->attrs[i].sem_index; + } + + /* shader stage uniform blocks and image slots */ + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; + _sg_d3d11_shader_stage_t* d3d11_stage = &shd->d3d11.stage[stage_index]; + for (int ub_index = 0; ub_index < cmn_stage->num_uniform_blocks; ub_index++) { + const _sg_uniform_block_t* ub = &cmn_stage->uniform_blocks[ub_index]; + + /* create a D3D constant buffer for each uniform block */ + SOKOL_ASSERT(0 == d3d11_stage->cbufs[ub_index]); + D3D11_BUFFER_DESC cb_desc; + memset(&cb_desc, 0, sizeof(cb_desc)); + cb_desc.ByteWidth = (UINT)_sg_roundup((int)ub->size, 16); + cb_desc.Usage = D3D11_USAGE_DEFAULT; + cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &cb_desc, NULL, &d3d11_stage->cbufs[ub_index]); + if (!(SUCCEEDED(hr) && d3d11_stage->cbufs[ub_index])) { + SOKOL_LOG("failed to create D3D11 buffer\n"); + return SG_RESOURCESTATE_FAILED; + } + } + } + + const void* vs_ptr = 0, *fs_ptr = 0; + SIZE_T vs_length = 0, fs_length = 0; + ID3DBlob* vs_blob = 0, *fs_blob = 0; + if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { + /* create from shader byte code */ + vs_ptr = desc->vs.bytecode.ptr; + fs_ptr = desc->fs.bytecode.ptr; + vs_length = desc->vs.bytecode.size; + fs_length = desc->fs.bytecode.size; + } + else { + /* compile from shader source code */ + vs_blob = _sg_d3d11_compile_shader(&desc->vs); + fs_blob = _sg_d3d11_compile_shader(&desc->fs); + if (vs_blob && fs_blob) { + vs_ptr = _sg_d3d11_GetBufferPointer(vs_blob); + vs_length = _sg_d3d11_GetBufferSize(vs_blob); + fs_ptr = _sg_d3d11_GetBufferPointer(fs_blob); + fs_length = _sg_d3d11_GetBufferSize(fs_blob); + } + } + sg_resource_state result = SG_RESOURCESTATE_FAILED; + if (vs_ptr && fs_ptr && (vs_length > 0) && (fs_length > 0)) { + /* create the D3D vertex- and pixel-shader objects */ + hr = _sg_d3d11_CreateVertexShader(_sg.d3d11.dev, vs_ptr, vs_length, NULL, &shd->d3d11.vs); + bool vs_succeeded = SUCCEEDED(hr) && shd->d3d11.vs; + hr = _sg_d3d11_CreatePixelShader(_sg.d3d11.dev, fs_ptr, fs_length, NULL, &shd->d3d11.fs); + bool fs_succeeded = SUCCEEDED(hr) && shd->d3d11.fs; + + /* need to store the vertex shader byte code, this is needed later in sg_create_pipeline */ + if (vs_succeeded && fs_succeeded) { + shd->d3d11.vs_blob_length = vs_length; + shd->d3d11.vs_blob = SOKOL_MALLOC((size_t)vs_length); + SOKOL_ASSERT(shd->d3d11.vs_blob); + memcpy(shd->d3d11.vs_blob, vs_ptr, vs_length); + result = SG_RESOURCESTATE_VALID; + } + } + if (vs_blob) { + _sg_d3d11_Release(vs_blob); vs_blob = 0; + } + if (fs_blob) { + _sg_d3d11_Release(fs_blob); fs_blob = 0; + } + return result; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + if (shd->d3d11.vs) { + _sg_d3d11_Release(shd->d3d11.vs); + } + if (shd->d3d11.fs) { + _sg_d3d11_Release(shd->d3d11.fs); + } + if (shd->d3d11.vs_blob) { + SOKOL_FREE(shd->d3d11.vs_blob); + } + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; + _sg_d3d11_shader_stage_t* d3d11_stage = &shd->d3d11.stage[stage_index]; + for (int ub_index = 0; ub_index < cmn_stage->num_uniform_blocks; ub_index++) { + if (d3d11_stage->cbufs[ub_index]) { + _sg_d3d11_Release(d3d11_stage->cbufs[ub_index]); + } + } + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && shd && desc); + SOKOL_ASSERT(desc->shader.id == shd->slot.id); + SOKOL_ASSERT(shd->slot.state == SG_RESOURCESTATE_VALID); + SOKOL_ASSERT(shd->d3d11.vs_blob && shd->d3d11.vs_blob_length > 0); + SOKOL_ASSERT(!pip->d3d11.il && !pip->d3d11.rs && !pip->d3d11.dss && !pip->d3d11.bs); + + pip->shader = shd; + _sg_pipeline_common_init(&pip->cmn, desc); + pip->d3d11.index_format = _sg_d3d11_index_format(pip->cmn.index_type); + pip->d3d11.topology = _sg_d3d11_primitive_topology(desc->primitive_type); + pip->d3d11.stencil_ref = desc->stencil.ref; + + /* create input layout object */ + HRESULT hr; + D3D11_INPUT_ELEMENT_DESC d3d11_comps[SG_MAX_VERTEX_ATTRIBUTES]; + memset(d3d11_comps, 0, sizeof(d3d11_comps)); + int attr_index = 0; + for (; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[a_desc->buffer_index]; + const sg_vertex_step step_func = l_desc->step_func; + const int step_rate = l_desc->step_rate; + D3D11_INPUT_ELEMENT_DESC* d3d11_comp = &d3d11_comps[attr_index]; + d3d11_comp->SemanticName = _sg_strptr(&shd->d3d11.attrs[attr_index].sem_name); + d3d11_comp->SemanticIndex = (UINT)shd->d3d11.attrs[attr_index].sem_index; + d3d11_comp->Format = _sg_d3d11_vertex_format(a_desc->format); + d3d11_comp->InputSlot = (UINT)a_desc->buffer_index; + d3d11_comp->AlignedByteOffset = (UINT)a_desc->offset; + d3d11_comp->InputSlotClass = _sg_d3d11_input_classification(step_func); + if (SG_VERTEXSTEP_PER_INSTANCE == step_func) { + d3d11_comp->InstanceDataStepRate = (UINT)step_rate; + pip->cmn.use_instanced_draw = true; + } + pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; + } + for (int layout_index = 0; layout_index < SG_MAX_SHADERSTAGE_BUFFERS; layout_index++) { + if (pip->cmn.vertex_layout_valid[layout_index]) { + const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[layout_index]; + SOKOL_ASSERT(l_desc->stride > 0); + pip->d3d11.vb_strides[layout_index] = (UINT)l_desc->stride; + } + else { + pip->d3d11.vb_strides[layout_index] = 0; + } + } + hr = _sg_d3d11_CreateInputLayout(_sg.d3d11.dev, + d3d11_comps, /* pInputElementDesc */ + (UINT)attr_index, /* NumElements */ + shd->d3d11.vs_blob, /* pShaderByteCodeWithInputSignature */ + shd->d3d11.vs_blob_length, /* BytecodeLength */ + &pip->d3d11.il); + if (!(SUCCEEDED(hr) && pip->d3d11.il)) { + SOKOL_LOG("failed to create D3D11 input layout\n"); + return SG_RESOURCESTATE_FAILED; + } + + /* create rasterizer state */ + D3D11_RASTERIZER_DESC rs_desc; + memset(&rs_desc, 0, sizeof(rs_desc)); + rs_desc.FillMode = D3D11_FILL_SOLID; + rs_desc.CullMode = _sg_d3d11_cull_mode(desc->cull_mode); + rs_desc.FrontCounterClockwise = desc->face_winding == SG_FACEWINDING_CCW; + rs_desc.DepthBias = (INT) pip->cmn.depth_bias; + rs_desc.DepthBiasClamp = pip->cmn.depth_bias_clamp; + rs_desc.SlopeScaledDepthBias = pip->cmn.depth_bias_slope_scale; + rs_desc.DepthClipEnable = TRUE; + rs_desc.ScissorEnable = TRUE; + rs_desc.MultisampleEnable = desc->sample_count > 1; + rs_desc.AntialiasedLineEnable = FALSE; + hr = _sg_d3d11_CreateRasterizerState(_sg.d3d11.dev, &rs_desc, &pip->d3d11.rs); + if (!(SUCCEEDED(hr) && pip->d3d11.rs)) { + SOKOL_LOG("failed to create D3D11 rasterizer state\n"); + return SG_RESOURCESTATE_FAILED; + } + + /* create depth-stencil state */ + D3D11_DEPTH_STENCIL_DESC dss_desc; + memset(&dss_desc, 0, sizeof(dss_desc)); + dss_desc.DepthEnable = TRUE; + dss_desc.DepthWriteMask = desc->depth.write_enabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dss_desc.DepthFunc = _sg_d3d11_compare_func(desc->depth.compare); + dss_desc.StencilEnable = desc->stencil.enabled; + dss_desc.StencilReadMask = desc->stencil.read_mask; + dss_desc.StencilWriteMask = desc->stencil.write_mask; + const sg_stencil_face_state* sf = &desc->stencil.front; + dss_desc.FrontFace.StencilFailOp = _sg_d3d11_stencil_op(sf->fail_op); + dss_desc.FrontFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sf->depth_fail_op); + dss_desc.FrontFace.StencilPassOp = _sg_d3d11_stencil_op(sf->pass_op); + dss_desc.FrontFace.StencilFunc = _sg_d3d11_compare_func(sf->compare); + const sg_stencil_face_state* sb = &desc->stencil.back; + dss_desc.BackFace.StencilFailOp = _sg_d3d11_stencil_op(sb->fail_op); + dss_desc.BackFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sb->depth_fail_op); + dss_desc.BackFace.StencilPassOp = _sg_d3d11_stencil_op(sb->pass_op); + dss_desc.BackFace.StencilFunc = _sg_d3d11_compare_func(sb->compare); + hr = _sg_d3d11_CreateDepthStencilState(_sg.d3d11.dev, &dss_desc, &pip->d3d11.dss); + if (!(SUCCEEDED(hr) && pip->d3d11.dss)) { + SOKOL_LOG("failed to create D3D11 depth stencil state\n"); + return SG_RESOURCESTATE_FAILED; + } + + /* create blend state */ + D3D11_BLEND_DESC bs_desc; + memset(&bs_desc, 0, sizeof(bs_desc)); + bs_desc.AlphaToCoverageEnable = desc->alpha_to_coverage_enabled; + bs_desc.IndependentBlendEnable = TRUE; + { + int i = 0; + for (i = 0; i < desc->color_count; i++) { + const sg_blend_state* src = &desc->colors[i].blend; + D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; + dst->BlendEnable = src->enabled; + dst->SrcBlend = _sg_d3d11_blend_factor(src->src_factor_rgb); + dst->DestBlend = _sg_d3d11_blend_factor(src->dst_factor_rgb); + dst->BlendOp = _sg_d3d11_blend_op(src->op_rgb); + dst->SrcBlendAlpha = _sg_d3d11_blend_factor(src->src_factor_alpha); + dst->DestBlendAlpha = _sg_d3d11_blend_factor(src->dst_factor_alpha); + dst->BlendOpAlpha = _sg_d3d11_blend_op(src->op_alpha); + dst->RenderTargetWriteMask = _sg_d3d11_color_write_mask(desc->colors[i].write_mask); + } + for (; i < 8; i++) { + D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; + dst->BlendEnable = FALSE; + dst->SrcBlend = dst->SrcBlendAlpha = D3D11_BLEND_ONE; + dst->DestBlend = dst->DestBlendAlpha = D3D11_BLEND_ZERO; + dst->BlendOp = dst->BlendOpAlpha = D3D11_BLEND_OP_ADD; + dst->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + } + hr = _sg_d3d11_CreateBlendState(_sg.d3d11.dev, &bs_desc, &pip->d3d11.bs); + if (!(SUCCEEDED(hr) && pip->d3d11.bs)) { + SOKOL_LOG("failed to create D3D11 blend state\n"); + return SG_RESOURCESTATE_FAILED; + } + + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + if (pip == _sg.d3d11.cur_pipeline) { + _sg.d3d11.cur_pipeline = 0; + _sg.d3d11.cur_pipeline_id.id = SG_INVALID_ID; + } + if (pip->d3d11.il) { + _sg_d3d11_Release(pip->d3d11.il); + } + if (pip->d3d11.rs) { + _sg_d3d11_Release(pip->d3d11.rs); + } + if (pip->d3d11.dss) { + _sg_d3d11_Release(pip->d3d11.dss); + } + if (pip->d3d11.bs) { + _sg_d3d11_Release(pip->d3d11.bs); + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass && desc); + SOKOL_ASSERT(att_images && att_images[0]); + SOKOL_ASSERT(_sg.d3d11.dev); + + _sg_pass_common_init(&pass->cmn, desc); + + for (int i = 0; i < pass->cmn.num_color_atts; i++) { + const sg_pass_attachment_desc* att_desc = &desc->color_attachments[i]; + _SOKOL_UNUSED(att_desc); + SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); + _sg_image_t* att_img = att_images[i]; + SOKOL_ASSERT(att_img && (att_img->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_img->cmn.pixel_format)); + SOKOL_ASSERT(0 == pass->d3d11.color_atts[i].image); + pass->d3d11.color_atts[i].image = att_img; + + /* create D3D11 render-target-view */ + const _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + SOKOL_ASSERT(0 == pass->d3d11.color_atts[i].rtv); + ID3D11Resource* d3d11_res = 0; + const bool is_msaa = att_img->cmn.sample_count > 1; + D3D11_RENDER_TARGET_VIEW_DESC d3d11_rtv_desc; + memset(&d3d11_rtv_desc, 0, sizeof(d3d11_rtv_desc)); + d3d11_rtv_desc.Format = att_img->d3d11.format; + if ((att_img->cmn.type == SG_IMAGETYPE_2D) || is_msaa) { + if (is_msaa) { + d3d11_res = (ID3D11Resource*) att_img->d3d11.texmsaa; + d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + else { + d3d11_res = (ID3D11Resource*) att_img->d3d11.tex2d; + d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + d3d11_rtv_desc.Texture2D.MipSlice = (UINT)cmn_att->mip_level; + } + } + else if ((att_img->cmn.type == SG_IMAGETYPE_CUBE) || (att_img->cmn.type == SG_IMAGETYPE_ARRAY)) { + d3d11_res = (ID3D11Resource*) att_img->d3d11.tex2d; + d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + d3d11_rtv_desc.Texture2DArray.MipSlice = (UINT)cmn_att->mip_level; + d3d11_rtv_desc.Texture2DArray.FirstArraySlice = (UINT)cmn_att->slice; + d3d11_rtv_desc.Texture2DArray.ArraySize = 1; + } + else { + SOKOL_ASSERT(att_img->cmn.type == SG_IMAGETYPE_3D); + d3d11_res = (ID3D11Resource*) att_img->d3d11.tex3d; + d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + d3d11_rtv_desc.Texture3D.MipSlice = (UINT)cmn_att->mip_level; + d3d11_rtv_desc.Texture3D.FirstWSlice = (UINT)cmn_att->slice; + d3d11_rtv_desc.Texture3D.WSize = 1; + } + SOKOL_ASSERT(d3d11_res); + HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, d3d11_res, &d3d11_rtv_desc, &pass->d3d11.color_atts[i].rtv); + if (!(SUCCEEDED(hr) && pass->d3d11.color_atts[i].rtv)) { + SOKOL_LOG("failed to create D3D11 render target view\n"); + return SG_RESOURCESTATE_FAILED; + } + } + + /* optional depth-stencil image */ + SOKOL_ASSERT(0 == pass->d3d11.ds_att.image); + SOKOL_ASSERT(0 == pass->d3d11.ds_att.dsv); + if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { + const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; + const sg_pass_attachment_desc* att_desc = &desc->depth_stencil_attachment; + _SOKOL_UNUSED(att_desc); + _sg_image_t* att_img = att_images[ds_img_index]; + SOKOL_ASSERT(att_img && (att_img->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_img->cmn.pixel_format)); + SOKOL_ASSERT(0 == pass->d3d11.ds_att.image); + pass->d3d11.ds_att.image = att_img; + + /* create D3D11 depth-stencil-view */ + D3D11_DEPTH_STENCIL_VIEW_DESC d3d11_dsv_desc; + memset(&d3d11_dsv_desc, 0, sizeof(d3d11_dsv_desc)); + d3d11_dsv_desc.Format = att_img->d3d11.format; + const bool is_msaa = att_img->cmn.sample_count > 1; + if (is_msaa) { + d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } + else { + d3d11_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + } + ID3D11Resource* d3d11_res = (ID3D11Resource*) att_img->d3d11.texds; + SOKOL_ASSERT(d3d11_res); + HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, d3d11_res, &d3d11_dsv_desc, &pass->d3d11.ds_att.dsv); + if (!(SUCCEEDED(hr) && pass->d3d11.ds_att.dsv)) { + SOKOL_LOG("failed to create D3D11 depth stencil view\n"); + return SG_RESOURCESTATE_FAILED; + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_d3d11_destroy_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + SOKOL_ASSERT(pass != _sg.d3d11.cur_pass); + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (pass->d3d11.color_atts[i].rtv) { + _sg_d3d11_Release(pass->d3d11.color_atts[i].rtv); + } + } + if (pass->d3d11.ds_att.dsv) { + _sg_d3d11_Release(pass->d3d11.ds_att.dsv); + } +} + +_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_color_image(const _sg_pass_t* pass, int index) { + SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + /* NOTE: may return null */ + return pass->d3d11.color_atts[index].image; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_ds_image(const _sg_pass_t* pass) { + /* NOTE: may return null */ + SOKOL_ASSERT(pass); + return pass->d3d11.ds_att.image; +} + +_SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + SOKOL_ASSERT(action); + SOKOL_ASSERT(!_sg.d3d11.in_pass); + SOKOL_ASSERT(_sg.d3d11.rtv_cb || _sg.d3d11.rtv_userdata_cb); + SOKOL_ASSERT(_sg.d3d11.dsv_cb || _sg.d3d11.dsv_userdata_cb); + _sg.d3d11.in_pass = true; + _sg.d3d11.cur_width = w; + _sg.d3d11.cur_height = h; + if (pass) { + _sg.d3d11.cur_pass = pass; + _sg.d3d11.cur_pass_id.id = pass->slot.id; + _sg.d3d11.num_rtvs = 0; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.d3d11.cur_rtvs[i] = pass->d3d11.color_atts[i].rtv; + if (_sg.d3d11.cur_rtvs[i]) { + _sg.d3d11.num_rtvs++; + } + } + _sg.d3d11.cur_dsv = pass->d3d11.ds_att.dsv; + } + else { + /* render to default frame buffer */ + _sg.d3d11.cur_pass = 0; + _sg.d3d11.cur_pass_id.id = SG_INVALID_ID; + _sg.d3d11.num_rtvs = 1; + if (_sg.d3d11.rtv_cb) { + _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_cb(); + } + else { + _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_userdata_cb(_sg.d3d11.user_data); + } + for (int i = 1; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.d3d11.cur_rtvs[i] = 0; + } + if (_sg.d3d11.dsv_cb) { + _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_cb(); + } + else { + _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_userdata_cb(_sg.d3d11.user_data); + } + SOKOL_ASSERT(_sg.d3d11.cur_rtvs[0] && _sg.d3d11.cur_dsv); + } + /* apply the render-target- and depth-stencil-views */ + _sg_d3d11_OMSetRenderTargets(_sg.d3d11.ctx, SG_MAX_COLOR_ATTACHMENTS, _sg.d3d11.cur_rtvs, _sg.d3d11.cur_dsv); + + /* set viewport and scissor rect to cover whole screen */ + D3D11_VIEWPORT vp; + memset(&vp, 0, sizeof(vp)); + vp.Width = (FLOAT) w; + vp.Height = (FLOAT) h; + vp.MaxDepth = 1.0f; + _sg_d3d11_RSSetViewports(_sg.d3d11.ctx, 1, &vp); + D3D11_RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = w; + rect.bottom = h; + _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); + + /* perform clear action */ + for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { + if (action->colors[i].action == SG_ACTION_CLEAR) { + _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, _sg.d3d11.cur_rtvs[i], &action->colors[i].value.r); + } + } + UINT ds_flags = 0; + if (action->depth.action == SG_ACTION_CLEAR) { + ds_flags |= D3D11_CLEAR_DEPTH; + } + if (action->stencil.action == SG_ACTION_CLEAR) { + ds_flags |= D3D11_CLEAR_STENCIL; + } + if ((0 != ds_flags) && _sg.d3d11.cur_dsv) { + _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, _sg.d3d11.cur_dsv, ds_flags, action->depth.value, action->stencil.value); + } +} + +/* D3D11CalcSubresource only exists for C++ */ +_SOKOL_PRIVATE UINT _sg_d3d11_calcsubresource(UINT mip_slice, UINT array_slice, UINT mip_levels) { + return mip_slice + array_slice * mip_levels; +} + +_SOKOL_PRIVATE void _sg_d3d11_end_pass(void) { + SOKOL_ASSERT(_sg.d3d11.in_pass && _sg.d3d11.ctx); + _sg.d3d11.in_pass = false; + + /* need to resolve MSAA render target into texture? */ + if (_sg.d3d11.cur_pass) { + SOKOL_ASSERT(_sg.d3d11.cur_pass->slot.id == _sg.d3d11.cur_pass_id.id); + for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { + _sg_pass_attachment_t* cmn_att = &_sg.d3d11.cur_pass->cmn.color_atts[i]; + _sg_image_t* att_img = _sg.d3d11.cur_pass->d3d11.color_atts[i].image; + SOKOL_ASSERT(att_img && (att_img->slot.id == cmn_att->image_id.id)); + if (att_img->cmn.sample_count > 1) { + /* FIXME: support MSAA resolve into 3D texture */ + SOKOL_ASSERT(att_img->d3d11.tex2d && att_img->d3d11.texmsaa && !att_img->d3d11.tex3d); + SOKOL_ASSERT(DXGI_FORMAT_UNKNOWN != att_img->d3d11.format); + UINT dst_subres = _sg_d3d11_calcsubresource((UINT)cmn_att->mip_level, (UINT)cmn_att->slice, (UINT)att_img->cmn.num_mipmaps); + _sg_d3d11_ResolveSubresource(_sg.d3d11.ctx, + (ID3D11Resource*) att_img->d3d11.tex2d, /* pDstResource */ + dst_subres, /* DstSubresource */ + (ID3D11Resource*) att_img->d3d11.texmsaa, /* pSrcResource */ + 0, /* SrcSubresource */ + att_img->d3d11.format); + } + } + } + _sg.d3d11.cur_pass = 0; + _sg.d3d11.cur_pass_id.id = SG_INVALID_ID; + _sg.d3d11.cur_pipeline = 0; + _sg.d3d11.cur_pipeline_id.id = SG_INVALID_ID; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.d3d11.cur_rtvs[i] = 0; + } + _sg.d3d11.cur_dsv = 0; + _sg_d3d11_clear_state(); +} + +_SOKOL_PRIVATE void _sg_d3d11_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(_sg.d3d11.in_pass); + D3D11_VIEWPORT vp; + vp.TopLeftX = (FLOAT) x; + vp.TopLeftY = (FLOAT) (origin_top_left ? y : (_sg.d3d11.cur_height - (y + h))); + vp.Width = (FLOAT) w; + vp.Height = (FLOAT) h; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + _sg_d3d11_RSSetViewports(_sg.d3d11.ctx, 1, &vp); +} + +_SOKOL_PRIVATE void _sg_d3d11_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(_sg.d3d11.in_pass); + D3D11_RECT rect; + rect.left = x; + rect.top = (origin_top_left ? y : (_sg.d3d11.cur_height - (y + h))); + rect.right = x + w; + rect.bottom = origin_top_left ? (y + h) : (_sg.d3d11.cur_height - y); + _sg_d3d11_RSSetScissorRects(_sg.d3d11.ctx, 1, &rect); +} + +_SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(_sg.d3d11.in_pass); + SOKOL_ASSERT(pip->d3d11.rs && pip->d3d11.bs && pip->d3d11.dss && pip->d3d11.il); + + _sg.d3d11.cur_pipeline = pip; + _sg.d3d11.cur_pipeline_id.id = pip->slot.id; + _sg.d3d11.use_indexed_draw = (pip->d3d11.index_format != DXGI_FORMAT_UNKNOWN); + _sg.d3d11.use_instanced_draw = pip->cmn.use_instanced_draw; + + _sg_d3d11_RSSetState(_sg.d3d11.ctx, pip->d3d11.rs); + _sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, pip->d3d11.dss, pip->d3d11.stencil_ref); + _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, &pip->cmn.blend_color.r, 0xFFFFFFFF); + _sg_d3d11_IASetPrimitiveTopology(_sg.d3d11.ctx, pip->d3d11.topology); + _sg_d3d11_IASetInputLayout(_sg.d3d11.ctx, pip->d3d11.il); + _sg_d3d11_VSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.vs, NULL, 0); + _sg_d3d11_VSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, pip->shader->d3d11.stage[SG_SHADERSTAGE_VS].cbufs); + _sg_d3d11_PSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.fs, NULL, 0); + _sg_d3d11_PSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, pip->shader->d3d11.stage[SG_SHADERSTAGE_FS].cbufs); +} + +_SOKOL_PRIVATE void _sg_d3d11_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + SOKOL_ASSERT(pip); + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(_sg.d3d11.in_pass); + + /* gather all the D3D11 resources into arrays */ + ID3D11Buffer* d3d11_ib = ib ? ib->d3d11.buf : 0; + ID3D11Buffer* d3d11_vbs[SG_MAX_SHADERSTAGE_BUFFERS]; + UINT d3d11_vb_offsets[SG_MAX_SHADERSTAGE_BUFFERS]; + ID3D11ShaderResourceView* d3d11_vs_srvs[SG_MAX_SHADERSTAGE_IMAGES]; + ID3D11SamplerState* d3d11_vs_smps[SG_MAX_SHADERSTAGE_IMAGES]; + ID3D11ShaderResourceView* d3d11_fs_srvs[SG_MAX_SHADERSTAGE_IMAGES]; + ID3D11SamplerState* d3d11_fs_smps[SG_MAX_SHADERSTAGE_IMAGES]; + int i; + for (i = 0; i < num_vbs; i++) { + SOKOL_ASSERT(vbs[i]->d3d11.buf); + d3d11_vbs[i] = vbs[i]->d3d11.buf; + d3d11_vb_offsets[i] = (UINT)vb_offsets[i]; + } + for (; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) { + d3d11_vbs[i] = 0; + d3d11_vb_offsets[i] = 0; + } + for (i = 0; i < num_vs_imgs; i++) { + SOKOL_ASSERT(vs_imgs[i]->d3d11.srv); + SOKOL_ASSERT(vs_imgs[i]->d3d11.smp); + d3d11_vs_srvs[i] = vs_imgs[i]->d3d11.srv; + d3d11_vs_smps[i] = vs_imgs[i]->d3d11.smp; + } + for (; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { + d3d11_vs_srvs[i] = 0; + d3d11_vs_smps[i] = 0; + } + for (i = 0; i < num_fs_imgs; i++) { + SOKOL_ASSERT(fs_imgs[i]->d3d11.srv); + SOKOL_ASSERT(fs_imgs[i]->d3d11.smp); + d3d11_fs_srvs[i] = fs_imgs[i]->d3d11.srv; + d3d11_fs_smps[i] = fs_imgs[i]->d3d11.smp; + } + for (; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { + d3d11_fs_srvs[i] = 0; + d3d11_fs_smps[i] = 0; + } + + _sg_d3d11_IASetVertexBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_BUFFERS, d3d11_vbs, pip->d3d11.vb_strides, d3d11_vb_offsets); + _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, d3d11_ib, pip->d3d11.index_format, (UINT)ib_offset); + _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_vs_srvs); + _sg_d3d11_VSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_vs_smps); + _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_fs_srvs); + _sg_d3d11_PSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_fs_smps); +} + +_SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + SOKOL_ASSERT(_sg.d3d11.ctx && _sg.d3d11.in_pass); + SOKOL_ASSERT(_sg.d3d11.cur_pipeline && _sg.d3d11.cur_pipeline->slot.id == _sg.d3d11.cur_pipeline_id.id); + SOKOL_ASSERT(_sg.d3d11.cur_pipeline->shader && _sg.d3d11.cur_pipeline->shader->slot.id == _sg.d3d11.cur_pipeline->cmn.shader_id.id); + SOKOL_ASSERT(ub_index < _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); + SOKOL_ASSERT(data->size == _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + ID3D11Buffer* cb = _sg.d3d11.cur_pipeline->shader->d3d11.stage[stage_index].cbufs[ub_index]; + SOKOL_ASSERT(cb); + _sg_d3d11_UpdateSubresource(_sg.d3d11.ctx, (ID3D11Resource*)cb, 0, NULL, data->ptr, 0, 0); +} + +_SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_instances) { + SOKOL_ASSERT(_sg.d3d11.in_pass); + if (_sg.d3d11.use_indexed_draw) { + if (_sg.d3d11.use_instanced_draw) { + _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0); + } + else { + _sg_d3d11_DrawIndexed(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element, 0); + } + } + else { + if (_sg.d3d11.use_instanced_draw) { + _sg_d3d11_DrawInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0); + } + else { + _sg_d3d11_Draw(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element); + } + } +} + +_SOKOL_PRIVATE void _sg_d3d11_commit(void) { + SOKOL_ASSERT(!_sg.d3d11.in_pass); +} + +_SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(buf->d3d11.buf); + D3D11_MAPPED_SUBRESOURCE d3d11_msr; + HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr); + if (SUCCEEDED(hr)) { + memcpy(d3d11_msr.pData, data->ptr, data->size); + _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); + } else { + SOKOL_LOG("failed to map buffer while updating!\n"); + } +} + +_SOKOL_PRIVATE int _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(buf->d3d11.buf); + D3D11_MAP map_type = new_frame ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE; + D3D11_MAPPED_SUBRESOURCE d3d11_msr; + HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, map_type, 0, &d3d11_msr); + if (SUCCEEDED(hr)) { + uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData + buf->cmn.append_pos; + memcpy(dst_ptr, data->ptr, data->size); + _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); + } else { + SOKOL_LOG("failed to map buffer while appending!\n"); + } + /* NOTE: this alignment is a requirement from WebGPU, but we want identical behaviour across all backend */ + return _sg_roundup((int)data->size, 4); +} + +_SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + SOKOL_ASSERT(_sg.d3d11.ctx); + SOKOL_ASSERT(img->d3d11.tex2d || img->d3d11.tex3d); + ID3D11Resource* d3d11_res = 0; + if (img->d3d11.tex3d) { + d3d11_res = (ID3D11Resource*) img->d3d11.tex3d; + } + else { + d3d11_res = (ID3D11Resource*) img->d3d11.tex2d; + } + SOKOL_ASSERT(d3d11_res); + const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; + const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; + UINT subres_index = 0; + HRESULT hr; + D3D11_MAPPED_SUBRESOURCE d3d11_msr; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int slice_index = 0; slice_index < num_slices; slice_index++) { + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, subres_index++) { + SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS)); + const int mip_width = ((img->cmn.width>>mip_index)>0) ? img->cmn.width>>mip_index : 1; + const int mip_height = ((img->cmn.height>>mip_index)>0) ? img->cmn.height>>mip_index : 1; + const int src_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); + const size_t slice_size = subimg_data->size / (size_t)num_slices; + const size_t slice_offset = slice_size * (size_t)slice_index; + const uint8_t* slice_ptr = ((const uint8_t*)subimg_data->ptr) + slice_offset; + hr = _sg_d3d11_Map(_sg.d3d11.ctx, d3d11_res, subres_index, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr); + if (SUCCEEDED(hr)) { + /* FIXME: need to handle difference in depth-pitch for 3D textures as well! */ + if (src_pitch == (int)d3d11_msr.RowPitch) { + memcpy(d3d11_msr.pData, slice_ptr, slice_size); + } + else { + SOKOL_ASSERT(src_pitch < (int)d3d11_msr.RowPitch); + const uint8_t* src_ptr = slice_ptr; + uint8_t* dst_ptr = (uint8_t*) d3d11_msr.pData; + for (int row_index = 0; row_index < mip_height; row_index++) { + memcpy(dst_ptr, src_ptr, (size_t)src_pitch); + src_ptr += src_pitch; + dst_ptr += d3d11_msr.RowPitch; + } + } + _sg_d3d11_Unmap(_sg.d3d11.ctx, d3d11_res, subres_index); + } else { + SOKOL_LOG("failed to map texture!\n"); + } + } + } + } +} + +/*== METAL BACKEND IMPLEMENTATION ============================================*/ +#elif defined(SOKOL_METAL) + +#if __has_feature(objc_arc) +#define _SG_OBJC_RETAIN(obj) { } +#define _SG_OBJC_RELEASE(obj) { obj = nil; } +#define _SG_OBJC_RELEASE_WITH_NULL(obj) { obj = [NSNull null]; } +#else +#define _SG_OBJC_RETAIN(obj) { [obj retain]; } +#define _SG_OBJC_RELEASE(obj) { [obj release]; obj = nil; } +#define _SG_OBJC_RELEASE_WITH_NULL(obj) { [obj release]; obj = [NSNull null]; } +#endif + +/*-- enum translation functions ----------------------------------------------*/ +_SOKOL_PRIVATE MTLLoadAction _sg_mtl_load_action(sg_action a) { + switch (a) { + case SG_ACTION_CLEAR: return MTLLoadActionClear; + case SG_ACTION_LOAD: return MTLLoadActionLoad; + case SG_ACTION_DONTCARE: return MTLLoadActionDontCare; + default: SOKOL_UNREACHABLE; return (MTLLoadAction)0; + } +} + +_SOKOL_PRIVATE MTLResourceOptions _sg_mtl_buffer_resource_options(sg_usage usg) { + switch (usg) { + case SG_USAGE_IMMUTABLE: + #if defined(_SG_TARGET_MACOS) + return MTLResourceStorageModeManaged; + #else + return MTLResourceStorageModeShared; + #endif + case SG_USAGE_DYNAMIC: + case SG_USAGE_STREAM: + #if defined(_SG_TARGET_MACOS) + return MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeManaged; + #else + return MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared; + #endif + default: + SOKOL_UNREACHABLE; + return 0; + } +} + +_SOKOL_PRIVATE MTLVertexStepFunction _sg_mtl_step_function(sg_vertex_step step) { + switch (step) { + case SG_VERTEXSTEP_PER_VERTEX: return MTLVertexStepFunctionPerVertex; + case SG_VERTEXSTEP_PER_INSTANCE: return MTLVertexStepFunctionPerInstance; + default: SOKOL_UNREACHABLE; return (MTLVertexStepFunction)0; + } +} + +_SOKOL_PRIVATE MTLVertexFormat _sg_mtl_vertex_format(sg_vertex_format fmt) { + switch (fmt) { + case SG_VERTEXFORMAT_FLOAT: return MTLVertexFormatFloat; + case SG_VERTEXFORMAT_FLOAT2: return MTLVertexFormatFloat2; + case SG_VERTEXFORMAT_FLOAT3: return MTLVertexFormatFloat3; + case SG_VERTEXFORMAT_FLOAT4: return MTLVertexFormatFloat4; + case SG_VERTEXFORMAT_BYTE4: return MTLVertexFormatChar4; + case SG_VERTEXFORMAT_BYTE4N: return MTLVertexFormatChar4Normalized; + case SG_VERTEXFORMAT_UBYTE4: return MTLVertexFormatUChar4; + case SG_VERTEXFORMAT_UBYTE4N: return MTLVertexFormatUChar4Normalized; + case SG_VERTEXFORMAT_SHORT2: return MTLVertexFormatShort2; + case SG_VERTEXFORMAT_SHORT2N: return MTLVertexFormatShort2Normalized; + case SG_VERTEXFORMAT_USHORT2N: return MTLVertexFormatUShort2Normalized; + case SG_VERTEXFORMAT_SHORT4: return MTLVertexFormatShort4; + case SG_VERTEXFORMAT_SHORT4N: return MTLVertexFormatShort4Normalized; + case SG_VERTEXFORMAT_USHORT4N: return MTLVertexFormatUShort4Normalized; + case SG_VERTEXFORMAT_UINT10_N2: return MTLVertexFormatUInt1010102Normalized; + default: SOKOL_UNREACHABLE; return (MTLVertexFormat)0; + } +} + +_SOKOL_PRIVATE MTLPrimitiveType _sg_mtl_primitive_type(sg_primitive_type t) { + switch (t) { + case SG_PRIMITIVETYPE_POINTS: return MTLPrimitiveTypePoint; + case SG_PRIMITIVETYPE_LINES: return MTLPrimitiveTypeLine; + case SG_PRIMITIVETYPE_LINE_STRIP: return MTLPrimitiveTypeLineStrip; + case SG_PRIMITIVETYPE_TRIANGLES: return MTLPrimitiveTypeTriangle; + case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip; + default: SOKOL_UNREACHABLE; return (MTLPrimitiveType)0; + } +} + +_SOKOL_PRIVATE MTLPixelFormat _sg_mtl_pixel_format(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_R8: return MTLPixelFormatR8Unorm; + case SG_PIXELFORMAT_R8SN: return MTLPixelFormatR8Snorm; + case SG_PIXELFORMAT_R8UI: return MTLPixelFormatR8Uint; + case SG_PIXELFORMAT_R8SI: return MTLPixelFormatR8Sint; + case SG_PIXELFORMAT_R16: return MTLPixelFormatR16Unorm; + case SG_PIXELFORMAT_R16SN: return MTLPixelFormatR16Snorm; + case SG_PIXELFORMAT_R16UI: return MTLPixelFormatR16Uint; + case SG_PIXELFORMAT_R16SI: return MTLPixelFormatR16Sint; + case SG_PIXELFORMAT_R16F: return MTLPixelFormatR16Float; + case SG_PIXELFORMAT_RG8: return MTLPixelFormatRG8Unorm; + case SG_PIXELFORMAT_RG8SN: return MTLPixelFormatRG8Snorm; + case SG_PIXELFORMAT_RG8UI: return MTLPixelFormatRG8Uint; + case SG_PIXELFORMAT_RG8SI: return MTLPixelFormatRG8Sint; + case SG_PIXELFORMAT_R32UI: return MTLPixelFormatR32Uint; + case SG_PIXELFORMAT_R32SI: return MTLPixelFormatR32Sint; + case SG_PIXELFORMAT_R32F: return MTLPixelFormatR32Float; + case SG_PIXELFORMAT_RG16: return MTLPixelFormatRG16Unorm; + case SG_PIXELFORMAT_RG16SN: return MTLPixelFormatRG16Snorm; + case SG_PIXELFORMAT_RG16UI: return MTLPixelFormatRG16Uint; + case SG_PIXELFORMAT_RG16SI: return MTLPixelFormatRG16Sint; + case SG_PIXELFORMAT_RG16F: return MTLPixelFormatRG16Float; + case SG_PIXELFORMAT_RGBA8: return MTLPixelFormatRGBA8Unorm; + case SG_PIXELFORMAT_RGBA8SN: return MTLPixelFormatRGBA8Snorm; + case SG_PIXELFORMAT_RGBA8UI: return MTLPixelFormatRGBA8Uint; + case SG_PIXELFORMAT_RGBA8SI: return MTLPixelFormatRGBA8Sint; + case SG_PIXELFORMAT_BGRA8: return MTLPixelFormatBGRA8Unorm; + case SG_PIXELFORMAT_RGB10A2: return MTLPixelFormatRGB10A2Unorm; + case SG_PIXELFORMAT_RG11B10F: return MTLPixelFormatRG11B10Float; + case SG_PIXELFORMAT_RG32UI: return MTLPixelFormatRG32Uint; + case SG_PIXELFORMAT_RG32SI: return MTLPixelFormatRG32Sint; + case SG_PIXELFORMAT_RG32F: return MTLPixelFormatRG32Float; + case SG_PIXELFORMAT_RGBA16: return MTLPixelFormatRGBA16Unorm; + case SG_PIXELFORMAT_RGBA16SN: return MTLPixelFormatRGBA16Snorm; + case SG_PIXELFORMAT_RGBA16UI: return MTLPixelFormatRGBA16Uint; + case SG_PIXELFORMAT_RGBA16SI: return MTLPixelFormatRGBA16Sint; + case SG_PIXELFORMAT_RGBA16F: return MTLPixelFormatRGBA16Float; + case SG_PIXELFORMAT_RGBA32UI: return MTLPixelFormatRGBA32Uint; + case SG_PIXELFORMAT_RGBA32SI: return MTLPixelFormatRGBA32Sint; + case SG_PIXELFORMAT_RGBA32F: return MTLPixelFormatRGBA32Float; + case SG_PIXELFORMAT_DEPTH: return MTLPixelFormatDepth32Float; + case SG_PIXELFORMAT_DEPTH_STENCIL: return MTLPixelFormatDepth32Float_Stencil8; + #if defined(_SG_TARGET_MACOS) + case SG_PIXELFORMAT_BC1_RGBA: return MTLPixelFormatBC1_RGBA; + case SG_PIXELFORMAT_BC2_RGBA: return MTLPixelFormatBC2_RGBA; + case SG_PIXELFORMAT_BC3_RGBA: return MTLPixelFormatBC3_RGBA; + case SG_PIXELFORMAT_BC4_R: return MTLPixelFormatBC4_RUnorm; + case SG_PIXELFORMAT_BC4_RSN: return MTLPixelFormatBC4_RSnorm; + case SG_PIXELFORMAT_BC5_RG: return MTLPixelFormatBC5_RGUnorm; + case SG_PIXELFORMAT_BC5_RGSN: return MTLPixelFormatBC5_RGSnorm; + case SG_PIXELFORMAT_BC6H_RGBF: return MTLPixelFormatBC6H_RGBFloat; + case SG_PIXELFORMAT_BC6H_RGBUF: return MTLPixelFormatBC6H_RGBUfloat; + case SG_PIXELFORMAT_BC7_RGBA: return MTLPixelFormatBC7_RGBAUnorm; + #else + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return MTLPixelFormatPVRTC_RGB_2BPP; + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return MTLPixelFormatPVRTC_RGB_4BPP; + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return MTLPixelFormatPVRTC_RGBA_2BPP; + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return MTLPixelFormatPVRTC_RGBA_4BPP; + case SG_PIXELFORMAT_ETC2_RGB8: return MTLPixelFormatETC2_RGB8; + case SG_PIXELFORMAT_ETC2_RGB8A1: return MTLPixelFormatETC2_RGB8A1; + case SG_PIXELFORMAT_ETC2_RGBA8: return MTLPixelFormatEAC_RGBA8; + case SG_PIXELFORMAT_ETC2_RG11: return MTLPixelFormatEAC_RG11Unorm; + case SG_PIXELFORMAT_ETC2_RG11SN: return MTLPixelFormatEAC_RG11Snorm; + #endif + default: return MTLPixelFormatInvalid; + } +} + +_SOKOL_PRIVATE MTLColorWriteMask _sg_mtl_color_write_mask(sg_color_mask m) { + MTLColorWriteMask mtl_mask = MTLColorWriteMaskNone; + if (m & SG_COLORMASK_R) { + mtl_mask |= MTLColorWriteMaskRed; + } + if (m & SG_COLORMASK_G) { + mtl_mask |= MTLColorWriteMaskGreen; + } + if (m & SG_COLORMASK_B) { + mtl_mask |= MTLColorWriteMaskBlue; + } + if (m & SG_COLORMASK_A) { + mtl_mask |= MTLColorWriteMaskAlpha; + } + return mtl_mask; +} + +_SOKOL_PRIVATE MTLBlendOperation _sg_mtl_blend_op(sg_blend_op op) { + switch (op) { + case SG_BLENDOP_ADD: return MTLBlendOperationAdd; + case SG_BLENDOP_SUBTRACT: return MTLBlendOperationSubtract; + case SG_BLENDOP_REVERSE_SUBTRACT: return MTLBlendOperationReverseSubtract; + default: SOKOL_UNREACHABLE; return (MTLBlendOperation)0; + } +} + +_SOKOL_PRIVATE MTLBlendFactor _sg_mtl_blend_factor(sg_blend_factor f) { + switch (f) { + case SG_BLENDFACTOR_ZERO: return MTLBlendFactorZero; + case SG_BLENDFACTOR_ONE: return MTLBlendFactorOne; + case SG_BLENDFACTOR_SRC_COLOR: return MTLBlendFactorSourceColor; + case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return MTLBlendFactorOneMinusSourceColor; + case SG_BLENDFACTOR_SRC_ALPHA: return MTLBlendFactorSourceAlpha; + case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha; + case SG_BLENDFACTOR_DST_COLOR: return MTLBlendFactorDestinationColor; + case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return MTLBlendFactorOneMinusDestinationColor; + case SG_BLENDFACTOR_DST_ALPHA: return MTLBlendFactorDestinationAlpha; + case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return MTLBlendFactorOneMinusDestinationAlpha; + case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return MTLBlendFactorSourceAlphaSaturated; + case SG_BLENDFACTOR_BLEND_COLOR: return MTLBlendFactorBlendColor; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return MTLBlendFactorOneMinusBlendColor; + case SG_BLENDFACTOR_BLEND_ALPHA: return MTLBlendFactorBlendAlpha; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return MTLBlendFactorOneMinusBlendAlpha; + default: SOKOL_UNREACHABLE; return (MTLBlendFactor)0; + } +} + +_SOKOL_PRIVATE MTLCompareFunction _sg_mtl_compare_func(sg_compare_func f) { + switch (f) { + case SG_COMPAREFUNC_NEVER: return MTLCompareFunctionNever; + case SG_COMPAREFUNC_LESS: return MTLCompareFunctionLess; + case SG_COMPAREFUNC_EQUAL: return MTLCompareFunctionEqual; + case SG_COMPAREFUNC_LESS_EQUAL: return MTLCompareFunctionLessEqual; + case SG_COMPAREFUNC_GREATER: return MTLCompareFunctionGreater; + case SG_COMPAREFUNC_NOT_EQUAL: return MTLCompareFunctionNotEqual; + case SG_COMPAREFUNC_GREATER_EQUAL: return MTLCompareFunctionGreaterEqual; + case SG_COMPAREFUNC_ALWAYS: return MTLCompareFunctionAlways; + default: SOKOL_UNREACHABLE; return (MTLCompareFunction)0; + } +} + +_SOKOL_PRIVATE MTLStencilOperation _sg_mtl_stencil_op(sg_stencil_op op) { + switch (op) { + case SG_STENCILOP_KEEP: return MTLStencilOperationKeep; + case SG_STENCILOP_ZERO: return MTLStencilOperationZero; + case SG_STENCILOP_REPLACE: return MTLStencilOperationReplace; + case SG_STENCILOP_INCR_CLAMP: return MTLStencilOperationIncrementClamp; + case SG_STENCILOP_DECR_CLAMP: return MTLStencilOperationDecrementClamp; + case SG_STENCILOP_INVERT: return MTLStencilOperationInvert; + case SG_STENCILOP_INCR_WRAP: return MTLStencilOperationIncrementWrap; + case SG_STENCILOP_DECR_WRAP: return MTLStencilOperationDecrementWrap; + default: SOKOL_UNREACHABLE; return (MTLStencilOperation)0; + } +} + +_SOKOL_PRIVATE MTLCullMode _sg_mtl_cull_mode(sg_cull_mode m) { + switch (m) { + case SG_CULLMODE_NONE: return MTLCullModeNone; + case SG_CULLMODE_FRONT: return MTLCullModeFront; + case SG_CULLMODE_BACK: return MTLCullModeBack; + default: SOKOL_UNREACHABLE; return (MTLCullMode)0; + } +} + +_SOKOL_PRIVATE MTLWinding _sg_mtl_winding(sg_face_winding w) { + switch (w) { + case SG_FACEWINDING_CW: return MTLWindingClockwise; + case SG_FACEWINDING_CCW: return MTLWindingCounterClockwise; + default: SOKOL_UNREACHABLE; return (MTLWinding)0; + } +} + +_SOKOL_PRIVATE MTLIndexType _sg_mtl_index_type(sg_index_type t) { + switch (t) { + case SG_INDEXTYPE_UINT16: return MTLIndexTypeUInt16; + case SG_INDEXTYPE_UINT32: return MTLIndexTypeUInt32; + default: SOKOL_UNREACHABLE; return (MTLIndexType)0; + } +} + +_SOKOL_PRIVATE int _sg_mtl_index_size(sg_index_type t) { + switch (t) { + case SG_INDEXTYPE_NONE: return 0; + case SG_INDEXTYPE_UINT16: return 2; + case SG_INDEXTYPE_UINT32: return 4; + default: SOKOL_UNREACHABLE; return 0; + } +} + +_SOKOL_PRIVATE MTLTextureType _sg_mtl_texture_type(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return MTLTextureType2D; + case SG_IMAGETYPE_CUBE: return MTLTextureTypeCube; + case SG_IMAGETYPE_3D: return MTLTextureType3D; + case SG_IMAGETYPE_ARRAY: return MTLTextureType2DArray; + default: SOKOL_UNREACHABLE; return (MTLTextureType)0; + } +} + +_SOKOL_PRIVATE bool _sg_mtl_is_pvrtc(sg_pixel_format fmt) { + switch (fmt) { + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + return true; + default: + return false; + } +} + +_SOKOL_PRIVATE MTLSamplerAddressMode _sg_mtl_address_mode(sg_wrap w) { + switch (w) { + case SG_WRAP_REPEAT: return MTLSamplerAddressModeRepeat; + case SG_WRAP_CLAMP_TO_EDGE: return MTLSamplerAddressModeClampToEdge; + #if defined(_SG_TARGET_MACOS) + case SG_WRAP_CLAMP_TO_BORDER: return MTLSamplerAddressModeClampToBorderColor; + #else + /* clamp-to-border not supported on iOS, fall back to clamp-to-edge */ + case SG_WRAP_CLAMP_TO_BORDER: return MTLSamplerAddressModeClampToEdge; + #endif + case SG_WRAP_MIRRORED_REPEAT: return MTLSamplerAddressModeMirrorRepeat; + default: SOKOL_UNREACHABLE; return (MTLSamplerAddressMode)0; + } +} + +#if defined(_SG_TARGET_MACOS) +_SOKOL_PRIVATE MTLSamplerBorderColor _sg_mtl_border_color(sg_border_color c) { + switch (c) { + case SG_BORDERCOLOR_TRANSPARENT_BLACK: return MTLSamplerBorderColorTransparentBlack; + case SG_BORDERCOLOR_OPAQUE_BLACK: return MTLSamplerBorderColorOpaqueBlack; + case SG_BORDERCOLOR_OPAQUE_WHITE: return MTLSamplerBorderColorOpaqueWhite; + default: SOKOL_UNREACHABLE; return (MTLSamplerBorderColor)0; + } +} +#endif + +_SOKOL_PRIVATE MTLSamplerMinMagFilter _sg_mtl_minmag_filter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + return MTLSamplerMinMagFilterNearest; + case SG_FILTER_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return MTLSamplerMinMagFilterLinear; + default: + SOKOL_UNREACHABLE; return (MTLSamplerMinMagFilter)0; + } +} + +_SOKOL_PRIVATE MTLSamplerMipFilter _sg_mtl_mip_filter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: + case SG_FILTER_LINEAR: + return MTLSamplerMipFilterNotMipmapped; + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + return MTLSamplerMipFilterNearest; + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return MTLSamplerMipFilterLinear; + default: + SOKOL_UNREACHABLE; return (MTLSamplerMipFilter)0; + } +} + +/*-- a pool for all Metal resource objects, with deferred release queue -------*/ + +_SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { + _sg.mtl.idpool.num_slots = 2 * + ( + 2 * desc->buffer_pool_size + + 5 * desc->image_pool_size + + 4 * desc->shader_pool_size + + 2 * desc->pipeline_pool_size + + desc->pass_pool_size + ); + _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:(NSUInteger)_sg.mtl.idpool.num_slots]; + _SG_OBJC_RETAIN(_sg.mtl.idpool.pool); + NSNull* null = [NSNull null]; + for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { + [_sg.mtl.idpool.pool addObject:null]; + } + SOKOL_ASSERT([_sg.mtl.idpool.pool count] == (NSUInteger)_sg.mtl.idpool.num_slots); + /* a queue of currently free slot indices */ + _sg.mtl.idpool.free_queue_top = 0; + _sg.mtl.idpool.free_queue = (int*)SOKOL_MALLOC((size_t)_sg.mtl.idpool.num_slots * sizeof(int)); + /* pool slot 0 is reserved! */ + for (int i = _sg.mtl.idpool.num_slots-1; i >= 1; i--) { + _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = i; + } + /* a circular queue which holds release items (frame index + when a resource is to be released, and the resource's + pool index + */ + _sg.mtl.idpool.release_queue_front = 0; + _sg.mtl.idpool.release_queue_back = 0; + _sg.mtl.idpool.release_queue = (_sg_mtl_release_item_t*)SOKOL_MALLOC((size_t)_sg.mtl.idpool.num_slots * sizeof(_sg_mtl_release_item_t)); + for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { + _sg.mtl.idpool.release_queue[i].frame_index = 0; + _sg.mtl.idpool.release_queue[i].slot_index = _SG_MTL_INVALID_SLOT_INDEX; + } +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_pool(void) { + SOKOL_FREE(_sg.mtl.idpool.release_queue); _sg.mtl.idpool.release_queue = 0; + SOKOL_FREE(_sg.mtl.idpool.free_queue); _sg.mtl.idpool.free_queue = 0; + _SG_OBJC_RELEASE(_sg.mtl.idpool.pool); +} + +/* get a new free resource pool slot */ +_SOKOL_PRIVATE int _sg_mtl_alloc_pool_slot(void) { + SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top > 0); + const int slot_index = _sg.mtl.idpool.free_queue[--_sg.mtl.idpool.free_queue_top]; + SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); + return slot_index; +} + +/* put a free resource pool slot back into the free-queue */ +_SOKOL_PRIVATE void _sg_mtl_free_pool_slot(int slot_index) { + SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top < _sg.mtl.idpool.num_slots); + SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); + _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = slot_index; +} + +/* add an MTLResource to the pool, return pool index or 0 if input was 'nil' */ +_SOKOL_PRIVATE int _sg_mtl_add_resource(id res) { + if (nil == res) { + return _SG_MTL_INVALID_SLOT_INDEX; + } + const int slot_index = _sg_mtl_alloc_pool_slot(); + SOKOL_ASSERT([NSNull null] == _sg.mtl.idpool.pool[(NSUInteger)slot_index]); + _sg.mtl.idpool.pool[(NSUInteger)slot_index] = res; + return slot_index; +} + +/* mark an MTLResource for release, this will put the resource into the + deferred-release queue, and the resource will then be released N frames later, + the special pool index 0 will be ignored (this means that a nil + value was provided to _sg_mtl_add_resource() +*/ +_SOKOL_PRIVATE void _sg_mtl_release_resource(uint32_t frame_index, int slot_index) { + if (slot_index == _SG_MTL_INVALID_SLOT_INDEX) { + return; + } + SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); + SOKOL_ASSERT([NSNull null] != _sg.mtl.idpool.pool[(NSUInteger)slot_index]); + int release_index = _sg.mtl.idpool.release_queue_front++; + if (_sg.mtl.idpool.release_queue_front >= _sg.mtl.idpool.num_slots) { + /* wrap-around */ + _sg.mtl.idpool.release_queue_front = 0; + } + /* release queue full? */ + SOKOL_ASSERT(_sg.mtl.idpool.release_queue_front != _sg.mtl.idpool.release_queue_back); + SOKOL_ASSERT(0 == _sg.mtl.idpool.release_queue[release_index].frame_index); + const uint32_t safe_to_release_frame_index = frame_index + SG_NUM_INFLIGHT_FRAMES + 1; + _sg.mtl.idpool.release_queue[release_index].frame_index = safe_to_release_frame_index; + _sg.mtl.idpool.release_queue[release_index].slot_index = slot_index; +} + +/* run garbage-collection pass on all resources in the release-queue */ +_SOKOL_PRIVATE void _sg_mtl_garbage_collect(uint32_t frame_index) { + while (_sg.mtl.idpool.release_queue_back != _sg.mtl.idpool.release_queue_front) { + if (frame_index < _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].frame_index) { + /* don't need to check further, release-items past this are too young */ + break; + } + /* safe to release this resource */ + const int slot_index = _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index; + SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); + SOKOL_ASSERT(_sg.mtl.idpool.pool[(NSUInteger)slot_index] != [NSNull null]); + _SG_OBJC_RELEASE_WITH_NULL(_sg.mtl.idpool.pool[(NSUInteger)slot_index]); + /* put the now free pool index back on the free queue */ + _sg_mtl_free_pool_slot(slot_index); + /* reset the release queue slot and advance the back index */ + _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].frame_index = 0; + _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index = _SG_MTL_INVALID_SLOT_INDEX; + _sg.mtl.idpool.release_queue_back++; + if (_sg.mtl.idpool.release_queue_back >= _sg.mtl.idpool.num_slots) { + /* wrap-around */ + _sg.mtl.idpool.release_queue_back = 0; + } + } +} + +_SOKOL_PRIVATE id _sg_mtl_id(int slot_index) { + return _sg.mtl.idpool.pool[(NSUInteger)slot_index]; +} + +_SOKOL_PRIVATE void _sg_mtl_init_sampler_cache(const sg_desc* desc) { + SOKOL_ASSERT(desc->sampler_cache_size > 0); + _sg_smpcache_init(&_sg.mtl.sampler_cache, desc->sampler_cache_size); +} + +/* destroy the sampler cache, and release all sampler objects */ +_SOKOL_PRIVATE void _sg_mtl_destroy_sampler_cache(uint32_t frame_index) { + SOKOL_ASSERT(_sg.mtl.sampler_cache.items); + SOKOL_ASSERT(_sg.mtl.sampler_cache.num_items <= _sg.mtl.sampler_cache.capacity); + for (int i = 0; i < _sg.mtl.sampler_cache.num_items; i++) { + _sg_mtl_release_resource(frame_index, (int)_sg_smpcache_sampler(&_sg.mtl.sampler_cache, i)); + } + _sg_smpcache_discard(&_sg.mtl.sampler_cache); +} + +/* + create and add an MTLSamplerStateObject and return its resource pool index, + reuse identical sampler state if one exists +*/ +_SOKOL_PRIVATE int _sg_mtl_create_sampler(id mtl_device, const sg_image_desc* img_desc) { + SOKOL_ASSERT(img_desc); + int index = _sg_smpcache_find_item(&_sg.mtl.sampler_cache, img_desc); + if (index >= 0) { + /* reuse existing sampler */ + return (int)_sg_smpcache_sampler(&_sg.mtl.sampler_cache, index); + } + else { + /* create a new Metal sampler state object and add to sampler cache */ + MTLSamplerDescriptor* mtl_desc = [[MTLSamplerDescriptor alloc] init]; + mtl_desc.sAddressMode = _sg_mtl_address_mode(img_desc->wrap_u); + mtl_desc.tAddressMode = _sg_mtl_address_mode(img_desc->wrap_v); + if (SG_IMAGETYPE_3D == img_desc->type) { + mtl_desc.rAddressMode = _sg_mtl_address_mode(img_desc->wrap_w); + } + #if defined(_SG_TARGET_MACOS) + mtl_desc.borderColor = _sg_mtl_border_color(img_desc->border_color); + #endif + mtl_desc.minFilter = _sg_mtl_minmag_filter(img_desc->min_filter); + mtl_desc.magFilter = _sg_mtl_minmag_filter(img_desc->mag_filter); + mtl_desc.mipFilter = _sg_mtl_mip_filter(img_desc->min_filter); + mtl_desc.lodMinClamp = img_desc->min_lod; + mtl_desc.lodMaxClamp = img_desc->max_lod; + mtl_desc.maxAnisotropy = img_desc->max_anisotropy; + mtl_desc.normalizedCoordinates = YES; + id mtl_sampler = [mtl_device newSamplerStateWithDescriptor:mtl_desc]; + _SG_OBJC_RELEASE(mtl_desc); + int sampler_handle = _sg_mtl_add_resource(mtl_sampler); + _sg_smpcache_add_item(&_sg.mtl.sampler_cache, img_desc, (uintptr_t)sampler_handle); + return sampler_handle; + } +} + +_SOKOL_PRIVATE void _sg_mtl_clear_state_cache(void) { + memset(&_sg.mtl.state_cache, 0, sizeof(_sg.mtl.state_cache)); +} + +/* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */ +_SOKOL_PRIVATE void _sg_mtl_init_caps(void) { + #if defined(_SG_TARGET_MACOS) + _sg.backend = SG_BACKEND_METAL_MACOS; + #elif defined(_SG_TARGET_IOS) + #if defined(_SG_TARGET_IOS_SIMULATOR) + _sg.backend = SG_BACKEND_METAL_SIMULATOR; + #else + _sg.backend = SG_BACKEND_METAL_IOS; + #endif + #endif + _sg.features.instancing = true; + _sg.features.origin_top_left = true; + _sg.features.multiple_render_targets = true; + _sg.features.msaa_render_targets = true; + _sg.features.imagetype_3d = true; + _sg.features.imagetype_array = true; + #if defined(_SG_TARGET_MACOS) + _sg.features.image_clamp_to_border = true; + #else + _sg.features.image_clamp_to_border = false; + #endif + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; + + #if defined(_SG_TARGET_MACOS) + _sg.limits.max_image_size_2d = 16 * 1024; + _sg.limits.max_image_size_cube = 16 * 1024; + _sg.limits.max_image_size_3d = 2 * 1024; + _sg.limits.max_image_size_array = 16 * 1024; + _sg.limits.max_image_array_layers = 2 * 1024; + #else + /* newer iOS devices support 16k textures */ + _sg.limits.max_image_size_2d = 8 * 1024; + _sg.limits.max_image_size_cube = 8 * 1024; + _sg.limits.max_image_size_3d = 2 * 1024; + _sg.limits.max_image_size_array = 8 * 1024; + _sg.limits.max_image_array_layers = 2 * 1024; + #endif + _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; + + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]); + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16SN]); + #else + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_R16]); + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_R16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R32F]); + #else + _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_R32F]); + #endif + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16SN]); + #else + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RG16]); + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RG16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG11B10F]); + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + #else + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + #endif + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG32F]); + #else + _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_RG32F]); + #endif + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); + #else + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RGBA16]); + _sg_pixelformat_sfbr(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]); + #endif + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + #else + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + #endif + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); + #if defined(_SG_TARGET_MACOS) + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); + #else + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_2BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_4BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_2BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_4BPP]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]); + #endif +} + +/*-- main Metal backend state and functions ----------------------------------*/ +_SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { + /* assume already zero-initialized */ + SOKOL_ASSERT(desc); + SOKOL_ASSERT(desc->context.metal.device); + SOKOL_ASSERT(desc->context.metal.renderpass_descriptor_cb || desc->context.metal.renderpass_descriptor_userdata_cb); + SOKOL_ASSERT(desc->context.metal.drawable_cb || desc->context.metal.drawable_userdata_cb); + SOKOL_ASSERT(desc->uniform_buffer_size > 0); + _sg_mtl_init_pool(desc); + _sg_mtl_init_sampler_cache(desc); + _sg_mtl_clear_state_cache(); + _sg.mtl.valid = true; + _sg.mtl.renderpass_descriptor_cb = desc->context.metal.renderpass_descriptor_cb; + _sg.mtl.renderpass_descriptor_userdata_cb = desc->context.metal.renderpass_descriptor_userdata_cb; + _sg.mtl.drawable_cb = desc->context.metal.drawable_cb; + _sg.mtl.drawable_userdata_cb = desc->context.metal.drawable_userdata_cb; + _sg.mtl.user_data = desc->context.metal.user_data; + _sg.mtl.frame_index = 1; + _sg.mtl.ub_size = desc->uniform_buffer_size; + _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); + _sg.mtl.device = (__bridge id) desc->context.metal.device; + _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _sg.mtl.uniform_buffers[i] = [_sg.mtl.device + newBufferWithLength:(NSUInteger)_sg.mtl.ub_size + options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared + ]; + } + _sg_mtl_init_caps(); +} + +_SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { + SOKOL_ASSERT(_sg.mtl.valid); + /* wait for the last frame to finish */ + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); + } + /* semaphore must be "relinquished" before destruction */ + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + dispatch_semaphore_signal(_sg.mtl.sem); + } + _sg_mtl_destroy_sampler_cache(_sg.mtl.frame_index); + _sg_mtl_garbage_collect(_sg.mtl.frame_index + SG_NUM_INFLIGHT_FRAMES + 2); + _sg_mtl_destroy_pool(); + _sg.mtl.valid = false; + + _SG_OBJC_RELEASE(_sg.mtl.sem); + _SG_OBJC_RELEASE(_sg.mtl.device); + _SG_OBJC_RELEASE(_sg.mtl.cmd_queue); + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _SG_OBJC_RELEASE(_sg.mtl.uniform_buffers[i]); + } + /* NOTE: MTLCommandBuffer and MTLRenderCommandEncoder are auto-released */ + _sg.mtl.cmd_buffer = nil; + _sg.mtl.cmd_encoder = nil; +} + +_SOKOL_PRIVATE void _sg_mtl_bind_uniform_buffers(void) { + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + for (int slot = 0; slot < SG_MAX_SHADERSTAGE_UBS; slot++) { + [_sg.mtl.cmd_encoder + setVertexBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] + offset:0 + atIndex:(NSUInteger)slot]; + [_sg.mtl.cmd_encoder + setFragmentBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] + offset:0 + atIndex:(NSUInteger)slot]; + } +} + +_SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { + _sg_mtl_clear_state_cache(); + + /* need to restore the uniform buffer binding (normally happens in + _sg_mtl_begin_pass() + */ + if (nil != _sg.mtl.cmd_encoder) { + _sg_mtl_bind_uniform_buffers(); + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + /* empty */ +} + +_SOKOL_PRIVATE void _sg_mtl_activate_context(_sg_context_t* ctx) { + _SOKOL_UNUSED(ctx); + _sg_mtl_clear_state_cache(); +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf && desc); + _sg_buffer_common_init(&buf->cmn, desc); + const bool injected = (0 != desc->mtl_buffers[0]); + MTLResourceOptions mtl_options = _sg_mtl_buffer_resource_options(buf->cmn.usage); + for (int slot = 0; slot < buf->cmn.num_slots; slot++) { + id mtl_buf; + if (injected) { + SOKOL_ASSERT(desc->mtl_buffers[slot]); + mtl_buf = (__bridge id) desc->mtl_buffers[slot]; + } + else { + if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { + SOKOL_ASSERT(desc->data.ptr); + mtl_buf = [_sg.mtl.device newBufferWithBytes:desc->data.ptr length:(NSUInteger)buf->cmn.size options:mtl_options]; + } + else { + mtl_buf = [_sg.mtl.device newBufferWithLength:(NSUInteger)buf->cmn.size options:mtl_options]; + } + } + buf->mtl.buf[slot] = _sg_mtl_add_resource(mtl_buf); + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + for (int slot = 0; slot < buf->cmn.num_slots; slot++) { + /* it's valid to call release resource with '0' */ + _sg_mtl_release_resource(_sg.mtl.frame_index, buf->mtl.buf[slot]); + } +} + +_SOKOL_PRIVATE void _sg_mtl_copy_image_data(const _sg_image_t* img, __unsafe_unretained id mtl_tex, const sg_image_data* data) { + const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; + const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { + SOKOL_ASSERT(data->subimage[face_index][mip_index].ptr); + SOKOL_ASSERT(data->subimage[face_index][mip_index].size > 0); + const uint8_t* data_ptr = (const uint8_t*)data->subimage[face_index][mip_index].ptr; + const int mip_width = _sg_max(img->cmn.width >> mip_index, 1); + const int mip_height = _sg_max(img->cmn.height >> mip_index, 1); + /* special case PVRTC formats: bytePerRow and bytesPerImage must be 0 */ + int bytes_per_row = 0; + int bytes_per_slice = 0; + if (!_sg_mtl_is_pvrtc(img->cmn.pixel_format)) { + bytes_per_row = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); + } + /* bytesPerImage special case: https://developer.apple.com/documentation/metal/mtltexture/1515679-replaceregion + + "Supply a nonzero value only when you copy data to a MTLTextureType3D type texture" + */ + MTLRegion region; + int bytes_per_image; + if (img->cmn.type == SG_IMAGETYPE_3D) { + const int mip_depth = _sg_max(img->cmn.num_slices >> mip_index, 1); + region = MTLRegionMake3D(0, 0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height, (NSUInteger)mip_depth); + bytes_per_image = bytes_per_slice; + /* FIXME: apparently the minimal bytes_per_image size for 3D texture + is 4 KByte... somehow need to handle this */ + } + else { + region = MTLRegionMake2D(0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height); + bytes_per_image = 0; + } + + for (int slice_index = 0; slice_index < num_slices; slice_index++) { + const int mtl_slice_index = (img->cmn.type == SG_IMAGETYPE_CUBE) ? face_index : slice_index; + const int slice_offset = slice_index * bytes_per_slice; + SOKOL_ASSERT((slice_offset + bytes_per_slice) <= (int)data->subimage[face_index][mip_index].size); + [mtl_tex replaceRegion:region + mipmapLevel:(NSUInteger)mip_index + slice:(NSUInteger)mtl_slice_index + withBytes:data_ptr + slice_offset + bytesPerRow:(NSUInteger)bytes_per_row + bytesPerImage:(NSUInteger)bytes_per_image]; + } + } + } +} + +/* + FIXME: METAL RESOURCE STORAGE MODE FOR macOS AND iOS + + For immutable textures on macOS, the recommended procedure is to create + a MTLStorageModeManaged texture with the immutable content first, + and then use the GPU to blit the content into a MTLStorageModePrivate + texture before the first use. + + On iOS use the same one-time-blit procedure, but from a + MTLStorageModeShared to a MTLStorageModePrivate texture. + + It probably makes sense to handle this in a separate 'resource manager' + with a recycable pool of blit-source-textures? +*/ + +/* initialize MTLTextureDescritor with common attributes */ +_SOKOL_PRIVATE bool _sg_mtl_init_texdesc_common(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + mtl_desc.textureType = _sg_mtl_texture_type(img->cmn.type); + mtl_desc.pixelFormat = _sg_mtl_pixel_format(img->cmn.pixel_format); + if (MTLPixelFormatInvalid == mtl_desc.pixelFormat) { + SOKOL_LOG("Unsupported texture pixel format!\n"); + return false; + } + mtl_desc.width = (NSUInteger)img->cmn.width; + mtl_desc.height = (NSUInteger)img->cmn.height; + if (SG_IMAGETYPE_3D == img->cmn.type) { + mtl_desc.depth = (NSUInteger)img->cmn.num_slices; + } + else { + mtl_desc.depth = 1; + } + mtl_desc.mipmapLevelCount = (NSUInteger)img->cmn.num_mipmaps; + if (SG_IMAGETYPE_ARRAY == img->cmn.type) { + mtl_desc.arrayLength = (NSUInteger)img->cmn.num_slices; + } + else { + mtl_desc.arrayLength = 1; + } + mtl_desc.usage = MTLTextureUsageShaderRead; + MTLResourceOptions res_options = 0; + if (img->cmn.usage != SG_USAGE_IMMUTABLE) { + res_options |= MTLResourceCPUCacheModeWriteCombined; + } + #if defined(_SG_TARGET_MACOS) + /* macOS: use managed textures */ + res_options |= MTLResourceStorageModeManaged; + #else + /* iOS: use CPU/GPU shared memory */ + res_options |= MTLResourceStorageModeShared; + #endif + mtl_desc.resourceOptions = res_options; + return true; +} + +/* initialize MTLTextureDescritor with rendertarget attributes */ +_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + SOKOL_ASSERT(img->cmn.render_target); + _SOKOL_UNUSED(img); + /* render targets are only visible to the GPU */ + mtl_desc.resourceOptions = MTLResourceStorageModePrivate; + /* non-MSAA render targets are shader-readable */ + mtl_desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget; +} + +/* initialize MTLTextureDescritor with MSAA attributes */ +_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt_msaa(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + SOKOL_ASSERT(img->cmn.sample_count > 1); + /* render targets are only visible to the GPU */ + mtl_desc.resourceOptions = MTLResourceStorageModePrivate; + /* MSAA render targets are not shader-readable (instead they are resolved) */ + mtl_desc.usage = MTLTextureUsageRenderTarget; + mtl_desc.textureType = MTLTextureType2DMultisample; + mtl_desc.depth = 1; + mtl_desc.arrayLength = 1; + mtl_desc.mipmapLevelCount = 1; + mtl_desc.sampleCount = (NSUInteger)img->cmn.sample_count; +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + _sg_image_common_init(&img->cmn, desc); + const bool injected = (0 != desc->mtl_textures[0]); + const bool msaa = (img->cmn.sample_count > 1); + + /* first initialize all Metal resource pool slots to 'empty' */ + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + img->mtl.tex[i] = _sg_mtl_add_resource(nil); + } + img->mtl.sampler_state = _sg_mtl_add_resource(nil); + img->mtl.depth_tex = _sg_mtl_add_resource(nil); + img->mtl.msaa_tex = _sg_mtl_add_resource(nil); + + /* initialize a Metal texture descriptor with common attributes */ + MTLTextureDescriptor* mtl_desc = [[MTLTextureDescriptor alloc] init]; + if (!_sg_mtl_init_texdesc_common(mtl_desc, img)) { + _SG_OBJC_RELEASE(mtl_desc); + return SG_RESOURCESTATE_FAILED; + } + + /* special case depth-stencil-buffer? */ + if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) { + /* depth-stencil buffer texture must always be a render target */ + SOKOL_ASSERT(img->cmn.render_target); + SOKOL_ASSERT(img->cmn.type == SG_IMAGETYPE_2D); + SOKOL_ASSERT(img->cmn.num_mipmaps == 1); + SOKOL_ASSERT(!injected); + if (msaa) { + _sg_mtl_init_texdesc_rt_msaa(mtl_desc, img); + } + else { + _sg_mtl_init_texdesc_rt(mtl_desc, img); + } + id tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; + SOKOL_ASSERT(nil != tex); + img->mtl.depth_tex = _sg_mtl_add_resource(tex); + } + else { + /* create the color texture + In case this is a render target without MSAA, add the relevant + render-target descriptor attributes. + In case this is a render target *with* MSAA, the color texture + will serve as MSAA-resolve target (not as render target), and rendering + will go into a separate render target texture of type + MTLTextureType2DMultisample. + */ + if (img->cmn.render_target && !msaa) { + _sg_mtl_init_texdesc_rt(mtl_desc, img); + } + for (int slot = 0; slot < img->cmn.num_slots; slot++) { + id tex; + if (injected) { + SOKOL_ASSERT(desc->mtl_textures[slot]); + tex = (__bridge id) desc->mtl_textures[slot]; + } + else { + tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; + if ((img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { + _sg_mtl_copy_image_data(img, tex, &desc->data); + } + } + img->mtl.tex[slot] = _sg_mtl_add_resource(tex); + } + + /* if MSAA color render target, create an additional MSAA render-surface texture */ + if (img->cmn.render_target && msaa) { + _sg_mtl_init_texdesc_rt_msaa(mtl_desc, img); + id tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; + img->mtl.msaa_tex = _sg_mtl_add_resource(tex); + } + + /* create (possibly shared) sampler state */ + img->mtl.sampler_state = _sg_mtl_create_sampler(_sg.mtl.device, desc); + } + _SG_OBJC_RELEASE(mtl_desc); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + /* it's valid to call release resource with a 'null resource' */ + for (int slot = 0; slot < img->cmn.num_slots; slot++) { + _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.tex[slot]); + } + _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.depth_tex); + _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.msaa_tex); + /* NOTE: sampler state objects are shared and not released until shutdown */ +} + +_SOKOL_PRIVATE id _sg_mtl_compile_library(const char* src) { + NSError* err = NULL; + id lib = [_sg.mtl.device + newLibraryWithSource:[NSString stringWithUTF8String:src] + options:nil + error:&err + ]; + if (err) { + SOKOL_LOG([err.localizedDescription UTF8String]); + } + return lib; +} + +_SOKOL_PRIVATE id _sg_mtl_library_from_bytecode(const void* ptr, size_t num_bytes) { + NSError* err = NULL; + dispatch_data_t lib_data = dispatch_data_create(ptr, num_bytes, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + id lib = [_sg.mtl.device newLibraryWithData:lib_data error:&err]; + if (err) { + SOKOL_LOG([err.localizedDescription UTF8String]); + } + _SG_OBJC_RELEASE(lib_data); + return lib; +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + + _sg_shader_common_init(&shd->cmn, desc); + + /* create metal libray objects and lookup entry functions */ + id vs_lib; + id fs_lib; + id vs_func; + id fs_func; + const char* vs_entry = desc->vs.entry; + const char* fs_entry = desc->fs.entry; + if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { + /* separate byte code provided */ + vs_lib = _sg_mtl_library_from_bytecode(desc->vs.bytecode.ptr, desc->vs.bytecode.size); + fs_lib = _sg_mtl_library_from_bytecode(desc->fs.bytecode.ptr, desc->fs.bytecode.size); + if (nil == vs_lib || nil == fs_lib) { + return SG_RESOURCESTATE_FAILED; + } + vs_func = [vs_lib newFunctionWithName:[NSString stringWithUTF8String:vs_entry]]; + fs_func = [fs_lib newFunctionWithName:[NSString stringWithUTF8String:fs_entry]]; + } + else if (desc->vs.source && desc->fs.source) { + /* separate sources provided */ + vs_lib = _sg_mtl_compile_library(desc->vs.source); + fs_lib = _sg_mtl_compile_library(desc->fs.source); + if (nil == vs_lib || nil == fs_lib) { + return SG_RESOURCESTATE_FAILED; + } + vs_func = [vs_lib newFunctionWithName:[NSString stringWithUTF8String:vs_entry]]; + fs_func = [fs_lib newFunctionWithName:[NSString stringWithUTF8String:fs_entry]]; + } + else { + return SG_RESOURCESTATE_FAILED; + } + if (nil == vs_func) { + SOKOL_LOG("vertex shader entry function not found\n"); + return SG_RESOURCESTATE_FAILED; + } + if (nil == fs_func) { + SOKOL_LOG("fragment shader entry function not found\n"); + return SG_RESOURCESTATE_FAILED; + } + /* it is legal to call _sg_mtl_add_resource with a nil value, this will return a special 0xFFFFFFFF index */ + shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib = _sg_mtl_add_resource(vs_lib); + shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib = _sg_mtl_add_resource(fs_lib); + shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func = _sg_mtl_add_resource(vs_func); + shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func = _sg_mtl_add_resource(fs_func); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + /* it is valid to call _sg_mtl_release_resource with a 'null resource' */ + _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); + _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib); + _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); + _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib); +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && shd && desc); + SOKOL_ASSERT(desc->shader.id == shd->slot.id); + + pip->shader = shd; + _sg_pipeline_common_init(&pip->cmn, desc); + + sg_primitive_type prim_type = desc->primitive_type; + pip->mtl.prim_type = _sg_mtl_primitive_type(prim_type); + pip->mtl.index_size = _sg_mtl_index_size(pip->cmn.index_type); + if (SG_INDEXTYPE_NONE != pip->cmn.index_type) { + pip->mtl.index_type = _sg_mtl_index_type(pip->cmn.index_type); + } + pip->mtl.cull_mode = _sg_mtl_cull_mode(desc->cull_mode); + pip->mtl.winding = _sg_mtl_winding(desc->face_winding); + pip->mtl.stencil_ref = desc->stencil.ref; + + /* create vertex-descriptor */ + MTLVertexDescriptor* vtx_desc = [MTLVertexDescriptor vertexDescriptor]; + for (NSUInteger attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + vtx_desc.attributes[attr_index].format = _sg_mtl_vertex_format(a_desc->format); + vtx_desc.attributes[attr_index].offset = (NSUInteger)a_desc->offset; + vtx_desc.attributes[attr_index].bufferIndex = (NSUInteger)(a_desc->buffer_index + SG_MAX_SHADERSTAGE_UBS); + pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; + } + for (NSUInteger layout_index = 0; layout_index < SG_MAX_SHADERSTAGE_BUFFERS; layout_index++) { + if (pip->cmn.vertex_layout_valid[layout_index]) { + const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[layout_index]; + const NSUInteger mtl_vb_slot = layout_index + SG_MAX_SHADERSTAGE_UBS; + SOKOL_ASSERT(l_desc->stride > 0); + vtx_desc.layouts[mtl_vb_slot].stride = (NSUInteger)l_desc->stride; + vtx_desc.layouts[mtl_vb_slot].stepFunction = _sg_mtl_step_function(l_desc->step_func); + vtx_desc.layouts[mtl_vb_slot].stepRate = (NSUInteger)l_desc->step_rate; + if (SG_VERTEXSTEP_PER_INSTANCE == l_desc->step_func) { + // NOTE: not actually used in _sg_mtl_draw() + pip->cmn.use_instanced_draw = true; + } + } + } + + /* render-pipeline descriptor */ + MTLRenderPipelineDescriptor* rp_desc = [[MTLRenderPipelineDescriptor alloc] init]; + rp_desc.vertexDescriptor = vtx_desc; + SOKOL_ASSERT(shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func != _SG_MTL_INVALID_SLOT_INDEX); + rp_desc.vertexFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); + SOKOL_ASSERT(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func != _SG_MTL_INVALID_SLOT_INDEX); + rp_desc.fragmentFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); + rp_desc.sampleCount = (NSUInteger)desc->sample_count; + rp_desc.alphaToCoverageEnabled = desc->alpha_to_coverage_enabled; + rp_desc.alphaToOneEnabled = NO; + rp_desc.rasterizationEnabled = YES; + rp_desc.depthAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); + if (desc->depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL) { + rp_desc.stencilAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); + } + /* FIXME: this only works on macOS 10.13! + for (int i = 0; i < (SG_MAX_SHADERSTAGE_UBS+SG_MAX_SHADERSTAGE_BUFFERS); i++) { + rp_desc.vertexBuffers[i].mutability = MTLMutabilityImmutable; + } + for (int i = 0; i < SG_MAX_SHADERSTAGE_UBS; i++) { + rp_desc.fragmentBuffers[i].mutability = MTLMutabilityImmutable; + } + */ + for (NSUInteger i = 0; i < (NSUInteger)desc->color_count; i++) { + SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); + const sg_color_state* cs = &desc->colors[i]; + rp_desc.colorAttachments[i].pixelFormat = _sg_mtl_pixel_format(cs->pixel_format); + rp_desc.colorAttachments[i].writeMask = _sg_mtl_color_write_mask(cs->write_mask); + rp_desc.colorAttachments[i].blendingEnabled = cs->blend.enabled; + rp_desc.colorAttachments[i].alphaBlendOperation = _sg_mtl_blend_op(cs->blend.op_alpha); + rp_desc.colorAttachments[i].rgbBlendOperation = _sg_mtl_blend_op(cs->blend.op_rgb); + rp_desc.colorAttachments[i].destinationAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_alpha); + rp_desc.colorAttachments[i].destinationRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_rgb); + rp_desc.colorAttachments[i].sourceAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_alpha); + rp_desc.colorAttachments[i].sourceRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_rgb); + } + NSError* err = NULL; + id mtl_rps = [_sg.mtl.device newRenderPipelineStateWithDescriptor:rp_desc error:&err]; + _SG_OBJC_RELEASE(rp_desc); + if (nil == mtl_rps) { + SOKOL_ASSERT(err); + SOKOL_LOG([err.localizedDescription UTF8String]); + return SG_RESOURCESTATE_FAILED; + } + + /* depth-stencil-state */ + MTLDepthStencilDescriptor* ds_desc = [[MTLDepthStencilDescriptor alloc] init]; + ds_desc.depthCompareFunction = _sg_mtl_compare_func(desc->depth.compare); + ds_desc.depthWriteEnabled = desc->depth.write_enabled; + if (desc->stencil.enabled) { + const sg_stencil_face_state* sb = &desc->stencil.back; + ds_desc.backFaceStencil = [[MTLStencilDescriptor alloc] init]; + ds_desc.backFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sb->fail_op); + ds_desc.backFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sb->depth_fail_op); + ds_desc.backFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sb->pass_op); + ds_desc.backFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sb->compare); + ds_desc.backFaceStencil.readMask = desc->stencil.read_mask; + ds_desc.backFaceStencil.writeMask = desc->stencil.write_mask; + const sg_stencil_face_state* sf = &desc->stencil.front; + ds_desc.frontFaceStencil = [[MTLStencilDescriptor alloc] init]; + ds_desc.frontFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sf->fail_op); + ds_desc.frontFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sf->depth_fail_op); + ds_desc.frontFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sf->pass_op); + ds_desc.frontFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sf->compare); + ds_desc.frontFaceStencil.readMask = desc->stencil.read_mask; + ds_desc.frontFaceStencil.writeMask = desc->stencil.write_mask; + } + id mtl_dss = [_sg.mtl.device newDepthStencilStateWithDescriptor:ds_desc]; + _SG_OBJC_RELEASE(ds_desc); + pip->mtl.rps = _sg_mtl_add_resource(mtl_rps); + pip->mtl.dss = _sg_mtl_add_resource(mtl_dss); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + /* it's valid to call release resource with a 'null resource' */ + _sg_mtl_release_resource(_sg.mtl.frame_index, pip->mtl.rps); + _sg_mtl_release_resource(_sg.mtl.frame_index, pip->mtl.dss); +} + +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass && desc); + SOKOL_ASSERT(att_images && att_images[0]); + + _sg_pass_common_init(&pass->cmn, desc); + + /* copy image pointers */ + const sg_pass_attachment_desc* att_desc; + for (int i = 0; i < pass->cmn.num_color_atts; i++) { + att_desc = &desc->color_attachments[i]; + if (att_desc->image.id != SG_INVALID_ID) { + SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); + SOKOL_ASSERT(0 == pass->mtl.color_atts[i].image); + SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_images[i]->cmn.pixel_format)); + pass->mtl.color_atts[i].image = att_images[i]; + } + } + SOKOL_ASSERT(0 == pass->mtl.ds_att.image); + att_desc = &desc->depth_stencil_attachment; + if (att_desc->image.id != SG_INVALID_ID) { + const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; + SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format)); + pass->mtl.ds_att.image = att_images[ds_img_index]; + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_mtl_destroy_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + _SOKOL_UNUSED(pass); +} + +_SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_color_image(const _sg_pass_t* pass, int index) { + SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + /* NOTE: may return null */ + return pass->mtl.color_atts[index].image; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_ds_image(const _sg_pass_t* pass) { + /* NOTE: may return null */ + SOKOL_ASSERT(pass); + return pass->mtl.ds_att.image; +} + +_SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + SOKOL_ASSERT(action); + SOKOL_ASSERT(!_sg.mtl.in_pass); + SOKOL_ASSERT(_sg.mtl.cmd_queue); + SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); + SOKOL_ASSERT(_sg.mtl.renderpass_descriptor_cb || _sg.mtl.renderpass_descriptor_userdata_cb); + _sg.mtl.in_pass = true; + _sg.mtl.cur_width = w; + _sg.mtl.cur_height = h; + _sg_mtl_clear_state_cache(); + + /* if this is the first pass in the frame, create a command buffer */ + if (nil == _sg.mtl.cmd_buffer) { + /* block until the oldest frame in flight has finished */ + dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); + _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; + [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { + // NOTE: this code is called on a different thread! + _SOKOL_UNUSED(cmd_buffer); + dispatch_semaphore_signal(_sg.mtl.sem); + }]; + } + + /* if this is first pass in frame, get uniform buffer base pointer */ + if (0 == _sg.mtl.cur_ub_base_ptr) { + _sg.mtl.cur_ub_base_ptr = (uint8_t*)[_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] contents]; + } + + /* initialize a render pass descriptor */ + MTLRenderPassDescriptor* pass_desc = nil; + if (pass) { + /* offscreen render pass */ + pass_desc = [MTLRenderPassDescriptor renderPassDescriptor]; + } + else { + /* default render pass, call user-provided callback to provide render pass descriptor */ + if (_sg.mtl.renderpass_descriptor_cb) { + pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_cb(); + } + else { + pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_userdata_cb(_sg.mtl.user_data); + } + + } + if (pass_desc) { + _sg.mtl.pass_valid = true; + } + else { + /* default pass descriptor will not be valid if window is minimized, + don't do any rendering in this case */ + _sg.mtl.pass_valid = false; + return; + } + if (pass) { + /* setup pass descriptor for offscreen rendering */ + SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); + for (NSUInteger i = 0; i < (NSUInteger)pass->cmn.num_color_atts; i++) { + const _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + const _sg_mtl_attachment_t* mtl_att = &pass->mtl.color_atts[i]; + const _sg_image_t* att_img = mtl_att->image; + SOKOL_ASSERT(att_img->slot.state == SG_RESOURCESTATE_VALID); + SOKOL_ASSERT(att_img->slot.id == cmn_att->image_id.id); + const bool is_msaa = (att_img->cmn.sample_count > 1); + pass_desc.colorAttachments[i].loadAction = _sg_mtl_load_action(action->colors[i].action); + pass_desc.colorAttachments[i].storeAction = is_msaa ? MTLStoreActionMultisampleResolve : MTLStoreActionStore; + sg_color c = action->colors[i].value; + pass_desc.colorAttachments[i].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); + if (is_msaa) { + SOKOL_ASSERT(att_img->mtl.msaa_tex != _SG_MTL_INVALID_SLOT_INDEX); + SOKOL_ASSERT(att_img->mtl.tex[mtl_att->image->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + pass_desc.colorAttachments[i].texture = _sg_mtl_id(att_img->mtl.msaa_tex); + pass_desc.colorAttachments[i].resolveTexture = _sg_mtl_id(att_img->mtl.tex[att_img->cmn.active_slot]); + pass_desc.colorAttachments[i].resolveLevel = (NSUInteger)cmn_att->mip_level; + switch (att_img->cmn.type) { + case SG_IMAGETYPE_CUBE: + case SG_IMAGETYPE_ARRAY: + pass_desc.colorAttachments[i].resolveSlice = (NSUInteger)cmn_att->slice; + break; + case SG_IMAGETYPE_3D: + pass_desc.colorAttachments[i].resolveDepthPlane = (NSUInteger)cmn_att->slice; + break; + default: break; + } + } + else { + SOKOL_ASSERT(att_img->mtl.tex[att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + pass_desc.colorAttachments[i].texture = _sg_mtl_id(att_img->mtl.tex[att_img->cmn.active_slot]); + pass_desc.colorAttachments[i].level = (NSUInteger)cmn_att->mip_level; + switch (att_img->cmn.type) { + case SG_IMAGETYPE_CUBE: + case SG_IMAGETYPE_ARRAY: + pass_desc.colorAttachments[i].slice = (NSUInteger)cmn_att->slice; + break; + case SG_IMAGETYPE_3D: + pass_desc.colorAttachments[i].depthPlane = (NSUInteger)cmn_att->slice; + break; + default: break; + } + } + } + const _sg_image_t* ds_att_img = pass->mtl.ds_att.image; + if (0 != ds_att_img) { + SOKOL_ASSERT(ds_att_img->slot.state == SG_RESOURCESTATE_VALID); + SOKOL_ASSERT(ds_att_img->slot.id == pass->cmn.ds_att.image_id.id); + SOKOL_ASSERT(ds_att_img->mtl.depth_tex != _SG_MTL_INVALID_SLOT_INDEX); + pass_desc.depthAttachment.texture = _sg_mtl_id(ds_att_img->mtl.depth_tex); + pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.action); + pass_desc.depthAttachment.clearDepth = action->depth.value; + if (_sg_is_depth_stencil_format(ds_att_img->cmn.pixel_format)) { + pass_desc.stencilAttachment.texture = _sg_mtl_id(ds_att_img->mtl.depth_tex); + pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.action); + pass_desc.stencilAttachment.clearStencil = action->stencil.value; + } + } + } + else { + /* setup pass descriptor for default rendering */ + pass_desc.colorAttachments[0].loadAction = _sg_mtl_load_action(action->colors[0].action); + sg_color c = action->colors[0].value; + pass_desc.colorAttachments[0].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); + pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.action); + pass_desc.depthAttachment.clearDepth = action->depth.value; + pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.action); + pass_desc.stencilAttachment.clearStencil = action->stencil.value; + } + + /* create a render command encoder, this might return nil if window is minimized */ + _sg.mtl.cmd_encoder = [_sg.mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc]; + if (nil == _sg.mtl.cmd_encoder) { + _sg.mtl.pass_valid = false; + return; + } + + /* bind the global uniform buffer, this only happens once per pass */ + _sg_mtl_bind_uniform_buffers(); +} + +_SOKOL_PRIVATE void _sg_mtl_end_pass(void) { + SOKOL_ASSERT(_sg.mtl.in_pass); + _sg.mtl.in_pass = false; + _sg.mtl.pass_valid = false; + if (nil != _sg.mtl.cmd_encoder) { + [_sg.mtl.cmd_encoder endEncoding]; + /* NOTE: MTLRenderCommandEncoder is autoreleased */ + _sg.mtl.cmd_encoder = nil; + } +} + +_SOKOL_PRIVATE void _sg_mtl_commit(void) { + SOKOL_ASSERT(!_sg.mtl.in_pass); + SOKOL_ASSERT(!_sg.mtl.pass_valid); + SOKOL_ASSERT(_sg.mtl.drawable_cb || _sg.mtl.drawable_userdata_cb); + SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); + SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); + + /* present, commit and signal semaphore when done */ + id cur_drawable = nil; + if (_sg.mtl.drawable_cb) { + cur_drawable = (__bridge id) _sg.mtl.drawable_cb(); + } + else { + cur_drawable = (__bridge id) _sg.mtl.drawable_userdata_cb(_sg.mtl.user_data); + } + if (nil != cur_drawable) { + [_sg.mtl.cmd_buffer presentDrawable:cur_drawable]; + } + [_sg.mtl.cmd_buffer commit]; + + /* garbage-collect resources pending for release */ + _sg_mtl_garbage_collect(_sg.mtl.frame_index); + + /* rotate uniform buffer slot */ + if (++_sg.mtl.cur_frame_rotate_index >= SG_NUM_INFLIGHT_FRAMES) { + _sg.mtl.cur_frame_rotate_index = 0; + } + _sg.mtl.frame_index++; + _sg.mtl.cur_ub_offset = 0; + _sg.mtl.cur_ub_base_ptr = 0; + /* NOTE: MTLCommandBuffer is autoreleased */ + _sg.mtl.cmd_buffer = nil; +} + +_SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + MTLViewport vp; + vp.originX = (double) x; + vp.originY = (double) (origin_top_left ? y : (_sg.mtl.cur_height - (y + h))); + vp.width = (double) w; + vp.height = (double) h; + vp.znear = 0.0; + vp.zfar = 1.0; + [_sg.mtl.cmd_encoder setViewport:vp]; +} + +_SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + /* clip against framebuffer rect */ + x = _sg_min(_sg_max(0, x), _sg.mtl.cur_width-1); + y = _sg_min(_sg_max(0, y), _sg.mtl.cur_height-1); + if ((x + w) > _sg.mtl.cur_width) { + w = _sg.mtl.cur_width - x; + } + if ((y + h) > _sg.mtl.cur_height) { + h = _sg.mtl.cur_height - y; + } + w = _sg_max(w, 1); + h = _sg_max(h, 1); + + MTLScissorRect r; + r.x = (NSUInteger)x; + r.y = (NSUInteger) (origin_top_left ? y : (_sg.mtl.cur_height - (y + h))); + r.width = (NSUInteger)w; + r.height = (NSUInteger)h; + [_sg.mtl.cmd_encoder setScissorRect:r]; +} + +_SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + + if ((_sg.mtl.state_cache.cur_pipeline != pip) || (_sg.mtl.state_cache.cur_pipeline_id.id != pip->slot.id)) { + _sg.mtl.state_cache.cur_pipeline = pip; + _sg.mtl.state_cache.cur_pipeline_id.id = pip->slot.id; + sg_color c = pip->cmn.blend_color; + [_sg.mtl.cmd_encoder setBlendColorRed:c.r green:c.g blue:c.b alpha:c.a]; + [_sg.mtl.cmd_encoder setCullMode:pip->mtl.cull_mode]; + [_sg.mtl.cmd_encoder setFrontFacingWinding:pip->mtl.winding]; + [_sg.mtl.cmd_encoder setStencilReferenceValue:pip->mtl.stencil_ref]; + [_sg.mtl.cmd_encoder setDepthBias:pip->cmn.depth_bias slopeScale:pip->cmn.depth_bias_slope_scale clamp:pip->cmn.depth_bias_clamp]; + SOKOL_ASSERT(pip->mtl.rps != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setRenderPipelineState:_sg_mtl_id(pip->mtl.rps)]; + SOKOL_ASSERT(pip->mtl.dss != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setDepthStencilState:_sg_mtl_id(pip->mtl.dss)]; + } +} + +_SOKOL_PRIVATE void _sg_mtl_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + _SOKOL_UNUSED(pip); + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + + /* store index buffer binding, this will be needed later in sg_draw() */ + _sg.mtl.state_cache.cur_indexbuffer = ib; + _sg.mtl.state_cache.cur_indexbuffer_offset = ib_offset; + if (ib) { + SOKOL_ASSERT(pip->cmn.index_type != SG_INDEXTYPE_NONE); + _sg.mtl.state_cache.cur_indexbuffer_id.id = ib->slot.id; + } + else { + SOKOL_ASSERT(pip->cmn.index_type == SG_INDEXTYPE_NONE); + _sg.mtl.state_cache.cur_indexbuffer_id.id = SG_INVALID_ID; + } + + /* apply vertex buffers */ + NSUInteger slot; + for (slot = 0; slot < (NSUInteger)num_vbs; slot++) { + const _sg_buffer_t* vb = vbs[slot]; + if ((_sg.mtl.state_cache.cur_vertexbuffers[slot] != vb) || + (_sg.mtl.state_cache.cur_vertexbuffer_offsets[slot] != vb_offsets[slot]) || + (_sg.mtl.state_cache.cur_vertexbuffer_ids[slot].id != vb->slot.id)) + { + _sg.mtl.state_cache.cur_vertexbuffers[slot] = vb; + _sg.mtl.state_cache.cur_vertexbuffer_offsets[slot] = vb_offsets[slot]; + _sg.mtl.state_cache.cur_vertexbuffer_ids[slot].id = vb->slot.id; + const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + slot; + SOKOL_ASSERT(vb->mtl.buf[vb->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setVertexBuffer:_sg_mtl_id(vb->mtl.buf[vb->cmn.active_slot]) + offset:(NSUInteger)vb_offsets[slot] + atIndex:mtl_slot]; + } + } + + /* apply vertex shader images */ + for (slot = 0; slot < (NSUInteger)num_vs_imgs; slot++) { + const _sg_image_t* img = vs_imgs[slot]; + if ((_sg.mtl.state_cache.cur_vs_images[slot] != img) || (_sg.mtl.state_cache.cur_vs_image_ids[slot].id != img->slot.id)) { + _sg.mtl.state_cache.cur_vs_images[slot] = img; + _sg.mtl.state_cache.cur_vs_image_ids[slot].id = img->slot.id; + SOKOL_ASSERT(img->mtl.tex[img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setVertexTexture:_sg_mtl_id(img->mtl.tex[img->cmn.active_slot]) atIndex:slot]; + SOKOL_ASSERT(img->mtl.sampler_state != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setVertexSamplerState:_sg_mtl_id(img->mtl.sampler_state) atIndex:slot]; + } + } + + /* apply fragment shader images */ + for (slot = 0; slot < (NSUInteger)num_fs_imgs; slot++) { + const _sg_image_t* img = fs_imgs[slot]; + if ((_sg.mtl.state_cache.cur_fs_images[slot] != img) || (_sg.mtl.state_cache.cur_fs_image_ids[slot].id != img->slot.id)) { + _sg.mtl.state_cache.cur_fs_images[slot] = img; + _sg.mtl.state_cache.cur_fs_image_ids[slot].id = img->slot.id; + SOKOL_ASSERT(img->mtl.tex[img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setFragmentTexture:_sg_mtl_id(img->mtl.tex[img->cmn.active_slot]) atIndex:slot]; + SOKOL_ASSERT(img->mtl.sampler_state != _SG_MTL_INVALID_SLOT_INDEX); + [_sg.mtl.cmd_encoder setFragmentSamplerState:_sg_mtl_id(img->mtl.sampler_state) atIndex:slot]; + } + } +} + +_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); + SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); + SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && _sg.mtl.state_cache.cur_pipeline->shader); + SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id); + SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->shader->slot.id == _sg.mtl.state_cache.cur_pipeline->cmn.shader_id.id); + SOKOL_ASSERT(ub_index < _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); + SOKOL_ASSERT(data->size <= _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + + /* copy to global uniform buffer, record offset into cmd encoder, and advance offset */ + uint8_t* dst = &_sg.mtl.cur_ub_base_ptr[_sg.mtl.cur_ub_offset]; + memcpy(dst, data->ptr, data->size); + if (stage_index == SG_SHADERSTAGE_VS) { + [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; + } + else { + [_sg.mtl.cmd_encoder setFragmentBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; + } + _sg.mtl.cur_ub_offset = _sg_roundup(_sg.mtl.cur_ub_offset + (int)data->size, _SG_MTL_UB_ALIGN); +} + +_SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) { + SOKOL_ASSERT(_sg.mtl.in_pass); + if (!_sg.mtl.pass_valid) { + return; + } + SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); + SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && (_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id)); + if (SG_INDEXTYPE_NONE != _sg.mtl.state_cache.cur_pipeline->cmn.index_type) { + /* indexed rendering */ + SOKOL_ASSERT(_sg.mtl.state_cache.cur_indexbuffer && (_sg.mtl.state_cache.cur_indexbuffer->slot.id == _sg.mtl.state_cache.cur_indexbuffer_id.id)); + const _sg_buffer_t* ib = _sg.mtl.state_cache.cur_indexbuffer; + SOKOL_ASSERT(ib->mtl.buf[ib->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + const NSUInteger index_buffer_offset = (NSUInteger) (_sg.mtl.state_cache.cur_indexbuffer_offset + base_element * _sg.mtl.state_cache.cur_pipeline->mtl.index_size); + [_sg.mtl.cmd_encoder drawIndexedPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type + indexCount:(NSUInteger)num_elements + indexType:_sg.mtl.state_cache.cur_pipeline->mtl.index_type + indexBuffer:_sg_mtl_id(ib->mtl.buf[ib->cmn.active_slot]) + indexBufferOffset:index_buffer_offset + instanceCount:(NSUInteger)num_instances]; + } + else { + /* non-indexed rendering */ + [_sg.mtl.cmd_encoder drawPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type + vertexStart:(NSUInteger)base_element + vertexCount:(NSUInteger)num_elements + instanceCount:(NSUInteger)num_instances]; + } +} + +_SOKOL_PRIVATE void _sg_mtl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } + __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); + void* dst_ptr = [mtl_buf contents]; + memcpy(dst_ptr, data->ptr, data->size); + #if defined(_SG_TARGET_MACOS) + [mtl_buf didModifyRange:NSMakeRange(0, data->size)]; + #endif +} + +_SOKOL_PRIVATE int _sg_mtl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + if (new_frame) { + if (++buf->cmn.active_slot >= buf->cmn.num_slots) { + buf->cmn.active_slot = 0; + } + } + __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); + uint8_t* dst_ptr = (uint8_t*) [mtl_buf contents]; + dst_ptr += buf->cmn.append_pos; + memcpy(dst_ptr, data->ptr, data->size); + #if defined(_SG_TARGET_MACOS) + [mtl_buf didModifyRange:NSMakeRange((NSUInteger)buf->cmn.append_pos, (NSUInteger)data->size)]; + #endif + /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backends */ + return _sg_roundup((int)data->size, 4); +} + +_SOKOL_PRIVATE void _sg_mtl_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + if (++img->cmn.active_slot >= img->cmn.num_slots) { + img->cmn.active_slot = 0; + } + __unsafe_unretained id mtl_tex = _sg_mtl_id(img->mtl.tex[img->cmn.active_slot]); + _sg_mtl_copy_image_data(img, mtl_tex, data); +} + +/*== WEBGPU BACKEND IMPLEMENTATION ===========================================*/ +#elif defined(SOKOL_WGPU) + +_SOKOL_PRIVATE WGPUBufferUsageFlags _sg_wgpu_buffer_usage(sg_buffer_type t, sg_usage u) { + WGPUBufferUsageFlags res = 0; + if (SG_BUFFERTYPE_VERTEXBUFFER == t) { + res |= WGPUBufferUsage_Vertex; + } + else { + res |= WGPUBufferUsage_Index; + } + if (SG_USAGE_IMMUTABLE != u) { + res |= WGPUBufferUsage_CopyDst; + } + return res; +} + +_SOKOL_PRIVATE WGPULoadOp _sg_wgpu_load_op(sg_action a) { + switch (a) { + case SG_ACTION_CLEAR: + case SG_ACTION_DONTCARE: + return WGPULoadOp_Clear; + case SG_ACTION_LOAD: + return WGPULoadOp_Load; + default: + SOKOL_UNREACHABLE; + return (WGPULoadOp)0; + } +} + +_SOKOL_PRIVATE WGPUTextureViewDimension _sg_wgpu_tex_viewdim(sg_image_type t) { + switch (t) { + case SG_IMAGETYPE_2D: return WGPUTextureViewDimension_2D; + case SG_IMAGETYPE_CUBE: return WGPUTextureViewDimension_Cube; + case SG_IMAGETYPE_3D: return WGPUTextureViewDimension_3D; + case SG_IMAGETYPE_ARRAY: return WGPUTextureViewDimension_2DArray; + default: SOKOL_UNREACHABLE; return WGPUTextureViewDimension_Force32; + } +} + +_SOKOL_PRIVATE WGPUTextureComponentType _sg_wgpu_tex_comptype(sg_sampler_type t) { + switch (t) { + case SG_SAMPLERTYPE_FLOAT: return WGPUTextureComponentType_Float; + case SG_SAMPLERTYPE_SINT: return WGPUTextureComponentType_Sint; + case SG_SAMPLERTYPE_UINT: return WGPUTextureComponentType_Uint; + default: SOKOL_UNREACHABLE; return WGPUTextureComponentType_Force32; + } +} + +_SOKOL_PRIVATE WGPUTextureDimension _sg_wgpu_tex_dim(sg_image_type t) { + if (SG_IMAGETYPE_3D == t) { + return WGPUTextureDimension_3D; + } + else { + return WGPUTextureDimension_2D; + } +} + +_SOKOL_PRIVATE WGPUAddressMode _sg_wgpu_sampler_addrmode(sg_wrap m) { + switch (m) { + case SG_WRAP_REPEAT: + return WGPUAddressMode_Repeat; + case SG_WRAP_CLAMP_TO_EDGE: + case SG_WRAP_CLAMP_TO_BORDER: + return WGPUAddressMode_ClampToEdge; + case SG_WRAP_MIRRORED_REPEAT: + return WGPUAddressMode_MirrorRepeat; + default: + SOKOL_UNREACHABLE; + return WGPUAddressMode_Force32; + } +} + +_SOKOL_PRIVATE WGPUFilterMode _sg_wgpu_sampler_minmagfilter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + return WGPUFilterMode_Nearest; + case SG_FILTER_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return WGPUFilterMode_Linear; + default: + SOKOL_UNREACHABLE; + return WGPUFilterMode_Force32; + } +} + +_SOKOL_PRIVATE WGPUFilterMode _sg_wgpu_sampler_mipfilter(sg_filter f) { + switch (f) { + case SG_FILTER_NEAREST: + case SG_FILTER_LINEAR: + case SG_FILTER_NEAREST_MIPMAP_NEAREST: + case SG_FILTER_LINEAR_MIPMAP_NEAREST: + return WGPUFilterMode_Nearest; + case SG_FILTER_NEAREST_MIPMAP_LINEAR: + case SG_FILTER_LINEAR_MIPMAP_LINEAR: + return WGPUFilterMode_Linear; + default: + SOKOL_UNREACHABLE; + return WGPUFilterMode_Force32; + } +} + +_SOKOL_PRIVATE WGPUIndexFormat _sg_wgpu_indexformat(sg_index_type t) { + /* NOTE: there's no WGPUIndexFormat_None */ + return (t == SG_INDEXTYPE_UINT16) ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32; +} + +_SOKOL_PRIVATE WGPUInputStepMode _sg_wgpu_stepmode(sg_vertex_step s) { + return (s == SG_VERTEXSTEP_PER_VERTEX) ? WGPUInputStepMode_Vertex : WGPUInputStepMode_Instance; +} + +_SOKOL_PRIVATE WGPUVertexFormat _sg_wgpu_vertexformat(sg_vertex_format f) { + switch (f) { + case SG_VERTEXFORMAT_FLOAT: return WGPUVertexFormat_Float; + case SG_VERTEXFORMAT_FLOAT2: return WGPUVertexFormat_Float2; + case SG_VERTEXFORMAT_FLOAT3: return WGPUVertexFormat_Float3; + case SG_VERTEXFORMAT_FLOAT4: return WGPUVertexFormat_Float4; + case SG_VERTEXFORMAT_BYTE4: return WGPUVertexFormat_Char4; + case SG_VERTEXFORMAT_BYTE4N: return WGPUVertexFormat_Char4Norm; + case SG_VERTEXFORMAT_UBYTE4: return WGPUVertexFormat_UChar4; + case SG_VERTEXFORMAT_UBYTE4N: return WGPUVertexFormat_UChar4Norm; + case SG_VERTEXFORMAT_SHORT2: return WGPUVertexFormat_Short2; + case SG_VERTEXFORMAT_SHORT2N: return WGPUVertexFormat_Short2Norm; + case SG_VERTEXFORMAT_USHORT2N: return WGPUVertexFormat_UShort2Norm; + case SG_VERTEXFORMAT_SHORT4: return WGPUVertexFormat_Short4; + case SG_VERTEXFORMAT_SHORT4N: return WGPUVertexFormat_Short4Norm; + case SG_VERTEXFORMAT_USHORT4N: return WGPUVertexFormat_UShort4Norm; + /* FIXME! UINT10_N2 */ + case SG_VERTEXFORMAT_UINT10_N2: + default: + SOKOL_UNREACHABLE; + return WGPUVertexFormat_Force32; + } +} + +_SOKOL_PRIVATE WGPUPrimitiveTopology _sg_wgpu_topology(sg_primitive_type t) { + switch (t) { + case SG_PRIMITIVETYPE_POINTS: return WGPUPrimitiveTopology_PointList; + case SG_PRIMITIVETYPE_LINES: return WGPUPrimitiveTopology_LineList; + case SG_PRIMITIVETYPE_LINE_STRIP: return WGPUPrimitiveTopology_LineStrip; + case SG_PRIMITIVETYPE_TRIANGLES: return WGPUPrimitiveTopology_TriangleList; + case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return WGPUPrimitiveTopology_TriangleStrip; + default: SOKOL_UNREACHABLE; return WGPUPrimitiveTopology_Force32; + } +} + +_SOKOL_PRIVATE WGPUFrontFace _sg_wgpu_frontface(sg_face_winding fw) { + return (fw == SG_FACEWINDING_CCW) ? WGPUFrontFace_CCW : WGPUFrontFace_CW; +} + +_SOKOL_PRIVATE WGPUCullMode _sg_wgpu_cullmode(sg_cull_mode cm) { + switch (cm) { + case SG_CULLMODE_NONE: return WGPUCullMode_None; + case SG_CULLMODE_FRONT: return WGPUCullMode_Front; + case SG_CULLMODE_BACK: return WGPUCullMode_Back; + default: SOKOL_UNREACHABLE; return WGPUCullMode_Force32; + } +} + +_SOKOL_PRIVATE WGPUTextureFormat _sg_wgpu_textureformat(sg_pixel_format p) { + switch (p) { + case SG_PIXELFORMAT_NONE: return WGPUTextureFormat_Undefined; + case SG_PIXELFORMAT_R8: return WGPUTextureFormat_R8Unorm; + case SG_PIXELFORMAT_R8SN: return WGPUTextureFormat_R8Snorm; + case SG_PIXELFORMAT_R8UI: return WGPUTextureFormat_R8Uint; + case SG_PIXELFORMAT_R8SI: return WGPUTextureFormat_R8Sint; + case SG_PIXELFORMAT_R16UI: return WGPUTextureFormat_R16Uint; + case SG_PIXELFORMAT_R16SI: return WGPUTextureFormat_R16Sint; + case SG_PIXELFORMAT_R16F: return WGPUTextureFormat_R16Float; + case SG_PIXELFORMAT_RG8: return WGPUTextureFormat_RG8Unorm; + case SG_PIXELFORMAT_RG8SN: return WGPUTextureFormat_RG8Snorm; + case SG_PIXELFORMAT_RG8UI: return WGPUTextureFormat_RG8Uint; + case SG_PIXELFORMAT_RG8SI: return WGPUTextureFormat_RG8Sint; + case SG_PIXELFORMAT_R32UI: return WGPUTextureFormat_R32Uint; + case SG_PIXELFORMAT_R32SI: return WGPUTextureFormat_R32Sint; + case SG_PIXELFORMAT_R32F: return WGPUTextureFormat_R32Float; + case SG_PIXELFORMAT_RG16UI: return WGPUTextureFormat_RG16Uint; + case SG_PIXELFORMAT_RG16SI: return WGPUTextureFormat_RG16Sint; + case SG_PIXELFORMAT_RG16F: return WGPUTextureFormat_RG16Float; + case SG_PIXELFORMAT_RGBA8: return WGPUTextureFormat_RGBA8Unorm; + case SG_PIXELFORMAT_RGBA8SN: return WGPUTextureFormat_RGBA8Snorm; + case SG_PIXELFORMAT_RGBA8UI: return WGPUTextureFormat_RGBA8Uint; + case SG_PIXELFORMAT_RGBA8SI: return WGPUTextureFormat_RGBA8Sint; + case SG_PIXELFORMAT_BGRA8: return WGPUTextureFormat_BGRA8Unorm; + case SG_PIXELFORMAT_RGB10A2: return WGPUTextureFormat_RGB10A2Unorm; + case SG_PIXELFORMAT_RG11B10F: return WGPUTextureFormat_RG11B10Float; + case SG_PIXELFORMAT_RG32UI: return WGPUTextureFormat_RG32Uint; + case SG_PIXELFORMAT_RG32SI: return WGPUTextureFormat_RG32Sint; + case SG_PIXELFORMAT_RG32F: return WGPUTextureFormat_RG32Float; + case SG_PIXELFORMAT_RGBA16UI: return WGPUTextureFormat_RGBA16Uint; + case SG_PIXELFORMAT_RGBA16SI: return WGPUTextureFormat_RGBA16Sint; + case SG_PIXELFORMAT_RGBA16F: return WGPUTextureFormat_RGBA16Float; + case SG_PIXELFORMAT_RGBA32UI: return WGPUTextureFormat_RGBA32Uint; + case SG_PIXELFORMAT_RGBA32SI: return WGPUTextureFormat_RGBA32Sint; + case SG_PIXELFORMAT_RGBA32F: return WGPUTextureFormat_RGBA32Float; + case SG_PIXELFORMAT_DEPTH: return WGPUTextureFormat_Depth24Plus; + case SG_PIXELFORMAT_DEPTH_STENCIL: return WGPUTextureFormat_Depth24PlusStencil8; + case SG_PIXELFORMAT_BC1_RGBA: return WGPUTextureFormat_BC1RGBAUnorm; + case SG_PIXELFORMAT_BC2_RGBA: return WGPUTextureFormat_BC2RGBAUnorm; + case SG_PIXELFORMAT_BC3_RGBA: return WGPUTextureFormat_BC3RGBAUnorm; + case SG_PIXELFORMAT_BC4_R: return WGPUTextureFormat_BC4RUnorm; + case SG_PIXELFORMAT_BC4_RSN: return WGPUTextureFormat_BC4RSnorm; + case SG_PIXELFORMAT_BC5_RG: return WGPUTextureFormat_BC5RGUnorm; + case SG_PIXELFORMAT_BC5_RGSN: return WGPUTextureFormat_BC5RGSnorm; + case SG_PIXELFORMAT_BC6H_RGBF: return WGPUTextureFormat_BC6HRGBSfloat; + case SG_PIXELFORMAT_BC6H_RGBUF: return WGPUTextureFormat_BC6HRGBUfloat; + case SG_PIXELFORMAT_BC7_RGBA: return WGPUTextureFormat_BC7RGBAUnorm; + + /* NOT SUPPORTED */ + case SG_PIXELFORMAT_R16: + case SG_PIXELFORMAT_R16SN: + case SG_PIXELFORMAT_RG16: + case SG_PIXELFORMAT_RG16SN: + case SG_PIXELFORMAT_RGBA16: + case SG_PIXELFORMAT_RGBA16SN: + case SG_PIXELFORMAT_PVRTC_RGB_2BPP: + case SG_PIXELFORMAT_PVRTC_RGB_4BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: + case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: + case SG_PIXELFORMAT_ETC2_RGB8: + case SG_PIXELFORMAT_ETC2_RGB8A1: + case SG_PIXELFORMAT_ETC2_RGBA8: + case SG_PIXELFORMAT_ETC2_RG11: + case SG_PIXELFORMAT_ETC2_RG11SN: + default: + SOKOL_UNREACHABLE; + return WGPUTextureFormat_Force32; + } +} + +/* +FIXME ??? this isn't needed anywhere? +_SOKOL_PRIVATE WGPUTextureAspect _sg_wgpu_texture_aspect(sg_pixel_format fmt) { + if (_sg_is_valid_rendertarget_depth_format(fmt)) { + if (!_sg_is_depth_stencil_format(fmt)) { + return WGPUTextureAspect_DepthOnly; + } + } + return WGPUTextureAspect_All; +} +*/ + +_SOKOL_PRIVATE WGPUCompareFunction _sg_wgpu_comparefunc(sg_compare_func f) { + switch (f) { + case SG_COMPAREFUNC_NEVER: return WGPUCompareFunction_Never; + case SG_COMPAREFUNC_LESS: return WGPUCompareFunction_Less; + case SG_COMPAREFUNC_EQUAL: return WGPUCompareFunction_Equal; + case SG_COMPAREFUNC_LESS_EQUAL: return WGPUCompareFunction_LessEqual; + case SG_COMPAREFUNC_GREATER: return WGPUCompareFunction_Greater; + case SG_COMPAREFUNC_NOT_EQUAL: return WGPUCompareFunction_NotEqual; + case SG_COMPAREFUNC_GREATER_EQUAL: return WGPUCompareFunction_GreaterEqual; + case SG_COMPAREFUNC_ALWAYS: return WGPUCompareFunction_Always; + default: SOKOL_UNREACHABLE; return WGPUCompareFunction_Force32; + } +} + +_SOKOL_PRIVATE WGPUStencilOperation _sg_wgpu_stencilop(sg_stencil_op op) { + switch (op) { + case SG_STENCILOP_KEEP: return WGPUStencilOperation_Keep; + case SG_STENCILOP_ZERO: return WGPUStencilOperation_Zero; + case SG_STENCILOP_REPLACE: return WGPUStencilOperation_Replace; + case SG_STENCILOP_INCR_CLAMP: return WGPUStencilOperation_IncrementClamp; + case SG_STENCILOP_DECR_CLAMP: return WGPUStencilOperation_DecrementClamp; + case SG_STENCILOP_INVERT: return WGPUStencilOperation_Invert; + case SG_STENCILOP_INCR_WRAP: return WGPUStencilOperation_IncrementWrap; + case SG_STENCILOP_DECR_WRAP: return WGPUStencilOperation_DecrementWrap; + default: SOKOL_UNREACHABLE; return WGPUStencilOperation_Force32; + } +} + +_SOKOL_PRIVATE WGPUBlendOperation _sg_wgpu_blendop(sg_blend_op op) { + switch (op) { + case SG_BLENDOP_ADD: return WGPUBlendOperation_Add; + case SG_BLENDOP_SUBTRACT: return WGPUBlendOperation_Subtract; + case SG_BLENDOP_REVERSE_SUBTRACT: return WGPUBlendOperation_ReverseSubtract; + default: SOKOL_UNREACHABLE; return WGPUBlendOperation_Force32; + } +} + +_SOKOL_PRIVATE WGPUBlendFactor _sg_wgpu_blendfactor(sg_blend_factor f) { + switch (f) { + case SG_BLENDFACTOR_ZERO: return WGPUBlendFactor_Zero; + case SG_BLENDFACTOR_ONE: return WGPUBlendFactor_One; + case SG_BLENDFACTOR_SRC_COLOR: return WGPUBlendFactor_SrcColor; + case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return WGPUBlendFactor_OneMinusSrcColor; + case SG_BLENDFACTOR_SRC_ALPHA: return WGPUBlendFactor_SrcAlpha; + case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return WGPUBlendFactor_OneMinusSrcAlpha; + case SG_BLENDFACTOR_DST_COLOR: return WGPUBlendFactor_DstColor; + case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return WGPUBlendFactor_OneMinusDstColor; + case SG_BLENDFACTOR_DST_ALPHA: return WGPUBlendFactor_DstAlpha; + case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return WGPUBlendFactor_OneMinusDstAlpha; + case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return WGPUBlendFactor_SrcAlphaSaturated; + case SG_BLENDFACTOR_BLEND_COLOR: return WGPUBlendFactor_BlendColor; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return WGPUBlendFactor_OneMinusBlendColor; + /* FIXME: separate blend alpha value not supported? */ + case SG_BLENDFACTOR_BLEND_ALPHA: return WGPUBlendFactor_BlendColor; + case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return WGPUBlendFactor_OneMinusBlendColor; + default: + SOKOL_UNREACHABLE; return WGPUBlendFactor_Force32; + } +} + +_SOKOL_PRIVATE WGPUColorWriteMaskFlags _sg_wgpu_colorwritemask(uint8_t m) { + WGPUColorWriteMaskFlags res = 0; + if (0 != (m & SG_COLORMASK_R)) { + res |= WGPUColorWriteMask_Red; + } + if (0 != (m & SG_COLORMASK_G)) { + res |= WGPUColorWriteMask_Green; + } + if (0 != (m & SG_COLORMASK_B)) { + res |= WGPUColorWriteMask_Blue; + } + if (0 != (m & SG_COLORMASK_A)) { + res |= WGPUColorWriteMask_Alpha; + } + return res; +} + +_SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { + _sg.backend = SG_BACKEND_WGPU; + _sg.features.instancing = true; + _sg.features.origin_top_left = true; + _sg.features.multiple_render_targets = true; + _sg.features.msaa_render_targets = true; + _sg.features.imagetype_3d = true; + _sg.features.imagetype_array = true; + _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; + + /* FIXME: max images size??? */ + _sg.limits.max_image_size_2d = 8 * 1024; + _sg.limits.max_image_size_cube = 8 * 1024; + _sg.limits.max_image_size_3d = 2 * 1024; + _sg.limits.max_image_size_array = 8 * 1024; + _sg.limits.max_image_array_layers = 2 * 1024; + _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES; + + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]); + _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32SI]); + _sg_pixelformat_sbr(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]); + _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]); + _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); + _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); + + /* FIXME FIXME FIXME: need to check if BC texture compression is + actually supported, currently the WebGPU C-API doesn't allow this + */ + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]); +} + +/* + WGPU uniform buffer pool implementation: + + At start of frame, a mapped buffer is grabbed from the pool, + or a new buffer is created if there is no mapped buffer available. + + At end of frame, the current buffer is unmapped before queue submit, + and async-mapped immediately again. + + UNIFORM BUFFER FIXME: + + - As per WebGPU spec, it should be possible to create a Uniform|MapWrite + buffer, but this isn't currently allowed in Dawn. +*/ +_SOKOL_PRIVATE void _sg_wgpu_ubpool_init(const sg_desc* desc) { + + /* Add the max-uniform-update size (64 KB) to the requested buffer size, + this is to prevent validation errors in the WebGPU implementation + if the entire buffer size is used per frame. 64 KB is the allowed + max uniform update size on NVIDIA + */ + _sg.wgpu.ub.num_bytes = desc->uniform_buffer_size + _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE; + + WGPUBufferDescriptor ub_desc; + memset(&ub_desc, 0, sizeof(ub_desc)); + ub_desc.size = _sg.wgpu.ub.num_bytes; + ub_desc.usage = WGPUBufferUsage_Uniform|WGPUBufferUsage_CopyDst; + _sg.wgpu.ub.buf = wgpuDeviceCreateBuffer(_sg.wgpu.dev, &ub_desc); + SOKOL_ASSERT(_sg.wgpu.ub.buf); + + WGPUBindGroupLayoutBinding ub_bglb_desc[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; + memset(ub_bglb_desc, 0, sizeof(ub_bglb_desc)); + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + WGPUShaderStage vis = (stage_index == SG_SHADERSTAGE_VS) ? WGPUShaderStage_Vertex : WGPUShaderStage_Fragment; + for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { + int bind_index = stage_index * SG_MAX_SHADERSTAGE_UBS + ub_index; + ub_bglb_desc[stage_index][ub_index].binding = bind_index; + ub_bglb_desc[stage_index][ub_index].visibility = vis; + ub_bglb_desc[stage_index][ub_index].type = WGPUBindingType_UniformBuffer; + ub_bglb_desc[stage_index][ub_index].hasDynamicOffset = true; + } + } + + WGPUBindGroupLayoutDescriptor ub_bgl_desc; + memset(&ub_bgl_desc, 0, sizeof(ub_bgl_desc)); + ub_bgl_desc.bindingCount = SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS; + ub_bgl_desc.bindings = &ub_bglb_desc[0][0]; + _sg.wgpu.ub.bindgroup_layout = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &ub_bgl_desc); + SOKOL_ASSERT(_sg.wgpu.ub.bindgroup_layout); + + WGPUBindGroupBinding ub_bgb[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS]; + memset(ub_bgb, 0, sizeof(ub_bgb)); + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { + int bind_index = stage_index * SG_MAX_SHADERSTAGE_UBS + ub_index; + ub_bgb[stage_index][ub_index].binding = bind_index; + ub_bgb[stage_index][ub_index].buffer = _sg.wgpu.ub.buf; + // FIXME FIXME FIXME FIXME: HACK FOR VALIDATION BUG IN DAWN + ub_bgb[stage_index][ub_index].size = (1<<16); + } + } + WGPUBindGroupDescriptor bg_desc; + memset(&bg_desc, 0, sizeof(bg_desc)); + bg_desc.layout = _sg.wgpu.ub.bindgroup_layout; + bg_desc.bindingCount = SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS; + bg_desc.bindings = &ub_bgb[0][0]; + _sg.wgpu.ub.bindgroup = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); + SOKOL_ASSERT(_sg.wgpu.ub.bindgroup); +} + +_SOKOL_PRIVATE void _sg_wgpu_ubpool_discard(void) { + if (_sg.wgpu.ub.buf) { + wgpuBufferRelease(_sg.wgpu.ub.buf); + _sg.wgpu.ub.buf = 0; + } + if (_sg.wgpu.ub.bindgroup) { + wgpuBindGroupRelease(_sg.wgpu.ub.bindgroup); + _sg.wgpu.ub.bindgroup = 0; + } + if (_sg.wgpu.ub.bindgroup_layout) { + wgpuBindGroupLayoutRelease(_sg.wgpu.ub.bindgroup_layout); + _sg.wgpu.ub.bindgroup_layout = 0; + } + for (int i = 0; i < _sg.wgpu.ub.stage.num; i++) { + if (_sg.wgpu.ub.stage.buf[i]) { + wgpuBufferRelease(_sg.wgpu.ub.stage.buf[i]); + _sg.wgpu.ub.stage.buf[i] = 0; + _sg.wgpu.ub.stage.ptr[i] = 0; + } + } +} + +_SOKOL_PRIVATE void _sg_wgpu_ubpool_mapped_callback(WGPUBufferMapAsyncStatus status, void* data, uint64_t data_len, void* user_data) { + if (!_sg.wgpu.valid) { + return; + } + /* FIXME: better handling for this */ + if (WGPUBufferMapAsyncStatus_Success != status) { + SOKOL_LOG("Mapping uniform buffer failed!\n"); + SOKOL_ASSERT(false); + } + SOKOL_ASSERT(data && (data_len == _sg.wgpu.ub.num_bytes)); + int index = (int)(intptr_t) user_data; + SOKOL_ASSERT(index < _sg.wgpu.ub.stage.num); + SOKOL_ASSERT(0 == _sg.wgpu.ub.stage.ptr[index]); + _sg.wgpu.ub.stage.ptr[index] = (uint8_t*) data; +} + +_SOKOL_PRIVATE void _sg_wgpu_ubpool_next_frame(bool first_frame) { + + /* immediately request a new mapping for the last frame's current staging buffer */ + if (!first_frame) { + WGPUBuffer ub_src = _sg.wgpu.ub.stage.buf[_sg.wgpu.ub.stage.cur]; + wgpuBufferMapWriteAsync(ub_src, _sg_wgpu_ubpool_mapped_callback, (void*)(intptr_t)_sg.wgpu.ub.stage.cur); + } + + /* rewind per-frame offsets */ + _sg.wgpu.ub.offset = 0; + memset(&_sg.wgpu.ub.bind_offsets, 0, sizeof(_sg.wgpu.ub.bind_offsets)); + + /* check if a mapped staging buffer is available, otherwise create one */ + for (int i = 0; i < _sg.wgpu.ub.stage.num; i++) { + if (_sg.wgpu.ub.stage.ptr[i]) { + _sg.wgpu.ub.stage.cur = i; + return; + } + } + + /* no mapped uniform buffer available, create one */ + SOKOL_ASSERT(_sg.wgpu.ub.stage.num < _SG_WGPU_STAGING_PIPELINE_SIZE); + _sg.wgpu.ub.stage.cur = _sg.wgpu.ub.stage.num++; + const int cur = _sg.wgpu.ub.stage.cur; + + WGPUBufferDescriptor desc; + memset(&desc, 0, sizeof(desc)); + desc.size = _sg.wgpu.ub.num_bytes; + desc.usage = WGPUBufferUsage_CopySrc|WGPUBufferUsage_MapWrite; + WGPUCreateBufferMappedResult res = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &desc); + _sg.wgpu.ub.stage.buf[cur] = res.buffer; + _sg.wgpu.ub.stage.ptr[cur] = (uint8_t*) res.data; + SOKOL_ASSERT(_sg.wgpu.ub.stage.buf[cur]); + SOKOL_ASSERT(_sg.wgpu.ub.stage.ptr[cur]); + SOKOL_ASSERT(res.dataLength == _sg.wgpu.ub.num_bytes); +} + +_SOKOL_PRIVATE void _sg_wgpu_ubpool_flush(void) { + /* unmap staging buffer and copy to uniform buffer */ + const int cur = _sg.wgpu.ub.stage.cur; + SOKOL_ASSERT(_sg.wgpu.ub.stage.ptr[cur]); + _sg.wgpu.ub.stage.ptr[cur] = 0; + WGPUBuffer src_buf = _sg.wgpu.ub.stage.buf[cur]; + wgpuBufferUnmap(src_buf); + if (_sg.wgpu.ub.offset > 0) { + WGPUBuffer dst_buf = _sg.wgpu.ub.buf; + wgpuCommandEncoderCopyBufferToBuffer(_sg.wgpu.render_cmd_enc, src_buf, 0, dst_buf, 0, _sg.wgpu.ub.offset); + } +} + +/* helper function to compute number of bytes needed in staging buffer to copy image data */ +_SOKOL_PRIVATE uint32_t _sg_wgpu_image_data_buffer_size(const _sg_image_t* img) { + uint32_t num_bytes = 0; + const uint32_t num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; + const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { + const uint32_t mip_width = _sg_max(img->cmn.width >> mip_index, 1); + const uint32_t mip_height = _sg_max(img->cmn.height >> mip_index, 1); + /* row-pitch must be 256-aligend */ + const uint32_t bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, _SG_WGPU_ROWPITCH_ALIGN); + num_bytes += bytes_per_slice * num_slices * num_faces; + } + return num_bytes; +} + +/* helper function to copy image data into a texture via a staging buffer, returns number of + bytes copied +*/ +_SOKOL_PRIVATE uint32_t _sg_wgpu_copy_image_data(WGPUBuffer stg_buf, uint8_t* stg_base_ptr, uint32_t stg_base_offset, _sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + SOKOL_ASSERT(stg_buf && stg_base_ptr); + SOKOL_ASSERT(img); + SOKOL_ASSERT(data); + uint32_t stg_offset = stg_base_offset; + const uint32_t num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; + const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; + const sg_pixel_format fmt = img->cmn.pixel_format; + WGPUBufferCopyView src_view; + memset(&src_view, 0, sizeof(src_view)); + src_view.buffer = stg_buf; + WGPUTextureCopyView dst_view; + memset(&dst_view, 0, sizeof(dst_view)); + dst_view.texture = img->wgpu.tex; + WGPUExtent3D extent; + memset(&extent, 0, sizeof(extent)); + + for (uint32_t face_index = 0; face_index < num_faces; face_index++) { + for (uint32_t mip_index = 0; mip_index < (uint32_t)img->cmn.num_mipmaps; mip_index++) { + SOKOL_ASSERT(data->subimage[face_index][mip_index].ptr); + SOKOL_ASSERT(data->subimage[face_index][mip_index].size > 0); + const uint8_t* src_base_ptr = (const uint8_t*)data->subimage[face_index][mip_index].ptr; + SOKOL_ASSERT(src_base_ptr); + uint8_t* dst_base_ptr = stg_base_ptr + stg_offset; + + const uint32_t mip_width = _sg_max(img->cmn.width >> mip_index, 1); + const uint32_t mip_height = _sg_max(img->cmn.height >> mip_index, 1); + const uint32_t mip_depth = (img->cmn.type == SG_IMAGETYPE_3D) ? _sg_max(img->cmn.num_slices >> mip_index, 1) : 1; + const uint32_t num_rows = _sg_num_rows(fmt, mip_height); + const uint32_t src_bytes_per_row = _sg_row_pitch(fmt, mip_width, 1); + const uint32_t dst_bytes_per_row = _sg_row_pitch(fmt, mip_width, _SG_WGPU_ROWPITCH_ALIGN); + const uint32_t src_bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, 1); + const uint32_t dst_bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, _SG_WGPU_ROWPITCH_ALIGN); + SOKOL_ASSERT((uint32_t)data->subimage[face_index][mip_index].size == (src_bytes_per_slice * num_slices)); + SOKOL_ASSERT(src_bytes_per_row <= dst_bytes_per_row); + SOKOL_ASSERT(src_bytes_per_slice == (src_bytes_per_row * num_rows)); + SOKOL_ASSERT(dst_bytes_per_slice == (dst_bytes_per_row * num_rows)); + _SOKOL_UNUSED(src_bytes_per_slice); + + /* copy data into mapped staging buffer */ + if (src_bytes_per_row == dst_bytes_per_row) { + /* can do a single memcpy */ + uint32_t num_bytes = data->subimage[face_index][mip_index].size; + memcpy(dst_base_ptr, src_base_ptr, num_bytes); + } + else { + /* src/dst pitch doesn't match, need to copy row by row */ + uint8_t* dst_ptr = dst_base_ptr; + const uint8_t* src_ptr = src_base_ptr; + for (uint32_t slice_index = 0; slice_index < num_slices; slice_index++) { + SOKOL_ASSERT(dst_ptr == dst_base_ptr + slice_index * dst_bytes_per_slice); + for (uint32_t row_index = 0; row_index < num_rows; row_index++) { + memcpy(dst_ptr, src_ptr, src_bytes_per_row); + src_ptr += src_bytes_per_row; + dst_ptr += dst_bytes_per_row; + } + } + } + + /* record the staging copy operation into command encoder */ + src_view.imageHeight = mip_height; + src_view.rowPitch = dst_bytes_per_row; + dst_view.mipLevel = mip_index; + extent.width = mip_width; + extent.height = mip_height; + extent.depth = mip_depth; + SOKOL_ASSERT((img->cmn.type != SG_IMAGETYPE_CUBE) || (num_slices == 1)); + for (uint32_t slice_index = 0; slice_index < num_slices; slice_index++) { + const uint32_t layer_index = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? slice_index : face_index; + src_view.offset = stg_offset; + dst_view.arrayLayer = layer_index; + wgpuCommandEncoderCopyBufferToTexture(_sg.wgpu.staging_cmd_enc, &src_view, &dst_view, &extent); + stg_offset += dst_bytes_per_slice; + SOKOL_ASSERT(stg_offset <= _sg.wgpu.staging.num_bytes); + } + } + } + SOKOL_ASSERT(stg_offset >= stg_base_offset); + return (stg_offset - stg_base_offset); +} + +/* + The WGPU staging buffer implementation: + + Very similar to the uniform buffer pool, there's a pool of big + per-frame staging buffers, each must be big enough to hold + all data uploaded to dynamic resources for one frame. + + Staging buffers are created on demand and reused, because the + 'frame pipeline depth' of WGPU isn't predictable. + + The difference to the uniform buffer system is that there isn't + a 1:1 relationship for source- and destination for the + data-copy operation. There's always one staging buffer as copy-source + per frame, but many copy-destinations (regular vertex/index buffers + or images). Instead of one big copy-operation at the end of the frame, + multiple copy-operations will be written throughout the frame. +*/ +_SOKOL_PRIVATE void _sg_wgpu_staging_init(const sg_desc* desc) { + SOKOL_ASSERT(desc && (desc->staging_buffer_size > 0)); + _sg.wgpu.staging.num_bytes = desc->staging_buffer_size; + /* there's actually nothing more to do here */ +} + +_SOKOL_PRIVATE void _sg_wgpu_staging_discard(void) { + for (int i = 0; i < _sg.wgpu.staging.num; i++) { + if (_sg.wgpu.staging.buf[i]) { + wgpuBufferRelease(_sg.wgpu.staging.buf[i]); + _sg.wgpu.staging.buf[i] = 0; + _sg.wgpu.staging.ptr[i] = 0; + } + } +} + +_SOKOL_PRIVATE void _sg_wgpu_staging_mapped_callback(WGPUBufferMapAsyncStatus status, void* data, uint64_t data_len, void* user_data) { + if (!_sg.wgpu.valid) { + return; + } + /* FIXME: better handling for this */ + if (WGPUBufferMapAsyncStatus_Success != status) { + SOKOL_ASSERT("Mapping staging buffer failed!\n"); + SOKOL_ASSERT(false); + } + SOKOL_ASSERT(data && (data_len == _sg.wgpu.staging.num_bytes)); + int index = (int)(intptr_t) user_data; + SOKOL_ASSERT(index < _sg.wgpu.staging.num); + SOKOL_ASSERT(0 == _sg.wgpu.staging.ptr[index]); + _sg.wgpu.staging.ptr[index] = (uint8_t*) data; +} + +_SOKOL_PRIVATE void _sg_wgpu_staging_next_frame(bool first_frame) { + + /* immediately request a new mapping for the last frame's current staging buffer */ + if (!first_frame) { + WGPUBuffer cur_buf = _sg.wgpu.staging.buf[_sg.wgpu.staging.cur]; + wgpuBufferMapWriteAsync(cur_buf, _sg_wgpu_staging_mapped_callback, (void*)(intptr_t)_sg.wgpu.staging.cur); + } + + /* rewind staging-buffer offset */ + _sg.wgpu.staging.offset = 0; + + /* check if mapped staging buffer is available, otherwise create one */ + for (int i = 0; i < _sg.wgpu.staging.num; i++) { + if (_sg.wgpu.staging.ptr[i]) { + _sg.wgpu.staging.cur = i; + return; + } + } + + /* no mapped buffer available, create one */ + SOKOL_ASSERT(_sg.wgpu.staging.num < _SG_WGPU_STAGING_PIPELINE_SIZE); + _sg.wgpu.staging.cur = _sg.wgpu.staging.num++; + const int cur = _sg.wgpu.staging.cur; + + WGPUBufferDescriptor desc; + memset(&desc, 0, sizeof(desc)); + desc.size = _sg.wgpu.staging.num_bytes; + desc.usage = WGPUBufferUsage_CopySrc|WGPUBufferUsage_MapWrite; + WGPUCreateBufferMappedResult res = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &desc); + _sg.wgpu.staging.buf[cur] = res.buffer; + _sg.wgpu.staging.ptr[cur] = (uint8_t*) res.data; + SOKOL_ASSERT(_sg.wgpu.staging.buf[cur]); + SOKOL_ASSERT(_sg.wgpu.staging.ptr[cur]); + SOKOL_ASSERT(res.dataLength == _sg.wgpu.staging.num_bytes); +} + +_SOKOL_PRIVATE uint32_t _sg_wgpu_staging_copy_to_buffer(WGPUBuffer dst_buf, uint32_t dst_buf_offset, const void* data, uint32_t data_num_bytes) { + /* Copy a chunk of data into the staging buffer, and record a blit-operation into + the command encoder, bump the offset for the next data chunk, return 0 if there + was not enough room in the staging buffer, return the number of actually + copied bytes on success. + + NOTE: that the number of staging bytes to be copied must be a multiple of 4. + + */ + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + SOKOL_ASSERT((dst_buf_offset & 3) == 0); + SOKOL_ASSERT(data_num_bytes > 0); + uint32_t copy_num_bytes = _sg_roundup(data_num_bytes, 4); + if ((_sg.wgpu.staging.offset + copy_num_bytes) >= _sg.wgpu.staging.num_bytes) { + SOKOL_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_buffer())!\n"); + return false; + } + const int cur = _sg.wgpu.staging.cur; + SOKOL_ASSERT(_sg.wgpu.staging.ptr[cur]); + uint32_t stg_buf_offset = _sg.wgpu.staging.offset; + uint8_t* stg_ptr = _sg.wgpu.staging.ptr[cur] + stg_buf_offset; + memcpy(stg_ptr, data, data_num_bytes); + WGPUBuffer stg_buf = _sg.wgpu.staging.buf[cur]; + wgpuCommandEncoderCopyBufferToBuffer(_sg.wgpu.staging_cmd_enc, stg_buf, stg_buf_offset, dst_buf, dst_buf_offset, copy_num_bytes); + _sg.wgpu.staging.offset = stg_buf_offset + copy_num_bytes; + return copy_num_bytes; +} + +_SOKOL_PRIVATE bool _sg_wgpu_staging_copy_to_texture(_sg_image_t* img, const sg_image_data* data) { + /* similar to _sg_wgpu_staging_copy_to_buffer(), but with image data instead */ + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + uint32_t num_bytes = _sg_wgpu_image_data_buffer_size(img); + if ((_sg.wgpu.staging.offset + num_bytes) >= _sg.wgpu.staging.num_bytes) { + SOKOL_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_texture)!\n"); + return false; + } + const int cur = _sg.wgpu.staging.cur; + SOKOL_ASSERT(_sg.wgpu.staging.ptr[cur]); + uint32_t stg_offset = _sg.wgpu.staging.offset; + uint8_t* stg_ptr = _sg.wgpu.staging.ptr[cur]; + WGPUBuffer stg_buf = _sg.wgpu.staging.buf[cur]; + uint32_t bytes_copied = _sg_wgpu_copy_image_data(stg_buf, stg_ptr, stg_offset, img, data); + _SOKOL_UNUSED(bytes_copied); + SOKOL_ASSERT(bytes_copied == num_bytes); + _sg.wgpu.staging.offset = _sg_roundup(stg_offset + num_bytes, _SG_WGPU_STAGING_ALIGN); + return true; +} + +_SOKOL_PRIVATE void _sg_wgpu_staging_unmap(void) { + /* called at end of frame before queue-submit */ + const int cur = _sg.wgpu.staging.cur; + SOKOL_ASSERT(_sg.wgpu.staging.ptr[cur]); + _sg.wgpu.staging.ptr[cur] = 0; + wgpuBufferUnmap(_sg.wgpu.staging.buf[cur]); +} + +/*--- WGPU sampler cache functions ---*/ +_SOKOL_PRIVATE void _sg_wgpu_init_sampler_cache(const sg_desc* desc) { + SOKOL_ASSERT(desc->sampler_cache_size > 0); + _sg_smpcache_init(&_sg.wgpu.sampler_cache, desc->sampler_cache_size); +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_sampler_cache(void) { + SOKOL_ASSERT(_sg.wgpu.sampler_cache.items); + SOKOL_ASSERT(_sg.wgpu.sampler_cache.num_items <= _sg.wgpu.sampler_cache.capacity); + for (int i = 0; i < _sg.wgpu.sampler_cache.num_items; i++) { + wgpuSamplerRelease((WGPUSampler)_sg_smpcache_sampler(&_sg.wgpu.sampler_cache, i)); + } + _sg_smpcache_discard(&_sg.wgpu.sampler_cache); +} + +_SOKOL_PRIVATE WGPUSampler _sg_wgpu_create_sampler(const sg_image_desc* img_desc) { + SOKOL_ASSERT(img_desc); + int index = _sg_smpcache_find_item(&_sg.wgpu.sampler_cache, img_desc); + if (index >= 0) { + /* reuse existing sampler */ + return (WGPUSampler) _sg_smpcache_sampler(&_sg.wgpu.sampler_cache, index); + } + else { + /* create a new WGPU sampler and add to sampler cache */ + /* FIXME: anisotropic filtering not supported? */ + WGPUSamplerDescriptor smp_desc; + memset(&smp_desc, 0, sizeof(smp_desc)); + smp_desc.addressModeU = _sg_wgpu_sampler_addrmode(img_desc->wrap_u); + smp_desc.addressModeV = _sg_wgpu_sampler_addrmode(img_desc->wrap_v); + smp_desc.addressModeW = _sg_wgpu_sampler_addrmode(img_desc->wrap_w); + smp_desc.magFilter = _sg_wgpu_sampler_minmagfilter(img_desc->mag_filter); + smp_desc.minFilter = _sg_wgpu_sampler_minmagfilter(img_desc->min_filter); + smp_desc.mipmapFilter = _sg_wgpu_sampler_mipfilter(img_desc->min_filter); + smp_desc.lodMinClamp = img_desc->min_lod; + smp_desc.lodMaxClamp = img_desc->max_lod; + WGPUSampler smp = wgpuDeviceCreateSampler(_sg.wgpu.dev, &smp_desc); + SOKOL_ASSERT(smp); + _sg_smpcache_add_item(&_sg.wgpu.sampler_cache, img_desc, (uintptr_t)smp); + return smp; + } +} + +/*--- WGPU backend API functions ---*/ +_SOKOL_PRIVATE void _sg_wgpu_setup_backend(const sg_desc* desc) { + SOKOL_ASSERT(desc); + SOKOL_ASSERT(desc->context.wgpu.device); + SOKOL_ASSERT(desc->context.wgpu.render_view_cb || desc->context.wgpu.render_view_userdata_cb); + SOKOL_ASSERT(desc->context.wgpu.resolve_view_cb || desc->context.wgpu.resolve_view_userdata_cb); + SOKOL_ASSERT(desc->context.wgpu.depth_stencil_view_cb || desc->context.wgpu.depth_stencil_view_userdata_cb); + SOKOL_ASSERT(desc->uniform_buffer_size > 0); + SOKOL_ASSERT(desc->staging_buffer_size > 0); + _sg.backend = SG_BACKEND_WGPU; + _sg.wgpu.valid = true; + _sg.wgpu.dev = (WGPUDevice) desc->context.wgpu.device; + _sg.wgpu.render_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.render_view_cb; + _sg.wgpu.render_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.render_view_userdata_cb; + _sg.wgpu.resolve_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.resolve_view_cb; + _sg.wgpu.resolve_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.resolve_view_userdata_cb; + _sg.wgpu.depth_stencil_view_cb = (WGPUTextureView(*)(void)) desc->context.wgpu.depth_stencil_view_cb; + _sg.wgpu.depth_stencil_view_userdata_cb = (WGPUTextureView(*)(void*)) desc->context.wgpu.depth_stencil_view_userdata_cb; + _sg.wgpu.user_data = desc->context.wgpu.user_data; + _sg.wgpu.queue = wgpuDeviceCreateQueue(_sg.wgpu.dev); + SOKOL_ASSERT(_sg.wgpu.queue); + + /* setup WebGPU features and limits */ + _sg_wgpu_init_caps(); + + /* setup the sampler cache, uniform and staging buffer pools */ + _sg_wgpu_init_sampler_cache(&_sg.desc); + _sg_wgpu_ubpool_init(desc); + _sg_wgpu_ubpool_next_frame(true); + _sg_wgpu_staging_init(desc); + _sg_wgpu_staging_next_frame(true); + + /* create an empty bind group for shader stages without bound images */ + WGPUBindGroupLayoutDescriptor bgl_desc; + memset(&bgl_desc, 0, sizeof(bgl_desc)); + WGPUBindGroupLayout empty_bgl = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &bgl_desc); + SOKOL_ASSERT(empty_bgl); + WGPUBindGroupDescriptor bg_desc; + memset(&bg_desc, 0, sizeof(bg_desc)); + bg_desc.layout = empty_bgl; + _sg.wgpu.empty_bind_group = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); + SOKOL_ASSERT(_sg.wgpu.empty_bind_group); + wgpuBindGroupLayoutRelease(empty_bgl); + + /* create initial per-frame command encoders */ + WGPUCommandEncoderDescriptor cmd_enc_desc; + memset(&cmd_enc_desc, 0, sizeof(cmd_enc_desc)); + _sg.wgpu.render_cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); + SOKOL_ASSERT(_sg.wgpu.render_cmd_enc); + _sg.wgpu.staging_cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); +} + +_SOKOL_PRIVATE void _sg_wgpu_discard_backend(void) { + SOKOL_ASSERT(_sg.wgpu.valid); + SOKOL_ASSERT(_sg.wgpu.render_cmd_enc); + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + _sg.wgpu.valid = false; + _sg_wgpu_ubpool_discard(); + _sg_wgpu_staging_discard(); + _sg_wgpu_destroy_sampler_cache(); + wgpuBindGroupRelease(_sg.wgpu.empty_bind_group); + wgpuCommandEncoderRelease(_sg.wgpu.render_cmd_enc); + _sg.wgpu.render_cmd_enc = 0; + wgpuCommandEncoderRelease(_sg.wgpu.staging_cmd_enc); + _sg.wgpu.staging_cmd_enc = 0; + if (_sg.wgpu.queue) { + wgpuQueueRelease(_sg.wgpu.queue); + _sg.wgpu.queue = 0; + } +} + +_SOKOL_PRIVATE void _sg_wgpu_reset_state_cache(void) { + SOKOL_LOG("_sg_wgpu_reset_state_cache: FIXME\n"); +} + +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SOKOL_UNUSED(ctx); +} + +_SOKOL_PRIVATE void _sg_wgpu_activate_context(_sg_context_t* ctx) { + (void)ctx; + SOKOL_LOG("_sg_wgpu_activate_context: FIXME\n"); +} + +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf && desc); + const bool injected = (0 != desc->wgpu_buffer); + _sg_buffer_common_init(&buf->cmn, desc); + if (injected) { + buf->wgpu.buf = (WGPUBuffer) desc->wgpu_buffer; + wgpuBufferReference(buf->wgpu.buf); + } + else { + WGPUBufferDescriptor wgpu_buf_desc; + memset(&wgpu_buf_desc, 0, sizeof(wgpu_buf_desc)); + wgpu_buf_desc.usage = _sg_wgpu_buffer_usage(buf->cmn.type, buf->cmn.usage); + wgpu_buf_desc.size = buf->cmn.size; + if (SG_USAGE_IMMUTABLE == buf->cmn.usage) { + SOKOL_ASSERT(desc->data.ptr); + WGPUCreateBufferMappedResult res = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &wgpu_buf_desc); + buf->wgpu.buf = res.buffer; + SOKOL_ASSERT(res.data && (res.dataLength == buf->cmn.size)); + memcpy(res.data, desc->data.ptr, buf->cmn.size); + wgpuBufferUnmap(res.buffer); + } + else { + buf->wgpu.buf = wgpuDeviceCreateBuffer(_sg.wgpu.dev, &wgpu_buf_desc); + } + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + WGPUBuffer wgpu_buf = buf->wgpu.buf; + if (0 != wgpu_buf) { + wgpuBufferRelease(wgpu_buf); + } +} + +_SOKOL_PRIVATE void _sg_wgpu_init_texdesc_common(WGPUTextureDescriptor* wgpu_tex_desc, const sg_image_desc* desc) { + wgpu_tex_desc->usage = WGPUTextureUsage_Sampled|WGPUTextureUsage_CopyDst; + wgpu_tex_desc->dimension = _sg_wgpu_tex_dim(desc->type); + wgpu_tex_desc->size.width = desc->width; + wgpu_tex_desc->size.height = desc->height; + if (desc->type == SG_IMAGETYPE_3D) { + wgpu_tex_desc->size.depth = desc->num_slices; + wgpu_tex_desc->arrayLayerCount = 1; + } + else if (desc->type == SG_IMAGETYPE_CUBE) { + wgpu_tex_desc->size.depth = 1; + wgpu_tex_desc->arrayLayerCount = 6; + } + else { + wgpu_tex_desc->size.depth = 1; + wgpu_tex_desc->arrayLayerCount = desc->num_slices; + } + wgpu_tex_desc->format = _sg_wgpu_textureformat(desc->pixel_format); + wgpu_tex_desc->mipLevelCount = desc->num_mipmaps; + wgpu_tex_desc->sampleCount = 1; +} + +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_image(_sg_image_t* img, const sg_image_desc* desc) { + SOKOL_ASSERT(img && desc); + SOKOL_ASSERT(_sg.wgpu.dev); + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + + _sg_image_common_init(&img->cmn, desc); + + const bool injected = (0 != desc->wgpu_texture); + const bool is_msaa = desc->sample_count > 1; + WGPUTextureDescriptor wgpu_tex_desc; + memset(&wgpu_tex_desc, 0, sizeof(wgpu_tex_desc)); + _sg_wgpu_init_texdesc_common(&wgpu_tex_desc, desc); + if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) { + SOKOL_ASSERT(img->cmn.render_target); + SOKOL_ASSERT(img->cmn.type == SG_IMAGETYPE_2D); + SOKOL_ASSERT(img->cmn.num_mipmaps == 1); + SOKOL_ASSERT(!injected); + /* NOTE: a depth-stencil texture will never be MSAA-resolved, so there + won't be a separate MSAA- and resolve-texture + */ + wgpu_tex_desc.usage = WGPUTextureUsage_OutputAttachment; + wgpu_tex_desc.sampleCount = desc->sample_count; + img->wgpu.tex = wgpuDeviceCreateTexture(_sg.wgpu.dev, &wgpu_tex_desc); + SOKOL_ASSERT(img->wgpu.tex); + } + else { + if (injected) { + img->wgpu.tex = (WGPUTexture) desc->wgpu_texture; + wgpuTextureReference(img->wgpu.tex); + } + else { + /* NOTE: in the MSAA-rendertarget case, both the MSAA texture *and* + the resolve texture need OutputAttachment usage + */ + if (img->cmn.render_target) { + wgpu_tex_desc.usage = WGPUTextureUsage_Sampled|WGPUTextureUsage_OutputAttachment; + } + img->wgpu.tex = wgpuDeviceCreateTexture(_sg.wgpu.dev, &wgpu_tex_desc); + SOKOL_ASSERT(img->wgpu.tex); + + /* copy content into texture via a throw-away staging buffer */ + if (desc->usage == SG_USAGE_IMMUTABLE && !desc->render_target) { + WGPUBufferDescriptor wgpu_buf_desc; + memset(&wgpu_buf_desc, 0, sizeof(wgpu_buf_desc)); + wgpu_buf_desc.size = _sg_wgpu_image_data_buffer_size(img); + wgpu_buf_desc.usage = WGPUBufferUsage_CopySrc|WGPUBufferUsage_CopyDst; + WGPUCreateBufferMappedResult map = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &wgpu_buf_desc); + SOKOL_ASSERT(map.buffer && map.data); + uint32_t num_bytes = _sg_wgpu_copy_image_data(map.buffer, (uint8_t*)map.data, 0, img, &desc->data); + _SOKOL_UNUSED(num_bytes); + SOKOL_ASSERT(num_bytes == wgpu_buf_desc.size); + wgpuBufferUnmap(map.buffer); + wgpuBufferRelease(map.buffer); + } + } + + /* create texture view object */ + WGPUTextureViewDescriptor wgpu_view_desc; + memset(&wgpu_view_desc, 0, sizeof(wgpu_view_desc)); + wgpu_view_desc.dimension = _sg_wgpu_tex_viewdim(desc->type); + img->wgpu.tex_view = wgpuTextureCreateView(img->wgpu.tex, &wgpu_view_desc); + + /* if render target and MSAA, then a separate texture in MSAA format is needed + which will be resolved into the regular texture at the end of the + offscreen-render pass + */ + if (desc->render_target && is_msaa) { + wgpu_tex_desc.dimension = WGPUTextureDimension_2D; + wgpu_tex_desc.size.depth = 1; + wgpu_tex_desc.arrayLayerCount = 1; + wgpu_tex_desc.mipLevelCount = 1; + wgpu_tex_desc.usage = WGPUTextureUsage_OutputAttachment; + wgpu_tex_desc.sampleCount = desc->sample_count; + img->wgpu.msaa_tex = wgpuDeviceCreateTexture(_sg.wgpu.dev, &wgpu_tex_desc); + SOKOL_ASSERT(img->wgpu.msaa_tex); + } + + /* create sampler via shared-sampler-cache */ + img->wgpu.sampler = _sg_wgpu_create_sampler(desc); + SOKOL_ASSERT(img->wgpu.sampler); + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + if (img->wgpu.tex) { + wgpuTextureRelease(img->wgpu.tex); + img->wgpu.tex = 0; + } + if (img->wgpu.tex_view) { + wgpuTextureViewRelease(img->wgpu.tex_view); + img->wgpu.tex_view = 0; + } + if (img->wgpu.msaa_tex) { + wgpuTextureRelease(img->wgpu.msaa_tex); + img->wgpu.msaa_tex = 0; + } + /* NOTE: do *not* destroy the sampler from the shared-sampler-cache */ + img->wgpu.sampler = 0; +} + +/* + How BindGroups work in WebGPU: + + - up to 4 bind groups can be bound simultaneously + - up to 16 bindings per bind group + - 'binding' slots are local per bind group + - in the shader: + layout(set=0, binding=1) corresponds to bind group 0, binding 1 + + Now how to map this to sokol-gfx's bind model: + + Reduce SG_MAX_SHADERSTAGE_IMAGES to 8, then: + + 1 bind group for all 8 uniform buffers + 1 bind group for vertex shader textures + samplers + 1 bind group for fragment shader textures + samples + + Alternatively: + + 1 bind group for 8 uniform buffer slots + 1 bind group for 8 vs images + 8 vs samplers + 1 bind group for 12 fs images + 1 bind group for 12 fs samplers + + I guess this means that we need to create BindGroups on the + fly during sg_apply_bindings() :/ +*/ +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd && desc); + SOKOL_ASSERT(desc->vs.bytecode.ptr && desc->fs.bytecode.ptr); + _sg_shader_common_init(&shd->cmn, desc); + + bool success = true; + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; + SOKOL_ASSERT((stage_desc->bytecode.size & 3) == 0); + + _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; + _sg_wgpu_shader_stage_t* wgpu_stage = &shd->wgpu.stage[stage_index]; + + _sg_strcpy(&wgpu_stage->entry, stage_desc->entry); + WGPUShaderModuleDescriptor wgpu_shdmod_desc; + memset(&wgpu_shdmod_desc, 0, sizeof(wgpu_shdmod_desc)); + wgpu_shdmod_desc.codeSize = stage_desc->bytecode.size >> 2; + wgpu_shdmod_desc.code = (const uint32_t*) stage_desc->bytecode.ptr; + wgpu_stage->module = wgpuDeviceCreateShaderModule(_sg.wgpu.dev, &wgpu_shdmod_desc); + if (0 == wgpu_stage->module) { + success = false; + } + + /* create image/sampler bind group for the shader stage */ + WGPUShaderStage vis = (stage_index == SG_SHADERSTAGE_VS) ? WGPUShaderStage_Vertex : WGPUShaderStage_Fragment; + int num_imgs = cmn_stage->num_images; + if (num_imgs > _SG_WGPU_MAX_SHADERSTAGE_IMAGES) { + num_imgs = _SG_WGPU_MAX_SHADERSTAGE_IMAGES; + } + WGPUBindGroupLayoutBinding bglb_desc[_SG_WGPU_MAX_SHADERSTAGE_IMAGES * 2]; + memset(bglb_desc, 0, sizeof(bglb_desc)); + for (int img_index = 0; img_index < num_imgs; img_index++) { + /* texture- and sampler-bindings */ + WGPUBindGroupLayoutBinding* tex_desc = &bglb_desc[img_index*2 + 0]; + WGPUBindGroupLayoutBinding* smp_desc = &bglb_desc[img_index*2 + 1]; + + tex_desc->binding = img_index; + tex_desc->visibility = vis; + tex_desc->type = WGPUBindingType_SampledTexture; + tex_desc->textureDimension = _sg_wgpu_tex_viewdim(cmn_stage->images[img_index].image_type); + tex_desc->textureComponentType = _sg_wgpu_tex_comptype(cmn_stage->images[img_index].sampler_type); + + smp_desc->binding = img_index + _SG_WGPU_MAX_SHADERSTAGE_IMAGES; + smp_desc->visibility = vis; + smp_desc->type = WGPUBindingType_Sampler; + } + WGPUBindGroupLayoutDescriptor img_bgl_desc; + memset(&img_bgl_desc, 0, sizeof(img_bgl_desc)); + img_bgl_desc.bindingCount = num_imgs * 2; + img_bgl_desc.bindings = &bglb_desc[0]; + wgpu_stage->bind_group_layout = wgpuDeviceCreateBindGroupLayout(_sg.wgpu.dev, &img_bgl_desc); + SOKOL_ASSERT(wgpu_stage->bind_group_layout); + } + return success ? SG_RESOURCESTATE_VALID : SG_RESOURCESTATE_FAILED; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + _sg_wgpu_shader_stage_t* wgpu_stage = &shd->wgpu.stage[stage_index]; + if (wgpu_stage->module) { + wgpuShaderModuleRelease(wgpu_stage->module); + wgpu_stage->module = 0; + } + if (wgpu_stage->bind_group_layout) { + wgpuBindGroupLayoutRelease(wgpu_stage->bind_group_layout); + wgpu_stage->bind_group_layout = 0; + } + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip && shd && desc); + SOKOL_ASSERT(desc->shader.id == shd->slot.id); + SOKOL_ASSERT(shd->wgpu.stage[SG_SHADERSTAGE_VS].bind_group_layout); + SOKOL_ASSERT(shd->wgpu.stage[SG_SHADERSTAGE_FS].bind_group_layout); + pip->shader = shd; + _sg_pipeline_common_init(&pip->cmn, desc); + pip->wgpu.stencil_ref = (uint32_t) desc->stencil.ref; + + WGPUBindGroupLayout pip_bgl[3] = { + _sg.wgpu.ub.bindgroup_layout, + shd->wgpu.stage[SG_SHADERSTAGE_VS].bind_group_layout, + shd->wgpu.stage[SG_SHADERSTAGE_FS].bind_group_layout + }; + WGPUPipelineLayoutDescriptor pl_desc; + memset(&pl_desc, 0, sizeof(pl_desc)); + pl_desc.bindGroupLayoutCount = 3; + pl_desc.bindGroupLayouts = &pip_bgl[0]; + WGPUPipelineLayout pip_layout = wgpuDeviceCreatePipelineLayout(_sg.wgpu.dev, &pl_desc); + + WGPUVertexBufferLayoutDescriptor vb_desc[SG_MAX_SHADERSTAGE_BUFFERS]; + memset(&vb_desc, 0, sizeof(vb_desc)); + WGPUVertexAttributeDescriptor va_desc[SG_MAX_SHADERSTAGE_BUFFERS][SG_MAX_VERTEX_ATTRIBUTES]; + memset(&va_desc, 0, sizeof(va_desc)); + int vb_idx = 0; + for (; vb_idx < SG_MAX_SHADERSTAGE_BUFFERS; vb_idx++) { + const sg_buffer_layout_desc* src_vb_desc = &desc->layout.buffers[vb_idx]; + if (0 == src_vb_desc->stride) { + break; + } + vb_desc[vb_idx].arrayStride = src_vb_desc->stride; + vb_desc[vb_idx].stepMode = _sg_wgpu_stepmode(src_vb_desc->step_func); + /* NOTE: WebGPU has no support for vertex step rate (because that's + not supported by Core Vulkan + */ + int va_idx = 0; + for (int va_loc = 0; va_loc < SG_MAX_VERTEX_ATTRIBUTES; va_loc++) { + const sg_vertex_attr_desc* src_va_desc = &desc->layout.attrs[va_loc]; + if (SG_VERTEXFORMAT_INVALID == src_va_desc->format) { + break; + } + pip->cmn.vertex_layout_valid[src_va_desc->buffer_index] = true; + if (vb_idx == src_va_desc->buffer_index) { + va_desc[vb_idx][va_idx].format = _sg_wgpu_vertexformat(src_va_desc->format); + va_desc[vb_idx][va_idx].offset = src_va_desc->offset; + va_desc[vb_idx][va_idx].shaderLocation = va_loc; + va_idx++; + } + } + vb_desc[vb_idx].attributeCount = va_idx; + vb_desc[vb_idx].attributes = &va_desc[vb_idx][0]; + } + WGPUVertexStateDescriptor vx_state_desc; + memset(&vx_state_desc, 0, sizeof(vx_state_desc)); + vx_state_desc.indexFormat = _sg_wgpu_indexformat(desc->index_type); + vx_state_desc.vertexBufferCount = vb_idx; + vx_state_desc.vertexBuffers = vb_desc; + + WGPURasterizationStateDescriptor rs_desc; + memset(&rs_desc, 0, sizeof(rs_desc)); + rs_desc.frontFace = _sg_wgpu_frontface(desc->face_winding); + rs_desc.cullMode = _sg_wgpu_cullmode(desc->cull_mode); + rs_desc.depthBias = (int32_t) desc->depth.bias; + rs_desc.depthBiasClamp = desc->depth.bias_clamp; + rs_desc.depthBiasSlopeScale = desc->depth.bias_slope_scale; + + WGPUDepthStencilStateDescriptor ds_desc; + memset(&ds_desc, 0, sizeof(ds_desc)); + ds_desc.format = _sg_wgpu_textureformat(desc->depth.pixel_format); + ds_desc.depthWriteEnabled = desc->depth.write_enabled; + ds_desc.depthCompare = _sg_wgpu_comparefunc(desc->depth.compare); + ds_desc.stencilReadMask = desc->stencil.read_mask; + ds_desc.stencilWriteMask = desc->stencil.write_mask; + ds_desc.stencilFront.compare = _sg_wgpu_comparefunc(desc->stencil.front.compare); + ds_desc.stencilFront.failOp = _sg_wgpu_stencilop(desc->stencil.front.fail_op); + ds_desc.stencilFront.depthFailOp = _sg_wgpu_stencilop(desc->stencil.front.depth_fail_op); + ds_desc.stencilFront.passOp = _sg_wgpu_stencilop(desc->stencil.front.pass_op); + ds_desc.stencilBack.compare = _sg_wgpu_comparefunc(desc->stencil.back.compare); + ds_desc.stencilBack.failOp = _sg_wgpu_stencilop(desc->stencil.back.fail_op); + ds_desc.stencilBack.depthFailOp = _sg_wgpu_stencilop(desc->stencil.back.depth_fail_op); + ds_desc.stencilBack.passOp = _sg_wgpu_stencilop(desc->stencil.back.pass_op); + + WGPUProgrammableStageDescriptor fs_desc; + memset(&fs_desc, 0, sizeof(fs_desc)); + fs_desc.module = shd->wgpu.stage[SG_SHADERSTAGE_FS].module; + fs_desc.entryPoint = shd->wgpu.stage[SG_SHADERSTAGE_VS].entry.buf; + + WGPUColorStateDescriptor cs_desc[SG_MAX_COLOR_ATTACHMENTS]; + memset(cs_desc, 0, sizeof(cs_desc)); + for (uint32_t i = 0; i < desc->color_count; i++) { + SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); + cs_desc[i].format = _sg_wgpu_textureformat(desc->colors[i].pixel_format); + cs_desc[i].colorBlend.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_rgb); + cs_desc[i].colorBlend.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_rgb); + cs_desc[i].colorBlend.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_rgb); + cs_desc[i].alphaBlend.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_alpha); + cs_desc[i].alphaBlend.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_alpha); + cs_desc[i].alphaBlend.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_alpha); + cs_desc[i].writeMask = _sg_wgpu_colorwritemask(desc->colors[i].write_mask); + } + + WGPURenderPipelineDescriptor pip_desc; + memset(&pip_desc, 0, sizeof(pip_desc)); + pip_desc.layout = pip_layout; + pip_desc.vertexStage.module = shd->wgpu.stage[SG_SHADERSTAGE_VS].module; + pip_desc.vertexStage.entryPoint = shd->wgpu.stage[SG_SHADERSTAGE_VS].entry.buf; + pip_desc.fragmentStage = &fs_desc; + pip_desc.vertexState = &vx_state_desc; + pip_desc.primitiveTopology = _sg_wgpu_topology(desc->primitive_type); + pip_desc.rasterizationState = &rs_desc; + pip_desc.sampleCount = desc->sample_count; + if (SG_PIXELFORMAT_NONE != desc->depth.pixel_format) { + pip_desc.depthStencilState = &ds_desc; + } + pip_desc.colorStateCount = desc->color_count; + pip_desc.colorStates = cs_desc; + pip_desc.sampleMask = 0xFFFFFFFF; /* FIXME: ??? */ + pip->wgpu.pip = wgpuDeviceCreateRenderPipeline(_sg.wgpu.dev, &pip_desc); + SOKOL_ASSERT(0 != pip->wgpu.pip); + wgpuPipelineLayoutRelease(pip_layout); + + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + if (pip == _sg.wgpu.cur_pipeline) { + _sg.wgpu.cur_pipeline = 0; + _Sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; + } + if (pip->wgpu.pip) { + wgpuRenderPipelineRelease(pip->wgpu.pip); + pip->wgpu.pip = 0; + } +} + +_SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass && desc); + SOKOL_ASSERT(att_images && att_images[0]); + _sg_pass_common_init(&pass->cmn, desc); + + /* copy image pointers and create render-texture views */ + const sg_pass_attachment_desc* att_desc; + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { + att_desc = &desc->color_attachments[i]; + if (att_desc->image.id != SG_INVALID_ID) { + SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); + SOKOL_ASSERT(0 == pass->wgpu.color_atts[i].image); + _sg_image_t* img = att_images[i]; + SOKOL_ASSERT(img && (img->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format)); + pass->wgpu.color_atts[i].image = img; + /* create a render-texture-view to render into the right sub-surface */ + const bool is_msaa = img->cmn.sample_count > 1; + WGPUTextureViewDescriptor view_desc; + memset(&view_desc, 0, sizeof(view_desc)); + view_desc.baseMipLevel = is_msaa ? 0 : att_desc->mip_level; + view_desc.mipLevelCount = 1; + view_desc.baseArrayLayer = is_msaa ? 0 : att_desc->slice; + view_desc.arrayLayerCount = 1; + WGPUTexture wgpu_tex = is_msaa ? img->wgpu.msaa_tex : img->wgpu.tex; + SOKOL_ASSERT(wgpu_tex); + pass->wgpu.color_atts[i].render_tex_view = wgpuTextureCreateView(wgpu_tex, &view_desc); + SOKOL_ASSERT(pass->wgpu.color_atts[i].render_tex_view); + /* ... and if needed a separate resolve texture view */ + if (is_msaa) { + view_desc.baseMipLevel = att_desc->mip_level; + view_desc.baseArrayLayer = att_desc->slice; + WGPUTexture wgpu_tex = img->wgpu.tex; + pass->wgpu.color_atts[i].resolve_tex_view = wgpuTextureCreateView(wgpu_tex, &view_desc); + SOKOL_ASSERT(pass->wgpu.color_atts[i].resolve_tex_view); + } + } + } + SOKOL_ASSERT(0 == pass->wgpu.ds_att.image); + att_desc = &desc->depth_stencil_attachment; + if (att_desc->image.id != SG_INVALID_ID) { + const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; + SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id)); + SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format)); + _sg_image_t* ds_img = att_images[ds_img_index]; + pass->wgpu.ds_att.image = ds_img; + /* create a render-texture view */ + SOKOL_ASSERT(0 == att_desc->mip_level); + SOKOL_ASSERT(0 == att_desc->slice); + WGPUTextureViewDescriptor view_desc; + memset(&view_desc, 0, sizeof(view_desc)); + WGPUTexture wgpu_tex = ds_img->wgpu.tex; + SOKOL_ASSERT(wgpu_tex); + pass->wgpu.ds_att.render_tex_view = wgpuTextureCreateView(wgpu_tex, &view_desc); + SOKOL_ASSERT(pass->wgpu.ds_att.render_tex_view); + } + return SG_RESOURCESTATE_VALID; +} + +_SOKOL_PRIVATE void _sg_wgpu_destroy_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { + if (pass->wgpu.color_atts[i].render_tex_view) { + wgpuTextureViewRelease(pass->wgpu.color_atts[i].render_tex_view); + pass->wgpu.color_atts[i].render_tex_view = 0; + } + if (pass->wgpu.color_atts[i].resolve_tex_view) { + wgpuTextureViewRelease(pass->wgpu.color_atts[i].resolve_tex_view); + pass->wgpu.color_atts[i].resolve_tex_view = 0; + } + } + if (pass->wgpu.ds_att.render_tex_view) { + wgpuTextureViewRelease(pass->wgpu.ds_att.render_tex_view); + pass->wgpu.ds_att.render_tex_view = 0; + } +} + +_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_pass_color_image(const _sg_pass_t* pass, int index) { + SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS)); + /* NOTE: may return null */ + return pass->wgpu.color_atts[index].image; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_wgpu_pass_ds_image(const _sg_pass_t* pass) { + /* NOTE: may return null */ + SOKOL_ASSERT(pass); + return pass->wgpu.ds_att.image; +} + +_SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + SOKOL_ASSERT(action); + SOKOL_ASSERT(!_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.render_cmd_enc); + SOKOL_ASSERT(_sg.wgpu.dev); + SOKOL_ASSERT(_sg.wgpu.render_view_cb || _sg.wgpu.render_view_userdata_cb); + SOKOL_ASSERT(_sg.wgpu.resolve_view_cb || _sg.wgpu.resolve_view_userdata_cb); + SOKOL_ASSERT(_sg.wgpu.depth_stencil_view_cb || _sg.wgpu.depth_stencil_view_userdata_cb); + _sg.wgpu.in_pass = true; + _sg.wgpu.cur_width = w; + _sg.wgpu.cur_height = h; + _sg.wgpu.cur_pipeline = 0; + _sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; + + SOKOL_ASSERT(_sg.wgpu.render_cmd_enc); + if (pass) { + WGPURenderPassDescriptor wgpu_pass_desc; + memset(&wgpu_pass_desc, 0, sizeof(wgpu_pass_desc)); + WGPURenderPassColorAttachmentDescriptor wgpu_color_att_desc[SG_MAX_COLOR_ATTACHMENTS]; + memset(&wgpu_color_att_desc, 0, sizeof(wgpu_color_att_desc)); + SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { + const _sg_wgpu_attachment_t* wgpu_att = &pass->wgpu.color_atts[i]; + wgpu_color_att_desc[i].loadOp = _sg_wgpu_load_op(action->colors[i].action); + wgpu_color_att_desc[i].storeOp = WGPUStoreOp_Store; + wgpu_color_att_desc[i].clearColor.r = action->colors[i].value.r; + wgpu_color_att_desc[i].clearColor.g = action->colors[i].value.g; + wgpu_color_att_desc[i].clearColor.b = action->colors[i].value.b; + wgpu_color_att_desc[i].clearColor.a = action->colors[i].value.a; + wgpu_color_att_desc[i].attachment = wgpu_att->render_tex_view; + if (wgpu_att->image->cmn.sample_count > 1) { + wgpu_color_att_desc[i].resolveTarget = wgpu_att->resolve_tex_view; + } + } + wgpu_pass_desc.colorAttachmentCount = pass->cmn.num_color_atts; + wgpu_pass_desc.colorAttachments = &wgpu_color_att_desc[0]; + if (pass->wgpu.ds_att.image) { + WGPURenderPassDepthStencilAttachmentDescriptor wgpu_ds_att_desc; + memset(&wgpu_ds_att_desc, 0, sizeof(wgpu_ds_att_desc)); + wgpu_ds_att_desc.depthLoadOp = _sg_wgpu_load_op(action->depth.action); + wgpu_ds_att_desc.clearDepth = action->depth.value; + wgpu_ds_att_desc.stencilLoadOp = _sg_wgpu_load_op(action->stencil.action); + wgpu_ds_att_desc.clearStencil = action->stencil.value; + wgpu_ds_att_desc.attachment = pass->wgpu.ds_att.render_tex_view; + wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att_desc; + _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.render_cmd_enc, &wgpu_pass_desc); + } + } + else { + /* default render pass */ + WGPUTextureView wgpu_render_view = _sg.wgpu.render_view_cb ? _sg.wgpu.render_view_cb() : _sg.wgpu.render_view_userdata_cb(_sg.wgpu.user_data); + WGPUTextureView wgpu_resolve_view = _sg.wgpu.resolve_view_cb ? _sg.wgpu.resolve_view_cb() : _sg.wgpu.resolve_view_userdata_cb(_sg.wgpu.user_data); + WGPUTextureView wgpu_depth_stencil_view = _sg.wgpu.depth_stencil_view_cb ? _sg.wgpu.depth_stencil_view_cb() : _sg.wgpu.depth_stencil_view_userdata_cb(_sg.wgpu.user_data); + + WGPURenderPassDescriptor pass_desc; + memset(&pass_desc, 0, sizeof(pass_desc)); + WGPURenderPassColorAttachmentDescriptor color_att_desc; + memset(&color_att_desc, 0, sizeof(color_att_desc)); + color_att_desc.loadOp = _sg_wgpu_load_op(action->colors[0].action); + color_att_desc.clearColor.r = action->colors[0].value.r; + color_att_desc.clearColor.g = action->colors[0].value.g; + color_att_desc.clearColor.b = action->colors[0].value.b; + color_att_desc.clearColor.a = action->colors[0].value.a; + color_att_desc.attachment = wgpu_render_view; + color_att_desc.resolveTarget = wgpu_resolve_view; /* null if no MSAA rendering */ + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_att_desc; + WGPURenderPassDepthStencilAttachmentDescriptor ds_att_desc; + memset(&ds_att_desc, 0, sizeof(ds_att_desc)); + ds_att_desc.attachment = wgpu_depth_stencil_view; + SOKOL_ASSERT(0 != ds_att_desc.attachment); + ds_att_desc.depthLoadOp = _sg_wgpu_load_op(action->depth.action); + ds_att_desc.clearDepth = action->depth.value; + ds_att_desc.stencilLoadOp = _sg_wgpu_load_op(action->stencil.action); + ds_att_desc.clearStencil = action->stencil.value; + pass_desc.depthStencilAttachment = &ds_att_desc; + _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.render_cmd_enc, &pass_desc); + } + SOKOL_ASSERT(_sg.wgpu.pass_enc); + + /* initial uniform buffer binding (required even if no uniforms are set in the frame) */ + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, + 0, /* groupIndex 0 is reserved for uniform buffers */ + _sg.wgpu.ub.bindgroup, + SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS, + &_sg.wgpu.ub.bind_offsets[0][0]); +} + +_SOKOL_PRIVATE void _sg_wgpu_end_pass(void) { + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + _sg.wgpu.in_pass = false; + wgpuRenderPassEncoderEndPass(_sg.wgpu.pass_enc); + wgpuRenderPassEncoderRelease(_sg.wgpu.pass_enc); + _sg.wgpu.pass_enc = 0; +} + +_SOKOL_PRIVATE void _sg_wgpu_commit(void) { + SOKOL_ASSERT(!_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.queue); + SOKOL_ASSERT(_sg.wgpu.render_cmd_enc); + SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); + + /* finish and submit this frame's work */ + _sg_wgpu_ubpool_flush(); + _sg_wgpu_staging_unmap(); + + WGPUCommandBuffer cmd_bufs[2]; + + WGPUCommandBufferDescriptor cmd_buf_desc; + memset(&cmd_buf_desc, 0, sizeof(cmd_buf_desc)); + cmd_bufs[0] = wgpuCommandEncoderFinish(_sg.wgpu.staging_cmd_enc, &cmd_buf_desc); + SOKOL_ASSERT(cmd_bufs[0]); + wgpuCommandEncoderRelease(_sg.wgpu.staging_cmd_enc); + _sg.wgpu.staging_cmd_enc = 0; + + cmd_bufs[1] = wgpuCommandEncoderFinish(_sg.wgpu.render_cmd_enc, &cmd_buf_desc); + SOKOL_ASSERT(cmd_bufs[1]); + wgpuCommandEncoderRelease(_sg.wgpu.render_cmd_enc); + _sg.wgpu.render_cmd_enc = 0; + + wgpuQueueSubmit(_sg.wgpu.queue, 2, &cmd_bufs[0]); + + wgpuCommandBufferRelease(cmd_bufs[0]); + wgpuCommandBufferRelease(cmd_bufs[1]); + + /* create a new render- and staging-command-encoders for next frame */ + WGPUCommandEncoderDescriptor cmd_enc_desc; + memset(&cmd_enc_desc, 0, sizeof(cmd_enc_desc)); + _sg.wgpu.staging_cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); + _sg.wgpu.render_cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc); + + /* grab new staging buffers for uniform- and vertex/image-updates */ + _sg_wgpu_ubpool_next_frame(false); + _sg_wgpu_staging_next_frame(false); +} + +_SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + float xf = (float) x; + float yf = (float) (origin_top_left ? y : (_sg.wgpu.cur_height - (y + h))); + float wf = (float) w; + float hf = (float) h; + wgpuRenderPassEncoderSetViewport(_sg.wgpu.pass_enc, xf, yf, wf, hf, 0.0f, 1.0f); +} + +_SOKOL_PRIVATE void _sg_wgpu_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + + /* clip against framebuffer rect */ + x = _sg_min(_sg_max(0, x), _sg.wgpu.cur_width-1); + y = _sg_min(_sg_max(0, y), _sg.wgpu.cur_height-1); + if ((x + w) > _sg.wgpu.cur_width) { + w = _sg.wgpu.cur_width - x; + } + if ((y + h) > _sg.wgpu.cur_height) { + h = _sg.wgpu.cur_height - y; + } + w = _sg_max(w, 1); + h = _sg_max(h, 1); + + uint32_t sx = (uint32_t) x; + uint32_t sy = origin_top_left ? y : (_sg.wgpu.cur_height - (y + h)); + uint32_t sw = w; + uint32_t sh = h; + wgpuRenderPassEncoderSetScissorRect(_sg.wgpu.pass_enc, sx, sy, sw, sh); +} + +_SOKOL_PRIVATE void _sg_wgpu_apply_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + SOKOL_ASSERT(pip->wgpu.pip); + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + _sg.wgpu.draw_indexed = (pip->cmn.index_type != SG_INDEXTYPE_NONE); + _sg.wgpu.cur_pipeline = pip; + _sg.wgpu.cur_pipeline_id.id = pip->slot.id; + wgpuRenderPassEncoderSetPipeline(_sg.wgpu.pass_enc, pip->wgpu.pip); + wgpuRenderPassEncoderSetBlendColor(_sg.wgpu.pass_enc, (WGPUColor*)&pip->cmn.blend_color); + wgpuRenderPassEncoderSetStencilReference(_sg.wgpu.pass_enc, pip->wgpu.stencil_ref); +} + +_SOKOL_PRIVATE WGPUBindGroup _sg_wgpu_create_images_bindgroup(WGPUBindGroupLayout bgl, _sg_image_t** imgs, int num_imgs) { + SOKOL_ASSERT(_sg.wgpu.dev); + SOKOL_ASSERT(num_imgs <= _SG_WGPU_MAX_SHADERSTAGE_IMAGES); + WGPUBindGroupBinding img_bgb[_SG_WGPU_MAX_SHADERSTAGE_IMAGES * 2]; + memset(&img_bgb, 0, sizeof(img_bgb)); + for (int img_index = 0; img_index < num_imgs; img_index++) { + WGPUBindGroupBinding* tex_bdg = &img_bgb[img_index*2 + 0]; + WGPUBindGroupBinding* smp_bdg = &img_bgb[img_index*2 + 1]; + tex_bdg->binding = img_index; + tex_bdg->textureView = imgs[img_index]->wgpu.tex_view; + smp_bdg->binding = img_index + _SG_WGPU_MAX_SHADERSTAGE_IMAGES; + smp_bdg->sampler = imgs[img_index]->wgpu.sampler; + } + WGPUBindGroupDescriptor bg_desc; + memset(&bg_desc, 0, sizeof(bg_desc)); + bg_desc.layout = bgl; + bg_desc.bindingCount = 2 * num_imgs; + bg_desc.bindings = &img_bgb[0]; + WGPUBindGroup bg = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc); + SOKOL_ASSERT(bg); + return bg; +} + +_SOKOL_PRIVATE void _sg_wgpu_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); + + /* index buffer */ + if (ib) { + wgpuRenderPassEncoderSetIndexBuffer(_sg.wgpu.pass_enc, ib->wgpu.buf, ib_offset); + } + + /* vertex buffers */ + for (uint32_t slot = 0; slot < (uint32_t)num_vbs; slot++) { + wgpuRenderPassEncoderSetVertexBuffer(_sg.wgpu.pass_enc, slot, vbs[slot]->wgpu.buf, (uint64_t)vb_offsets[slot]); + } + + /* need to create throw-away bind groups for images */ + if (num_vs_imgs > 0) { + if (num_vs_imgs > _SG_WGPU_MAX_SHADERSTAGE_IMAGES) { + num_vs_imgs = _SG_WGPU_MAX_SHADERSTAGE_IMAGES; + } + WGPUBindGroupLayout vs_bgl = pip->shader->wgpu.stage[SG_SHADERSTAGE_VS].bind_group_layout; + SOKOL_ASSERT(vs_bgl); + WGPUBindGroup vs_img_bg = _sg_wgpu_create_images_bindgroup(vs_bgl, vs_imgs, num_vs_imgs); + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, 1, vs_img_bg, 0, 0); + wgpuBindGroupRelease(vs_img_bg); + } + else { + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, 1, _sg.wgpu.empty_bind_group, 0, 0); + } + if (num_fs_imgs > 0) { + if (num_fs_imgs > _SG_WGPU_MAX_SHADERSTAGE_IMAGES) { + num_fs_imgs = _SG_WGPU_MAX_SHADERSTAGE_IMAGES; + } + WGPUBindGroupLayout fs_bgl = pip->shader->wgpu.stage[SG_SHADERSTAGE_FS].bind_group_layout; + SOKOL_ASSERT(fs_bgl); + WGPUBindGroup fs_img_bg = _sg_wgpu_create_images_bindgroup(fs_bgl, fs_imgs, num_fs_imgs); + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, 2, fs_img_bg, 0, 0); + wgpuBindGroupRelease(fs_img_bg); + } + else { + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, 2, _sg.wgpu.empty_bind_group, 0, 0); + } +} + +_SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + SOKOL_ASSERT((_sg.wgpu.ub.offset + data->size) <= _sg.wgpu.ub.num_bytes); + SOKOL_ASSERT((_sg.wgpu.ub.offset & (_SG_WGPU_STAGING_ALIGN-1)) == 0); + SOKOL_ASSERT(_sg.wgpu.cur_pipeline && _sg.wgpu.cur_pipeline->shader); + SOKOL_ASSERT(_sg.wgpu.cur_pipeline->slot.id == _sg.wgpu.cur_pipeline_id.id); + SOKOL_ASSERT(_sg.wgpu.cur_pipeline->shader->slot.id == _sg.wgpu.cur_pipeline->cmn.shader_id.id); + SOKOL_ASSERT(ub_index < _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); + SOKOL_ASSERT(data->size <= _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + SOKOL_ASSERT(data->size <= _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE); + SOKOL_ASSERT(0 != _sg.wgpu.ub.stage.ptr[_sg.wgpu.ub.stage.cur]); + + uint8_t* dst_ptr = _sg.wgpu.ub.stage.ptr[_sg.wgpu.ub.stage.cur] + _sg.wgpu.ub.offset; + memcpy(dst_ptr, data->ptr, data->size); + _sg.wgpu.ub.bind_offsets[stage_index][ub_index] = _sg.wgpu.ub.offset; + wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, + 0, /* groupIndex 0 is reserved for uniform buffers */ + _sg.wgpu.ub.bindgroup, + SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS, + &_sg.wgpu.ub.bind_offsets[0][0]); + _sg.wgpu.ub.offset = _sg_roundup(_sg.wgpu.ub.offset + data->size, _SG_WGPU_STAGING_ALIGN); +} + +_SOKOL_PRIVATE void _sg_wgpu_draw(int base_element, int num_elements, int num_instances) { + SOKOL_ASSERT(_sg.wgpu.in_pass); + SOKOL_ASSERT(_sg.wgpu.pass_enc); + if (_sg.wgpu.draw_indexed) { + wgpuRenderPassEncoderDrawIndexed(_sg.wgpu.pass_enc, num_elements, num_instances, base_element, 0, 0); + } + else { + wgpuRenderPassEncoderDraw(_sg.wgpu.pass_enc, num_elements, num_instances, base_element, 0); + } +} + +_SOKOL_PRIVATE void _sg_wgpu_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, 0, data->ptr, data->size); + SOKOL_ASSERT(copied_num_bytes > 0); _SOKOL_UNUSED(copied_num_bytes); +} + +_SOKOL_PRIVATE int _sg_wgpu_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + _SOKOL_UNUSED(new_frame); + uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, buf->cmn.append_pos, data->ptr, data->size); + SOKOL_ASSERT(copied_num_bytes > 0); _SOKOL_UNUSED(copied_num_bytes); + return (int)copied_num_bytes; +} + +_SOKOL_PRIVATE void _sg_wgpu_update_image(_sg_image_t* img, const sg_image_data* data) { + SOKOL_ASSERT(img && data); + bool success = _sg_wgpu_staging_copy_to_texture(img, data); + SOKOL_ASSERT(success); + _SOKOL_UNUSED(success); +} +#endif + +/*== BACKEND API WRAPPERS ====================================================*/ +static inline void _sg_setup_backend(const sg_desc* desc) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_setup_backend(desc); + #elif defined(SOKOL_METAL) + _sg_mtl_setup_backend(desc); + #elif defined(SOKOL_D3D11) + _sg_d3d11_setup_backend(desc); + #elif defined(SOKOL_WGPU) + _sg_wgpu_setup_backend(desc); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_setup_backend(desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_discard_backend(void) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_discard_backend(); + #elif defined(SOKOL_METAL) + _sg_mtl_discard_backend(); + #elif defined(SOKOL_D3D11) + _sg_d3d11_discard_backend(); + #elif defined(SOKOL_WGPU) + _sg_wgpu_discard_backend(); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_discard_backend(); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_reset_state_cache(void) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_reset_state_cache(); + #elif defined(SOKOL_METAL) + _sg_mtl_reset_state_cache(); + #elif defined(SOKOL_D3D11) + _sg_d3d11_reset_state_cache(); + #elif defined(SOKOL_WGPU) + _sg_wgpu_reset_state_cache(); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_reset_state_cache(); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_activate_context(_sg_context_t* ctx) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_activate_context(ctx); + #elif defined(SOKOL_METAL) + _sg_mtl_activate_context(ctx); + #elif defined(SOKOL_D3D11) + _sg_d3d11_activate_context(ctx); + #elif defined(SOKOL_WGPU) + _sg_wgpu_activate_context(ctx); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_activate_context(ctx); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_context(_sg_context_t* ctx) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_context(ctx); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_context(ctx); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_context(ctx); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_context(ctx); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_context(ctx); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_context(_sg_context_t* ctx) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_context(ctx); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_context(ctx); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_context(ctx); + #elif defined(SOKOL_WGPU) + _sg_wgpu_destroy_context(ctx); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_context(ctx); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_buffer(buf, desc); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_buffer(buf, desc); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_buffer(buf, desc); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_buffer(buf, desc); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_buffer(buf, desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_buffer(_sg_buffer_t* buf) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_buffer(buf); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_buffer(buf); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_buffer(buf); + #elif defined(SOKOL_WGPU) + _sg_wgpu_destroy_buffer(buf); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_buffer(buf); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_image(_sg_image_t* img, const sg_image_desc* desc) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_image(img, desc); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_image(img, desc); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_image(img, desc); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_image(img, desc); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_image(img, desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_image(_sg_image_t* img) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_image(img); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_image(img); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_image(img); + #elif defined(SOKOL_WGPU) + _sg_wgpu_destroy_image(img); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_image(img); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_shader(shd, desc); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_shader(shd, desc); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_shader(shd, desc); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_shader(shd, desc); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_shader(shd, desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_shader(_sg_shader_t* shd) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_shader(shd); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_shader(shd); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_shader(shd); + #elif defined(SOKOL_WGPU) + _sg_wgpu_destroy_shader(shd); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_shader(shd); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_pipeline(pip, shd, desc); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_pipeline(pip, shd, desc); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_pipeline(pip, shd, desc); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_pipeline(pip, shd, desc); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_pipeline(pip, shd, desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_pipeline(_sg_pipeline_t* pip) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_pipeline(pip); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_pipeline(pip); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_pipeline(pip); + #elif defined(SOKOL_WGPU) + _sg_wgpu_destroy_pipeline(pip); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_pipeline(pip); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline sg_resource_state _sg_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_create_pass(pass, att_images, desc); + #elif defined(SOKOL_METAL) + return _sg_mtl_create_pass(pass, att_images, desc); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_create_pass(pass, att_images, desc); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_create_pass(pass, att_images, desc); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_create_pass(pass, att_images, desc); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_destroy_pass(_sg_pass_t* pass) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_destroy_pass(pass); + #elif defined(SOKOL_METAL) + _sg_mtl_destroy_pass(pass); + #elif defined(SOKOL_D3D11) + _sg_d3d11_destroy_pass(pass); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_destroy_pass(pass); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_destroy_pass(pass); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline _sg_image_t* _sg_pass_color_image(const _sg_pass_t* pass, int index) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_pass_color_image(pass, index); + #elif defined(SOKOL_METAL) + return _sg_mtl_pass_color_image(pass, index); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_pass_color_image(pass, index); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_pass_color_image(pass, index); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_pass_color_image(pass, index); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline _sg_image_t* _sg_pass_ds_image(const _sg_pass_t* pass) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_pass_ds_image(pass); + #elif defined(SOKOL_METAL) + return _sg_mtl_pass_ds_image(pass); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_pass_ds_image(pass); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_pass_ds_image(pass); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_pass_ds_image(pass); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_begin_pass(pass, action, w, h); + #elif defined(SOKOL_METAL) + _sg_mtl_begin_pass(pass, action, w, h); + #elif defined(SOKOL_D3D11) + _sg_d3d11_begin_pass(pass, action, w, h); + #elif defined(SOKOL_WGPU) + _sg_wgpu_begin_pass(pass, action, w, h); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_begin_pass(pass, action, w, h); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_end_pass(void) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_end_pass(); + #elif defined(SOKOL_METAL) + _sg_mtl_end_pass(); + #elif defined(SOKOL_D3D11) + _sg_d3d11_end_pass(); + #elif defined(SOKOL_WGPU) + _sg_wgpu_end_pass(); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_end_pass(); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_apply_viewport(x, y, w, h, origin_top_left); + #elif defined(SOKOL_METAL) + _sg_mtl_apply_viewport(x, y, w, h, origin_top_left); + #elif defined(SOKOL_D3D11) + _sg_d3d11_apply_viewport(x, y, w, h, origin_top_left); + #elif defined(SOKOL_WGPU) + _sg_wgpu_apply_viewport(x, y, w, h, origin_top_left); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_apply_viewport(x, y, w, h, origin_top_left); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_apply_scissor_rect(x, y, w, h, origin_top_left); + #elif defined(SOKOL_METAL) + _sg_mtl_apply_scissor_rect(x, y, w, h, origin_top_left); + #elif defined(SOKOL_D3D11) + _sg_d3d11_apply_scissor_rect(x, y, w, h, origin_top_left); + #elif defined(SOKOL_WGPU) + _sg_wgpu_apply_scissor_rect(x, y, w, h, origin_top_left); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_apply_scissor_rect(x, y, w, h, origin_top_left); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_apply_pipeline(_sg_pipeline_t* pip) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_apply_pipeline(pip); + #elif defined(SOKOL_METAL) + _sg_mtl_apply_pipeline(pip); + #elif defined(SOKOL_D3D11) + _sg_d3d11_apply_pipeline(pip); + #elif defined(SOKOL_WGPU) + _sg_wgpu_apply_pipeline(pip); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_apply_pipeline(pip); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_apply_bindings( + _sg_pipeline_t* pip, + _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs, + _sg_buffer_t* ib, int ib_offset, + _sg_image_t** vs_imgs, int num_vs_imgs, + _sg_image_t** fs_imgs, int num_fs_imgs) +{ + #if defined(_SOKOL_ANY_GL) + _sg_gl_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + #elif defined(SOKOL_METAL) + _sg_mtl_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + #elif defined(SOKOL_D3D11) + _sg_d3d11_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + #elif defined(SOKOL_WGPU) + _sg_wgpu_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_apply_uniforms(stage_index, ub_index, data); + #elif defined(SOKOL_METAL) + _sg_mtl_apply_uniforms(stage_index, ub_index, data); + #elif defined(SOKOL_D3D11) + _sg_d3d11_apply_uniforms(stage_index, ub_index, data); + #elif defined(SOKOL_WGPU) + _sg_wgpu_apply_uniforms(stage_index, ub_index, data); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_apply_uniforms(stage_index, ub_index, data); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_draw(int base_element, int num_elements, int num_instances) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_draw(base_element, num_elements, num_instances); + #elif defined(SOKOL_METAL) + _sg_mtl_draw(base_element, num_elements, num_instances); + #elif defined(SOKOL_D3D11) + _sg_d3d11_draw(base_element, num_elements, num_instances); + #elif defined(SOKOL_WGPU) + _sg_wgpu_draw(base_element, num_elements, num_instances); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_draw(base_element, num_elements, num_instances); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_commit(void) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_commit(); + #elif defined(SOKOL_METAL) + _sg_mtl_commit(); + #elif defined(SOKOL_D3D11) + _sg_d3d11_commit(); + #elif defined(SOKOL_WGPU) + _sg_wgpu_commit(); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_commit(); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_update_buffer(buf, data); + #elif defined(SOKOL_METAL) + _sg_mtl_update_buffer(buf, data); + #elif defined(SOKOL_D3D11) + _sg_d3d11_update_buffer(buf, data); + #elif defined(SOKOL_WGPU) + _sg_wgpu_update_buffer(buf, data); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_update_buffer(buf, data); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline int _sg_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + #if defined(_SOKOL_ANY_GL) + return _sg_gl_append_buffer(buf, data, new_frame); + #elif defined(SOKOL_METAL) + return _sg_mtl_append_buffer(buf, data, new_frame); + #elif defined(SOKOL_D3D11) + return _sg_d3d11_append_buffer(buf, data, new_frame); + #elif defined(SOKOL_WGPU) + return _sg_wgpu_append_buffer(buf, data, new_frame); + #elif defined(SOKOL_DUMMY_BACKEND) + return _sg_dummy_append_buffer(buf, data, new_frame); + #else + #error("INVALID BACKEND"); + #endif +} + +static inline void _sg_update_image(_sg_image_t* img, const sg_image_data* data) { + #if defined(_SOKOL_ANY_GL) + _sg_gl_update_image(img, data); + #elif defined(SOKOL_METAL) + _sg_mtl_update_image(img, data); + #elif defined(SOKOL_D3D11) + _sg_d3d11_update_image(img, data); + #elif defined(SOKOL_WGPU) + _sg_wgpu_update_image(img, data); + #elif defined(SOKOL_DUMMY_BACKEND) + _sg_dummy_update_image(img, data); + #else + #error("INVALID BACKEND"); + #endif +} + +/*== RESOURCE POOLS ==========================================================*/ + +_SOKOL_PRIVATE void _sg_init_pool(_sg_pool_t* pool, int num) { + SOKOL_ASSERT(pool && (num >= 1)); + /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */ + pool->size = num + 1; + pool->queue_top = 0; + /* generation counters indexable by pool slot index, slot 0 is reserved */ + size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; + pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size); + SOKOL_ASSERT(pool->gen_ctrs); + memset(pool->gen_ctrs, 0, gen_ctrs_size); + /* it's not a bug to only reserve 'num' here */ + pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int) * (size_t)num); + SOKOL_ASSERT(pool->free_queue); + /* never allocate the zero-th pool item since the invalid id is 0 */ + for (int i = pool->size-1; i >= 1; i--) { + pool->free_queue[pool->queue_top++] = i; + } +} + +_SOKOL_PRIVATE void _sg_discard_pool(_sg_pool_t* pool) { + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + SOKOL_FREE(pool->free_queue); + pool->free_queue = 0; + SOKOL_ASSERT(pool->gen_ctrs); + SOKOL_FREE(pool->gen_ctrs); + pool->gen_ctrs = 0; + pool->size = 0; + pool->queue_top = 0; +} + +_SOKOL_PRIVATE int _sg_pool_alloc_index(_sg_pool_t* pool) { + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + if (pool->queue_top > 0) { + int slot_index = pool->free_queue[--pool->queue_top]; + SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); + return slot_index; + } + else { + /* pool exhausted */ + return _SG_INVALID_SLOT_INDEX; + } +} + +_SOKOL_PRIVATE void _sg_pool_free_index(_sg_pool_t* pool, int slot_index) { + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < pool->size)); + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + SOKOL_ASSERT(pool->queue_top < pool->size); + #ifdef SOKOL_DEBUG + /* debug check against double-free */ + for (int i = 0; i < pool->queue_top; i++) { + SOKOL_ASSERT(pool->free_queue[i] != slot_index); + } + #endif + pool->free_queue[pool->queue_top++] = slot_index; + SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); +} + +_SOKOL_PRIVATE void _sg_reset_slot(_sg_slot_t* slot) { + SOKOL_ASSERT(slot); + memset(slot, 0, sizeof(_sg_slot_t)); +} + +_SOKOL_PRIVATE void _sg_reset_buffer(_sg_buffer_t* buf) { + SOKOL_ASSERT(buf); + _sg_slot_t slot = buf->slot; + memset(buf, 0, sizeof(_sg_buffer_t)); + buf->slot = slot; + buf->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_reset_image(_sg_image_t* img) { + SOKOL_ASSERT(img); + _sg_slot_t slot = img->slot; + memset(img, 0, sizeof(_sg_image_t)); + img->slot = slot; + img->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_reset_shader(_sg_shader_t* shd) { + SOKOL_ASSERT(shd); + _sg_slot_t slot = shd->slot; + memset(shd, 0, sizeof(_sg_shader_t)); + shd->slot = slot; + shd->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_reset_pipeline(_sg_pipeline_t* pip) { + SOKOL_ASSERT(pip); + _sg_slot_t slot = pip->slot; + memset(pip, 0, sizeof(_sg_pipeline_t)); + pip->slot = slot; + pip->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_reset_pass(_sg_pass_t* pass) { + SOKOL_ASSERT(pass); + _sg_slot_t slot = pass->slot; + memset(pass, 0, sizeof(_sg_pass_t)); + pass->slot = slot; + pass->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_reset_context(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _sg_slot_t slot = ctx->slot; + memset(ctx, 0, sizeof(_sg_context_t)); + ctx->slot = slot; + ctx->slot.state = SG_RESOURCESTATE_ALLOC; +} + +_SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { + SOKOL_ASSERT(p); + SOKOL_ASSERT(desc); + /* note: the pools here will have an additional item, since slot 0 is reserved */ + SOKOL_ASSERT((desc->buffer_pool_size > 0) && (desc->buffer_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->buffer_pool, desc->buffer_pool_size); + size_t buffer_pool_byte_size = sizeof(_sg_buffer_t) * (size_t)p->buffer_pool.size; + p->buffers = (_sg_buffer_t*) SOKOL_MALLOC(buffer_pool_byte_size); + SOKOL_ASSERT(p->buffers); + memset(p->buffers, 0, buffer_pool_byte_size); + + SOKOL_ASSERT((desc->image_pool_size > 0) && (desc->image_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->image_pool, desc->image_pool_size); + size_t image_pool_byte_size = sizeof(_sg_image_t) * (size_t)p->image_pool.size; + p->images = (_sg_image_t*) SOKOL_MALLOC(image_pool_byte_size); + SOKOL_ASSERT(p->images); + memset(p->images, 0, image_pool_byte_size); + + SOKOL_ASSERT((desc->shader_pool_size > 0) && (desc->shader_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->shader_pool, desc->shader_pool_size); + size_t shader_pool_byte_size = sizeof(_sg_shader_t) * (size_t)p->shader_pool.size; + p->shaders = (_sg_shader_t*) SOKOL_MALLOC(shader_pool_byte_size); + SOKOL_ASSERT(p->shaders); + memset(p->shaders, 0, shader_pool_byte_size); + + SOKOL_ASSERT((desc->pipeline_pool_size > 0) && (desc->pipeline_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->pipeline_pool, desc->pipeline_pool_size); + size_t pipeline_pool_byte_size = sizeof(_sg_pipeline_t) * (size_t)p->pipeline_pool.size; + p->pipelines = (_sg_pipeline_t*) SOKOL_MALLOC(pipeline_pool_byte_size); + SOKOL_ASSERT(p->pipelines); + memset(p->pipelines, 0, pipeline_pool_byte_size); + + SOKOL_ASSERT((desc->pass_pool_size > 0) && (desc->pass_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->pass_pool, desc->pass_pool_size); + size_t pass_pool_byte_size = sizeof(_sg_pass_t) * (size_t)p->pass_pool.size; + p->passes = (_sg_pass_t*) SOKOL_MALLOC(pass_pool_byte_size); + SOKOL_ASSERT(p->passes); + memset(p->passes, 0, pass_pool_byte_size); + + SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SG_MAX_POOL_SIZE)); + _sg_init_pool(&p->context_pool, desc->context_pool_size); + size_t context_pool_byte_size = sizeof(_sg_context_t) * (size_t)p->context_pool.size; + p->contexts = (_sg_context_t*) SOKOL_MALLOC(context_pool_byte_size); + SOKOL_ASSERT(p->contexts); + memset(p->contexts, 0, context_pool_byte_size); +} + +_SOKOL_PRIVATE void _sg_discard_pools(_sg_pools_t* p) { + SOKOL_ASSERT(p); + SOKOL_FREE(p->contexts); p->contexts = 0; + SOKOL_FREE(p->passes); p->passes = 0; + SOKOL_FREE(p->pipelines); p->pipelines = 0; + SOKOL_FREE(p->shaders); p->shaders = 0; + SOKOL_FREE(p->images); p->images = 0; + SOKOL_FREE(p->buffers); p->buffers = 0; + _sg_discard_pool(&p->context_pool); + _sg_discard_pool(&p->pass_pool); + _sg_discard_pool(&p->pipeline_pool); + _sg_discard_pool(&p->shader_pool); + _sg_discard_pool(&p->image_pool); + _sg_discard_pool(&p->buffer_pool); +} + +/* allocate the slot at slot_index: + - bump the slot's generation counter + - create a resource id from the generation counter and slot index + - set the slot's id to this id + - set the slot's state to ALLOC + - return the resource id +*/ +_SOKOL_PRIVATE uint32_t _sg_slot_alloc(_sg_pool_t* pool, _sg_slot_t* slot, int slot_index) { + /* FIXME: add handling for an overflowing generation counter, + for now, just overflow (another option is to disable + the slot) + */ + SOKOL_ASSERT(pool && pool->gen_ctrs); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < pool->size)); + SOKOL_ASSERT((slot->state == SG_RESOURCESTATE_INITIAL) && (slot->id == SG_INVALID_ID)); + uint32_t ctr = ++pool->gen_ctrs[slot_index]; + slot->id = (ctr<<_SG_SLOT_SHIFT)|(slot_index & _SG_SLOT_MASK); + slot->state = SG_RESOURCESTATE_ALLOC; + return slot->id; +} + +/* extract slot index from id */ +_SOKOL_PRIVATE int _sg_slot_index(uint32_t id) { + int slot_index = (int) (id & _SG_SLOT_MASK); + SOKOL_ASSERT(_SG_INVALID_SLOT_INDEX != slot_index); + return slot_index; +} + +/* returns pointer to resource by id without matching id check */ +_SOKOL_PRIVATE _sg_buffer_t* _sg_buffer_at(const _sg_pools_t* p, uint32_t buf_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != buf_id)); + int slot_index = _sg_slot_index(buf_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->buffer_pool.size)); + return &p->buffers[slot_index]; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_image_at(const _sg_pools_t* p, uint32_t img_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != img_id)); + int slot_index = _sg_slot_index(img_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->image_pool.size)); + return &p->images[slot_index]; +} + +_SOKOL_PRIVATE _sg_shader_t* _sg_shader_at(const _sg_pools_t* p, uint32_t shd_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != shd_id)); + int slot_index = _sg_slot_index(shd_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->shader_pool.size)); + return &p->shaders[slot_index]; +} + +_SOKOL_PRIVATE _sg_pipeline_t* _sg_pipeline_at(const _sg_pools_t* p, uint32_t pip_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != pip_id)); + int slot_index = _sg_slot_index(pip_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->pipeline_pool.size)); + return &p->pipelines[slot_index]; +} + +_SOKOL_PRIVATE _sg_pass_t* _sg_pass_at(const _sg_pools_t* p, uint32_t pass_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != pass_id)); + int slot_index = _sg_slot_index(pass_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->pass_pool.size)); + return &p->passes[slot_index]; +} + +_SOKOL_PRIVATE _sg_context_t* _sg_context_at(const _sg_pools_t* p, uint32_t context_id) { + SOKOL_ASSERT(p && (SG_INVALID_ID != context_id)); + int slot_index = _sg_slot_index(context_id); + SOKOL_ASSERT((slot_index > _SG_INVALID_SLOT_INDEX) && (slot_index < p->context_pool.size)); + return &p->contexts[slot_index]; +} + +/* returns pointer to resource with matching id check, may return 0 */ +_SOKOL_PRIVATE _sg_buffer_t* _sg_lookup_buffer(const _sg_pools_t* p, uint32_t buf_id) { + if (SG_INVALID_ID != buf_id) { + _sg_buffer_t* buf = _sg_buffer_at(p, buf_id); + if (buf->slot.id == buf_id) { + return buf; + } + } + return 0; +} + +_SOKOL_PRIVATE _sg_image_t* _sg_lookup_image(const _sg_pools_t* p, uint32_t img_id) { + if (SG_INVALID_ID != img_id) { + _sg_image_t* img = _sg_image_at(p, img_id); + if (img->slot.id == img_id) { + return img; + } + } + return 0; +} + +_SOKOL_PRIVATE _sg_shader_t* _sg_lookup_shader(const _sg_pools_t* p, uint32_t shd_id) { + SOKOL_ASSERT(p); + if (SG_INVALID_ID != shd_id) { + _sg_shader_t* shd = _sg_shader_at(p, shd_id); + if (shd->slot.id == shd_id) { + return shd; + } + } + return 0; +} + +_SOKOL_PRIVATE _sg_pipeline_t* _sg_lookup_pipeline(const _sg_pools_t* p, uint32_t pip_id) { + SOKOL_ASSERT(p); + if (SG_INVALID_ID != pip_id) { + _sg_pipeline_t* pip = _sg_pipeline_at(p, pip_id); + if (pip->slot.id == pip_id) { + return pip; + } + } + return 0; +} + +_SOKOL_PRIVATE _sg_pass_t* _sg_lookup_pass(const _sg_pools_t* p, uint32_t pass_id) { + SOKOL_ASSERT(p); + if (SG_INVALID_ID != pass_id) { + _sg_pass_t* pass = _sg_pass_at(p, pass_id); + if (pass->slot.id == pass_id) { + return pass; + } + } + return 0; +} + +_SOKOL_PRIVATE _sg_context_t* _sg_lookup_context(const _sg_pools_t* p, uint32_t ctx_id) { + SOKOL_ASSERT(p); + if (SG_INVALID_ID != ctx_id) { + _sg_context_t* ctx = _sg_context_at(p, ctx_id); + if (ctx->slot.id == ctx_id) { + return ctx; + } + } + return 0; +} + +_SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { + /* this is a bit dumb since it loops over all pool slots to + find the occupied slots, on the other hand it is only ever + executed at shutdown + NOTE: ONLY EXECUTE THIS AT SHUTDOWN + ...because the free queues will not be reset + and the resource slots not be cleared! + */ + for (int i = 1; i < p->buffer_pool.size; i++) { + if (p->buffers[i].slot.ctx_id == ctx_id) { + sg_resource_state state = p->buffers[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_buffer(&p->buffers[i]); + } + } + } + for (int i = 1; i < p->image_pool.size; i++) { + if (p->images[i].slot.ctx_id == ctx_id) { + sg_resource_state state = p->images[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_image(&p->images[i]); + } + } + } + for (int i = 1; i < p->shader_pool.size; i++) { + if (p->shaders[i].slot.ctx_id == ctx_id) { + sg_resource_state state = p->shaders[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_shader(&p->shaders[i]); + } + } + } + for (int i = 1; i < p->pipeline_pool.size; i++) { + if (p->pipelines[i].slot.ctx_id == ctx_id) { + sg_resource_state state = p->pipelines[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_pipeline(&p->pipelines[i]); + } + } + } + for (int i = 1; i < p->pass_pool.size; i++) { + if (p->passes[i].slot.ctx_id == ctx_id) { + sg_resource_state state = p->passes[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_pass(&p->passes[i]); + } + } + } +} + +/*== VALIDATION LAYER ========================================================*/ +#if defined(SOKOL_DEBUG) +/* return a human readable string for an _sg_validate_error */ +_SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { + switch (err) { + /* buffer creation validation errors */ + case _SG_VALIDATE_BUFFERDESC_CANARY: return "sg_buffer_desc not initialized"; + case _SG_VALIDATE_BUFFERDESC_SIZE: return "sg_buffer_desc.size cannot be 0"; + case _SG_VALIDATE_BUFFERDESC_DATA: return "immutable buffers must be initialized with data (sg_buffer_desc.data.ptr and sg_buffer_desc.data.size)"; + case _SG_VALIDATE_BUFFERDESC_DATA_SIZE: return "immutable buffer data size differs from buffer size"; + case _SG_VALIDATE_BUFFERDESC_NO_DATA: return "dynamic/stream usage buffers cannot be initialized with data"; + + /* image data (in image creation and updating) */ + case _SG_VALIDATE_IMAGEDATA_NODATA: return "sg_image_data: no data (.ptr and/or .size is zero)"; + case _SG_VALIDATE_IMAGEDATA_DATA_SIZE: return "sg_image_data: data size doesn't match expected surface size"; + + /* image creation validation errros */ + case _SG_VALIDATE_IMAGEDESC_CANARY: return "sg_image_desc not initialized"; + case _SG_VALIDATE_IMAGEDESC_WIDTH: return "sg_image_desc.width must be > 0"; + case _SG_VALIDATE_IMAGEDESC_HEIGHT: return "sg_image_desc.height must be > 0"; + case _SG_VALIDATE_IMAGEDESC_RT_PIXELFORMAT: return "invalid pixel format for render-target image"; + case _SG_VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT: return "invalid pixel format for non-render-target image"; + case _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT: return "non-render-target images cannot be multisampled"; + case _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT: return "MSAA not supported for this pixel format"; + case _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE: return "render target images must be SG_USAGE_IMMUTABLE"; + case _SG_VALIDATE_IMAGEDESC_RT_NO_DATA: return "render target images cannot be initialized with data"; + case _SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA: return "images with injected textures cannot be initialized with data"; + case _SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA: return "dynamic/stream images cannot be initialized with data"; + case _SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE: return "compressed images must be immutable"; + + /* shader creation */ + case _SG_VALIDATE_SHADERDESC_CANARY: return "sg_shader_desc not initialized"; + case _SG_VALIDATE_SHADERDESC_SOURCE: return "shader source code required"; + case _SG_VALIDATE_SHADERDESC_BYTECODE: return "shader byte code required"; + case _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE: return "shader source or byte code required"; + case _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE: return "shader byte code length (in bytes) required"; + case _SG_VALIDATE_SHADERDESC_NO_CONT_UBS: return "shader uniform blocks must occupy continuous slots"; + case _SG_VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS: return "uniform block members must occupy continuous slots"; + case _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS: return "GL backend requires uniform block member declarations"; + case _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME: return "uniform block member name missing"; + case _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH: return "size of uniform block members doesn't match uniform block size"; + case _SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT: return "uniform array count must be >= 1"; + case _SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE: return "uniform arrays only allowed for FLOAT4, INT4, MAT4 in std140 layout"; + + case _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS: return "shader images must occupy continuous slots"; + case _SG_VALIDATE_SHADERDESC_IMG_NAME: return "GL backend requires uniform block member names"; + case _SG_VALIDATE_SHADERDESC_ATTR_NAMES: return "GLES2 backend requires vertex attribute names"; + case _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS: return "D3D11 backend requires vertex attribute semantics"; + case _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG: return "vertex attribute name/semantic string too long (max len 16)"; + + /* pipeline creation */ + case _SG_VALIDATE_PIPELINEDESC_CANARY: return "sg_pipeline_desc not initialized"; + case _SG_VALIDATE_PIPELINEDESC_SHADER: return "sg_pipeline_desc.shader missing or invalid"; + case _SG_VALIDATE_PIPELINEDESC_NO_ATTRS: return "sg_pipeline_desc.layout.attrs is empty or not continuous"; + case _SG_VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4: return "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4"; + case _SG_VALIDATE_PIPELINEDESC_ATTR_NAME: return "GLES2/WebGL missing vertex attribute name in shader"; + case _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS: return "D3D11 missing vertex attribute semantics in shader"; + + /* pass creation */ + case _SG_VALIDATE_PASSDESC_CANARY: return "sg_pass_desc not initialized"; + case _SG_VALIDATE_PASSDESC_NO_COLOR_ATTS: return "sg_pass_desc.color_attachments[0] must be valid"; + case _SG_VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS: return "color attachments must occupy continuous slots"; + case _SG_VALIDATE_PASSDESC_IMAGE: return "pass attachment image is not valid"; + case _SG_VALIDATE_PASSDESC_MIPLEVEL: return "pass attachment mip level is bigger than image has mipmaps"; + case _SG_VALIDATE_PASSDESC_FACE: return "pass attachment image is cubemap, but face index is too big"; + case _SG_VALIDATE_PASSDESC_LAYER: return "pass attachment image is array texture, but layer index is too big"; + case _SG_VALIDATE_PASSDESC_SLICE: return "pass attachment image is 3d texture, but slice value is too big"; + case _SG_VALIDATE_PASSDESC_IMAGE_NO_RT: return "pass attachment image must be render targets"; + case _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT: return "pass color-attachment images must have a renderable pixel format"; + case _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT: return "pass depth-attachment image must have depth pixel format"; + case _SG_VALIDATE_PASSDESC_IMAGE_SIZES: return "all pass attachments must have the same size"; + case _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS: return "all pass attachments must have the same sample count"; + + /* sg_begin_pass */ + case _SG_VALIDATE_BEGINPASS_PASS: return "sg_begin_pass: pass must be valid"; + case _SG_VALIDATE_BEGINPASS_IMAGE: return "sg_begin_pass: one or more attachment images are not valid"; + + /* sg_apply_pipeline */ + case _SG_VALIDATE_APIP_PIPELINE_VALID_ID: return "sg_apply_pipeline: invalid pipeline id provided"; + case _SG_VALIDATE_APIP_PIPELINE_EXISTS: return "sg_apply_pipeline: pipeline object no longer alive"; + case _SG_VALIDATE_APIP_PIPELINE_VALID: return "sg_apply_pipeline: pipeline object not in valid state"; + case _SG_VALIDATE_APIP_SHADER_EXISTS: return "sg_apply_pipeline: shader object no longer alive"; + case _SG_VALIDATE_APIP_SHADER_VALID: return "sg_apply_pipeline: shader object not in valid state"; + case _SG_VALIDATE_APIP_ATT_COUNT: return "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments"; + case _SG_VALIDATE_APIP_COLOR_FORMAT: return "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format"; + case _SG_VALIDATE_APIP_DEPTH_FORMAT: return "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format"; + case _SG_VALIDATE_APIP_SAMPLE_COUNT: return "sg_apply_pipeline: pipeline MSAA sample count doesn't match render pass attachment sample count"; + + /* sg_apply_bindings */ + case _SG_VALIDATE_ABND_PIPELINE: return "sg_apply_bindings: must be called after sg_apply_pipeline"; + case _SG_VALIDATE_ABND_PIPELINE_EXISTS: return "sg_apply_bindings: currently applied pipeline object no longer alive"; + case _SG_VALIDATE_ABND_PIPELINE_VALID: return "sg_apply_bindings: currently applied pipeline object not in valid state"; + case _SG_VALIDATE_ABND_VBS: return "sg_apply_bindings: number of vertex buffers doesn't match number of pipeline vertex layouts"; + case _SG_VALIDATE_ABND_VB_EXISTS: return "sg_apply_bindings: vertex buffer no longer alive"; + case _SG_VALIDATE_ABND_VB_TYPE: return "sg_apply_bindings: buffer in vertex buffer slot is not a SG_BUFFERTYPE_VERTEXBUFFER"; + case _SG_VALIDATE_ABND_VB_OVERFLOW: return "sg_apply_bindings: buffer in vertex buffer slot is overflown"; + case _SG_VALIDATE_ABND_NO_IB: return "sg_apply_bindings: pipeline object defines indexed rendering, but no index buffer provided"; + case _SG_VALIDATE_ABND_IB: return "sg_apply_bindings: pipeline object defines non-indexed rendering, but index buffer provided"; + case _SG_VALIDATE_ABND_IB_EXISTS: return "sg_apply_bindings: index buffer no longer alive"; + case _SG_VALIDATE_ABND_IB_TYPE: return "sg_apply_bindings: buffer in index buffer slot is not a SG_BUFFERTYPE_INDEXBUFFER"; + case _SG_VALIDATE_ABND_IB_OVERFLOW: return "sg_apply_bindings: buffer in index buffer slot is overflown"; + case _SG_VALIDATE_ABND_VS_IMGS: return "sg_apply_bindings: vertex shader image count doesn't match sg_shader_desc"; + case _SG_VALIDATE_ABND_VS_IMG_EXISTS: return "sg_apply_bindings: vertex shader image no longer alive"; + case _SG_VALIDATE_ABND_VS_IMG_TYPES: return "sg_apply_bindings: one or more vertex shader image types don't match sg_shader_desc"; + case _SG_VALIDATE_ABND_FS_IMGS: return "sg_apply_bindings: fragment shader image count doesn't match sg_shader_desc"; + case _SG_VALIDATE_ABND_FS_IMG_EXISTS: return "sg_apply_bindings: fragment shader image no longer alive"; + case _SG_VALIDATE_ABND_FS_IMG_TYPES: return "sg_apply_bindings: one or more fragment shader image types don't match sg_shader_desc"; + + /* sg_apply_uniforms */ + case _SG_VALIDATE_AUB_NO_PIPELINE: return "sg_apply_uniforms: must be called after sg_apply_pipeline()"; + case _SG_VALIDATE_AUB_NO_UB_AT_SLOT: return "sg_apply_uniforms: no uniform block declaration at this shader stage UB slot"; + case _SG_VALIDATE_AUB_SIZE: return "sg_apply_uniforms: data size exceeds declared uniform block size"; + + /* sg_update_buffer */ + case _SG_VALIDATE_UPDATEBUF_USAGE: return "sg_update_buffer: cannot update immutable buffer"; + case _SG_VALIDATE_UPDATEBUF_SIZE: return "sg_update_buffer: update size is bigger than buffer size"; + case _SG_VALIDATE_UPDATEBUF_ONCE: return "sg_update_buffer: only one update allowed per buffer and frame"; + case _SG_VALIDATE_UPDATEBUF_APPEND: return "sg_update_buffer: cannot call sg_update_buffer and sg_append_buffer in same frame"; + + /* sg_append_buffer */ + case _SG_VALIDATE_APPENDBUF_USAGE: return "sg_append_buffer: cannot append to immutable buffer"; + case _SG_VALIDATE_APPENDBUF_SIZE: return "sg_append_buffer: overall appended size is bigger than buffer size"; + case _SG_VALIDATE_APPENDBUF_UPDATE: return "sg_append_buffer: cannot call sg_append_buffer and sg_update_buffer in same frame"; + + /* sg_update_image */ + case _SG_VALIDATE_UPDIMG_USAGE: return "sg_update_image: cannot update immutable image"; + case _SG_VALIDATE_UPDIMG_ONCE: return "sg_update_image: only one update allowed per image and frame"; + + default: return "unknown validation error"; + } +} +#endif /* defined(SOKOL_DEBUG) */ + +/*-- validation checks -------------------------------------------------------*/ +#if defined(SOKOL_DEBUG) +_SOKOL_PRIVATE void _sg_validate_begin(void) { + _sg.validate_error = _SG_VALIDATE_SUCCESS; +} + +_SOKOL_PRIVATE void _sg_validate(bool cond, _sg_validate_error_t err) { + if (!cond) { + _sg.validate_error = err; + SOKOL_LOG(_sg_validate_string(err)); + } +} + +_SOKOL_PRIVATE bool _sg_validate_end(void) { + if (_sg.validate_error != _SG_VALIDATE_SUCCESS) { + #if !defined(SOKOL_VALIDATE_NON_FATAL) + SOKOL_LOG("^^^^ SOKOL-GFX VALIDATION FAILED, TERMINATING ^^^^"); + SOKOL_ASSERT(false); + #endif + return false; + } + else { + return true; + } +} +#endif + +_SOKOL_PRIVATE bool _sg_validate_buffer_desc(const sg_buffer_desc* desc) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(desc); + return true; + #else + SOKOL_ASSERT(desc); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_BUFFERDESC_CANARY); + SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_BUFFERDESC_CANARY); + SOKOL_VALIDATE(desc->size > 0, _SG_VALIDATE_BUFFERDESC_SIZE); + bool injected = (0 != desc->gl_buffers[0]) || + (0 != desc->mtl_buffers[0]) || + (0 != desc->d3d11_buffer) || + (0 != desc->wgpu_buffer); + if (!injected && (desc->usage == SG_USAGE_IMMUTABLE)) { + SOKOL_VALIDATE((0 != desc->data.ptr) && (desc->data.size > 0), _SG_VALIDATE_BUFFERDESC_DATA); + SOKOL_VALIDATE(desc->size == desc->data.size, _SG_VALIDATE_BUFFERDESC_DATA_SIZE); + } + else { + SOKOL_VALIDATE(0 == desc->data.ptr, _SG_VALIDATE_BUFFERDESC_NO_DATA); + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE void _sg_validate_image_data(const sg_image_data* data, sg_pixel_format fmt, int width, int height, int num_faces, int num_mips, int num_slices) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(data); + _SOKOL_UNUSED(fmt); + _SOKOL_UNUSED(width); + _SOKOL_UNUSED(height); + _SOKOL_UNUSED(num_faces); + _SOKOL_UNUSED(num_mips); + _SOKOL_UNUSED(num_slices); + #else + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int mip_index = 0; mip_index < num_mips; mip_index++) { + const bool has_data = data->subimage[face_index][mip_index].ptr != 0; + const bool has_size = data->subimage[face_index][mip_index].size > 0; + SOKOL_VALIDATE(has_data && has_size, _SG_VALIDATE_IMAGEDATA_NODATA); + const int mip_width = _sg_max(width >> mip_index, 1); + const int mip_height = _sg_max(height >> mip_index, 1); + const int bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, 1); + const int expected_size = bytes_per_slice * num_slices; + SOKOL_VALIDATE(expected_size == (int)data->subimage[face_index][mip_index].size, _SG_VALIDATE_IMAGEDATA_DATA_SIZE); + } + } + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(desc); + return true; + #else + SOKOL_ASSERT(desc); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_IMAGEDESC_CANARY); + SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_IMAGEDESC_CANARY); + SOKOL_VALIDATE(desc->width > 0, _SG_VALIDATE_IMAGEDESC_WIDTH); + SOKOL_VALIDATE(desc->height > 0, _SG_VALIDATE_IMAGEDESC_HEIGHT); + const sg_pixel_format fmt = desc->pixel_format; + const sg_usage usage = desc->usage; + const bool injected = (0 != desc->gl_textures[0]) || + (0 != desc->mtl_textures[0]) || + (0 != desc->d3d11_texture) || + (0 != desc->wgpu_texture); + if (desc->render_target) { + SOKOL_ASSERT(((int)fmt >= 0) && ((int)fmt < _SG_PIXELFORMAT_NUM)); + SOKOL_VALIDATE(_sg.formats[fmt].render, _SG_VALIDATE_IMAGEDESC_RT_PIXELFORMAT); + /* on GLES2, sample count for render targets is completely ignored */ + #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + if (!_sg.gl.gles2) { + #endif + if (desc->sample_count > 1) { + SOKOL_VALIDATE(_sg.features.msaa_render_targets && _sg.formats[fmt].msaa, _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT); + } + #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + } + #endif + SOKOL_VALIDATE(usage == SG_USAGE_IMMUTABLE, _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE); + SOKOL_VALIDATE(desc->data.subimage[0][0].ptr==0, _SG_VALIDATE_IMAGEDESC_RT_NO_DATA); + } + else { + SOKOL_VALIDATE(desc->sample_count <= 1, _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT); + const bool valid_nonrt_fmt = !_sg_is_valid_rendertarget_depth_format(fmt); + SOKOL_VALIDATE(valid_nonrt_fmt, _SG_VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT); + const bool is_compressed = _sg_is_compressed_pixel_format(desc->pixel_format); + const bool is_immutable = (usage == SG_USAGE_IMMUTABLE); + if (is_compressed) { + SOKOL_VALIDATE(is_immutable, _SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE); + } + if (!injected && is_immutable) { + // image desc must have valid data + _sg_validate_image_data(&desc->data, + desc->pixel_format, + desc->width, + desc->height, + (desc->type == SG_IMAGETYPE_CUBE) ? 6 : 1, + desc->num_mipmaps, + desc->num_slices); + } + else { + // image desc must not have data + for (int face_index = 0; face_index < SG_CUBEFACE_NUM; face_index++) { + for (int mip_index = 0; mip_index < SG_MAX_MIPMAPS; mip_index++) { + const bool no_data = 0 == desc->data.subimage[face_index][mip_index].ptr; + const bool no_size = 0 == desc->data.subimage[face_index][mip_index].size; + if (injected) { + SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA); + } + if (!is_immutable) { + SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA); + } + } + } + } + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(desc); + return true; + #else + SOKOL_ASSERT(desc); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_SHADERDESC_CANARY); + SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_SHADERDESC_CANARY); + #if defined(SOKOL_GLES2) + SOKOL_VALIDATE(0 != desc->attrs[0].name, _SG_VALIDATE_SHADERDESC_ATTR_NAMES); + #elif defined(SOKOL_D3D11) + // SOKOL_VALIDATE(0 != desc->attrs[0].sem_name, _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS); + #endif + #if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + /* on GL, must provide shader source code */ + SOKOL_VALIDATE(0 != desc->vs.source, _SG_VALIDATE_SHADERDESC_SOURCE); + SOKOL_VALIDATE(0 != desc->fs.source, _SG_VALIDATE_SHADERDESC_SOURCE); + #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) + /* on Metal or D3D11, must provide shader source code or byte code */ + SOKOL_VALIDATE((0 != desc->vs.source)||(0 != desc->vs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); + SOKOL_VALIDATE((0 != desc->fs.source)||(0 != desc->fs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); + #elif defined(SOKOL_WGPU) + /* on WGPU byte code must be provided */ + SOKOL_VALIDATE((0 != desc->vs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_BYTECODE); + SOKOL_VALIDATE((0 != desc->fs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_BYTECODE); + #else + /* Dummy Backend, don't require source or bytecode */ + #endif + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + if (desc->attrs[i].name) { + SOKOL_VALIDATE(strlen(desc->attrs[i].name) < _SG_STRING_SIZE, _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); + } + if (desc->attrs[i].sem_name) { + SOKOL_VALIDATE(strlen(desc->attrs[i].sem_name) < _SG_STRING_SIZE, _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); + } + } + /* if shader byte code, the size must also be provided */ + if (0 != desc->vs.bytecode.ptr) { + SOKOL_VALIDATE(desc->vs.bytecode.size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); + } + if (0 != desc->fs.bytecode.ptr) { + SOKOL_VALIDATE(desc->fs.bytecode.size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); + } + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + const sg_shader_stage_desc* stage_desc = (stage_index == 0)? &desc->vs : &desc->fs; + bool uniform_blocks_continuous = true; + for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { + const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; + if (ub_desc->size > 0) { + SOKOL_VALIDATE(uniform_blocks_continuous, _SG_VALIDATE_SHADERDESC_NO_CONT_UBS); + #if defined(_SOKOL_ANY_GL) + bool uniforms_continuous = true; + uint32_t uniform_offset = 0; + int num_uniforms = 0; + for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { + const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; + if (u_desc->type != SG_UNIFORMTYPE_INVALID) { + SOKOL_VALIDATE(uniforms_continuous, _SG_VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS); + #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + SOKOL_VALIDATE(0 != u_desc->name, _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME); + #endif + const int array_count = u_desc->array_count; + SOKOL_VALIDATE(array_count > 0, _SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT); + const uint32_t u_align = _sg_uniform_alignment(u_desc->type, array_count, ub_desc->layout); + const uint32_t u_size = _sg_uniform_size(u_desc->type, array_count, ub_desc->layout); + uniform_offset = _sg_align_u32(uniform_offset, u_align); + uniform_offset += u_size; + num_uniforms++; + // with std140, arrays are only allowed for FLOAT4, INT4, MAT4 + if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { + if (array_count > 1) { + SOKOL_VALIDATE((u_desc->type == SG_UNIFORMTYPE_FLOAT4) || (u_desc->type == SG_UNIFORMTYPE_INT4) || (u_desc->type == SG_UNIFORMTYPE_MAT4), _SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE); + } + } + } + else { + uniforms_continuous = false; + } + } + if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) { + uniform_offset = _sg_align_u32(uniform_offset, 16); + } + SOKOL_VALIDATE((size_t)uniform_offset == ub_desc->size, _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH); + SOKOL_VALIDATE(num_uniforms > 0, _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS); + #endif + } + else { + uniform_blocks_continuous = false; + } + } + bool images_continuous = true; + for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { + const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; + if (img_desc->image_type != _SG_IMAGETYPE_DEFAULT) { + SOKOL_VALIDATE(images_continuous, _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS); + #if defined(SOKOL_GLES2) + SOKOL_VALIDATE(0 != img_desc->name, _SG_VALIDATE_SHADERDESC_IMG_NAME); + #endif + } + else { + images_continuous = false; + } + } + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(desc); + return true; + #else + SOKOL_ASSERT(desc); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_PIPELINEDESC_CANARY); + SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_PIPELINEDESC_CANARY); + SOKOL_VALIDATE(desc->shader.id != SG_INVALID_ID, _SG_VALIDATE_PIPELINEDESC_SHADER); + for (int buf_index = 0; buf_index < SG_MAX_SHADERSTAGE_BUFFERS; buf_index++) { + const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[buf_index]; + if (l_desc->stride == 0) { + continue; + } + SOKOL_VALIDATE((l_desc->stride & 3) == 0, _SG_VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4); + } + // SOKOL_VALIDATE(desc->layout.attrs[0].format != SG_VERTEXFORMAT_INVALID, _SG_VALIDATE_PIPELINEDESC_NO_ATTRS); + const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); + SOKOL_VALIDATE(0 != shd, _SG_VALIDATE_PIPELINEDESC_SHADER); + if (shd) { + SOKOL_VALIDATE(shd->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_PIPELINEDESC_SHADER); + bool attrs_cont = true; + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + attrs_cont = false; + continue; + } + SOKOL_VALIDATE(attrs_cont, _SG_VALIDATE_PIPELINEDESC_NO_ATTRS); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + #if defined(SOKOL_GLES2) + /* on GLES2, vertex attribute names must be provided */ + SOKOL_VALIDATE(!_sg_strempty(&shd->gl.attrs[attr_index].name), _SG_VALIDATE_PIPELINEDESC_ATTR_NAME); + #elif defined(SOKOL_D3D11) + /* on D3D11, semantic names (and semantic indices) must be provided */ + SOKOL_VALIDATE(!_sg_strempty(&shd->d3d11.attrs[attr_index].sem_name), _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS); + #endif + } + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(desc); + return true; + #else + SOKOL_ASSERT(desc); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_PASSDESC_CANARY); + SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_PASSDESC_CANARY); + bool atts_cont = true; + int width = -1, height = -1, sample_count = -1; + for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) { + const sg_pass_attachment_desc* att = &desc->color_attachments[att_index]; + if (att->image.id == SG_INVALID_ID) { + SOKOL_VALIDATE(att_index > 0, _SG_VALIDATE_PASSDESC_NO_COLOR_ATTS); + atts_cont = false; + continue; + } + SOKOL_VALIDATE(atts_cont, _SG_VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS); + const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); + SOKOL_ASSERT(img); + SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_PASSDESC_IMAGE); + SOKOL_VALIDATE(att->mip_level < img->cmn.num_mipmaps, _SG_VALIDATE_PASSDESC_MIPLEVEL); + if (img->cmn.type == SG_IMAGETYPE_CUBE) { + SOKOL_VALIDATE(att->slice < 6, _SG_VALIDATE_PASSDESC_FACE); + } + else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_LAYER); + } + else if (img->cmn.type == SG_IMAGETYPE_3D) { + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_SLICE); + } + SOKOL_VALIDATE(img->cmn.render_target, _SG_VALIDATE_PASSDESC_IMAGE_NO_RT); + if (att_index == 0) { + width = img->cmn.width >> att->mip_level; + height = img->cmn.height >> att->mip_level; + sample_count = img->cmn.sample_count; + } + else { + SOKOL_VALIDATE(width == img->cmn.width >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); + SOKOL_VALIDATE(height == img->cmn.height >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); + SOKOL_VALIDATE(sample_count == img->cmn.sample_count, _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS); + } + SOKOL_VALIDATE(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format), _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT); + } + if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { + const sg_pass_attachment_desc* att = &desc->depth_stencil_attachment; + const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); + SOKOL_ASSERT(img); + SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_PASSDESC_IMAGE); + SOKOL_VALIDATE(att->mip_level < img->cmn.num_mipmaps, _SG_VALIDATE_PASSDESC_MIPLEVEL); + if (img->cmn.type == SG_IMAGETYPE_CUBE) { + SOKOL_VALIDATE(att->slice < 6, _SG_VALIDATE_PASSDESC_FACE); + } + else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_LAYER); + } + else if (img->cmn.type == SG_IMAGETYPE_3D) { + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_SLICE); + } + SOKOL_VALIDATE(img->cmn.render_target, _SG_VALIDATE_PASSDESC_IMAGE_NO_RT); + SOKOL_VALIDATE(width == img->cmn.width >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); + SOKOL_VALIDATE(height == img->cmn.height >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); + SOKOL_VALIDATE(sample_count == img->cmn.sample_count, _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS); + SOKOL_VALIDATE(_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format), _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT); + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_begin_pass(_sg_pass_t* pass) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(pass); + return true; + #else + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(pass->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_PASS); + + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + const _sg_pass_attachment_t* att = &pass->cmn.color_atts[i]; + const _sg_image_t* img = _sg_pass_color_image(pass, i); + if (img) { + SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_IMAGE); + SOKOL_VALIDATE(img->slot.id == att->image_id.id, _SG_VALIDATE_BEGINPASS_IMAGE); + } + } + const _sg_image_t* ds_img = _sg_pass_ds_image(pass); + if (ds_img) { + const _sg_pass_attachment_t* att = &pass->cmn.ds_att; + SOKOL_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_IMAGE); + SOKOL_VALIDATE(ds_img->slot.id == att->image_id.id, _SG_VALIDATE_BEGINPASS_IMAGE); + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(pip_id); + return true; + #else + SOKOL_VALIDATE_BEGIN(); + /* the pipeline object must be alive and valid */ + SOKOL_VALIDATE(pip_id.id != SG_INVALID_ID, _SG_VALIDATE_APIP_PIPELINE_VALID_ID); + const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_VALIDATE(pip != 0, _SG_VALIDATE_APIP_PIPELINE_EXISTS); + if (!pip) { + return SOKOL_VALIDATE_END(); + } + SOKOL_VALIDATE(pip->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_APIP_PIPELINE_VALID); + /* the pipeline's shader must be alive and valid */ + SOKOL_ASSERT(pip->shader); + SOKOL_VALIDATE(pip->shader->slot.id == pip->cmn.shader_id.id, _SG_VALIDATE_APIP_SHADER_EXISTS); + SOKOL_VALIDATE(pip->shader->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_APIP_SHADER_VALID); + /* check that pipeline attributes match current pass attributes */ + const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, _sg.cur_pass.id); + if (pass) { + /* an offscreen pass */ + SOKOL_VALIDATE(pip->cmn.color_attachment_count == pass->cmn.num_color_atts, _SG_VALIDATE_APIP_ATT_COUNT); + for (int i = 0; i < pip->cmn.color_attachment_count; i++) { + const _sg_image_t* att_img = _sg_pass_color_image(pass, i); + SOKOL_VALIDATE(pip->cmn.color_formats[i] == att_img->cmn.pixel_format, _SG_VALIDATE_APIP_COLOR_FORMAT); + SOKOL_VALIDATE(pip->cmn.sample_count == att_img->cmn.sample_count, _SG_VALIDATE_APIP_SAMPLE_COUNT); + } + const _sg_image_t* att_dsimg = _sg_pass_ds_image(pass); + if (att_dsimg) { + SOKOL_VALIDATE(pip->cmn.depth_format == att_dsimg->cmn.pixel_format, _SG_VALIDATE_APIP_DEPTH_FORMAT); + } + else { + SOKOL_VALIDATE(pip->cmn.depth_format == SG_PIXELFORMAT_NONE, _SG_VALIDATE_APIP_DEPTH_FORMAT); + } + } + else { + /* default pass */ + SOKOL_VALIDATE(pip->cmn.color_attachment_count == 1, _SG_VALIDATE_APIP_ATT_COUNT); + SOKOL_VALIDATE(pip->cmn.color_formats[0] == _sg.desc.context.color_format, _SG_VALIDATE_APIP_COLOR_FORMAT); + SOKOL_VALIDATE(pip->cmn.depth_format == _sg.desc.context.depth_format, _SG_VALIDATE_APIP_DEPTH_FORMAT); + SOKOL_VALIDATE(pip->cmn.sample_count == _sg.desc.context.sample_count, _SG_VALIDATE_APIP_SAMPLE_COUNT); + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(bindings); + return true; + #else + SOKOL_VALIDATE_BEGIN(); + + /* a pipeline object must have been applied */ + SOKOL_VALIDATE(_sg.cur_pipeline.id != SG_INVALID_ID, _SG_VALIDATE_ABND_PIPELINE); + const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); + SOKOL_VALIDATE(pip != 0, _SG_VALIDATE_ABND_PIPELINE_EXISTS); + if (!pip) { + return SOKOL_VALIDATE_END(); + } + SOKOL_VALIDATE(pip->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_ABND_PIPELINE_VALID); + SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); + + /* has expected vertex buffers, and vertex buffers still exist */ + for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) { + if (bindings->vertex_buffers[i].id != SG_INVALID_ID) { + SOKOL_VALIDATE(pip->cmn.vertex_layout_valid[i], _SG_VALIDATE_ABND_VBS); + /* buffers in vertex-buffer-slots must be of type SG_BUFFERTYPE_VERTEXBUFFER */ + const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, bindings->vertex_buffers[i].id); + SOKOL_VALIDATE(buf != 0, _SG_VALIDATE_ABND_VB_EXISTS); + if (buf && buf->slot.state == SG_RESOURCESTATE_VALID) { + SOKOL_VALIDATE(SG_BUFFERTYPE_VERTEXBUFFER == buf->cmn.type, _SG_VALIDATE_ABND_VB_TYPE); + SOKOL_VALIDATE(!buf->cmn.append_overflow, _SG_VALIDATE_ABND_VB_OVERFLOW); + } + } + else { + /* vertex buffer provided in a slot which has no vertex layout in pipeline */ + SOKOL_VALIDATE(!pip->cmn.vertex_layout_valid[i], _SG_VALIDATE_ABND_VBS); + } + } + + /* index buffer expected or not, and index buffer still exists */ + if (pip->cmn.index_type == SG_INDEXTYPE_NONE) { + /* pipeline defines non-indexed rendering, but index buffer provided */ + SOKOL_VALIDATE(bindings->index_buffer.id == SG_INVALID_ID, _SG_VALIDATE_ABND_IB); + } + else { + /* pipeline defines indexed rendering, but no index buffer provided */ + SOKOL_VALIDATE(bindings->index_buffer.id != SG_INVALID_ID, _SG_VALIDATE_ABND_NO_IB); + } + if (bindings->index_buffer.id != SG_INVALID_ID) { + /* buffer in index-buffer-slot must be of type SG_BUFFERTYPE_INDEXBUFFER */ + const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, bindings->index_buffer.id); + SOKOL_VALIDATE(buf != 0, _SG_VALIDATE_ABND_IB_EXISTS); + if (buf && buf->slot.state == SG_RESOURCESTATE_VALID) { + SOKOL_VALIDATE(SG_BUFFERTYPE_INDEXBUFFER == buf->cmn.type, _SG_VALIDATE_ABND_IB_TYPE); + SOKOL_VALIDATE(!buf->cmn.append_overflow, _SG_VALIDATE_ABND_IB_OVERFLOW); + } + } + + /* has expected vertex shader images */ + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { + _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_VS]; + if (bindings->vs_images[i].id != SG_INVALID_ID) { + SOKOL_VALIDATE(i < stage->num_images, _SG_VALIDATE_ABND_VS_IMGS); + const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->vs_images[i].id); + SOKOL_VALIDATE(img != 0, _SG_VALIDATE_ABND_VS_IMG_EXISTS); + if (img && img->slot.state == SG_RESOURCESTATE_VALID) { + SOKOL_VALIDATE(img->cmn.type == stage->images[i].image_type, _SG_VALIDATE_ABND_VS_IMG_TYPES); + } + } + else { + SOKOL_VALIDATE(i >= stage->num_images, _SG_VALIDATE_ABND_VS_IMGS); + } + } + + /* has expected fragment shader images */ + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { + _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; + if (bindings->fs_images[i].id != SG_INVALID_ID) { + SOKOL_VALIDATE(i < stage->num_images, _SG_VALIDATE_ABND_FS_IMGS); + const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->fs_images[i].id); + SOKOL_VALIDATE(img != 0, _SG_VALIDATE_ABND_FS_IMG_EXISTS); + if (img && img->slot.state == SG_RESOURCESTATE_VALID) { + SOKOL_VALIDATE(img->cmn.type == stage->images[i].image_type, _SG_VALIDATE_ABND_FS_IMG_TYPES); + } + } + else { + SOKOL_VALIDATE(i >= stage->num_images, _SG_VALIDATE_ABND_FS_IMGS); + } + } + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(stage_index); + _SOKOL_UNUSED(ub_index); + _SOKOL_UNUSED(data); + return true; + #else + SOKOL_ASSERT((stage_index == SG_SHADERSTAGE_VS) || (stage_index == SG_SHADERSTAGE_FS)); + SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(_sg.cur_pipeline.id != SG_INVALID_ID, _SG_VALIDATE_AUB_NO_PIPELINE); + const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); + SOKOL_ASSERT(pip && (pip->slot.id == _sg.cur_pipeline.id)); + SOKOL_ASSERT(pip->shader && (pip->shader->slot.id == pip->cmn.shader_id.id)); + + /* check that there is a uniform block at 'stage' and 'ub_index' */ + const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[stage_index]; + SOKOL_VALIDATE(ub_index < stage->num_uniform_blocks, _SG_VALIDATE_AUB_NO_UB_AT_SLOT); + + /* check that the provided data size doesn't exceed the uniform block size */ + SOKOL_VALIDATE(data->size <= stage->uniform_blocks[ub_index].size, _SG_VALIDATE_AUB_SIZE); + + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_update_buffer(const _sg_buffer_t* buf, const sg_range* data) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(buf); + _SOKOL_UNUSED(data); + return true; + #else + SOKOL_ASSERT(buf && data && data->ptr); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_UPDATEBUF_USAGE); + SOKOL_VALIDATE(buf->cmn.size >= (int)data->size, _SG_VALIDATE_UPDATEBUF_SIZE); + SOKOL_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, _SG_VALIDATE_UPDATEBUF_ONCE); + SOKOL_VALIDATE(buf->cmn.append_frame_index != _sg.frame_index, _SG_VALIDATE_UPDATEBUF_APPEND); + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_append_buffer(const _sg_buffer_t* buf, const sg_range* data) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(buf); + _SOKOL_UNUSED(data); + return true; + #else + SOKOL_ASSERT(buf && data && data->ptr); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_APPENDBUF_USAGE); + SOKOL_VALIDATE(buf->cmn.size >= (buf->cmn.append_pos + (int)data->size), _SG_VALIDATE_APPENDBUF_SIZE); + SOKOL_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, _SG_VALIDATE_APPENDBUF_UPDATE); + return SOKOL_VALIDATE_END(); + #endif +} + +_SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_image_data* data) { + #if !defined(SOKOL_DEBUG) + _SOKOL_UNUSED(img); + _SOKOL_UNUSED(data); + return true; + #else + SOKOL_ASSERT(img && data); + SOKOL_VALIDATE_BEGIN(); + SOKOL_VALIDATE(img->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_UPDIMG_USAGE); + SOKOL_VALIDATE(img->cmn.upd_frame_index != _sg.frame_index, _SG_VALIDATE_UPDIMG_ONCE); + _sg_validate_image_data(data, + img->cmn.pixel_format, + img->cmn.width, + img->cmn.height, + (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6 : 1, + img->cmn.num_mipmaps, + img->cmn.num_slices); + return SOKOL_VALIDATE_END(); + #endif +} + +/*== fill in desc default values =============================================*/ +_SOKOL_PRIVATE sg_buffer_desc _sg_buffer_desc_defaults(const sg_buffer_desc* desc) { + sg_buffer_desc def = *desc; + def.type = _sg_def(def.type, SG_BUFFERTYPE_VERTEXBUFFER); + def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); + if (def.size == 0) { + def.size = def.data.size; + } + else if (def.data.size == 0) { + def.data.size = def.size; + } + return def; +} + +_SOKOL_PRIVATE sg_image_desc _sg_image_desc_defaults(const sg_image_desc* desc) { + sg_image_desc def = *desc; + def.type = _sg_def(def.type, SG_IMAGETYPE_2D); + def.num_slices = _sg_def(def.num_slices, 1); + def.num_mipmaps = _sg_def(def.num_mipmaps, 1); + def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); + if (desc->render_target) { + def.pixel_format = _sg_def(def.pixel_format, _sg.desc.context.color_format); + def.sample_count = _sg_def(def.sample_count, _sg.desc.context.sample_count); + } + else { + def.pixel_format = _sg_def(def.pixel_format, SG_PIXELFORMAT_RGBA8); + def.sample_count = _sg_def(def.sample_count, 1); + } + def.min_filter = _sg_def(def.min_filter, SG_FILTER_NEAREST); + def.mag_filter = _sg_def(def.mag_filter, SG_FILTER_NEAREST); + def.wrap_u = _sg_def(def.wrap_u, SG_WRAP_REPEAT); + def.wrap_v = _sg_def(def.wrap_v, SG_WRAP_REPEAT); + def.wrap_w = _sg_def(def.wrap_w, SG_WRAP_REPEAT); + def.border_color = _sg_def(def.border_color, SG_BORDERCOLOR_OPAQUE_BLACK); + def.max_anisotropy = _sg_def(def.max_anisotropy, 1); + def.max_lod = _sg_def_flt(def.max_lod, FLT_MAX); + return def; +} + +_SOKOL_PRIVATE sg_shader_desc _sg_shader_desc_defaults(const sg_shader_desc* desc) { + sg_shader_desc def = *desc; + #if defined(SOKOL_METAL) + def.vs.entry = _sg_def(def.vs.entry, "_main"); + def.fs.entry = _sg_def(def.fs.entry, "_main"); + #else + def.vs.entry = _sg_def(def.vs.entry, "main"); + def.fs.entry = _sg_def(def.fs.entry, "main"); + #endif + #if defined(SOKOL_D3D11) + if (def.vs.source) { + def.vs.d3d11_target = _sg_def(def.vs.d3d11_target, "vs_4_0"); + } + if (def.fs.source) { + def.fs.d3d11_target = _sg_def(def.fs.d3d11_target, "ps_4_0"); + } + #endif + for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { + sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &def.vs : &def.fs; + for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) { + sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index]; + if (0 == ub_desc->size) { + break; + } + ub_desc->layout = _sg_def(ub_desc->layout, SG_UNIFORMLAYOUT_NATIVE); + for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) { + sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index]; + if (u_desc->type == SG_UNIFORMTYPE_INVALID) { + break; + } + u_desc->array_count = _sg_def(u_desc->array_count, 1); + } + } + for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { + sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; + if (img_desc->image_type == _SG_IMAGETYPE_DEFAULT) { + break; + } + img_desc->sampler_type = _sg_def(img_desc->sampler_type, SG_SAMPLERTYPE_FLOAT); + } + } + return def; +} + +_SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_desc* desc) { + sg_pipeline_desc def = *desc; + + def.primitive_type = _sg_def(def.primitive_type, SG_PRIMITIVETYPE_TRIANGLES); + def.index_type = _sg_def(def.index_type, SG_INDEXTYPE_NONE); + def.cull_mode = _sg_def(def.cull_mode, SG_CULLMODE_NONE); + def.face_winding = _sg_def(def.face_winding, SG_FACEWINDING_CW); + def.sample_count = _sg_def(def.sample_count, _sg.desc.context.sample_count); + + def.stencil.front.compare = _sg_def(def.stencil.front.compare, SG_COMPAREFUNC_ALWAYS); + def.stencil.front.fail_op = _sg_def(def.stencil.front.fail_op, SG_STENCILOP_KEEP); + def.stencil.front.depth_fail_op = _sg_def(def.stencil.front.depth_fail_op, SG_STENCILOP_KEEP); + def.stencil.front.pass_op = _sg_def(def.stencil.front.pass_op, SG_STENCILOP_KEEP); + def.stencil.back.compare = _sg_def(def.stencil.back.compare, SG_COMPAREFUNC_ALWAYS); + def.stencil.back.fail_op = _sg_def(def.stencil.back.fail_op, SG_STENCILOP_KEEP); + def.stencil.back.depth_fail_op = _sg_def(def.stencil.back.depth_fail_op, SG_STENCILOP_KEEP); + def.stencil.back.pass_op = _sg_def(def.stencil.back.pass_op, SG_STENCILOP_KEEP); + + def.depth.compare = _sg_def(def.depth.compare, SG_COMPAREFUNC_ALWAYS); + def.depth.pixel_format = _sg_def(def.depth.pixel_format, _sg.desc.context.depth_format); + def.color_count = _sg_def(def.color_count, 1); + if (def.color_count > SG_MAX_COLOR_ATTACHMENTS) { + def.color_count = SG_MAX_COLOR_ATTACHMENTS; + } + for (int i = 0; i < def.color_count; i++) { + sg_color_state* cs = &def.colors[i]; + cs->pixel_format = _sg_def(cs->pixel_format, _sg.desc.context.color_format); + cs->write_mask = _sg_def(cs->write_mask, SG_COLORMASK_RGBA); + sg_blend_state* bs = &def.colors[i].blend; + bs->src_factor_rgb = _sg_def(bs->src_factor_rgb, SG_BLENDFACTOR_ONE); + bs->dst_factor_rgb = _sg_def(bs->dst_factor_rgb, SG_BLENDFACTOR_ZERO); + bs->op_rgb = _sg_def(bs->op_rgb, SG_BLENDOP_ADD); + bs->src_factor_alpha = _sg_def(bs->src_factor_alpha, SG_BLENDFACTOR_ONE); + bs->dst_factor_alpha = _sg_def(bs->dst_factor_alpha, SG_BLENDFACTOR_ZERO); + bs->op_alpha = _sg_def(bs->op_alpha, SG_BLENDOP_ADD); + } + + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + sg_vertex_attr_desc* a_desc = &def.layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + sg_buffer_layout_desc* b_desc = &def.layout.buffers[a_desc->buffer_index]; + b_desc->step_func = _sg_def(b_desc->step_func, SG_VERTEXSTEP_PER_VERTEX); + b_desc->step_rate = _sg_def(b_desc->step_rate, 1); + } + + /* resolve vertex layout strides and offsets */ + int auto_offset[SG_MAX_SHADERSTAGE_BUFFERS]; + memset(auto_offset, 0, sizeof(auto_offset)); + bool use_auto_offset = true; + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + /* to use computed offsets, *all* attr offsets must be 0 */ + if (def.layout.attrs[attr_index].offset != 0) { + use_auto_offset = false; + } + } + for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + sg_vertex_attr_desc* a_desc = &def.layout.attrs[attr_index]; + if (a_desc->format == SG_VERTEXFORMAT_INVALID) { + break; + } + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); + if (use_auto_offset) { + a_desc->offset = auto_offset[a_desc->buffer_index]; + } + auto_offset[a_desc->buffer_index] += _sg_vertexformat_bytesize(a_desc->format); + } + /* compute vertex strides if needed */ + for (int buf_index = 0; buf_index < SG_MAX_SHADERSTAGE_BUFFERS; buf_index++) { + sg_buffer_layout_desc* l_desc = &def.layout.buffers[buf_index]; + if (l_desc->stride == 0) { + l_desc->stride = auto_offset[buf_index]; + } + } + + return def; +} + +_SOKOL_PRIVATE sg_pass_desc _sg_pass_desc_defaults(const sg_pass_desc* desc) { + /* FIXME: no values to replace in sg_pass_desc? */ + sg_pass_desc def = *desc; + return def; +} + +/*== allocate/initialize resource private functions ==========================*/ +_SOKOL_PRIVATE sg_buffer _sg_alloc_buffer(void) { + sg_buffer res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.buffer_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id = _sg_slot_alloc(&_sg.pools.buffer_pool, &_sg.pools.buffers[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + return res; +} + +_SOKOL_PRIVATE sg_image _sg_alloc_image(void) { + sg_image res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.image_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id = _sg_slot_alloc(&_sg.pools.image_pool, &_sg.pools.images[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + return res; +} + +_SOKOL_PRIVATE sg_shader _sg_alloc_shader(void) { + sg_shader res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.shader_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id = _sg_slot_alloc(&_sg.pools.shader_pool, &_sg.pools.shaders[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + return res; +} + +_SOKOL_PRIVATE sg_pipeline _sg_alloc_pipeline(void) { + sg_pipeline res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.pipeline_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id =_sg_slot_alloc(&_sg.pools.pipeline_pool, &_sg.pools.pipelines[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + return res; +} + +_SOKOL_PRIVATE sg_pass _sg_alloc_pass(void) { + sg_pass res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.pass_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id = _sg_slot_alloc(&_sg.pools.pass_pool, &_sg.pools.passes[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + return res; +} + +_SOKOL_PRIVATE void _sg_dealloc_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(buf_id.id != SG_INVALID_ID); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&buf->slot); + _sg_pool_free_index(&_sg.pools.buffer_pool, _sg_slot_index(buf_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_image(sg_image img_id) { + SOKOL_ASSERT(img_id.id != SG_INVALID_ID); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&img->slot); + _sg_pool_free_index(&_sg.pools.image_pool, _sg_slot_index(img_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_shader(sg_shader shd_id) { + SOKOL_ASSERT(shd_id.id != SG_INVALID_ID); + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&shd->slot); + _sg_pool_free_index(&_sg.pools.shader_pool, _sg_slot_index(shd_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(pip_id.id != SG_INVALID_ID); + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&pip->slot); + _sg_pool_free_index(&_sg.pools.pipeline_pool, _sg_slot_index(pip_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_pass(sg_pass pass_id) { + SOKOL_ASSERT(pass_id.id != SG_INVALID_ID); + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&pass->slot); + _sg_pool_free_index(&_sg.pools.pass_pool, _sg_slot_index(pass_id.id)); +} + +_SOKOL_PRIVATE void _sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { + SOKOL_ASSERT(buf_id.id != SG_INVALID_ID && desc); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); + buf->slot.ctx_id = _sg.active_context.id; + if (_sg_validate_buffer_desc(desc)) { + buf->slot.state = _sg_create_buffer(buf, desc); + } + else { + buf->slot.state = SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT((buf->slot.state == SG_RESOURCESTATE_VALID)||(buf->slot.state == SG_RESOURCESTATE_FAILED)); +} + +_SOKOL_PRIVATE void _sg_init_image(sg_image img_id, const sg_image_desc* desc) { + SOKOL_ASSERT(img_id.id != SG_INVALID_ID && desc); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); + img->slot.ctx_id = _sg.active_context.id; + if (_sg_validate_image_desc(desc)) { + img->slot.state = _sg_create_image(img, desc); + } + else { + img->slot.state = SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT((img->slot.state == SG_RESOURCESTATE_VALID)||(img->slot.state == SG_RESOURCESTATE_FAILED)); +} + +_SOKOL_PRIVATE void _sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc) { + SOKOL_ASSERT(shd_id.id != SG_INVALID_ID && desc); + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); + shd->slot.ctx_id = _sg.active_context.id; + if (_sg_validate_shader_desc(desc)) { + shd->slot.state = _sg_create_shader(shd, desc); + } + else { + shd->slot.state = SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT((shd->slot.state == SG_RESOURCESTATE_VALID)||(shd->slot.state == SG_RESOURCESTATE_FAILED)); +} + +_SOKOL_PRIVATE void _sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(pip_id.id != SG_INVALID_ID && desc); + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); + pip->slot.ctx_id = _sg.active_context.id; + if (_sg_validate_pipeline_desc(desc)) { + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); + if (shd && (shd->slot.state == SG_RESOURCESTATE_VALID)) { + pip->slot.state = _sg_create_pipeline(pip, shd, desc); + } + else { + pip->slot.state = SG_RESOURCESTATE_FAILED; + } + } + else { + pip->slot.state = SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT((pip->slot.state == SG_RESOURCESTATE_VALID)||(pip->slot.state == SG_RESOURCESTATE_FAILED)); +} + +_SOKOL_PRIVATE void _sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { + SOKOL_ASSERT(pass_id.id != SG_INVALID_ID && desc); + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); + pass->slot.ctx_id = _sg.active_context.id; + if (_sg_validate_pass_desc(desc)) { + /* lookup pass attachment image pointers */ + _sg_image_t* att_imgs[SG_MAX_COLOR_ATTACHMENTS + 1]; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (desc->color_attachments[i].image.id) { + att_imgs[i] = _sg_lookup_image(&_sg.pools, desc->color_attachments[i].image.id); + /* FIXME: this shouldn't be an assertion, but result in a SG_RESOURCESTATE_FAILED pass */ + SOKOL_ASSERT(att_imgs[i] && att_imgs[i]->slot.state == SG_RESOURCESTATE_VALID); + } + else { + att_imgs[i] = 0; + } + } + const int ds_att_index = SG_MAX_COLOR_ATTACHMENTS; + if (desc->depth_stencil_attachment.image.id) { + att_imgs[ds_att_index] = _sg_lookup_image(&_sg.pools, desc->depth_stencil_attachment.image.id); + /* FIXME: this shouldn't be an assertion, but result in a SG_RESOURCESTATE_FAILED pass */ + SOKOL_ASSERT(att_imgs[ds_att_index] && att_imgs[ds_att_index]->slot.state == SG_RESOURCESTATE_VALID); + } + else { + att_imgs[ds_att_index] = 0; + } + pass->slot.state = _sg_create_pass(pass, att_imgs, desc); + } + else { + pass->slot.state = SG_RESOURCESTATE_FAILED; + } + SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID)||(pass->slot.state == SG_RESOURCESTATE_FAILED)); +} + +_SOKOL_PRIVATE bool _sg_uninit_buffer(sg_buffer buf_id) { + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + if (buf) { + if (buf->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_buffer(buf); + _sg_reset_buffer(buf); + return true; + } + else { + SOKOL_LOG("_sg_uninit_buffer: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_image(sg_image img_id) { + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + if (img) { + if (img->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_image(img); + _sg_reset_image(img); + return true; + } + else { + SOKOL_LOG("_sg_uninit_image: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_shader(sg_shader shd_id) { + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + if (shd) { + if (shd->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_shader(shd); + _sg_reset_shader(shd); + return true; + } + else { + SOKOL_LOG("_sg_uninit_shader: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_pipeline(sg_pipeline pip_id) { + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + if (pip) { + if (pip->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_pipeline(pip); + _sg_reset_pipeline(pip); + return true; + } + else { + SOKOL_LOG("_sg_uninit_pipeline: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_pass(sg_pass pass_id) { + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + if (pass) { + if (pass->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_pass(pass); + _sg_reset_pass(pass); + return true; + } + else { + SOKOL_LOG("_sg_uninit_pass: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +/*== PUBLIC API FUNCTIONS ====================================================*/ + +#if defined(SOKOL_METAL) + // this is ARC compatible + #if defined(__cplusplus) + #define _SG_CLEAR(type, item) { item = (type) { }; } + #else + #define _SG_CLEAR(type, item) { item = (type) { 0 }; } + #endif +#else + #define _SG_CLEAR(type, item) { memset(&item, 0, sizeof(item)); } +#endif + +SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { + SOKOL_ASSERT(desc); + SOKOL_ASSERT((desc->_start_canary == 0) && (desc->_end_canary == 0)); + _SG_CLEAR(_sg_state_t, _sg); + _sg.desc = *desc; + + /* replace zero-init items with their default values + NOTE: on WebGPU, the default color pixel format MUST be provided, + cannot be a default compile-time constant. + */ + #if defined(SOKOL_WGPU) + SOKOL_ASSERT(SG_PIXELFORMAT_NONE != _sg.desc.context.color_format); + #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) + _sg.desc.context.color_format = _sg_def(_sg.desc.context.color_format, SG_PIXELFORMAT_BGRA8); + #else + _sg.desc.context.color_format = _sg_def(_sg.desc.context.color_format, SG_PIXELFORMAT_RGBA8); + #endif + _sg.desc.context.depth_format = _sg_def(_sg.desc.context.depth_format, SG_PIXELFORMAT_DEPTH_STENCIL); + _sg.desc.context.sample_count = _sg_def(_sg.desc.context.sample_count, 1); + _sg.desc.buffer_pool_size = _sg_def(_sg.desc.buffer_pool_size, _SG_DEFAULT_BUFFER_POOL_SIZE); + _sg.desc.image_pool_size = _sg_def(_sg.desc.image_pool_size, _SG_DEFAULT_IMAGE_POOL_SIZE); + _sg.desc.shader_pool_size = _sg_def(_sg.desc.shader_pool_size, _SG_DEFAULT_SHADER_POOL_SIZE); + _sg.desc.pipeline_pool_size = _sg_def(_sg.desc.pipeline_pool_size, _SG_DEFAULT_PIPELINE_POOL_SIZE); + _sg.desc.pass_pool_size = _sg_def(_sg.desc.pass_pool_size, _SG_DEFAULT_PASS_POOL_SIZE); + _sg.desc.context_pool_size = _sg_def(_sg.desc.context_pool_size, _SG_DEFAULT_CONTEXT_POOL_SIZE); + _sg.desc.uniform_buffer_size = _sg_def(_sg.desc.uniform_buffer_size, _SG_DEFAULT_UB_SIZE); + _sg.desc.staging_buffer_size = _sg_def(_sg.desc.staging_buffer_size, _SG_DEFAULT_STAGING_SIZE); + _sg.desc.sampler_cache_size = _sg_def(_sg.desc.sampler_cache_size, _SG_DEFAULT_SAMPLER_CACHE_CAPACITY); + + _sg_setup_pools(&_sg.pools, &_sg.desc); + _sg.frame_index = 1; + _sg_setup_backend(&_sg.desc); + _sg.valid = true; + sg_setup_context(); +} + +SOKOL_API_IMPL void sg_shutdown(void) { + /* can only delete resources for the currently set context here, if multiple + contexts are used, the app code must take care of properly releasing them + (since only the app code can switch between 3D-API contexts) + */ + if (_sg.active_context.id != SG_INVALID_ID) { + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.active_context.id); + if (ctx) { + _sg_destroy_all_resources(&_sg.pools, _sg.active_context.id); + _sg_destroy_context(ctx); + } + } + _sg_discard_backend(); + _sg_discard_pools(&_sg.pools); + _sg.valid = false; +} + +SOKOL_API_IMPL bool sg_isvalid(void) { + return _sg.valid; +} + +SOKOL_API_IMPL sg_desc sg_query_desc(void) { + SOKOL_ASSERT(_sg.valid); + return _sg.desc; +} + +SOKOL_API_IMPL sg_backend sg_query_backend(void) { + SOKOL_ASSERT(_sg.valid); + return _sg.backend; +} + +SOKOL_API_IMPL sg_features sg_query_features(void) { + SOKOL_ASSERT(_sg.valid); + return _sg.features; +} + +SOKOL_API_IMPL sg_limits sg_query_limits(void) { + SOKOL_ASSERT(_sg.valid); + return _sg.limits; +} + +SOKOL_API_IMPL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt) { + SOKOL_ASSERT(_sg.valid); + int fmt_index = (int) fmt; + SOKOL_ASSERT((fmt_index > SG_PIXELFORMAT_NONE) && (fmt_index < _SG_PIXELFORMAT_NUM)); + return _sg.formats[fmt_index]; +} + +SOKOL_API_IMPL sg_context sg_setup_context(void) { + SOKOL_ASSERT(_sg.valid); + sg_context res; + int slot_index = _sg_pool_alloc_index(&_sg.pools.context_pool); + if (_SG_INVALID_SLOT_INDEX != slot_index) { + res.id = _sg_slot_alloc(&_sg.pools.context_pool, &_sg.pools.contexts[slot_index].slot, slot_index); + _sg_context_t* ctx = _sg_context_at(&_sg.pools, res.id); + ctx->slot.state = _sg_create_context(ctx); + SOKOL_ASSERT(ctx->slot.state == SG_RESOURCESTATE_VALID); + _sg_activate_context(ctx); + } + else { + /* pool is exhausted */ + res.id = SG_INVALID_ID; + } + _sg.active_context = res; + return res; +} + +SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { + SOKOL_ASSERT(_sg.valid); + _sg_destroy_all_resources(&_sg.pools, ctx_id.id); + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); + if (ctx) { + _sg_destroy_context(ctx); + _sg_reset_context(ctx); + _sg_reset_slot(&ctx->slot); + _sg_pool_free_index(&_sg.pools.context_pool, _sg_slot_index(ctx_id.id)); + } + _sg.active_context.id = SG_INVALID_ID; + _sg_activate_context(0); +} + +SOKOL_API_IMPL void sg_activate_context(sg_context ctx_id) { + SOKOL_ASSERT(_sg.valid); + _sg.active_context = ctx_id; + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); + /* NOTE: ctx can be 0 here if the context is no longer valid */ + _sg_activate_context(ctx); +} + +SOKOL_API_IMPL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(trace_hooks); + _SOKOL_UNUSED(trace_hooks); + #if defined(SOKOL_TRACE_HOOKS) + sg_trace_hooks old_hooks = _sg.hooks; + _sg.hooks = *trace_hooks; + #else + static sg_trace_hooks old_hooks; + SOKOL_LOG("sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined!"); + #endif + return old_hooks; +} + +SOKOL_API_IMPL sg_buffer sg_alloc_buffer(void) { + SOKOL_ASSERT(_sg.valid); + sg_buffer res = _sg_alloc_buffer(); + _SG_TRACE_ARGS(alloc_buffer, res); + return res; +} + +SOKOL_API_IMPL sg_image sg_alloc_image(void) { + SOKOL_ASSERT(_sg.valid); + sg_image res = _sg_alloc_image(); + _SG_TRACE_ARGS(alloc_image, res); + return res; +} + +SOKOL_API_IMPL sg_shader sg_alloc_shader(void) { + SOKOL_ASSERT(_sg.valid); + sg_shader res = _sg_alloc_shader(); + _SG_TRACE_ARGS(alloc_shader, res); + return res; +} + +SOKOL_API_IMPL sg_pipeline sg_alloc_pipeline(void) { + SOKOL_ASSERT(_sg.valid); + sg_pipeline res = _sg_alloc_pipeline(); + _SG_TRACE_ARGS(alloc_pipeline, res); + return res; +} + +SOKOL_API_IMPL sg_pass sg_alloc_pass(void) { + SOKOL_ASSERT(_sg.valid); + sg_pass res = _sg_alloc_pass(); + _SG_TRACE_ARGS(alloc_pass, res); + return res; +} + +SOKOL_API_IMPL void sg_dealloc_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_buffer(buf_id); + _SG_TRACE_ARGS(dealloc_buffer, buf_id); +} + +SOKOL_API_IMPL void sg_dealloc_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_image(img_id); + _SG_TRACE_ARGS(dealloc_image, img_id); +} + +SOKOL_API_IMPL void sg_dealloc_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_shader(shd_id); + _SG_TRACE_ARGS(dealloc_shader, shd_id); +} + +SOKOL_API_IMPL void sg_dealloc_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_pipeline(pip_id); + _SG_TRACE_ARGS(dealloc_pipeline, pip_id); +} + +SOKOL_API_IMPL void sg_dealloc_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_pass(pass_id); + _SG_TRACE_ARGS(dealloc_pass, pass_id); +} + +SOKOL_API_IMPL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { + SOKOL_ASSERT(_sg.valid); + sg_buffer_desc desc_def = _sg_buffer_desc_defaults(desc); + _sg_init_buffer(buf_id, &desc_def); + _SG_TRACE_ARGS(init_buffer, buf_id, &desc_def); +} + +SOKOL_API_IMPL void sg_init_image(sg_image img_id, const sg_image_desc* desc) { + SOKOL_ASSERT(_sg.valid); + sg_image_desc desc_def = _sg_image_desc_defaults(desc); + _sg_init_image(img_id, &desc_def); + _SG_TRACE_ARGS(init_image, img_id, &desc_def); +} + +SOKOL_API_IMPL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc) { + SOKOL_ASSERT(_sg.valid); + sg_shader_desc desc_def = _sg_shader_desc_defaults(desc); + _sg_init_shader(shd_id, &desc_def); + _SG_TRACE_ARGS(init_shader, shd_id, &desc_def); +} + +SOKOL_API_IMPL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(_sg.valid); + sg_pipeline_desc desc_def = _sg_pipeline_desc_defaults(desc); + _sg_init_pipeline(pip_id, &desc_def); + _SG_TRACE_ARGS(init_pipeline, pip_id, &desc_def); +} + +SOKOL_API_IMPL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { + SOKOL_ASSERT(_sg.valid); + sg_pass_desc desc_def = _sg_pass_desc_defaults(desc); + _sg_init_pass(pass_id, &desc_def); + _SG_TRACE_ARGS(init_pass, pass_id, &desc_def); +} + +SOKOL_API_IMPL bool sg_uninit_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_buffer(buf_id); + _SG_TRACE_ARGS(uninit_buffer, buf_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_image(img_id); + _SG_TRACE_ARGS(uninit_image, img_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_shader(shd_id); + _SG_TRACE_ARGS(uninit_shader, shd_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_pipeline(pip_id); + _SG_TRACE_ARGS(uninit_pipeline, pip_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_pass(pass_id); + _SG_TRACE_ARGS(uninit_pass, pass_id); + return res; +} + +/*-- set allocated resource to failed state ----------------------------------*/ +SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(buf_id.id != SG_INVALID_ID); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); + buf->slot.ctx_id = _sg.active_context.id; + buf->slot.state = SG_RESOURCESTATE_FAILED; + _SG_TRACE_ARGS(fail_buffer, buf_id); +} + +SOKOL_API_IMPL void sg_fail_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(img_id.id != SG_INVALID_ID); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); + img->slot.ctx_id = _sg.active_context.id; + img->slot.state = SG_RESOURCESTATE_FAILED; + _SG_TRACE_ARGS(fail_image, img_id); +} + +SOKOL_API_IMPL void sg_fail_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(shd_id.id != SG_INVALID_ID); + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); + shd->slot.ctx_id = _sg.active_context.id; + shd->slot.state = SG_RESOURCESTATE_FAILED; + _SG_TRACE_ARGS(fail_shader, shd_id); +} + +SOKOL_API_IMPL void sg_fail_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(pip_id.id != SG_INVALID_ID); + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); + pip->slot.ctx_id = _sg.active_context.id; + pip->slot.state = SG_RESOURCESTATE_FAILED; + _SG_TRACE_ARGS(fail_pipeline, pip_id); +} + +SOKOL_API_IMPL void sg_fail_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(pass_id.id != SG_INVALID_ID); + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); + pass->slot.ctx_id = _sg.active_context.id; + pass->slot.state = SG_RESOURCESTATE_FAILED; + _SG_TRACE_ARGS(fail_pass, pass_id); +} + +/*-- get resource state */ +SOKOL_API_IMPL sg_resource_state sg_query_buffer_state(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + sg_resource_state res = buf ? buf->slot.state : SG_RESOURCESTATE_INVALID; + return res; +} + +SOKOL_API_IMPL sg_resource_state sg_query_image_state(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + sg_resource_state res = img ? img->slot.state : SG_RESOURCESTATE_INVALID; + return res; +} + +SOKOL_API_IMPL sg_resource_state sg_query_shader_state(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + sg_resource_state res = shd ? shd->slot.state : SG_RESOURCESTATE_INVALID; + return res; +} + +SOKOL_API_IMPL sg_resource_state sg_query_pipeline_state(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + sg_resource_state res = pip ? pip->slot.state : SG_RESOURCESTATE_INVALID; + return res; +} + +SOKOL_API_IMPL sg_resource_state sg_query_pass_state(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + sg_resource_state res = pass ? pass->slot.state : SG_RESOURCESTATE_INVALID; + return res; +} + +/*-- allocate and initialize resource ----------------------------------------*/ +SOKOL_API_IMPL sg_buffer sg_make_buffer(const sg_buffer_desc* desc) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(desc); + sg_buffer_desc desc_def = _sg_buffer_desc_defaults(desc); + sg_buffer buf_id = _sg_alloc_buffer(); + if (buf_id.id != SG_INVALID_ID) { + _sg_init_buffer(buf_id, &desc_def); + } + else { + SOKOL_LOG("buffer pool exhausted!"); + _SG_TRACE_NOARGS(err_buffer_pool_exhausted); + } + _SG_TRACE_ARGS(make_buffer, &desc_def, buf_id); + return buf_id; +} + +SOKOL_API_IMPL sg_image sg_make_image(const sg_image_desc* desc) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(desc); + sg_image_desc desc_def = _sg_image_desc_defaults(desc); + sg_image img_id = _sg_alloc_image(); + if (img_id.id != SG_INVALID_ID) { + _sg_init_image(img_id, &desc_def); + } + else { + SOKOL_LOG("image pool exhausted!"); + _SG_TRACE_NOARGS(err_image_pool_exhausted); + } + _SG_TRACE_ARGS(make_image, &desc_def, img_id); + return img_id; +} + +SOKOL_API_IMPL sg_shader sg_make_shader(const sg_shader_desc* desc) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(desc); + sg_shader_desc desc_def = _sg_shader_desc_defaults(desc); + sg_shader shd_id = _sg_alloc_shader(); + if (shd_id.id != SG_INVALID_ID) { + _sg_init_shader(shd_id, &desc_def); + } + else { + SOKOL_LOG("shader pool exhausted!"); + _SG_TRACE_NOARGS(err_shader_pool_exhausted); + } + _SG_TRACE_ARGS(make_shader, &desc_def, shd_id); + return shd_id; +} + +SOKOL_API_IMPL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(desc); + sg_pipeline_desc desc_def = _sg_pipeline_desc_defaults(desc); + sg_pipeline pip_id = _sg_alloc_pipeline(); + if (pip_id.id != SG_INVALID_ID) { + _sg_init_pipeline(pip_id, &desc_def); + } + else { + SOKOL_LOG("pipeline pool exhausted!"); + _SG_TRACE_NOARGS(err_pipeline_pool_exhausted); + } + _SG_TRACE_ARGS(make_pipeline, &desc_def, pip_id); + return pip_id; +} + +SOKOL_API_IMPL sg_pass sg_make_pass(const sg_pass_desc* desc) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(desc); + sg_pass_desc desc_def = _sg_pass_desc_defaults(desc); + sg_pass pass_id = _sg_alloc_pass(); + if (pass_id.id != SG_INVALID_ID) { + _sg_init_pass(pass_id, &desc_def); + } + else { + SOKOL_LOG("pass pool exhausted!"); + _SG_TRACE_NOARGS(err_pass_pool_exhausted); + } + _SG_TRACE_ARGS(make_pass, &desc_def, pass_id); + return pass_id; +} + +/*-- destroy resource --------------------------------------------------------*/ +SOKOL_API_IMPL void sg_destroy_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_ARGS(destroy_buffer, buf_id); + if (_sg_uninit_buffer(buf_id)) { + _sg_dealloc_buffer(buf_id); + } +} + +SOKOL_API_IMPL void sg_destroy_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_ARGS(destroy_image, img_id); + if (_sg_uninit_image(img_id)) { + _sg_dealloc_image(img_id); + } +} + +SOKOL_API_IMPL void sg_destroy_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_ARGS(destroy_shader, shd_id); + if (_sg_uninit_shader(shd_id)) { + _sg_dealloc_shader(shd_id); + } +} + +SOKOL_API_IMPL void sg_destroy_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_ARGS(destroy_pipeline, pip_id); + if (_sg_uninit_pipeline(pip_id)) { + _sg_dealloc_pipeline(pip_id); + } +} + +SOKOL_API_IMPL void sg_destroy_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_ARGS(destroy_pass, pass_id); + if (_sg_uninit_pass(pass_id)) { + _sg_dealloc_pass(pass_id); + } +} + +SOKOL_API_IMPL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(pass_action); + SOKOL_ASSERT((pass_action->_start_canary == 0) && (pass_action->_end_canary == 0)); + sg_pass_action pa; + _sg_resolve_default_pass_action(pass_action, &pa); + _sg.cur_pass.id = SG_INVALID_ID; + _sg.pass_valid = true; + _sg_begin_pass(0, &pa, width, height); + _SG_TRACE_ARGS(begin_default_pass, pass_action, width, height); +} + +SOKOL_API_IMPL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height) { + sg_begin_default_pass(pass_action, (int)width, (int)height); +} + +SOKOL_API_IMPL void sg_begin_pass(sg_pass pass_id, const sg_pass_action* pass_action) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(pass_action); + SOKOL_ASSERT((pass_action->_start_canary == 0) && (pass_action->_end_canary == 0)); + _sg.cur_pass = pass_id; + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + if (pass && _sg_validate_begin_pass(pass)) { + _sg.pass_valid = true; + sg_pass_action pa; + _sg_resolve_default_pass_action(pass_action, &pa); + const _sg_image_t* img = _sg_pass_color_image(pass, 0); + SOKOL_ASSERT(img); + const int w = img->cmn.width; + const int h = img->cmn.height; + _sg_begin_pass(pass, &pa, w, h); + _SG_TRACE_ARGS(begin_pass, pass_id, pass_action); + } + else { + _sg.pass_valid = false; + _SG_TRACE_NOARGS(err_pass_invalid); + } +} + +SOKOL_API_IMPL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) { + SOKOL_ASSERT(_sg.valid); + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + _sg_apply_viewport(x, y, width, height, origin_top_left); + _SG_TRACE_ARGS(apply_viewport, x, y, width, height, origin_top_left); +} + +SOKOL_API_IMPL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) { + sg_apply_viewport((int)x, (int)y, (int)width, (int)height, origin_top_left); +} + +SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) { + SOKOL_ASSERT(_sg.valid); + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + _sg_apply_scissor_rect(x, y, width, height, origin_top_left); + _SG_TRACE_ARGS(apply_scissor_rect, x, y, width, height, origin_top_left); +} + +SOKOL_API_IMPL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) { + sg_apply_scissor_rect((int)x, (int)y, (int)width, (int)height, origin_top_left); +} + +SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + _sg.bindings_valid = false; + if (!_sg_validate_apply_pipeline(pip_id)) { + _sg.next_draw_valid = false; + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + _sg.cur_pipeline = pip_id; + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_ASSERT(pip); + _sg.next_draw_valid = (SG_RESOURCESTATE_VALID == pip->slot.state); + SOKOL_ASSERT(pip->shader && (pip->shader->slot.id == pip->cmn.shader_id.id)); + _sg_apply_pipeline(pip); + _SG_TRACE_ARGS(apply_pipeline, pip_id); +} + +SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(bindings); + SOKOL_ASSERT((bindings->_start_canary == 0) && (bindings->_end_canary==0)); + if (!_sg_validate_apply_bindings(bindings)) { + _sg.next_draw_valid = false; + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + _sg.bindings_valid = true; + + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, _sg.cur_pipeline.id); + SOKOL_ASSERT(pip); + + _sg_buffer_t* vbs[SG_MAX_SHADERSTAGE_BUFFERS] = { 0 }; + int num_vbs = 0; + for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++, num_vbs++) { + if (bindings->vertex_buffers[i].id) { + vbs[i] = _sg_lookup_buffer(&_sg.pools, bindings->vertex_buffers[i].id); + SOKOL_ASSERT(vbs[i]); + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == vbs[i]->slot.state); + _sg.next_draw_valid &= !vbs[i]->cmn.append_overflow; + } + else { + break; + } + } + + _sg_buffer_t* ib = 0; + if (bindings->index_buffer.id) { + ib = _sg_lookup_buffer(&_sg.pools, bindings->index_buffer.id); + SOKOL_ASSERT(ib); + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == ib->slot.state); + _sg.next_draw_valid &= !ib->cmn.append_overflow; + } + + _sg_image_t* vs_imgs[SG_MAX_SHADERSTAGE_IMAGES] = { 0 }; + int num_vs_imgs = 0; + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++, num_vs_imgs++) { + if (bindings->vs_images[i].id) { + vs_imgs[i] = _sg_lookup_image(&_sg.pools, bindings->vs_images[i].id); + SOKOL_ASSERT(vs_imgs[i]); + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == vs_imgs[i]->slot.state); + } + else { + break; + } + } + + _sg_image_t* fs_imgs[SG_MAX_SHADERSTAGE_IMAGES] = { 0 }; + int num_fs_imgs = 0; + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++, num_fs_imgs++) { + if (bindings->fs_images[i].id) { + fs_imgs[i] = _sg_lookup_image(&_sg.pools, bindings->fs_images[i].id); + SOKOL_ASSERT(fs_imgs[i]); + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == fs_imgs[i]->slot.state); + } + else { + break; + } + } + if (_sg.next_draw_valid) { + const int* vb_offsets = bindings->vertex_buffer_offsets; + int ib_offset = bindings->index_buffer_offset; + _sg_apply_bindings(pip, vbs, vb_offsets, num_vbs, ib, ib_offset, vs_imgs, num_vs_imgs, fs_imgs, num_fs_imgs); + _SG_TRACE_ARGS(apply_bindings, bindings); + } + else { + _SG_TRACE_NOARGS(err_draw_invalid); + } +} + +SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS)); + SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + if (!_sg_validate_apply_uniforms(stage, ub_index, data)) { + _sg.next_draw_valid = false; + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + if (!_sg.next_draw_valid) { + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + _sg_apply_uniforms(stage, ub_index, data); + _SG_TRACE_ARGS(apply_uniforms, stage, ub_index, data); +} + +SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instances) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(base_element >= 0); + SOKOL_ASSERT(num_elements >= 0); + SOKOL_ASSERT(num_instances >= 0); + #if defined(SOKOL_DEBUG) + if (!_sg.bindings_valid) { + SOKOL_LOG("attempting to draw without resource bindings"); + } + #endif + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + if (!_sg.next_draw_valid) { + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + if (!_sg.bindings_valid) { + _SG_TRACE_NOARGS(err_bindings_invalid); + return; + } + /* attempting to draw with zero elements or instances is not technically an + error, but might be handled as an error in the backend API (e.g. on Metal) + */ + if ((0 == num_elements) || (0 == num_instances)) { + _SG_TRACE_NOARGS(err_draw_invalid); + return; + } + _sg_draw(base_element, num_elements, num_instances); + _SG_TRACE_ARGS(draw, base_element, num_elements, num_instances); +} + +SOKOL_API_IMPL void sg_end_pass(void) { + SOKOL_ASSERT(_sg.valid); + if (!_sg.pass_valid) { + _SG_TRACE_NOARGS(err_pass_invalid); + return; + } + _sg_end_pass(); + _sg.cur_pass.id = SG_INVALID_ID; + _sg.cur_pipeline.id = SG_INVALID_ID; + _sg.pass_valid = false; + _SG_TRACE_NOARGS(end_pass); +} + +SOKOL_API_IMPL void sg_commit(void) { + SOKOL_ASSERT(_sg.valid); + _sg_commit(); + _SG_TRACE_NOARGS(commit); + _sg.frame_index++; +} + +SOKOL_API_IMPL void sg_reset_state_cache(void) { + SOKOL_ASSERT(_sg.valid); + _sg_reset_state_cache(); + _SG_TRACE_NOARGS(reset_state_cache); +} + +SOKOL_API_IMPL void sg_update_buffer(sg_buffer buf_id, const sg_range* data) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + if ((data->size > 0) && buf && (buf->slot.state == SG_RESOURCESTATE_VALID)) { + if (_sg_validate_update_buffer(buf, data)) { + SOKOL_ASSERT(data->size <= (size_t)buf->cmn.size); + /* only one update allowed per buffer and frame */ + SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); + /* update and append on same buffer in same frame not allowed */ + SOKOL_ASSERT(buf->cmn.append_frame_index != _sg.frame_index); + _sg_update_buffer(buf, data); + buf->cmn.update_frame_index = _sg.frame_index; + } + } + _SG_TRACE_ARGS(update_buffer, buf_id, data); +} + +SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const sg_range* data) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(data && data->ptr); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + int result; + if (buf) { + /* rewind append cursor in a new frame */ + if (buf->cmn.append_frame_index != _sg.frame_index) { + buf->cmn.append_pos = 0; + buf->cmn.append_overflow = false; + } + if ((buf->cmn.append_pos + _sg_roundup((int)data->size, 4)) > buf->cmn.size) { + buf->cmn.append_overflow = true; + } + const int start_pos = buf->cmn.append_pos; + if (buf->slot.state == SG_RESOURCESTATE_VALID) { + if (_sg_validate_append_buffer(buf, data)) { + if (!buf->cmn.append_overflow && (data->size > 0)) { + /* update and append on same buffer in same frame not allowed */ + SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); + int copied_num_bytes = _sg_append_buffer(buf, data, buf->cmn.append_frame_index != _sg.frame_index); + buf->cmn.append_pos += copied_num_bytes; + buf->cmn.append_frame_index = _sg.frame_index; + } + } + } + result = start_pos; + } + else { + /* FIXME: should we return -1 here? */ + result = 0; + } + _SG_TRACE_ARGS(append_buffer, buf_id, data, result); + return result; +} + +SOKOL_API_IMPL bool sg_query_buffer_overflow(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + bool result = buf ? buf->cmn.append_overflow : false; + return result; +} + +SOKOL_API_IMPL void sg_update_image(sg_image img_id, const sg_image_data* data) { + SOKOL_ASSERT(_sg.valid); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + if (img && img->slot.state == SG_RESOURCESTATE_VALID) { + if (_sg_validate_update_image(img, data)) { + SOKOL_ASSERT(img->cmn.upd_frame_index != _sg.frame_index); + _sg_update_image(img, data); + img->cmn.upd_frame_index = _sg.frame_index; + } + } + _SG_TRACE_ARGS(update_image, img_id, data); +} + +SOKOL_API_IMPL void sg_push_debug_group(const char* name) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(name); + _SOKOL_UNUSED(name); + _SG_TRACE_ARGS(push_debug_group, name); +} + +SOKOL_API_IMPL void sg_pop_debug_group(void) { + SOKOL_ASSERT(_sg.valid); + _SG_TRACE_NOARGS(pop_debug_group); +} + +SOKOL_API_IMPL sg_buffer_info sg_query_buffer_info(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + sg_buffer_info info; + memset(&info, 0, sizeof(info)); + const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + if (buf) { + info.slot.state = buf->slot.state; + info.slot.res_id = buf->slot.id; + info.slot.ctx_id = buf->slot.ctx_id; + info.update_frame_index = buf->cmn.update_frame_index; + info.append_frame_index = buf->cmn.append_frame_index; + info.append_pos = buf->cmn.append_pos; + info.append_overflow = buf->cmn.append_overflow; + #if defined(SOKOL_D3D11) + info.num_slots = 1; + info.active_slot = 0; + #else + info.num_slots = buf->cmn.num_slots; + info.active_slot = buf->cmn.active_slot; + #endif + } + return info; +} + +SOKOL_API_IMPL sg_image_info sg_query_image_info(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + sg_image_info info; + memset(&info, 0, sizeof(info)); + const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + if (img) { + info.slot.state = img->slot.state; + info.slot.res_id = img->slot.id; + info.slot.ctx_id = img->slot.ctx_id; + info.upd_frame_index = img->cmn.upd_frame_index; + #if defined(SOKOL_D3D11) + info.num_slots = 1; + info.active_slot = 0; + #else + info.num_slots = img->cmn.num_slots; + info.active_slot = img->cmn.active_slot; + #endif + info.width = img->cmn.width; + info.height = img->cmn.height; + } + return info; +} + +SOKOL_API_IMPL sg_shader_info sg_query_shader_info(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + sg_shader_info info; + memset(&info, 0, sizeof(info)); + const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + if (shd) { + info.slot.state = shd->slot.state; + info.slot.res_id = shd->slot.id; + info.slot.ctx_id = shd->slot.ctx_id; + } + return info; +} + +SOKOL_API_IMPL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + sg_pipeline_info info; + memset(&info, 0, sizeof(info)); + const _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + if (pip) { + info.slot.state = pip->slot.state; + info.slot.res_id = pip->slot.id; + info.slot.ctx_id = pip->slot.ctx_id; + } + return info; +} + +SOKOL_API_IMPL sg_pass_info sg_query_pass_info(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + sg_pass_info info; + memset(&info, 0, sizeof(info)); + const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + if (pass) { + info.slot.state = pass->slot.state; + info.slot.res_id = pass->slot.id; + info.slot.ctx_id = pass->slot.ctx_id; + } + return info; +} + +SOKOL_API_IMPL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc) { + SOKOL_ASSERT(_sg.valid && desc); + return _sg_buffer_desc_defaults(desc); +} + +SOKOL_API_IMPL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc) { + SOKOL_ASSERT(_sg.valid && desc); + return _sg_image_desc_defaults(desc); +} + +SOKOL_API_IMPL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc) { + SOKOL_ASSERT(_sg.valid && desc); + return _sg_shader_desc_defaults(desc); +} + +SOKOL_API_IMPL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc) { + SOKOL_ASSERT(_sg.valid && desc); + return _sg_pipeline_desc_defaults(desc); +} + +SOKOL_API_IMPL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc) { + SOKOL_ASSERT(_sg.valid && desc); + return _sg_pass_desc_defaults(desc); +} + +SOKOL_API_IMPL const void* sg_d3d11_device(void) { +#if defined(SOKOL_D3D11) + return (const void*) _sg.d3d11.dev; +#else + return 0; +#endif +} + +SOKOL_API_IMPL const void* sg_mtl_device(void) { +#if defined(SOKOL_METAL) + if (nil != _sg.mtl.device) { + return (__bridge const void*) _sg.mtl.device; + } + else { + return 0; + } +#else + return 0; +#endif +} + +SOKOL_API_IMPL const void* sg_mtl_render_command_encoder(void) { + #if defined(SOKOL_METAL) + if (nil != _sg.mtl.cmd_encoder) { + return (__bridge const void*) _sg.mtl.cmd_encoder; + } + else { + return 0; + } + #else + return 0; + #endif +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* SOKOL_GFX_IMPL */ diff --git a/thirdparty/sokol_imgui/CMakeLists.txt b/thirdparty/sokol_imgui/CMakeLists.txt new file mode 100644 index 0000000..5ce9e17 --- /dev/null +++ b/thirdparty/sokol_imgui/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(sokol_imgui STATIC + sokol_imgui.cpp + sokol_imgui.h + cimgui.cpp + cimgui.h +) + +target_link_libraries(sokol_imgui sokol_app sokol_gfx imgui) +target_include_directories(sokol_imgui PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(sokol_imgui PROPERTIES FOLDER "thirdparty") \ No newline at end of file diff --git a/thirdparty/sokol_imgui/cimgui.cpp b/thirdparty/sokol_imgui/cimgui.cpp new file mode 100644 index 0000000..f988231 --- /dev/null +++ b/thirdparty/sokol_imgui/cimgui.cpp @@ -0,0 +1,4725 @@ +//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui +//based on imgui.h file version "1.86" from Dear ImGui https://github.com/ocornut/imgui +//with imgui_internal.h api + +#include +#ifdef CIMGUI_FREETYPE +#include "./imgui/misc/freetype/imgui_freetype.h" +#endif +#include +#include "cimgui.h" + + +CIMGUI_API ImVec2* ImVec2_ImVec2_Nil(void) +{ + return IM_NEW(ImVec2)(); +} +CIMGUI_API void ImVec2_destroy(ImVec2* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImVec2* ImVec2_ImVec2_Float(float _x,float _y) +{ + return IM_NEW(ImVec2)(_x,_y); +} +CIMGUI_API ImVec4* ImVec4_ImVec4_Nil(void) +{ + return IM_NEW(ImVec4)(); +} +CIMGUI_API void ImVec4_destroy(ImVec4* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImVec4* ImVec4_ImVec4_Float(float _x,float _y,float _z,float _w) +{ + return IM_NEW(ImVec4)(_x,_y,_z,_w); +} +CIMGUI_API ImGuiContext* igCreateContext(ImFontAtlas* shared_font_atlas) +{ + return ImGui::CreateContext(shared_font_atlas); +} +CIMGUI_API void igDestroyContext(ImGuiContext* ctx) +{ + return ImGui::DestroyContext(ctx); +} +CIMGUI_API ImGuiContext* igGetCurrentContext() +{ + return ImGui::GetCurrentContext(); +} +CIMGUI_API void igSetCurrentContext(ImGuiContext* ctx) +{ + return ImGui::SetCurrentContext(ctx); +} +CIMGUI_API ImGuiIO* igGetIO() +{ + return &ImGui::GetIO(); +} +CIMGUI_API ImGuiStyle* igGetStyle() +{ + return &ImGui::GetStyle(); +} +CIMGUI_API void igNewFrame() +{ + return ImGui::NewFrame(); +} +CIMGUI_API void igEndFrame() +{ + return ImGui::EndFrame(); +} +CIMGUI_API void igRender() +{ + return ImGui::Render(); +} +CIMGUI_API ImDrawData* igGetDrawData() +{ + return ImGui::GetDrawData(); +} +CIMGUI_API void igShowDemoWindow(bool* p_open) +{ + return ImGui::ShowDemoWindow(p_open); +} +CIMGUI_API void igShowMetricsWindow(bool* p_open) +{ + return ImGui::ShowMetricsWindow(p_open); +} +CIMGUI_API void igShowStackToolWindow(bool* p_open) +{ + return ImGui::ShowStackToolWindow(p_open); +} +CIMGUI_API void igShowAboutWindow(bool* p_open) +{ + return ImGui::ShowAboutWindow(p_open); +} +CIMGUI_API void igShowStyleEditor(ImGuiStyle* ref) +{ + return ImGui::ShowStyleEditor(ref); +} +CIMGUI_API bool igShowStyleSelector(const char* label) +{ + return ImGui::ShowStyleSelector(label); +} +CIMGUI_API void igShowFontSelector(const char* label) +{ + return ImGui::ShowFontSelector(label); +} +CIMGUI_API void igShowUserGuide() +{ + return ImGui::ShowUserGuide(); +} +CIMGUI_API const char* igGetVersion() +{ + return ImGui::GetVersion(); +} +CIMGUI_API void igStyleColorsDark(ImGuiStyle* dst) +{ + return ImGui::StyleColorsDark(dst); +} +CIMGUI_API void igStyleColorsLight(ImGuiStyle* dst) +{ + return ImGui::StyleColorsLight(dst); +} +CIMGUI_API void igStyleColorsClassic(ImGuiStyle* dst) +{ + return ImGui::StyleColorsClassic(dst); +} +CIMGUI_API bool igBegin(const char* name,bool* p_open,ImGuiWindowFlags flags) +{ + return ImGui::Begin(name,p_open,flags); +} +CIMGUI_API void igEnd() +{ + return ImGui::End(); +} +CIMGUI_API bool igBeginChild_Str(const char* str_id,const ImVec2 size,bool border,ImGuiWindowFlags flags) +{ + return ImGui::BeginChild(str_id,size,border,flags); +} +CIMGUI_API bool igBeginChild_ID(ImGuiID id,const ImVec2 size,bool border,ImGuiWindowFlags flags) +{ + return ImGui::BeginChild(id,size,border,flags); +} +CIMGUI_API void igEndChild() +{ + return ImGui::EndChild(); +} +CIMGUI_API bool igIsWindowAppearing() +{ + return ImGui::IsWindowAppearing(); +} +CIMGUI_API bool igIsWindowCollapsed() +{ + return ImGui::IsWindowCollapsed(); +} +CIMGUI_API bool igIsWindowFocused(ImGuiFocusedFlags flags) +{ + return ImGui::IsWindowFocused(flags); +} +CIMGUI_API bool igIsWindowHovered(ImGuiHoveredFlags flags) +{ + return ImGui::IsWindowHovered(flags); +} +CIMGUI_API ImDrawList* igGetWindowDrawList() +{ + return ImGui::GetWindowDrawList(); +} +CIMGUI_API void igGetWindowPos(ImVec2 *pOut) +{ + *pOut = ImGui::GetWindowPos(); +} +CIMGUI_API void igGetWindowSize(ImVec2 *pOut) +{ + *pOut = ImGui::GetWindowSize(); +} +CIMGUI_API float igGetWindowWidth() +{ + return ImGui::GetWindowWidth(); +} +CIMGUI_API float igGetWindowHeight() +{ + return ImGui::GetWindowHeight(); +} +CIMGUI_API void igSetNextWindowPos(const ImVec2 pos,ImGuiCond cond,const ImVec2 pivot) +{ + return ImGui::SetNextWindowPos(pos,cond,pivot); +} +CIMGUI_API void igSetNextWindowSize(const ImVec2 size,ImGuiCond cond) +{ + return ImGui::SetNextWindowSize(size,cond); +} +CIMGUI_API void igSetNextWindowSizeConstraints(const ImVec2 size_min,const ImVec2 size_max,ImGuiSizeCallback custom_callback,void* custom_callback_data) +{ + return ImGui::SetNextWindowSizeConstraints(size_min,size_max,custom_callback,custom_callback_data); +} +CIMGUI_API void igSetNextWindowContentSize(const ImVec2 size) +{ + return ImGui::SetNextWindowContentSize(size); +} +CIMGUI_API void igSetNextWindowCollapsed(bool collapsed,ImGuiCond cond) +{ + return ImGui::SetNextWindowCollapsed(collapsed,cond); +} +CIMGUI_API void igSetNextWindowFocus() +{ + return ImGui::SetNextWindowFocus(); +} +CIMGUI_API void igSetNextWindowBgAlpha(float alpha) +{ + return ImGui::SetNextWindowBgAlpha(alpha); +} +CIMGUI_API void igSetWindowPos_Vec2(const ImVec2 pos,ImGuiCond cond) +{ + return ImGui::SetWindowPos(pos,cond); +} +CIMGUI_API void igSetWindowSize_Vec2(const ImVec2 size,ImGuiCond cond) +{ + return ImGui::SetWindowSize(size,cond); +} +CIMGUI_API void igSetWindowCollapsed_Bool(bool collapsed,ImGuiCond cond) +{ + return ImGui::SetWindowCollapsed(collapsed,cond); +} +CIMGUI_API void igSetWindowFocus_Nil() +{ + return ImGui::SetWindowFocus(); +} +CIMGUI_API void igSetWindowFontScale(float scale) +{ + return ImGui::SetWindowFontScale(scale); +} +CIMGUI_API void igSetWindowPos_Str(const char* name,const ImVec2 pos,ImGuiCond cond) +{ + return ImGui::SetWindowPos(name,pos,cond); +} +CIMGUI_API void igSetWindowSize_Str(const char* name,const ImVec2 size,ImGuiCond cond) +{ + return ImGui::SetWindowSize(name,size,cond); +} +CIMGUI_API void igSetWindowCollapsed_Str(const char* name,bool collapsed,ImGuiCond cond) +{ + return ImGui::SetWindowCollapsed(name,collapsed,cond); +} +CIMGUI_API void igSetWindowFocus_Str(const char* name) +{ + return ImGui::SetWindowFocus(name); +} +CIMGUI_API void igGetContentRegionAvail(ImVec2 *pOut) +{ + *pOut = ImGui::GetContentRegionAvail(); +} +CIMGUI_API void igGetContentRegionMax(ImVec2 *pOut) +{ + *pOut = ImGui::GetContentRegionMax(); +} +CIMGUI_API void igGetWindowContentRegionMin(ImVec2 *pOut) +{ + *pOut = ImGui::GetWindowContentRegionMin(); +} +CIMGUI_API void igGetWindowContentRegionMax(ImVec2 *pOut) +{ + *pOut = ImGui::GetWindowContentRegionMax(); +} +CIMGUI_API float igGetScrollX() +{ + return ImGui::GetScrollX(); +} +CIMGUI_API float igGetScrollY() +{ + return ImGui::GetScrollY(); +} +CIMGUI_API void igSetScrollX_Float(float scroll_x) +{ + return ImGui::SetScrollX(scroll_x); +} +CIMGUI_API void igSetScrollY_Float(float scroll_y) +{ + return ImGui::SetScrollY(scroll_y); +} +CIMGUI_API float igGetScrollMaxX() +{ + return ImGui::GetScrollMaxX(); +} +CIMGUI_API float igGetScrollMaxY() +{ + return ImGui::GetScrollMaxY(); +} +CIMGUI_API void igSetScrollHereX(float center_x_ratio) +{ + return ImGui::SetScrollHereX(center_x_ratio); +} +CIMGUI_API void igSetScrollHereY(float center_y_ratio) +{ + return ImGui::SetScrollHereY(center_y_ratio); +} +CIMGUI_API void igSetScrollFromPosX_Float(float local_x,float center_x_ratio) +{ + return ImGui::SetScrollFromPosX(local_x,center_x_ratio); +} +CIMGUI_API void igSetScrollFromPosY_Float(float local_y,float center_y_ratio) +{ + return ImGui::SetScrollFromPosY(local_y,center_y_ratio); +} +CIMGUI_API void igPushFont(ImFont* font) +{ + return ImGui::PushFont(font); +} +CIMGUI_API void igPopFont() +{ + return ImGui::PopFont(); +} +CIMGUI_API void igPushStyleColor_U32(ImGuiCol idx,ImU32 col) +{ + return ImGui::PushStyleColor(idx,col); +} +CIMGUI_API void igPushStyleColor_Vec4(ImGuiCol idx,const ImVec4 col) +{ + return ImGui::PushStyleColor(idx,col); +} +CIMGUI_API void igPopStyleColor(int count) +{ + return ImGui::PopStyleColor(count); +} +CIMGUI_API void igPushStyleVar_Float(ImGuiStyleVar idx,float val) +{ + return ImGui::PushStyleVar(idx,val); +} +CIMGUI_API void igPushStyleVar_Vec2(ImGuiStyleVar idx,const ImVec2 val) +{ + return ImGui::PushStyleVar(idx,val); +} +CIMGUI_API void igPopStyleVar(int count) +{ + return ImGui::PopStyleVar(count); +} +CIMGUI_API void igPushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + return ImGui::PushAllowKeyboardFocus(allow_keyboard_focus); +} +CIMGUI_API void igPopAllowKeyboardFocus() +{ + return ImGui::PopAllowKeyboardFocus(); +} +CIMGUI_API void igPushButtonRepeat(bool repeat) +{ + return ImGui::PushButtonRepeat(repeat); +} +CIMGUI_API void igPopButtonRepeat() +{ + return ImGui::PopButtonRepeat(); +} +CIMGUI_API void igPushItemWidth(float item_width) +{ + return ImGui::PushItemWidth(item_width); +} +CIMGUI_API void igPopItemWidth() +{ + return ImGui::PopItemWidth(); +} +CIMGUI_API void igSetNextItemWidth(float item_width) +{ + return ImGui::SetNextItemWidth(item_width); +} +CIMGUI_API float igCalcItemWidth() +{ + return ImGui::CalcItemWidth(); +} +CIMGUI_API void igPushTextWrapPos(float wrap_local_pos_x) +{ + return ImGui::PushTextWrapPos(wrap_local_pos_x); +} +CIMGUI_API void igPopTextWrapPos() +{ + return ImGui::PopTextWrapPos(); +} +CIMGUI_API ImFont* igGetFont() +{ + return ImGui::GetFont(); +} +CIMGUI_API float igGetFontSize() +{ + return ImGui::GetFontSize(); +} +CIMGUI_API void igGetFontTexUvWhitePixel(ImVec2 *pOut) +{ + *pOut = ImGui::GetFontTexUvWhitePixel(); +} +CIMGUI_API ImU32 igGetColorU32_Col(ImGuiCol idx,float alpha_mul) +{ + return ImGui::GetColorU32(idx,alpha_mul); +} +CIMGUI_API ImU32 igGetColorU32_Vec4(const ImVec4 col) +{ + return ImGui::GetColorU32(col); +} +CIMGUI_API ImU32 igGetColorU32_U32(ImU32 col) +{ + return ImGui::GetColorU32(col); +} +CIMGUI_API const ImVec4* igGetStyleColorVec4(ImGuiCol idx) +{ + return &ImGui::GetStyleColorVec4(idx); +} +CIMGUI_API void igSeparator() +{ + return ImGui::Separator(); +} +CIMGUI_API void igSameLine(float offset_from_start_x,float spacing) +{ + return ImGui::SameLine(offset_from_start_x,spacing); +} +CIMGUI_API void igNewLine() +{ + return ImGui::NewLine(); +} +CIMGUI_API void igSpacing() +{ + return ImGui::Spacing(); +} +CIMGUI_API void igDummy(const ImVec2 size) +{ + return ImGui::Dummy(size); +} +CIMGUI_API void igIndent(float indent_w) +{ + return ImGui::Indent(indent_w); +} +CIMGUI_API void igUnindent(float indent_w) +{ + return ImGui::Unindent(indent_w); +} +CIMGUI_API void igBeginGroup() +{ + return ImGui::BeginGroup(); +} +CIMGUI_API void igEndGroup() +{ + return ImGui::EndGroup(); +} +CIMGUI_API void igGetCursorPos(ImVec2 *pOut) +{ + *pOut = ImGui::GetCursorPos(); +} +CIMGUI_API float igGetCursorPosX() +{ + return ImGui::GetCursorPosX(); +} +CIMGUI_API float igGetCursorPosY() +{ + return ImGui::GetCursorPosY(); +} +CIMGUI_API void igSetCursorPos(const ImVec2 local_pos) +{ + return ImGui::SetCursorPos(local_pos); +} +CIMGUI_API void igSetCursorPosX(float local_x) +{ + return ImGui::SetCursorPosX(local_x); +} +CIMGUI_API void igSetCursorPosY(float local_y) +{ + return ImGui::SetCursorPosY(local_y); +} +CIMGUI_API void igGetCursorStartPos(ImVec2 *pOut) +{ + *pOut = ImGui::GetCursorStartPos(); +} +CIMGUI_API void igGetCursorScreenPos(ImVec2 *pOut) +{ + *pOut = ImGui::GetCursorScreenPos(); +} +CIMGUI_API void igSetCursorScreenPos(const ImVec2 pos) +{ + return ImGui::SetCursorScreenPos(pos); +} +CIMGUI_API void igAlignTextToFramePadding() +{ + return ImGui::AlignTextToFramePadding(); +} +CIMGUI_API float igGetTextLineHeight() +{ + return ImGui::GetTextLineHeight(); +} +CIMGUI_API float igGetTextLineHeightWithSpacing() +{ + return ImGui::GetTextLineHeightWithSpacing(); +} +CIMGUI_API float igGetFrameHeight() +{ + return ImGui::GetFrameHeight(); +} +CIMGUI_API float igGetFrameHeightWithSpacing() +{ + return ImGui::GetFrameHeightWithSpacing(); +} +CIMGUI_API void igPushID_Str(const char* str_id) +{ + return ImGui::PushID(str_id); +} +CIMGUI_API void igPushID_StrStr(const char* str_id_begin,const char* str_id_end) +{ + return ImGui::PushID(str_id_begin,str_id_end); +} +CIMGUI_API void igPushID_Ptr(const void* ptr_id) +{ + return ImGui::PushID(ptr_id); +} +CIMGUI_API void igPushID_Int(int int_id) +{ + return ImGui::PushID(int_id); +} +CIMGUI_API void igPopID() +{ + return ImGui::PopID(); +} +CIMGUI_API ImGuiID igGetID_Str(const char* str_id) +{ + return ImGui::GetID(str_id); +} +CIMGUI_API ImGuiID igGetID_StrStr(const char* str_id_begin,const char* str_id_end) +{ + return ImGui::GetID(str_id_begin,str_id_end); +} +CIMGUI_API ImGuiID igGetID_Ptr(const void* ptr_id) +{ + return ImGui::GetID(ptr_id); +} +CIMGUI_API void igTextUnformatted(const char* text,const char* text_end) +{ + return ImGui::TextUnformatted(text,text_end); +} +CIMGUI_API void igText(const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::TextV(fmt,args); + va_end(args); +} +CIMGUI_API void igTextV(const char* fmt,va_list args) +{ + return ImGui::TextV(fmt,args); +} +CIMGUI_API void igTextColored(const ImVec4 col,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::TextColoredV(col,fmt,args); + va_end(args); +} +CIMGUI_API void igTextColoredV(const ImVec4 col,const char* fmt,va_list args) +{ + return ImGui::TextColoredV(col,fmt,args); +} +CIMGUI_API void igTextDisabled(const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::TextDisabledV(fmt,args); + va_end(args); +} +CIMGUI_API void igTextDisabledV(const char* fmt,va_list args) +{ + return ImGui::TextDisabledV(fmt,args); +} +CIMGUI_API void igTextWrapped(const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::TextWrappedV(fmt,args); + va_end(args); +} +CIMGUI_API void igTextWrappedV(const char* fmt,va_list args) +{ + return ImGui::TextWrappedV(fmt,args); +} +CIMGUI_API void igLabelText(const char* label,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::LabelTextV(label,fmt,args); + va_end(args); +} +CIMGUI_API void igLabelTextV(const char* label,const char* fmt,va_list args) +{ + return ImGui::LabelTextV(label,fmt,args); +} +CIMGUI_API void igBulletText(const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::BulletTextV(fmt,args); + va_end(args); +} +CIMGUI_API void igBulletTextV(const char* fmt,va_list args) +{ + return ImGui::BulletTextV(fmt,args); +} +CIMGUI_API bool igButton(const char* label,const ImVec2 size) +{ + return ImGui::Button(label,size); +} +CIMGUI_API bool igSmallButton(const char* label) +{ + return ImGui::SmallButton(label); +} +CIMGUI_API bool igInvisibleButton(const char* str_id,const ImVec2 size,ImGuiButtonFlags flags) +{ + return ImGui::InvisibleButton(str_id,size,flags); +} +CIMGUI_API bool igArrowButton(const char* str_id,ImGuiDir dir) +{ + return ImGui::ArrowButton(str_id,dir); +} +CIMGUI_API void igImage(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec4 tint_col,const ImVec4 border_col) +{ + return ImGui::Image(user_texture_id,size,uv0,uv1,tint_col,border_col); +} +CIMGUI_API bool igImageButton(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,int frame_padding,const ImVec4 bg_col,const ImVec4 tint_col) +{ + return ImGui::ImageButton(user_texture_id,size,uv0,uv1,frame_padding,bg_col,tint_col); +} +CIMGUI_API bool igCheckbox(const char* label,bool* v) +{ + return ImGui::Checkbox(label,v); +} +CIMGUI_API bool igCheckboxFlags_IntPtr(const char* label,int* flags,int flags_value) +{ + return ImGui::CheckboxFlags(label,flags,flags_value); +} +CIMGUI_API bool igCheckboxFlags_UintPtr(const char* label,unsigned int* flags,unsigned int flags_value) +{ + return ImGui::CheckboxFlags(label,flags,flags_value); +} +CIMGUI_API bool igRadioButton_Bool(const char* label,bool active) +{ + return ImGui::RadioButton(label,active); +} +CIMGUI_API bool igRadioButton_IntPtr(const char* label,int* v,int v_button) +{ + return ImGui::RadioButton(label,v,v_button); +} +CIMGUI_API void igProgressBar(float fraction,const ImVec2 size_arg,const char* overlay) +{ + return ImGui::ProgressBar(fraction,size_arg,overlay); +} +CIMGUI_API void igBullet() +{ + return ImGui::Bullet(); +} +CIMGUI_API bool igBeginCombo(const char* label,const char* preview_value,ImGuiComboFlags flags) +{ + return ImGui::BeginCombo(label,preview_value,flags); +} +CIMGUI_API void igEndCombo() +{ + return ImGui::EndCombo(); +} +CIMGUI_API bool igCombo_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int popup_max_height_in_items) +{ + return ImGui::Combo(label,current_item,items,items_count,popup_max_height_in_items); +} +CIMGUI_API bool igCombo_Str(const char* label,int* current_item,const char* items_separated_by_zeros,int popup_max_height_in_items) +{ + return ImGui::Combo(label,current_item,items_separated_by_zeros,popup_max_height_in_items); +} +CIMGUI_API bool igCombo_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int popup_max_height_in_items) +{ + return ImGui::Combo(label,current_item,items_getter,data,items_count,popup_max_height_in_items); +} +CIMGUI_API bool igDragFloat(const char* label,float* v,float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragFloat(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragFloat2(const char* label,float v[2],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragFloat2(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragFloat3(const char* label,float v[3],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragFloat3(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragFloat4(const char* label,float v[4],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragFloat4(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragFloatRange2(const char* label,float* v_current_min,float* v_current_max,float v_speed,float v_min,float v_max,const char* format,const char* format_max,ImGuiSliderFlags flags) +{ + return ImGui::DragFloatRange2(label,v_current_min,v_current_max,v_speed,v_min,v_max,format,format_max,flags); +} +CIMGUI_API bool igDragInt(const char* label,int* v,float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragInt(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragInt2(const char* label,int v[2],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragInt2(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragInt3(const char* label,int v[3],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragInt3(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragInt4(const char* label,int v[4],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragInt4(label,v,v_speed,v_min,v_max,format,flags); +} +CIMGUI_API bool igDragIntRange2(const char* label,int* v_current_min,int* v_current_max,float v_speed,int v_min,int v_max,const char* format,const char* format_max,ImGuiSliderFlags flags) +{ + return ImGui::DragIntRange2(label,v_current_min,v_current_max,v_speed,v_min,v_max,format,format_max,flags); +} +CIMGUI_API bool igDragScalar(const char* label,ImGuiDataType data_type,void* p_data,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragScalar(label,data_type,p_data,v_speed,p_min,p_max,format,flags); +} +CIMGUI_API bool igDragScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragScalarN(label,data_type,p_data,components,v_speed,p_min,p_max,format,flags); +} +CIMGUI_API bool igSliderFloat(const char* label,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderFloat(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderFloat2(const char* label,float v[2],float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderFloat2(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderFloat3(const char* label,float v[3],float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderFloat3(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderFloat4(const char* label,float v[4],float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderFloat4(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderAngle(const char* label,float* v_rad,float v_degrees_min,float v_degrees_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderAngle(label,v_rad,v_degrees_min,v_degrees_max,format,flags); +} +CIMGUI_API bool igSliderInt(const char* label,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderInt(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderInt2(const char* label,int v[2],int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderInt2(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderInt3(const char* label,int v[3],int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderInt3(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderInt4(const char* label,int v[4],int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderInt4(label,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igSliderScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderScalar(label,data_type,p_data,p_min,p_max,format,flags); +} +CIMGUI_API bool igSliderScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::SliderScalarN(label,data_type,p_data,components,p_min,p_max,format,flags); +} +CIMGUI_API bool igVSliderFloat(const char* label,const ImVec2 size,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::VSliderFloat(label,size,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igVSliderInt(const char* label,const ImVec2 size,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::VSliderInt(label,size,v,v_min,v_max,format,flags); +} +CIMGUI_API bool igVSliderScalar(const char* label,const ImVec2 size,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::VSliderScalar(label,size,data_type,p_data,p_min,p_max,format,flags); +} +CIMGUI_API bool igInputText(const char* label,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data) +{ + return ImGui::InputText(label,buf,buf_size,flags,callback,user_data); +} +CIMGUI_API bool igInputTextMultiline(const char* label,char* buf,size_t buf_size,const ImVec2 size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data) +{ + return ImGui::InputTextMultiline(label,buf,buf_size,size,flags,callback,user_data); +} +CIMGUI_API bool igInputTextWithHint(const char* label,const char* hint,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data) +{ + return ImGui::InputTextWithHint(label,hint,buf,buf_size,flags,callback,user_data); +} +CIMGUI_API bool igInputFloat(const char* label,float* v,float step,float step_fast,const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputFloat(label,v,step,step_fast,format,flags); +} +CIMGUI_API bool igInputFloat2(const char* label,float v[2],const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputFloat2(label,v,format,flags); +} +CIMGUI_API bool igInputFloat3(const char* label,float v[3],const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputFloat3(label,v,format,flags); +} +CIMGUI_API bool igInputFloat4(const char* label,float v[4],const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputFloat4(label,v,format,flags); +} +CIMGUI_API bool igInputInt(const char* label,int* v,int step,int step_fast,ImGuiInputTextFlags flags) +{ + return ImGui::InputInt(label,v,step,step_fast,flags); +} +CIMGUI_API bool igInputInt2(const char* label,int v[2],ImGuiInputTextFlags flags) +{ + return ImGui::InputInt2(label,v,flags); +} +CIMGUI_API bool igInputInt3(const char* label,int v[3],ImGuiInputTextFlags flags) +{ + return ImGui::InputInt3(label,v,flags); +} +CIMGUI_API bool igInputInt4(const char* label,int v[4],ImGuiInputTextFlags flags) +{ + return ImGui::InputInt4(label,v,flags); +} +CIMGUI_API bool igInputDouble(const char* label,double* v,double step,double step_fast,const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputDouble(label,v,step,step_fast,format,flags); +} +CIMGUI_API bool igInputScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputScalar(label,data_type,p_data,p_step,p_step_fast,format,flags); +} +CIMGUI_API bool igInputScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags) +{ + return ImGui::InputScalarN(label,data_type,p_data,components,p_step,p_step_fast,format,flags); +} +CIMGUI_API bool igColorEdit3(const char* label,float col[3],ImGuiColorEditFlags flags) +{ + return ImGui::ColorEdit3(label,col,flags); +} +CIMGUI_API bool igColorEdit4(const char* label,float col[4],ImGuiColorEditFlags flags) +{ + return ImGui::ColorEdit4(label,col,flags); +} +CIMGUI_API bool igColorPicker3(const char* label,float col[3],ImGuiColorEditFlags flags) +{ + return ImGui::ColorPicker3(label,col,flags); +} +CIMGUI_API bool igColorPicker4(const char* label,float col[4],ImGuiColorEditFlags flags,const float* ref_col) +{ + return ImGui::ColorPicker4(label,col,flags,ref_col); +} +CIMGUI_API bool igColorButton(const char* desc_id,const ImVec4 col,ImGuiColorEditFlags flags,ImVec2 size) +{ + return ImGui::ColorButton(desc_id,col,flags,size); +} +CIMGUI_API void igSetColorEditOptions(ImGuiColorEditFlags flags) +{ + return ImGui::SetColorEditOptions(flags); +} +CIMGUI_API bool igTreeNode_Str(const char* label) +{ + return ImGui::TreeNode(label); +} +CIMGUI_API bool igTreeNode_StrStr(const char* str_id,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + bool ret = ImGui::TreeNodeV(str_id,fmt,args); + va_end(args); + return ret; +} +CIMGUI_API bool igTreeNode_Ptr(const void* ptr_id,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + bool ret = ImGui::TreeNodeV(ptr_id,fmt,args); + va_end(args); + return ret; +} +CIMGUI_API bool igTreeNodeV_Str(const char* str_id,const char* fmt,va_list args) +{ + return ImGui::TreeNodeV(str_id,fmt,args); +} +CIMGUI_API bool igTreeNodeV_Ptr(const void* ptr_id,const char* fmt,va_list args) +{ + return ImGui::TreeNodeV(ptr_id,fmt,args); +} +CIMGUI_API bool igTreeNodeEx_Str(const char* label,ImGuiTreeNodeFlags flags) +{ + return ImGui::TreeNodeEx(label,flags); +} +CIMGUI_API bool igTreeNodeEx_StrStr(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + bool ret = ImGui::TreeNodeExV(str_id,flags,fmt,args); + va_end(args); + return ret; +} +CIMGUI_API bool igTreeNodeEx_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + bool ret = ImGui::TreeNodeExV(ptr_id,flags,fmt,args); + va_end(args); + return ret; +} +CIMGUI_API bool igTreeNodeExV_Str(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args) +{ + return ImGui::TreeNodeExV(str_id,flags,fmt,args); +} +CIMGUI_API bool igTreeNodeExV_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args) +{ + return ImGui::TreeNodeExV(ptr_id,flags,fmt,args); +} +CIMGUI_API void igTreePush_Str(const char* str_id) +{ + return ImGui::TreePush(str_id); +} +CIMGUI_API void igTreePush_Ptr(const void* ptr_id) +{ + return ImGui::TreePush(ptr_id); +} +CIMGUI_API void igTreePop() +{ + return ImGui::TreePop(); +} +CIMGUI_API float igGetTreeNodeToLabelSpacing() +{ + return ImGui::GetTreeNodeToLabelSpacing(); +} +CIMGUI_API bool igCollapsingHeader_TreeNodeFlags(const char* label,ImGuiTreeNodeFlags flags) +{ + return ImGui::CollapsingHeader(label,flags); +} +CIMGUI_API bool igCollapsingHeader_BoolPtr(const char* label,bool* p_visible,ImGuiTreeNodeFlags flags) +{ + return ImGui::CollapsingHeader(label,p_visible,flags); +} +CIMGUI_API void igSetNextItemOpen(bool is_open,ImGuiCond cond) +{ + return ImGui::SetNextItemOpen(is_open,cond); +} +CIMGUI_API bool igSelectable_Bool(const char* label,bool selected,ImGuiSelectableFlags flags,const ImVec2 size) +{ + return ImGui::Selectable(label,selected,flags,size); +} +CIMGUI_API bool igSelectable_BoolPtr(const char* label,bool* p_selected,ImGuiSelectableFlags flags,const ImVec2 size) +{ + return ImGui::Selectable(label,p_selected,flags,size); +} +CIMGUI_API bool igBeginListBox(const char* label,const ImVec2 size) +{ + return ImGui::BeginListBox(label,size); +} +CIMGUI_API void igEndListBox() +{ + return ImGui::EndListBox(); +} +CIMGUI_API bool igListBox_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int height_in_items) +{ + return ImGui::ListBox(label,current_item,items,items_count,height_in_items); +} +CIMGUI_API bool igListBox_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int height_in_items) +{ + return ImGui::ListBox(label,current_item,items_getter,data,items_count,height_in_items); +} +CIMGUI_API void igPlotLines_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride) +{ + return ImGui::PlotLines(label,values,values_count,values_offset,overlay_text,scale_min,scale_max,graph_size,stride); +} +CIMGUI_API void igPlotLines_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size) +{ + return ImGui::PlotLines(label,values_getter,data,values_count,values_offset,overlay_text,scale_min,scale_max,graph_size); +} +CIMGUI_API void igPlotHistogram_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride) +{ + return ImGui::PlotHistogram(label,values,values_count,values_offset,overlay_text,scale_min,scale_max,graph_size,stride); +} +CIMGUI_API void igPlotHistogram_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size) +{ + return ImGui::PlotHistogram(label,values_getter,data,values_count,values_offset,overlay_text,scale_min,scale_max,graph_size); +} +CIMGUI_API void igValue_Bool(const char* prefix,bool b) +{ + return ImGui::Value(prefix,b); +} +CIMGUI_API void igValue_Int(const char* prefix,int v) +{ + return ImGui::Value(prefix,v); +} +CIMGUI_API void igValue_Uint(const char* prefix,unsigned int v) +{ + return ImGui::Value(prefix,v); +} +CIMGUI_API void igValue_Float(const char* prefix,float v,const char* float_format) +{ + return ImGui::Value(prefix,v,float_format); +} +CIMGUI_API bool igBeginMenuBar() +{ + return ImGui::BeginMenuBar(); +} +CIMGUI_API void igEndMenuBar() +{ + return ImGui::EndMenuBar(); +} +CIMGUI_API bool igBeginMainMenuBar() +{ + return ImGui::BeginMainMenuBar(); +} +CIMGUI_API void igEndMainMenuBar() +{ + return ImGui::EndMainMenuBar(); +} +CIMGUI_API bool igBeginMenu(const char* label,bool enabled) +{ + return ImGui::BeginMenu(label,enabled); +} +CIMGUI_API void igEndMenu() +{ + return ImGui::EndMenu(); +} +CIMGUI_API bool igMenuItem_Bool(const char* label,const char* shortcut,bool selected,bool enabled) +{ + return ImGui::MenuItem(label,shortcut,selected,enabled); +} +CIMGUI_API bool igMenuItem_BoolPtr(const char* label,const char* shortcut,bool* p_selected,bool enabled) +{ + return ImGui::MenuItem(label,shortcut,p_selected,enabled); +} +CIMGUI_API void igBeginTooltip() +{ + return ImGui::BeginTooltip(); +} +CIMGUI_API void igEndTooltip() +{ + return ImGui::EndTooltip(); +} +CIMGUI_API void igSetTooltip(const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + ImGui::SetTooltipV(fmt,args); + va_end(args); +} +CIMGUI_API void igSetTooltipV(const char* fmt,va_list args) +{ + return ImGui::SetTooltipV(fmt,args); +} +CIMGUI_API bool igBeginPopup(const char* str_id,ImGuiWindowFlags flags) +{ + return ImGui::BeginPopup(str_id,flags); +} +CIMGUI_API bool igBeginPopupModal(const char* name,bool* p_open,ImGuiWindowFlags flags) +{ + return ImGui::BeginPopupModal(name,p_open,flags); +} +CIMGUI_API void igEndPopup() +{ + return ImGui::EndPopup(); +} +CIMGUI_API void igOpenPopup_Str(const char* str_id,ImGuiPopupFlags popup_flags) +{ + return ImGui::OpenPopup(str_id,popup_flags); +} +CIMGUI_API void igOpenPopup_ID(ImGuiID id,ImGuiPopupFlags popup_flags) +{ + return ImGui::OpenPopup(id,popup_flags); +} +CIMGUI_API void igOpenPopupOnItemClick(const char* str_id,ImGuiPopupFlags popup_flags) +{ + return ImGui::OpenPopupOnItemClick(str_id,popup_flags); +} +CIMGUI_API void igCloseCurrentPopup() +{ + return ImGui::CloseCurrentPopup(); +} +CIMGUI_API bool igBeginPopupContextItem(const char* str_id,ImGuiPopupFlags popup_flags) +{ + return ImGui::BeginPopupContextItem(str_id,popup_flags); +} +CIMGUI_API bool igBeginPopupContextWindow(const char* str_id,ImGuiPopupFlags popup_flags) +{ + return ImGui::BeginPopupContextWindow(str_id,popup_flags); +} +CIMGUI_API bool igBeginPopupContextVoid(const char* str_id,ImGuiPopupFlags popup_flags) +{ + return ImGui::BeginPopupContextVoid(str_id,popup_flags); +} +CIMGUI_API bool igIsPopupOpen_Str(const char* str_id,ImGuiPopupFlags flags) +{ + return ImGui::IsPopupOpen(str_id,flags); +} +CIMGUI_API bool igBeginTable(const char* str_id,int column,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width) +{ + return ImGui::BeginTable(str_id,column,flags,outer_size,inner_width); +} +CIMGUI_API void igEndTable() +{ + return ImGui::EndTable(); +} +CIMGUI_API void igTableNextRow(ImGuiTableRowFlags row_flags,float min_row_height) +{ + return ImGui::TableNextRow(row_flags,min_row_height); +} +CIMGUI_API bool igTableNextColumn() +{ + return ImGui::TableNextColumn(); +} +CIMGUI_API bool igTableSetColumnIndex(int column_n) +{ + return ImGui::TableSetColumnIndex(column_n); +} +CIMGUI_API void igTableSetupColumn(const char* label,ImGuiTableColumnFlags flags,float init_width_or_weight,ImGuiID user_id) +{ + return ImGui::TableSetupColumn(label,flags,init_width_or_weight,user_id); +} +CIMGUI_API void igTableSetupScrollFreeze(int cols,int rows) +{ + return ImGui::TableSetupScrollFreeze(cols,rows); +} +CIMGUI_API void igTableHeadersRow() +{ + return ImGui::TableHeadersRow(); +} +CIMGUI_API void igTableHeader(const char* label) +{ + return ImGui::TableHeader(label); +} +CIMGUI_API ImGuiTableSortSpecs* igTableGetSortSpecs() +{ + return ImGui::TableGetSortSpecs(); +} +CIMGUI_API int igTableGetColumnCount() +{ + return ImGui::TableGetColumnCount(); +} +CIMGUI_API int igTableGetColumnIndex() +{ + return ImGui::TableGetColumnIndex(); +} +CIMGUI_API int igTableGetRowIndex() +{ + return ImGui::TableGetRowIndex(); +} +CIMGUI_API const char* igTableGetColumnName_Int(int column_n) +{ + return ImGui::TableGetColumnName(column_n); +} +CIMGUI_API ImGuiTableColumnFlags igTableGetColumnFlags(int column_n) +{ + return ImGui::TableGetColumnFlags(column_n); +} +CIMGUI_API void igTableSetColumnEnabled(int column_n,bool v) +{ + return ImGui::TableSetColumnEnabled(column_n,v); +} +CIMGUI_API void igTableSetBgColor(ImGuiTableBgTarget target,ImU32 color,int column_n) +{ + return ImGui::TableSetBgColor(target,color,column_n); +} +CIMGUI_API void igColumns(int count,const char* id,bool border) +{ + return ImGui::Columns(count,id,border); +} +CIMGUI_API void igNextColumn() +{ + return ImGui::NextColumn(); +} +CIMGUI_API int igGetColumnIndex() +{ + return ImGui::GetColumnIndex(); +} +CIMGUI_API float igGetColumnWidth(int column_index) +{ + return ImGui::GetColumnWidth(column_index); +} +CIMGUI_API void igSetColumnWidth(int column_index,float width) +{ + return ImGui::SetColumnWidth(column_index,width); +} +CIMGUI_API float igGetColumnOffset(int column_index) +{ + return ImGui::GetColumnOffset(column_index); +} +CIMGUI_API void igSetColumnOffset(int column_index,float offset_x) +{ + return ImGui::SetColumnOffset(column_index,offset_x); +} +CIMGUI_API int igGetColumnsCount() +{ + return ImGui::GetColumnsCount(); +} +CIMGUI_API bool igBeginTabBar(const char* str_id,ImGuiTabBarFlags flags) +{ + return ImGui::BeginTabBar(str_id,flags); +} +CIMGUI_API void igEndTabBar() +{ + return ImGui::EndTabBar(); +} +CIMGUI_API bool igBeginTabItem(const char* label,bool* p_open,ImGuiTabItemFlags flags) +{ + return ImGui::BeginTabItem(label,p_open,flags); +} +CIMGUI_API void igEndTabItem() +{ + return ImGui::EndTabItem(); +} +CIMGUI_API bool igTabItemButton(const char* label,ImGuiTabItemFlags flags) +{ + return ImGui::TabItemButton(label,flags); +} +CIMGUI_API void igSetTabItemClosed(const char* tab_or_docked_window_label) +{ + return ImGui::SetTabItemClosed(tab_or_docked_window_label); +} +CIMGUI_API void igLogToTTY(int auto_open_depth) +{ + return ImGui::LogToTTY(auto_open_depth); +} +CIMGUI_API void igLogToFile(int auto_open_depth,const char* filename) +{ + return ImGui::LogToFile(auto_open_depth,filename); +} +CIMGUI_API void igLogToClipboard(int auto_open_depth) +{ + return ImGui::LogToClipboard(auto_open_depth); +} +CIMGUI_API void igLogFinish() +{ + return ImGui::LogFinish(); +} +CIMGUI_API void igLogButtons() +{ + return ImGui::LogButtons(); +} +CIMGUI_API void igLogTextV(const char* fmt,va_list args) +{ + return ImGui::LogTextV(fmt,args); +} +CIMGUI_API bool igBeginDragDropSource(ImGuiDragDropFlags flags) +{ + return ImGui::BeginDragDropSource(flags); +} +CIMGUI_API bool igSetDragDropPayload(const char* type,const void* data,size_t sz,ImGuiCond cond) +{ + return ImGui::SetDragDropPayload(type,data,sz,cond); +} +CIMGUI_API void igEndDragDropSource() +{ + return ImGui::EndDragDropSource(); +} +CIMGUI_API bool igBeginDragDropTarget() +{ + return ImGui::BeginDragDropTarget(); +} +CIMGUI_API const ImGuiPayload* igAcceptDragDropPayload(const char* type,ImGuiDragDropFlags flags) +{ + return ImGui::AcceptDragDropPayload(type,flags); +} +CIMGUI_API void igEndDragDropTarget() +{ + return ImGui::EndDragDropTarget(); +} +CIMGUI_API const ImGuiPayload* igGetDragDropPayload() +{ + return ImGui::GetDragDropPayload(); +} +CIMGUI_API void igBeginDisabled(bool disabled) +{ + return ImGui::BeginDisabled(disabled); +} +CIMGUI_API void igEndDisabled() +{ + return ImGui::EndDisabled(); +} +CIMGUI_API void igPushClipRect(const ImVec2 clip_rect_min,const ImVec2 clip_rect_max,bool intersect_with_current_clip_rect) +{ + return ImGui::PushClipRect(clip_rect_min,clip_rect_max,intersect_with_current_clip_rect); +} +CIMGUI_API void igPopClipRect() +{ + return ImGui::PopClipRect(); +} +CIMGUI_API void igSetItemDefaultFocus() +{ + return ImGui::SetItemDefaultFocus(); +} +CIMGUI_API void igSetKeyboardFocusHere(int offset) +{ + return ImGui::SetKeyboardFocusHere(offset); +} +CIMGUI_API bool igIsItemHovered(ImGuiHoveredFlags flags) +{ + return ImGui::IsItemHovered(flags); +} +CIMGUI_API bool igIsItemActive() +{ + return ImGui::IsItemActive(); +} +CIMGUI_API bool igIsItemFocused() +{ + return ImGui::IsItemFocused(); +} +CIMGUI_API bool igIsItemClicked(ImGuiMouseButton mouse_button) +{ + return ImGui::IsItemClicked(mouse_button); +} +CIMGUI_API bool igIsItemVisible() +{ + return ImGui::IsItemVisible(); +} +CIMGUI_API bool igIsItemEdited() +{ + return ImGui::IsItemEdited(); +} +CIMGUI_API bool igIsItemActivated() +{ + return ImGui::IsItemActivated(); +} +CIMGUI_API bool igIsItemDeactivated() +{ + return ImGui::IsItemDeactivated(); +} +CIMGUI_API bool igIsItemDeactivatedAfterEdit() +{ + return ImGui::IsItemDeactivatedAfterEdit(); +} +CIMGUI_API bool igIsItemToggledOpen() +{ + return ImGui::IsItemToggledOpen(); +} +CIMGUI_API bool igIsAnyItemHovered() +{ + return ImGui::IsAnyItemHovered(); +} +CIMGUI_API bool igIsAnyItemActive() +{ + return ImGui::IsAnyItemActive(); +} +CIMGUI_API bool igIsAnyItemFocused() +{ + return ImGui::IsAnyItemFocused(); +} +CIMGUI_API void igGetItemRectMin(ImVec2 *pOut) +{ + *pOut = ImGui::GetItemRectMin(); +} +CIMGUI_API void igGetItemRectMax(ImVec2 *pOut) +{ + *pOut = ImGui::GetItemRectMax(); +} +CIMGUI_API void igGetItemRectSize(ImVec2 *pOut) +{ + *pOut = ImGui::GetItemRectSize(); +} +CIMGUI_API void igSetItemAllowOverlap() +{ + return ImGui::SetItemAllowOverlap(); +} +CIMGUI_API ImGuiViewport* igGetMainViewport() +{ + return ImGui::GetMainViewport(); +} +CIMGUI_API bool igIsRectVisible_Nil(const ImVec2 size) +{ + return ImGui::IsRectVisible(size); +} +CIMGUI_API bool igIsRectVisible_Vec2(const ImVec2 rect_min,const ImVec2 rect_max) +{ + return ImGui::IsRectVisible(rect_min,rect_max); +} +CIMGUI_API double igGetTime() +{ + return ImGui::GetTime(); +} +CIMGUI_API int igGetFrameCount() +{ + return ImGui::GetFrameCount(); +} +CIMGUI_API ImDrawList* igGetBackgroundDrawList_Nil() +{ + return ImGui::GetBackgroundDrawList(); +} +CIMGUI_API ImDrawList* igGetForegroundDrawList_Nil() +{ + return ImGui::GetForegroundDrawList(); +} +CIMGUI_API ImDrawListSharedData* igGetDrawListSharedData() +{ + return ImGui::GetDrawListSharedData(); +} +CIMGUI_API const char* igGetStyleColorName(ImGuiCol idx) +{ + return ImGui::GetStyleColorName(idx); +} +CIMGUI_API void igSetStateStorage(ImGuiStorage* storage) +{ + return ImGui::SetStateStorage(storage); +} +CIMGUI_API ImGuiStorage* igGetStateStorage() +{ + return ImGui::GetStateStorage(); +} +CIMGUI_API bool igBeginChildFrame(ImGuiID id,const ImVec2 size,ImGuiWindowFlags flags) +{ + return ImGui::BeginChildFrame(id,size,flags); +} +CIMGUI_API void igEndChildFrame() +{ + return ImGui::EndChildFrame(); +} +CIMGUI_API void igCalcTextSize(ImVec2 *pOut,const char* text,const char* text_end,bool hide_text_after_double_hash,float wrap_width) +{ + *pOut = ImGui::CalcTextSize(text,text_end,hide_text_after_double_hash,wrap_width); +} +CIMGUI_API void igColorConvertU32ToFloat4(ImVec4 *pOut,ImU32 in) +{ + *pOut = ImGui::ColorConvertU32ToFloat4(in); +} +CIMGUI_API ImU32 igColorConvertFloat4ToU32(const ImVec4 in) +{ + return ImGui::ColorConvertFloat4ToU32(in); +} +CIMGUI_API void igColorConvertRGBtoHSV(float r,float g,float b,float* out_h,float* out_s,float* out_v) +{ + return ImGui::ColorConvertRGBtoHSV(r,g,b,*out_h,*out_s,*out_v); +} +CIMGUI_API void igColorConvertHSVtoRGB(float h,float s,float v,float* out_r,float* out_g,float* out_b) +{ + return ImGui::ColorConvertHSVtoRGB(h,s,v,*out_r,*out_g,*out_b); +} +CIMGUI_API int igGetKeyIndex(ImGuiKey imgui_key) +{ + return ImGui::GetKeyIndex(imgui_key); +} +CIMGUI_API bool igIsKeyDown(int user_key_index) +{ + return ImGui::IsKeyDown(user_key_index); +} +CIMGUI_API bool igIsKeyPressed(int user_key_index,bool repeat) +{ + return ImGui::IsKeyPressed(user_key_index,repeat); +} +CIMGUI_API bool igIsKeyReleased(int user_key_index) +{ + return ImGui::IsKeyReleased(user_key_index); +} +CIMGUI_API int igGetKeyPressedAmount(int key_index,float repeat_delay,float rate) +{ + return ImGui::GetKeyPressedAmount(key_index,repeat_delay,rate); +} +CIMGUI_API void igCaptureKeyboardFromApp(bool want_capture_keyboard_value) +{ + return ImGui::CaptureKeyboardFromApp(want_capture_keyboard_value); +} +CIMGUI_API bool igIsMouseDown(ImGuiMouseButton button) +{ + return ImGui::IsMouseDown(button); +} +CIMGUI_API bool igIsMouseClicked(ImGuiMouseButton button,bool repeat) +{ + return ImGui::IsMouseClicked(button,repeat); +} +CIMGUI_API bool igIsMouseReleased(ImGuiMouseButton button) +{ + return ImGui::IsMouseReleased(button); +} +CIMGUI_API bool igIsMouseDoubleClicked(ImGuiMouseButton button) +{ + return ImGui::IsMouseDoubleClicked(button); +} +CIMGUI_API int igGetMouseClickedCount(ImGuiMouseButton button) +{ + return ImGui::GetMouseClickedCount(button); +} +CIMGUI_API bool igIsMouseHoveringRect(const ImVec2 r_min,const ImVec2 r_max,bool clip) +{ + return ImGui::IsMouseHoveringRect(r_min,r_max,clip); +} +CIMGUI_API bool igIsMousePosValid(const ImVec2* mouse_pos) +{ + return ImGui::IsMousePosValid(mouse_pos); +} +CIMGUI_API bool igIsAnyMouseDown() +{ + return ImGui::IsAnyMouseDown(); +} +CIMGUI_API void igGetMousePos(ImVec2 *pOut) +{ + *pOut = ImGui::GetMousePos(); +} +CIMGUI_API void igGetMousePosOnOpeningCurrentPopup(ImVec2 *pOut) +{ + *pOut = ImGui::GetMousePosOnOpeningCurrentPopup(); +} +CIMGUI_API bool igIsMouseDragging(ImGuiMouseButton button,float lock_threshold) +{ + return ImGui::IsMouseDragging(button,lock_threshold); +} +CIMGUI_API void igGetMouseDragDelta(ImVec2 *pOut,ImGuiMouseButton button,float lock_threshold) +{ + *pOut = ImGui::GetMouseDragDelta(button,lock_threshold); +} +CIMGUI_API void igResetMouseDragDelta(ImGuiMouseButton button) +{ + return ImGui::ResetMouseDragDelta(button); +} +CIMGUI_API ImGuiMouseCursor igGetMouseCursor() +{ + return ImGui::GetMouseCursor(); +} +CIMGUI_API void igSetMouseCursor(ImGuiMouseCursor cursor_type) +{ + return ImGui::SetMouseCursor(cursor_type); +} +CIMGUI_API void igCaptureMouseFromApp(bool want_capture_mouse_value) +{ + return ImGui::CaptureMouseFromApp(want_capture_mouse_value); +} +CIMGUI_API const char* igGetClipboardText() +{ + return ImGui::GetClipboardText(); +} +CIMGUI_API void igSetClipboardText(const char* text) +{ + return ImGui::SetClipboardText(text); +} +CIMGUI_API void igLoadIniSettingsFromDisk(const char* ini_filename) +{ + return ImGui::LoadIniSettingsFromDisk(ini_filename); +} +CIMGUI_API void igLoadIniSettingsFromMemory(const char* ini_data,size_t ini_size) +{ + return ImGui::LoadIniSettingsFromMemory(ini_data,ini_size); +} +CIMGUI_API void igSaveIniSettingsToDisk(const char* ini_filename) +{ + return ImGui::SaveIniSettingsToDisk(ini_filename); +} +CIMGUI_API const char* igSaveIniSettingsToMemory(size_t* out_ini_size) +{ + return ImGui::SaveIniSettingsToMemory(out_ini_size); +} +CIMGUI_API bool igDebugCheckVersionAndDataLayout(const char* version_str,size_t sz_io,size_t sz_style,size_t sz_vec2,size_t sz_vec4,size_t sz_drawvert,size_t sz_drawidx) +{ + return ImGui::DebugCheckVersionAndDataLayout(version_str,sz_io,sz_style,sz_vec2,sz_vec4,sz_drawvert,sz_drawidx); +} +CIMGUI_API void igSetAllocatorFunctions(ImGuiMemAllocFunc alloc_func,ImGuiMemFreeFunc free_func,void* user_data) +{ + return ImGui::SetAllocatorFunctions(alloc_func,free_func,user_data); +} +CIMGUI_API void igGetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func,ImGuiMemFreeFunc* p_free_func,void** p_user_data) +{ + return ImGui::GetAllocatorFunctions(p_alloc_func,p_free_func,p_user_data); +} +CIMGUI_API void* igMemAlloc(size_t size) +{ + return ImGui::MemAlloc(size); +} +CIMGUI_API void igMemFree(void* ptr) +{ + return ImGui::MemFree(ptr); +} +CIMGUI_API ImGuiStyle* ImGuiStyle_ImGuiStyle(void) +{ + return IM_NEW(ImGuiStyle)(); +} +CIMGUI_API void ImGuiStyle_destroy(ImGuiStyle* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiStyle_ScaleAllSizes(ImGuiStyle* self,float scale_factor) +{ + return self->ScaleAllSizes(scale_factor); +} +CIMGUI_API void ImGuiIO_AddInputCharacter(ImGuiIO* self,unsigned int c) +{ + return self->AddInputCharacter(c); +} +CIMGUI_API void ImGuiIO_AddInputCharacterUTF16(ImGuiIO* self,ImWchar16 c) +{ + return self->AddInputCharacterUTF16(c); +} +CIMGUI_API void ImGuiIO_AddInputCharactersUTF8(ImGuiIO* self,const char* str) +{ + return self->AddInputCharactersUTF8(str); +} +CIMGUI_API void ImGuiIO_AddFocusEvent(ImGuiIO* self,bool focused) +{ + return self->AddFocusEvent(focused); +} +CIMGUI_API void ImGuiIO_ClearInputCharacters(ImGuiIO* self) +{ + return self->ClearInputCharacters(); +} +CIMGUI_API void ImGuiIO_ClearInputKeys(ImGuiIO* self) +{ + return self->ClearInputKeys(); +} +CIMGUI_API ImGuiIO* ImGuiIO_ImGuiIO(void) +{ + return IM_NEW(ImGuiIO)(); +} +CIMGUI_API void ImGuiIO_destroy(ImGuiIO* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiInputTextCallbackData* ImGuiInputTextCallbackData_ImGuiInputTextCallbackData(void) +{ + return IM_NEW(ImGuiInputTextCallbackData)(); +} +CIMGUI_API void ImGuiInputTextCallbackData_destroy(ImGuiInputTextCallbackData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiInputTextCallbackData_DeleteChars(ImGuiInputTextCallbackData* self,int pos,int bytes_count) +{ + return self->DeleteChars(pos,bytes_count); +} +CIMGUI_API void ImGuiInputTextCallbackData_InsertChars(ImGuiInputTextCallbackData* self,int pos,const char* text,const char* text_end) +{ + return self->InsertChars(pos,text,text_end); +} +CIMGUI_API void ImGuiInputTextCallbackData_SelectAll(ImGuiInputTextCallbackData* self) +{ + return self->SelectAll(); +} +CIMGUI_API void ImGuiInputTextCallbackData_ClearSelection(ImGuiInputTextCallbackData* self) +{ + return self->ClearSelection(); +} +CIMGUI_API bool ImGuiInputTextCallbackData_HasSelection(ImGuiInputTextCallbackData* self) +{ + return self->HasSelection(); +} +CIMGUI_API ImGuiPayload* ImGuiPayload_ImGuiPayload(void) +{ + return IM_NEW(ImGuiPayload)(); +} +CIMGUI_API void ImGuiPayload_destroy(ImGuiPayload* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiPayload_Clear(ImGuiPayload* self) +{ + return self->Clear(); +} +CIMGUI_API bool ImGuiPayload_IsDataType(ImGuiPayload* self,const char* type) +{ + return self->IsDataType(type); +} +CIMGUI_API bool ImGuiPayload_IsPreview(ImGuiPayload* self) +{ + return self->IsPreview(); +} +CIMGUI_API bool ImGuiPayload_IsDelivery(ImGuiPayload* self) +{ + return self->IsDelivery(); +} +CIMGUI_API ImGuiTableColumnSortSpecs* ImGuiTableColumnSortSpecs_ImGuiTableColumnSortSpecs(void) +{ + return IM_NEW(ImGuiTableColumnSortSpecs)(); +} +CIMGUI_API void ImGuiTableColumnSortSpecs_destroy(ImGuiTableColumnSortSpecs* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTableSortSpecs* ImGuiTableSortSpecs_ImGuiTableSortSpecs(void) +{ + return IM_NEW(ImGuiTableSortSpecs)(); +} +CIMGUI_API void ImGuiTableSortSpecs_destroy(ImGuiTableSortSpecs* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiOnceUponAFrame* ImGuiOnceUponAFrame_ImGuiOnceUponAFrame(void) +{ + return IM_NEW(ImGuiOnceUponAFrame)(); +} +CIMGUI_API void ImGuiOnceUponAFrame_destroy(ImGuiOnceUponAFrame* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTextFilter* ImGuiTextFilter_ImGuiTextFilter(const char* default_filter) +{ + return IM_NEW(ImGuiTextFilter)(default_filter); +} +CIMGUI_API void ImGuiTextFilter_destroy(ImGuiTextFilter* self) +{ + IM_DELETE(self); +} +CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label,float width) +{ + return self->Draw(label,width); +} +CIMGUI_API bool ImGuiTextFilter_PassFilter(ImGuiTextFilter* self,const char* text,const char* text_end) +{ + return self->PassFilter(text,text_end); +} +CIMGUI_API void ImGuiTextFilter_Build(ImGuiTextFilter* self) +{ + return self->Build(); +} +CIMGUI_API void ImGuiTextFilter_Clear(ImGuiTextFilter* self) +{ + return self->Clear(); +} +CIMGUI_API bool ImGuiTextFilter_IsActive(ImGuiTextFilter* self) +{ + return self->IsActive(); +} +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Nil(void) +{ + return IM_NEW(ImGuiTextRange)(); +} +CIMGUI_API void ImGuiTextRange_destroy(ImGuiTextRange* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Str(const char* _b,const char* _e) +{ + return IM_NEW(ImGuiTextRange)(_b,_e); +} +CIMGUI_API bool ImGuiTextRange_empty(ImGuiTextRange* self) +{ + return self->empty(); +} +CIMGUI_API void ImGuiTextRange_split(ImGuiTextRange* self,char separator,ImVector_ImGuiTextRange* out) +{ + return self->split(separator,out); +} +CIMGUI_API ImGuiTextBuffer* ImGuiTextBuffer_ImGuiTextBuffer(void) +{ + return IM_NEW(ImGuiTextBuffer)(); +} +CIMGUI_API void ImGuiTextBuffer_destroy(ImGuiTextBuffer* self) +{ + IM_DELETE(self); +} +CIMGUI_API const char* ImGuiTextBuffer_begin(ImGuiTextBuffer* self) +{ + return self->begin(); +} +CIMGUI_API const char* ImGuiTextBuffer_end(ImGuiTextBuffer* self) +{ + return self->end(); +} +CIMGUI_API int ImGuiTextBuffer_size(ImGuiTextBuffer* self) +{ + return self->size(); +} +CIMGUI_API bool ImGuiTextBuffer_empty(ImGuiTextBuffer* self) +{ + return self->empty(); +} +CIMGUI_API void ImGuiTextBuffer_clear(ImGuiTextBuffer* self) +{ + return self->clear(); +} +CIMGUI_API void ImGuiTextBuffer_reserve(ImGuiTextBuffer* self,int capacity) +{ + return self->reserve(capacity); +} +CIMGUI_API const char* ImGuiTextBuffer_c_str(ImGuiTextBuffer* self) +{ + return self->c_str(); +} +CIMGUI_API void ImGuiTextBuffer_append(ImGuiTextBuffer* self,const char* str,const char* str_end) +{ + return self->append(str,str_end); +} +CIMGUI_API void ImGuiTextBuffer_appendfv(ImGuiTextBuffer* self,const char* fmt,va_list args) +{ + return self->appendfv(fmt,args); +} +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Int(ImGuiID _key,int _val_i) +{ + return IM_NEW(ImGuiStoragePair)(_key,_val_i); +} +CIMGUI_API void ImGuiStoragePair_destroy(ImGuiStoragePair* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Float(ImGuiID _key,float _val_f) +{ + return IM_NEW(ImGuiStoragePair)(_key,_val_f); +} +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Ptr(ImGuiID _key,void* _val_p) +{ + return IM_NEW(ImGuiStoragePair)(_key,_val_p); +} +CIMGUI_API void ImGuiStorage_Clear(ImGuiStorage* self) +{ + return self->Clear(); +} +CIMGUI_API int ImGuiStorage_GetInt(ImGuiStorage* self,ImGuiID key,int default_val) +{ + return self->GetInt(key,default_val); +} +CIMGUI_API void ImGuiStorage_SetInt(ImGuiStorage* self,ImGuiID key,int val) +{ + return self->SetInt(key,val); +} +CIMGUI_API bool ImGuiStorage_GetBool(ImGuiStorage* self,ImGuiID key,bool default_val) +{ + return self->GetBool(key,default_val); +} +CIMGUI_API void ImGuiStorage_SetBool(ImGuiStorage* self,ImGuiID key,bool val) +{ + return self->SetBool(key,val); +} +CIMGUI_API float ImGuiStorage_GetFloat(ImGuiStorage* self,ImGuiID key,float default_val) +{ + return self->GetFloat(key,default_val); +} +CIMGUI_API void ImGuiStorage_SetFloat(ImGuiStorage* self,ImGuiID key,float val) +{ + return self->SetFloat(key,val); +} +CIMGUI_API void* ImGuiStorage_GetVoidPtr(ImGuiStorage* self,ImGuiID key) +{ + return self->GetVoidPtr(key); +} +CIMGUI_API void ImGuiStorage_SetVoidPtr(ImGuiStorage* self,ImGuiID key,void* val) +{ + return self->SetVoidPtr(key,val); +} +CIMGUI_API int* ImGuiStorage_GetIntRef(ImGuiStorage* self,ImGuiID key,int default_val) +{ + return self->GetIntRef(key,default_val); +} +CIMGUI_API bool* ImGuiStorage_GetBoolRef(ImGuiStorage* self,ImGuiID key,bool default_val) +{ + return self->GetBoolRef(key,default_val); +} +CIMGUI_API float* ImGuiStorage_GetFloatRef(ImGuiStorage* self,ImGuiID key,float default_val) +{ + return self->GetFloatRef(key,default_val); +} +CIMGUI_API void** ImGuiStorage_GetVoidPtrRef(ImGuiStorage* self,ImGuiID key,void* default_val) +{ + return self->GetVoidPtrRef(key,default_val); +} +CIMGUI_API void ImGuiStorage_SetAllInt(ImGuiStorage* self,int val) +{ + return self->SetAllInt(val); +} +CIMGUI_API void ImGuiStorage_BuildSortByKey(ImGuiStorage* self) +{ + return self->BuildSortByKey(); +} +CIMGUI_API ImGuiListClipper* ImGuiListClipper_ImGuiListClipper(void) +{ + return IM_NEW(ImGuiListClipper)(); +} +CIMGUI_API void ImGuiListClipper_destroy(ImGuiListClipper* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiListClipper_Begin(ImGuiListClipper* self,int items_count,float items_height) +{ + return self->Begin(items_count,items_height); +} +CIMGUI_API void ImGuiListClipper_End(ImGuiListClipper* self) +{ + return self->End(); +} +CIMGUI_API bool ImGuiListClipper_Step(ImGuiListClipper* self) +{ + return self->Step(); +} +CIMGUI_API void ImGuiListClipper_ForceDisplayRangeByIndices(ImGuiListClipper* self,int item_min,int item_max) +{ + return self->ForceDisplayRangeByIndices(item_min,item_max); +} +CIMGUI_API ImColor* ImColor_ImColor_Nil(void) +{ + return IM_NEW(ImColor)(); +} +CIMGUI_API void ImColor_destroy(ImColor* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImColor* ImColor_ImColor_Int(int r,int g,int b,int a) +{ + return IM_NEW(ImColor)(r,g,b,a); +} +CIMGUI_API ImColor* ImColor_ImColor_U32(ImU32 rgba) +{ + return IM_NEW(ImColor)(rgba); +} +CIMGUI_API ImColor* ImColor_ImColor_Float(float r,float g,float b,float a) +{ + return IM_NEW(ImColor)(r,g,b,a); +} +CIMGUI_API ImColor* ImColor_ImColor_Vec4(const ImVec4 col) +{ + return IM_NEW(ImColor)(col); +} +CIMGUI_API void ImColor_SetHSV(ImColor* self,float h,float s,float v,float a) +{ + return self->SetHSV(h,s,v,a); +} +CIMGUI_API void ImColor_HSV(ImColor *pOut,float h,float s,float v,float a) +{ + *pOut = ImColor::HSV(h,s,v,a); +} +CIMGUI_API ImDrawCmd* ImDrawCmd_ImDrawCmd(void) +{ + return IM_NEW(ImDrawCmd)(); +} +CIMGUI_API void ImDrawCmd_destroy(ImDrawCmd* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImTextureID ImDrawCmd_GetTexID(ImDrawCmd* self) +{ + return self->GetTexID(); +} +CIMGUI_API ImDrawListSplitter* ImDrawListSplitter_ImDrawListSplitter(void) +{ + return IM_NEW(ImDrawListSplitter)(); +} +CIMGUI_API void ImDrawListSplitter_destroy(ImDrawListSplitter* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImDrawListSplitter_Clear(ImDrawListSplitter* self) +{ + return self->Clear(); +} +CIMGUI_API void ImDrawListSplitter_ClearFreeMemory(ImDrawListSplitter* self) +{ + return self->ClearFreeMemory(); +} +CIMGUI_API void ImDrawListSplitter_Split(ImDrawListSplitter* self,ImDrawList* draw_list,int count) +{ + return self->Split(draw_list,count); +} +CIMGUI_API void ImDrawListSplitter_Merge(ImDrawListSplitter* self,ImDrawList* draw_list) +{ + return self->Merge(draw_list); +} +CIMGUI_API void ImDrawListSplitter_SetCurrentChannel(ImDrawListSplitter* self,ImDrawList* draw_list,int channel_idx) +{ + return self->SetCurrentChannel(draw_list,channel_idx); +} +CIMGUI_API ImDrawList* ImDrawList_ImDrawList(const ImDrawListSharedData* shared_data) +{ + return IM_NEW(ImDrawList)(shared_data); +} +CIMGUI_API void ImDrawList_destroy(ImDrawList* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImDrawList_PushClipRect(ImDrawList* self,ImVec2 clip_rect_min,ImVec2 clip_rect_max,bool intersect_with_current_clip_rect) +{ + return self->PushClipRect(clip_rect_min,clip_rect_max,intersect_with_current_clip_rect); +} +CIMGUI_API void ImDrawList_PushClipRectFullScreen(ImDrawList* self) +{ + return self->PushClipRectFullScreen(); +} +CIMGUI_API void ImDrawList_PopClipRect(ImDrawList* self) +{ + return self->PopClipRect(); +} +CIMGUI_API void ImDrawList_PushTextureID(ImDrawList* self,ImTextureID texture_id) +{ + return self->PushTextureID(texture_id); +} +CIMGUI_API void ImDrawList_PopTextureID(ImDrawList* self) +{ + return self->PopTextureID(); +} +CIMGUI_API void ImDrawList_GetClipRectMin(ImVec2 *pOut,ImDrawList* self) +{ + *pOut = self->GetClipRectMin(); +} +CIMGUI_API void ImDrawList_GetClipRectMax(ImVec2 *pOut,ImDrawList* self) +{ + *pOut = self->GetClipRectMax(); +} +CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,ImU32 col,float thickness) +{ + return self->AddLine(p1,p2,col,thickness); +} +CIMGUI_API void ImDrawList_AddRect(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags,float thickness) +{ + return self->AddRect(p_min,p_max,col,rounding,flags,thickness); +} +CIMGUI_API void ImDrawList_AddRectFilled(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags) +{ + return self->AddRectFilled(p_min,p_max,col,rounding,flags); +} +CIMGUI_API void ImDrawList_AddRectFilledMultiColor(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col_upr_left,ImU32 col_upr_right,ImU32 col_bot_right,ImU32 col_bot_left) +{ + return self->AddRectFilledMultiColor(p_min,p_max,col_upr_left,col_upr_right,col_bot_right,col_bot_left); +} +CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness) +{ + return self->AddQuad(p1,p2,p3,p4,col,thickness); +} +CIMGUI_API void ImDrawList_AddQuadFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col) +{ + return self->AddQuadFilled(p1,p2,p3,p4,col); +} +CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness) +{ + return self->AddTriangle(p1,p2,p3,col,thickness); +} +CIMGUI_API void ImDrawList_AddTriangleFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col) +{ + return self->AddTriangleFilled(p1,p2,p3,col); +} +CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness) +{ + return self->AddCircle(center,radius,col,num_segments,thickness); +} +CIMGUI_API void ImDrawList_AddCircleFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments) +{ + return self->AddCircleFilled(center,radius,col,num_segments); +} +CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness) +{ + return self->AddNgon(center,radius,col,num_segments,thickness); +} +CIMGUI_API void ImDrawList_AddNgonFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments) +{ + return self->AddNgonFilled(center,radius,col,num_segments); +} +CIMGUI_API void ImDrawList_AddText_Vec2(ImDrawList* self,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end) +{ + return self->AddText(pos,col,text_begin,text_end); +} +CIMGUI_API void ImDrawList_AddText_FontPtr(ImDrawList* self,const ImFont* font,float font_size,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end,float wrap_width,const ImVec4* cpu_fine_clip_rect) +{ + return self->AddText(font,font_size,pos,col,text_begin,text_end,wrap_width,cpu_fine_clip_rect); +} +CIMGUI_API void ImDrawList_AddPolyline(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col,ImDrawFlags flags,float thickness) +{ + return self->AddPolyline(points,num_points,col,flags,thickness); +} +CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col) +{ + return self->AddConvexPolyFilled(points,num_points,col); +} +CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness,int num_segments) +{ + return self->AddBezierCubic(p1,p2,p3,p4,col,thickness,num_segments); +} +CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness,int num_segments) +{ + return self->AddBezierQuadratic(p1,p2,p3,col,thickness,num_segments); +} +CIMGUI_API void ImDrawList_AddImage(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col) +{ + return self->AddImage(user_texture_id,p_min,p_max,uv_min,uv_max,col); +} +CIMGUI_API void ImDrawList_AddImageQuad(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 uv1,const ImVec2 uv2,const ImVec2 uv3,const ImVec2 uv4,ImU32 col) +{ + return self->AddImageQuad(user_texture_id,p1,p2,p3,p4,uv1,uv2,uv3,uv4,col); +} +CIMGUI_API void ImDrawList_AddImageRounded(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col,float rounding,ImDrawFlags flags) +{ + return self->AddImageRounded(user_texture_id,p_min,p_max,uv_min,uv_max,col,rounding,flags); +} +CIMGUI_API void ImDrawList_PathClear(ImDrawList* self) +{ + return self->PathClear(); +} +CIMGUI_API void ImDrawList_PathLineTo(ImDrawList* self,const ImVec2 pos) +{ + return self->PathLineTo(pos); +} +CIMGUI_API void ImDrawList_PathLineToMergeDuplicate(ImDrawList* self,const ImVec2 pos) +{ + return self->PathLineToMergeDuplicate(pos); +} +CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col) +{ + return self->PathFillConvex(col); +} +CIMGUI_API void ImDrawList_PathStroke(ImDrawList* self,ImU32 col,ImDrawFlags flags,float thickness) +{ + return self->PathStroke(col,flags,thickness); +} +CIMGUI_API void ImDrawList_PathArcTo(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments) +{ + return self->PathArcTo(center,radius,a_min,a_max,num_segments); +} +CIMGUI_API void ImDrawList_PathArcToFast(ImDrawList* self,const ImVec2 center,float radius,int a_min_of_12,int a_max_of_12) +{ + return self->PathArcToFast(center,radius,a_min_of_12,a_max_of_12); +} +CIMGUI_API void ImDrawList_PathBezierCubicCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,int num_segments) +{ + return self->PathBezierCubicCurveTo(p2,p3,p4,num_segments); +} +CIMGUI_API void ImDrawList_PathBezierQuadraticCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,int num_segments) +{ + return self->PathBezierQuadraticCurveTo(p2,p3,num_segments); +} +CIMGUI_API void ImDrawList_PathRect(ImDrawList* self,const ImVec2 rect_min,const ImVec2 rect_max,float rounding,ImDrawFlags flags) +{ + return self->PathRect(rect_min,rect_max,rounding,flags); +} +CIMGUI_API void ImDrawList_AddCallback(ImDrawList* self,ImDrawCallback callback,void* callback_data) +{ + return self->AddCallback(callback,callback_data); +} +CIMGUI_API void ImDrawList_AddDrawCmd(ImDrawList* self) +{ + return self->AddDrawCmd(); +} +CIMGUI_API ImDrawList* ImDrawList_CloneOutput(ImDrawList* self) +{ + return self->CloneOutput(); +} +CIMGUI_API void ImDrawList_ChannelsSplit(ImDrawList* self,int count) +{ + return self->ChannelsSplit(count); +} +CIMGUI_API void ImDrawList_ChannelsMerge(ImDrawList* self) +{ + return self->ChannelsMerge(); +} +CIMGUI_API void ImDrawList_ChannelsSetCurrent(ImDrawList* self,int n) +{ + return self->ChannelsSetCurrent(n); +} +CIMGUI_API void ImDrawList_PrimReserve(ImDrawList* self,int idx_count,int vtx_count) +{ + return self->PrimReserve(idx_count,vtx_count); +} +CIMGUI_API void ImDrawList_PrimUnreserve(ImDrawList* self,int idx_count,int vtx_count) +{ + return self->PrimUnreserve(idx_count,vtx_count); +} +CIMGUI_API void ImDrawList_PrimRect(ImDrawList* self,const ImVec2 a,const ImVec2 b,ImU32 col) +{ + return self->PrimRect(a,b,col); +} +CIMGUI_API void ImDrawList_PrimRectUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,ImU32 col) +{ + return self->PrimRectUV(a,b,uv_a,uv_b,col); +} +CIMGUI_API void ImDrawList_PrimQuadUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 d,const ImVec2 uv_a,const ImVec2 uv_b,const ImVec2 uv_c,const ImVec2 uv_d,ImU32 col) +{ + return self->PrimQuadUV(a,b,c,d,uv_a,uv_b,uv_c,uv_d,col); +} +CIMGUI_API void ImDrawList_PrimWriteVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col) +{ + return self->PrimWriteVtx(pos,uv,col); +} +CIMGUI_API void ImDrawList_PrimWriteIdx(ImDrawList* self,ImDrawIdx idx) +{ + return self->PrimWriteIdx(idx); +} +CIMGUI_API void ImDrawList_PrimVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col) +{ + return self->PrimVtx(pos,uv,col); +} +CIMGUI_API void ImDrawList__ResetForNewFrame(ImDrawList* self) +{ + return self->_ResetForNewFrame(); +} +CIMGUI_API void ImDrawList__ClearFreeMemory(ImDrawList* self) +{ + return self->_ClearFreeMemory(); +} +CIMGUI_API void ImDrawList__PopUnusedDrawCmd(ImDrawList* self) +{ + return self->_PopUnusedDrawCmd(); +} +CIMGUI_API void ImDrawList__TryMergeDrawCmds(ImDrawList* self) +{ + return self->_TryMergeDrawCmds(); +} +CIMGUI_API void ImDrawList__OnChangedClipRect(ImDrawList* self) +{ + return self->_OnChangedClipRect(); +} +CIMGUI_API void ImDrawList__OnChangedTextureID(ImDrawList* self) +{ + return self->_OnChangedTextureID(); +} +CIMGUI_API void ImDrawList__OnChangedVtxOffset(ImDrawList* self) +{ + return self->_OnChangedVtxOffset(); +} +CIMGUI_API int ImDrawList__CalcCircleAutoSegmentCount(ImDrawList* self,float radius) +{ + return self->_CalcCircleAutoSegmentCount(radius); +} +CIMGUI_API void ImDrawList__PathArcToFastEx(ImDrawList* self,const ImVec2 center,float radius,int a_min_sample,int a_max_sample,int a_step) +{ + return self->_PathArcToFastEx(center,radius,a_min_sample,a_max_sample,a_step); +} +CIMGUI_API void ImDrawList__PathArcToN(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments) +{ + return self->_PathArcToN(center,radius,a_min,a_max,num_segments); +} +CIMGUI_API ImDrawData* ImDrawData_ImDrawData(void) +{ + return IM_NEW(ImDrawData)(); +} +CIMGUI_API void ImDrawData_destroy(ImDrawData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImDrawData_Clear(ImDrawData* self) +{ + return self->Clear(); +} +CIMGUI_API void ImDrawData_DeIndexAllBuffers(ImDrawData* self) +{ + return self->DeIndexAllBuffers(); +} +CIMGUI_API void ImDrawData_ScaleClipRects(ImDrawData* self,const ImVec2 fb_scale) +{ + return self->ScaleClipRects(fb_scale); +} +CIMGUI_API ImFontConfig* ImFontConfig_ImFontConfig(void) +{ + return IM_NEW(ImFontConfig)(); +} +CIMGUI_API void ImFontConfig_destroy(ImFontConfig* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImFontGlyphRangesBuilder* ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder(void) +{ + return IM_NEW(ImFontGlyphRangesBuilder)(); +} +CIMGUI_API void ImFontGlyphRangesBuilder_destroy(ImFontGlyphRangesBuilder* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImFontGlyphRangesBuilder_Clear(ImFontGlyphRangesBuilder* self) +{ + return self->Clear(); +} +CIMGUI_API bool ImFontGlyphRangesBuilder_GetBit(ImFontGlyphRangesBuilder* self,size_t n) +{ + return self->GetBit(n); +} +CIMGUI_API void ImFontGlyphRangesBuilder_SetBit(ImFontGlyphRangesBuilder* self,size_t n) +{ + return self->SetBit(n); +} +CIMGUI_API void ImFontGlyphRangesBuilder_AddChar(ImFontGlyphRangesBuilder* self,ImWchar c) +{ + return self->AddChar(c); +} +CIMGUI_API void ImFontGlyphRangesBuilder_AddText(ImFontGlyphRangesBuilder* self,const char* text,const char* text_end) +{ + return self->AddText(text,text_end); +} +CIMGUI_API void ImFontGlyphRangesBuilder_AddRanges(ImFontGlyphRangesBuilder* self,const ImWchar* ranges) +{ + return self->AddRanges(ranges); +} +CIMGUI_API void ImFontGlyphRangesBuilder_BuildRanges(ImFontGlyphRangesBuilder* self,ImVector_ImWchar* out_ranges) +{ + return self->BuildRanges(out_ranges); +} +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlasCustomRect_ImFontAtlasCustomRect(void) +{ + return IM_NEW(ImFontAtlasCustomRect)(); +} +CIMGUI_API void ImFontAtlasCustomRect_destroy(ImFontAtlasCustomRect* self) +{ + IM_DELETE(self); +} +CIMGUI_API bool ImFontAtlasCustomRect_IsPacked(ImFontAtlasCustomRect* self) +{ + return self->IsPacked(); +} +CIMGUI_API ImFontAtlas* ImFontAtlas_ImFontAtlas(void) +{ + return IM_NEW(ImFontAtlas)(); +} +CIMGUI_API void ImFontAtlas_destroy(ImFontAtlas* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImFont* ImFontAtlas_AddFont(ImFontAtlas* self,const ImFontConfig* font_cfg) +{ + return self->AddFont(font_cfg); +} +CIMGUI_API ImFont* ImFontAtlas_AddFontDefault(ImFontAtlas* self,const ImFontConfig* font_cfg) +{ + return self->AddFontDefault(font_cfg); +} +CIMGUI_API ImFont* ImFontAtlas_AddFontFromFileTTF(ImFontAtlas* self,const char* filename,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges) +{ + return self->AddFontFromFileTTF(filename,size_pixels,font_cfg,glyph_ranges); +} +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryTTF(ImFontAtlas* self,void* font_data,int font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges) +{ + return self->AddFontFromMemoryTTF(font_data,font_size,size_pixels,font_cfg,glyph_ranges); +} +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedTTF(ImFontAtlas* self,const void* compressed_font_data,int compressed_font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges) +{ + return self->AddFontFromMemoryCompressedTTF(compressed_font_data,compressed_font_size,size_pixels,font_cfg,glyph_ranges); +} +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedBase85TTF(ImFontAtlas* self,const char* compressed_font_data_base85,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges) +{ + return self->AddFontFromMemoryCompressedBase85TTF(compressed_font_data_base85,size_pixels,font_cfg,glyph_ranges); +} +CIMGUI_API void ImFontAtlas_ClearInputData(ImFontAtlas* self) +{ + return self->ClearInputData(); +} +CIMGUI_API void ImFontAtlas_ClearTexData(ImFontAtlas* self) +{ + return self->ClearTexData(); +} +CIMGUI_API void ImFontAtlas_ClearFonts(ImFontAtlas* self) +{ + return self->ClearFonts(); +} +CIMGUI_API void ImFontAtlas_Clear(ImFontAtlas* self) +{ + return self->Clear(); +} +CIMGUI_API bool ImFontAtlas_Build(ImFontAtlas* self) +{ + return self->Build(); +} +CIMGUI_API void ImFontAtlas_GetTexDataAsAlpha8(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel) +{ + return self->GetTexDataAsAlpha8(out_pixels,out_width,out_height,out_bytes_per_pixel); +} +CIMGUI_API void ImFontAtlas_GetTexDataAsRGBA32(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel) +{ + return self->GetTexDataAsRGBA32(out_pixels,out_width,out_height,out_bytes_per_pixel); +} +CIMGUI_API bool ImFontAtlas_IsBuilt(ImFontAtlas* self) +{ + return self->IsBuilt(); +} +CIMGUI_API void ImFontAtlas_SetTexID(ImFontAtlas* self,ImTextureID id) +{ + return self->SetTexID(id); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesDefault(ImFontAtlas* self) +{ + return self->GetGlyphRangesDefault(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesKorean(ImFontAtlas* self) +{ + return self->GetGlyphRangesKorean(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesJapanese(ImFontAtlas* self) +{ + return self->GetGlyphRangesJapanese(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseFull(ImFontAtlas* self) +{ + return self->GetGlyphRangesChineseFull(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(ImFontAtlas* self) +{ + return self->GetGlyphRangesChineseSimplifiedCommon(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesCyrillic(ImFontAtlas* self) +{ + return self->GetGlyphRangesCyrillic(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesThai(ImFontAtlas* self) +{ + return self->GetGlyphRangesThai(); +} +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesVietnamese(ImFontAtlas* self) +{ + return self->GetGlyphRangesVietnamese(); +} +CIMGUI_API int ImFontAtlas_AddCustomRectRegular(ImFontAtlas* self,int width,int height) +{ + return self->AddCustomRectRegular(width,height); +} +CIMGUI_API int ImFontAtlas_AddCustomRectFontGlyph(ImFontAtlas* self,ImFont* font,ImWchar id,int width,int height,float advance_x,const ImVec2 offset) +{ + return self->AddCustomRectFontGlyph(font,id,width,height,advance_x,offset); +} +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlas_GetCustomRectByIndex(ImFontAtlas* self,int index) +{ + return self->GetCustomRectByIndex(index); +} +CIMGUI_API void ImFontAtlas_CalcCustomRectUV(ImFontAtlas* self,const ImFontAtlasCustomRect* rect,ImVec2* out_uv_min,ImVec2* out_uv_max) +{ + return self->CalcCustomRectUV(rect,out_uv_min,out_uv_max); +} +CIMGUI_API bool ImFontAtlas_GetMouseCursorTexData(ImFontAtlas* self,ImGuiMouseCursor cursor,ImVec2* out_offset,ImVec2* out_size,ImVec2 out_uv_border[2],ImVec2 out_uv_fill[2]) +{ + return self->GetMouseCursorTexData(cursor,out_offset,out_size,out_uv_border,out_uv_fill); +} +CIMGUI_API ImFont* ImFont_ImFont(void) +{ + return IM_NEW(ImFont)(); +} +CIMGUI_API void ImFont_destroy(ImFont* self) +{ + IM_DELETE(self); +} +CIMGUI_API const ImFontGlyph* ImFont_FindGlyph(ImFont* self,ImWchar c) +{ + return self->FindGlyph(c); +} +CIMGUI_API const ImFontGlyph* ImFont_FindGlyphNoFallback(ImFont* self,ImWchar c) +{ + return self->FindGlyphNoFallback(c); +} +CIMGUI_API float ImFont_GetCharAdvance(ImFont* self,ImWchar c) +{ + return self->GetCharAdvance(c); +} +CIMGUI_API bool ImFont_IsLoaded(ImFont* self) +{ + return self->IsLoaded(); +} +CIMGUI_API const char* ImFont_GetDebugName(ImFont* self) +{ + return self->GetDebugName(); +} +CIMGUI_API void ImFont_CalcTextSizeA(ImVec2 *pOut,ImFont* self,float size,float max_width,float wrap_width,const char* text_begin,const char* text_end,const char** remaining) +{ + *pOut = self->CalcTextSizeA(size,max_width,wrap_width,text_begin,text_end,remaining); +} +CIMGUI_API const char* ImFont_CalcWordWrapPositionA(ImFont* self,float scale,const char* text,const char* text_end,float wrap_width) +{ + return self->CalcWordWrapPositionA(scale,text,text_end,wrap_width); +} +CIMGUI_API void ImFont_RenderChar(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,ImWchar c) +{ + return self->RenderChar(draw_list,size,pos,col,c); +} +CIMGUI_API void ImFont_RenderText(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,const ImVec4 clip_rect,const char* text_begin,const char* text_end,float wrap_width,bool cpu_fine_clip) +{ + return self->RenderText(draw_list,size,pos,col,clip_rect,text_begin,text_end,wrap_width,cpu_fine_clip); +} +CIMGUI_API void ImFont_BuildLookupTable(ImFont* self) +{ + return self->BuildLookupTable(); +} +CIMGUI_API void ImFont_ClearOutputData(ImFont* self) +{ + return self->ClearOutputData(); +} +CIMGUI_API void ImFont_GrowIndex(ImFont* self,int new_size) +{ + return self->GrowIndex(new_size); +} +CIMGUI_API void ImFont_AddGlyph(ImFont* self,const ImFontConfig* src_cfg,ImWchar c,float x0,float y0,float x1,float y1,float u0,float v0,float u1,float v1,float advance_x) +{ + return self->AddGlyph(src_cfg,c,x0,y0,x1,y1,u0,v0,u1,v1,advance_x); +} +CIMGUI_API void ImFont_AddRemapChar(ImFont* self,ImWchar dst,ImWchar src,bool overwrite_dst) +{ + return self->AddRemapChar(dst,src,overwrite_dst); +} +CIMGUI_API void ImFont_SetGlyphVisible(ImFont* self,ImWchar c,bool visible) +{ + return self->SetGlyphVisible(c,visible); +} +CIMGUI_API bool ImFont_IsGlyphRangeUnused(ImFont* self,unsigned int c_begin,unsigned int c_last) +{ + return self->IsGlyphRangeUnused(c_begin,c_last); +} +CIMGUI_API ImGuiViewport* ImGuiViewport_ImGuiViewport(void) +{ + return IM_NEW(ImGuiViewport)(); +} +CIMGUI_API void ImGuiViewport_destroy(ImGuiViewport* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiViewport_GetCenter(ImVec2 *pOut,ImGuiViewport* self) +{ + *pOut = self->GetCenter(); +} +CIMGUI_API void ImGuiViewport_GetWorkCenter(ImVec2 *pOut,ImGuiViewport* self) +{ + *pOut = self->GetWorkCenter(); +} +CIMGUI_API ImGuiID igImHashData(const void* data,size_t data_size,ImU32 seed) +{ + return ImHashData(data,data_size,seed); +} +CIMGUI_API ImGuiID igImHashStr(const char* data,size_t data_size,ImU32 seed) +{ + return ImHashStr(data,data_size,seed); +} +CIMGUI_API void igImQsort(void* base,size_t count,size_t size_of_element,int(*compare_func)(void const*,void const*)) +{ + return ImQsort(base,count,size_of_element,compare_func); +} +CIMGUI_API ImU32 igImAlphaBlendColors(ImU32 col_a,ImU32 col_b) +{ + return ImAlphaBlendColors(col_a,col_b); +} +CIMGUI_API bool igImIsPowerOfTwo_Int(int v) +{ + return ImIsPowerOfTwo(v); +} +CIMGUI_API bool igImIsPowerOfTwo_U64(ImU64 v) +{ + return ImIsPowerOfTwo(v); +} +CIMGUI_API int igImUpperPowerOfTwo(int v) +{ + return ImUpperPowerOfTwo(v); +} +CIMGUI_API int igImStricmp(const char* str1,const char* str2) +{ + return ImStricmp(str1,str2); +} +CIMGUI_API int igImStrnicmp(const char* str1,const char* str2,size_t count) +{ + return ImStrnicmp(str1,str2,count); +} +CIMGUI_API void igImStrncpy(char* dst,const char* src,size_t count) +{ + return ImStrncpy(dst,src,count); +} +CIMGUI_API char* igImStrdup(const char* str) +{ + return ImStrdup(str); +} +CIMGUI_API char* igImStrdupcpy(char* dst,size_t* p_dst_size,const char* str) +{ + return ImStrdupcpy(dst,p_dst_size,str); +} +CIMGUI_API const char* igImStrchrRange(const char* str_begin,const char* str_end,char c) +{ + return ImStrchrRange(str_begin,str_end,c); +} +CIMGUI_API int igImStrlenW(const ImWchar* str) +{ + return ImStrlenW(str); +} +CIMGUI_API const char* igImStreolRange(const char* str,const char* str_end) +{ + return ImStreolRange(str,str_end); +} +CIMGUI_API const ImWchar* igImStrbolW(const ImWchar* buf_mid_line,const ImWchar* buf_begin) +{ + return ImStrbolW(buf_mid_line,buf_begin); +} +CIMGUI_API const char* igImStristr(const char* haystack,const char* haystack_end,const char* needle,const char* needle_end) +{ + return ImStristr(haystack,haystack_end,needle,needle_end); +} +CIMGUI_API void igImStrTrimBlanks(char* str) +{ + return ImStrTrimBlanks(str); +} +CIMGUI_API const char* igImStrSkipBlank(const char* str) +{ + return ImStrSkipBlank(str); +} +CIMGUI_API int igImFormatString(char* buf,size_t buf_size,const char* fmt,...) +{ + va_list args; + va_start(args, fmt); + int ret = ImFormatStringV(buf,buf_size,fmt,args); + va_end(args); + return ret; +} +CIMGUI_API int igImFormatStringV(char* buf,size_t buf_size,const char* fmt,va_list args) +{ + return ImFormatStringV(buf,buf_size,fmt,args); +} +CIMGUI_API const char* igImParseFormatFindStart(const char* format) +{ + return ImParseFormatFindStart(format); +} +CIMGUI_API const char* igImParseFormatFindEnd(const char* format) +{ + return ImParseFormatFindEnd(format); +} +CIMGUI_API const char* igImParseFormatTrimDecorations(const char* format,char* buf,size_t buf_size) +{ + return ImParseFormatTrimDecorations(format,buf,buf_size); +} +CIMGUI_API int igImParseFormatPrecision(const char* format,int default_value) +{ + return ImParseFormatPrecision(format,default_value); +} +CIMGUI_API bool igImCharIsBlankA(char c) +{ + return ImCharIsBlankA(c); +} +CIMGUI_API bool igImCharIsBlankW(unsigned int c) +{ + return ImCharIsBlankW(c); +} +CIMGUI_API const char* igImTextCharToUtf8(char out_buf[5],unsigned int c) +{ + return ImTextCharToUtf8(out_buf,c); +} +CIMGUI_API int igImTextStrToUtf8(char* out_buf,int out_buf_size,const ImWchar* in_text,const ImWchar* in_text_end) +{ + return ImTextStrToUtf8(out_buf,out_buf_size,in_text,in_text_end); +} +CIMGUI_API int igImTextCharFromUtf8(unsigned int* out_char,const char* in_text,const char* in_text_end) +{ + return ImTextCharFromUtf8(out_char,in_text,in_text_end); +} +CIMGUI_API int igImTextStrFromUtf8(ImWchar* out_buf,int out_buf_size,const char* in_text,const char* in_text_end,const char** in_remaining) +{ + return ImTextStrFromUtf8(out_buf,out_buf_size,in_text,in_text_end,in_remaining); +} +CIMGUI_API int igImTextCountCharsFromUtf8(const char* in_text,const char* in_text_end) +{ + return ImTextCountCharsFromUtf8(in_text,in_text_end); +} +CIMGUI_API int igImTextCountUtf8BytesFromChar(const char* in_text,const char* in_text_end) +{ + return ImTextCountUtf8BytesFromChar(in_text,in_text_end); +} +CIMGUI_API int igImTextCountUtf8BytesFromStr(const ImWchar* in_text,const ImWchar* in_text_end) +{ + return ImTextCountUtf8BytesFromStr(in_text,in_text_end); +} +CIMGUI_API ImFileHandle igImFileOpen(const char* filename,const char* mode) +{ + return ImFileOpen(filename,mode); +} +CIMGUI_API bool igImFileClose(ImFileHandle file) +{ + return ImFileClose(file); +} +CIMGUI_API ImU64 igImFileGetSize(ImFileHandle file) +{ + return ImFileGetSize(file); +} +CIMGUI_API ImU64 igImFileRead(void* data,ImU64 size,ImU64 count,ImFileHandle file) +{ + return ImFileRead(data,size,count,file); +} +CIMGUI_API ImU64 igImFileWrite(const void* data,ImU64 size,ImU64 count,ImFileHandle file) +{ + return ImFileWrite(data,size,count,file); +} +CIMGUI_API void* igImFileLoadToMemory(const char* filename,const char* mode,size_t* out_file_size,int padding_bytes) +{ + return ImFileLoadToMemory(filename,mode,out_file_size,padding_bytes); +} +CIMGUI_API float igImPow_Float(float x,float y) +{ + return ImPow(x,y); +} +CIMGUI_API double igImPow_double(double x,double y) +{ + return ImPow(x,y); +} +CIMGUI_API float igImLog_Float(float x) +{ + return ImLog(x); +} +CIMGUI_API double igImLog_double(double x) +{ + return ImLog(x); +} +CIMGUI_API int igImAbs_Int(int x) +{ + return ImAbs(x); +} +CIMGUI_API float igImAbs_Float(float x) +{ + return ImAbs(x); +} +CIMGUI_API double igImAbs_double(double x) +{ + return ImAbs(x); +} +CIMGUI_API float igImSign_Float(float x) +{ + return ImSign(x); +} +CIMGUI_API double igImSign_double(double x) +{ + return ImSign(x); +} +CIMGUI_API float igImRsqrt_Float(float x) +{ + return ImRsqrt(x); +} +CIMGUI_API double igImRsqrt_double(double x) +{ + return ImRsqrt(x); +} +CIMGUI_API void igImMin(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs) +{ + *pOut = ImMin(lhs,rhs); +} +CIMGUI_API void igImMax(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs) +{ + *pOut = ImMax(lhs,rhs); +} +CIMGUI_API void igImClamp(ImVec2 *pOut,const ImVec2 v,const ImVec2 mn,ImVec2 mx) +{ + *pOut = ImClamp(v,mn,mx); +} +CIMGUI_API void igImLerp_Vec2Float(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,float t) +{ + *pOut = ImLerp(a,b,t); +} +CIMGUI_API void igImLerp_Vec2Vec2(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 t) +{ + *pOut = ImLerp(a,b,t); +} +CIMGUI_API void igImLerp_Vec4(ImVec4 *pOut,const ImVec4 a,const ImVec4 b,float t) +{ + *pOut = ImLerp(a,b,t); +} +CIMGUI_API float igImSaturate(float f) +{ + return ImSaturate(f); +} +CIMGUI_API float igImLengthSqr_Vec2(const ImVec2 lhs) +{ + return ImLengthSqr(lhs); +} +CIMGUI_API float igImLengthSqr_Vec4(const ImVec4 lhs) +{ + return ImLengthSqr(lhs); +} +CIMGUI_API float igImInvLength(const ImVec2 lhs,float fail_value) +{ + return ImInvLength(lhs,fail_value); +} +CIMGUI_API float igImFloor_Float(float f) +{ + return ImFloor(f); +} +CIMGUI_API float igImFloorSigned(float f) +{ + return ImFloorSigned(f); +} +CIMGUI_API void igImFloor_Vec2(ImVec2 *pOut,const ImVec2 v) +{ + *pOut = ImFloor(v); +} +CIMGUI_API int igImModPositive(int a,int b) +{ + return ImModPositive(a,b); +} +CIMGUI_API float igImDot(const ImVec2 a,const ImVec2 b) +{ + return ImDot(a,b); +} +CIMGUI_API void igImRotate(ImVec2 *pOut,const ImVec2 v,float cos_a,float sin_a) +{ + *pOut = ImRotate(v,cos_a,sin_a); +} +CIMGUI_API float igImLinearSweep(float current,float target,float speed) +{ + return ImLinearSweep(current,target,speed); +} +CIMGUI_API void igImMul(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs) +{ + *pOut = ImMul(lhs,rhs); +} +CIMGUI_API bool igImIsFloatAboveGuaranteedIntegerPrecision(float f) +{ + return ImIsFloatAboveGuaranteedIntegerPrecision(f); +} +CIMGUI_API void igImBezierCubicCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,float t) +{ + *pOut = ImBezierCubicCalc(p1,p2,p3,p4,t); +} +CIMGUI_API void igImBezierCubicClosestPoint(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,int num_segments) +{ + *pOut = ImBezierCubicClosestPoint(p1,p2,p3,p4,p,num_segments); +} +CIMGUI_API void igImBezierCubicClosestPointCasteljau(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,float tess_tol) +{ + *pOut = ImBezierCubicClosestPointCasteljau(p1,p2,p3,p4,p,tess_tol); +} +CIMGUI_API void igImBezierQuadraticCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,float t) +{ + *pOut = ImBezierQuadraticCalc(p1,p2,p3,t); +} +CIMGUI_API void igImLineClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 p) +{ + *pOut = ImLineClosestPoint(a,b,p); +} +CIMGUI_API bool igImTriangleContainsPoint(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p) +{ + return ImTriangleContainsPoint(a,b,c,p); +} +CIMGUI_API void igImTriangleClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p) +{ + *pOut = ImTriangleClosestPoint(a,b,c,p); +} +CIMGUI_API void igImTriangleBarycentricCoords(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p,float* out_u,float* out_v,float* out_w) +{ + return ImTriangleBarycentricCoords(a,b,c,p,*out_u,*out_v,*out_w); +} +CIMGUI_API float igImTriangleArea(const ImVec2 a,const ImVec2 b,const ImVec2 c) +{ + return ImTriangleArea(a,b,c); +} +CIMGUI_API ImGuiDir igImGetDirQuadrantFromDelta(float dx,float dy) +{ + return ImGetDirQuadrantFromDelta(dx,dy); +} +CIMGUI_API ImVec1* ImVec1_ImVec1_Nil(void) +{ + return IM_NEW(ImVec1)(); +} +CIMGUI_API void ImVec1_destroy(ImVec1* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImVec1* ImVec1_ImVec1_Float(float _x) +{ + return IM_NEW(ImVec1)(_x); +} +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Nil(void) +{ + return IM_NEW(ImVec2ih)(); +} +CIMGUI_API void ImVec2ih_destroy(ImVec2ih* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_short(short _x,short _y) +{ + return IM_NEW(ImVec2ih)(_x,_y); +} +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Vec2(const ImVec2 rhs) +{ + return IM_NEW(ImVec2ih)(rhs); +} +CIMGUI_API ImRect* ImRect_ImRect_Nil(void) +{ + return IM_NEW(ImRect)(); +} +CIMGUI_API void ImRect_destroy(ImRect* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImRect* ImRect_ImRect_Vec2(const ImVec2 min,const ImVec2 max) +{ + return IM_NEW(ImRect)(min,max); +} +CIMGUI_API ImRect* ImRect_ImRect_Vec4(const ImVec4 v) +{ + return IM_NEW(ImRect)(v); +} +CIMGUI_API ImRect* ImRect_ImRect_Float(float x1,float y1,float x2,float y2) +{ + return IM_NEW(ImRect)(x1,y1,x2,y2); +} +CIMGUI_API void ImRect_GetCenter(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetCenter(); +} +CIMGUI_API void ImRect_GetSize(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetSize(); +} +CIMGUI_API float ImRect_GetWidth(ImRect* self) +{ + return self->GetWidth(); +} +CIMGUI_API float ImRect_GetHeight(ImRect* self) +{ + return self->GetHeight(); +} +CIMGUI_API float ImRect_GetArea(ImRect* self) +{ + return self->GetArea(); +} +CIMGUI_API void ImRect_GetTL(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetTL(); +} +CIMGUI_API void ImRect_GetTR(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetTR(); +} +CIMGUI_API void ImRect_GetBL(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetBL(); +} +CIMGUI_API void ImRect_GetBR(ImVec2 *pOut,ImRect* self) +{ + *pOut = self->GetBR(); +} +CIMGUI_API bool ImRect_Contains_Vec2(ImRect* self,const ImVec2 p) +{ + return self->Contains(p); +} +CIMGUI_API bool ImRect_Contains_Rect(ImRect* self,const ImRect r) +{ + return self->Contains(r); +} +CIMGUI_API bool ImRect_Overlaps(ImRect* self,const ImRect r) +{ + return self->Overlaps(r); +} +CIMGUI_API void ImRect_Add_Vec2(ImRect* self,const ImVec2 p) +{ + return self->Add(p); +} +CIMGUI_API void ImRect_Add_Rect(ImRect* self,const ImRect r) +{ + return self->Add(r); +} +CIMGUI_API void ImRect_Expand_Float(ImRect* self,const float amount) +{ + return self->Expand(amount); +} +CIMGUI_API void ImRect_Expand_Vec2(ImRect* self,const ImVec2 amount) +{ + return self->Expand(amount); +} +CIMGUI_API void ImRect_Translate(ImRect* self,const ImVec2 d) +{ + return self->Translate(d); +} +CIMGUI_API void ImRect_TranslateX(ImRect* self,float dx) +{ + return self->TranslateX(dx); +} +CIMGUI_API void ImRect_TranslateY(ImRect* self,float dy) +{ + return self->TranslateY(dy); +} +CIMGUI_API void ImRect_ClipWith(ImRect* self,const ImRect r) +{ + return self->ClipWith(r); +} +CIMGUI_API void ImRect_ClipWithFull(ImRect* self,const ImRect r) +{ + return self->ClipWithFull(r); +} +CIMGUI_API void ImRect_Floor(ImRect* self) +{ + return self->Floor(); +} +CIMGUI_API bool ImRect_IsInverted(ImRect* self) +{ + return self->IsInverted(); +} +CIMGUI_API void ImRect_ToVec4(ImVec4 *pOut,ImRect* self) +{ + *pOut = self->ToVec4(); +} +CIMGUI_API bool igImBitArrayTestBit(const ImU32* arr,int n) +{ + return ImBitArrayTestBit(arr,n); +} +CIMGUI_API void igImBitArrayClearBit(ImU32* arr,int n) +{ + return ImBitArrayClearBit(arr,n); +} +CIMGUI_API void igImBitArraySetBit(ImU32* arr,int n) +{ + return ImBitArraySetBit(arr,n); +} +CIMGUI_API void igImBitArraySetBitRange(ImU32* arr,int n,int n2) +{ + return ImBitArraySetBitRange(arr,n,n2); +} +CIMGUI_API void ImBitVector_Create(ImBitVector* self,int sz) +{ + return self->Create(sz); +} +CIMGUI_API void ImBitVector_Clear(ImBitVector* self) +{ + return self->Clear(); +} +CIMGUI_API bool ImBitVector_TestBit(ImBitVector* self,int n) +{ + return self->TestBit(n); +} +CIMGUI_API void ImBitVector_SetBit(ImBitVector* self,int n) +{ + return self->SetBit(n); +} +CIMGUI_API void ImBitVector_ClearBit(ImBitVector* self,int n) +{ + return self->ClearBit(n); +} +CIMGUI_API ImDrawListSharedData* ImDrawListSharedData_ImDrawListSharedData(void) +{ + return IM_NEW(ImDrawListSharedData)(); +} +CIMGUI_API void ImDrawListSharedData_destroy(ImDrawListSharedData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImDrawListSharedData_SetCircleTessellationMaxError(ImDrawListSharedData* self,float max_error) +{ + return self->SetCircleTessellationMaxError(max_error); +} +CIMGUI_API void ImDrawDataBuilder_Clear(ImDrawDataBuilder* self) +{ + return self->Clear(); +} +CIMGUI_API void ImDrawDataBuilder_ClearFreeMemory(ImDrawDataBuilder* self) +{ + return self->ClearFreeMemory(); +} +CIMGUI_API int ImDrawDataBuilder_GetDrawListCount(ImDrawDataBuilder* self) +{ + return self->GetDrawListCount(); +} +CIMGUI_API void ImDrawDataBuilder_FlattenIntoSingleLayer(ImDrawDataBuilder* self) +{ + return self->FlattenIntoSingleLayer(); +} +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Int(ImGuiStyleVar idx,int v) +{ + return IM_NEW(ImGuiStyleMod)(idx,v); +} +CIMGUI_API void ImGuiStyleMod_destroy(ImGuiStyleMod* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Float(ImGuiStyleVar idx,float v) +{ + return IM_NEW(ImGuiStyleMod)(idx,v); +} +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Vec2(ImGuiStyleVar idx,ImVec2 v) +{ + return IM_NEW(ImGuiStyleMod)(idx,v); +} +CIMGUI_API ImGuiComboPreviewData* ImGuiComboPreviewData_ImGuiComboPreviewData(void) +{ + return IM_NEW(ImGuiComboPreviewData)(); +} +CIMGUI_API void ImGuiComboPreviewData_destroy(ImGuiComboPreviewData* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiMenuColumns* ImGuiMenuColumns_ImGuiMenuColumns(void) +{ + return IM_NEW(ImGuiMenuColumns)(); +} +CIMGUI_API void ImGuiMenuColumns_destroy(ImGuiMenuColumns* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiMenuColumns_Update(ImGuiMenuColumns* self,float spacing,bool window_reappearing) +{ + return self->Update(spacing,window_reappearing); +} +CIMGUI_API float ImGuiMenuColumns_DeclColumns(ImGuiMenuColumns* self,float w_icon,float w_label,float w_shortcut,float w_mark) +{ + return self->DeclColumns(w_icon,w_label,w_shortcut,w_mark); +} +CIMGUI_API void ImGuiMenuColumns_CalcNextTotalWidth(ImGuiMenuColumns* self,bool update_offsets) +{ + return self->CalcNextTotalWidth(update_offsets); +} +CIMGUI_API ImGuiInputTextState* ImGuiInputTextState_ImGuiInputTextState(void) +{ + return IM_NEW(ImGuiInputTextState)(); +} +CIMGUI_API void ImGuiInputTextState_destroy(ImGuiInputTextState* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiInputTextState_ClearText(ImGuiInputTextState* self) +{ + return self->ClearText(); +} +CIMGUI_API void ImGuiInputTextState_ClearFreeMemory(ImGuiInputTextState* self) +{ + return self->ClearFreeMemory(); +} +CIMGUI_API int ImGuiInputTextState_GetUndoAvailCount(ImGuiInputTextState* self) +{ + return self->GetUndoAvailCount(); +} +CIMGUI_API int ImGuiInputTextState_GetRedoAvailCount(ImGuiInputTextState* self) +{ + return self->GetRedoAvailCount(); +} +CIMGUI_API void ImGuiInputTextState_OnKeyPressed(ImGuiInputTextState* self,int key) +{ + return self->OnKeyPressed(key); +} +CIMGUI_API void ImGuiInputTextState_CursorAnimReset(ImGuiInputTextState* self) +{ + return self->CursorAnimReset(); +} +CIMGUI_API void ImGuiInputTextState_CursorClamp(ImGuiInputTextState* self) +{ + return self->CursorClamp(); +} +CIMGUI_API bool ImGuiInputTextState_HasSelection(ImGuiInputTextState* self) +{ + return self->HasSelection(); +} +CIMGUI_API void ImGuiInputTextState_ClearSelection(ImGuiInputTextState* self) +{ + return self->ClearSelection(); +} +CIMGUI_API int ImGuiInputTextState_GetCursorPos(ImGuiInputTextState* self) +{ + return self->GetCursorPos(); +} +CIMGUI_API int ImGuiInputTextState_GetSelectionStart(ImGuiInputTextState* self) +{ + return self->GetSelectionStart(); +} +CIMGUI_API int ImGuiInputTextState_GetSelectionEnd(ImGuiInputTextState* self) +{ + return self->GetSelectionEnd(); +} +CIMGUI_API void ImGuiInputTextState_SelectAll(ImGuiInputTextState* self) +{ + return self->SelectAll(); +} +CIMGUI_API ImGuiPopupData* ImGuiPopupData_ImGuiPopupData(void) +{ + return IM_NEW(ImGuiPopupData)(); +} +CIMGUI_API void ImGuiPopupData_destroy(ImGuiPopupData* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiNextWindowData* ImGuiNextWindowData_ImGuiNextWindowData(void) +{ + return IM_NEW(ImGuiNextWindowData)(); +} +CIMGUI_API void ImGuiNextWindowData_destroy(ImGuiNextWindowData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiNextWindowData_ClearFlags(ImGuiNextWindowData* self) +{ + return self->ClearFlags(); +} +CIMGUI_API ImGuiNextItemData* ImGuiNextItemData_ImGuiNextItemData(void) +{ + return IM_NEW(ImGuiNextItemData)(); +} +CIMGUI_API void ImGuiNextItemData_destroy(ImGuiNextItemData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiNextItemData_ClearFlags(ImGuiNextItemData* self) +{ + return self->ClearFlags(); +} +CIMGUI_API ImGuiLastItemData* ImGuiLastItemData_ImGuiLastItemData(void) +{ + return IM_NEW(ImGuiLastItemData)(); +} +CIMGUI_API void ImGuiLastItemData_destroy(ImGuiLastItemData* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiStackSizes* ImGuiStackSizes_ImGuiStackSizes(void) +{ + return IM_NEW(ImGuiStackSizes)(); +} +CIMGUI_API void ImGuiStackSizes_destroy(ImGuiStackSizes* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiStackSizes_SetToCurrentState(ImGuiStackSizes* self) +{ + return self->SetToCurrentState(); +} +CIMGUI_API void ImGuiStackSizes_CompareWithCurrentState(ImGuiStackSizes* self) +{ + return self->CompareWithCurrentState(); +} +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Ptr(void* ptr) +{ + return IM_NEW(ImGuiPtrOrIndex)(ptr); +} +CIMGUI_API void ImGuiPtrOrIndex_destroy(ImGuiPtrOrIndex* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Int(int index) +{ + return IM_NEW(ImGuiPtrOrIndex)(index); +} +CIMGUI_API ImGuiListClipperRange ImGuiListClipperRange_FromIndices(int min,int max) +{ + return ImGuiListClipperRange::FromIndices(min,max); +} +CIMGUI_API ImGuiListClipperRange ImGuiListClipperRange_FromPositions(float y1,float y2,int off_min,int off_max) +{ + return ImGuiListClipperRange::FromPositions(y1,y2,off_min,off_max); +} +CIMGUI_API ImGuiListClipperData* ImGuiListClipperData_ImGuiListClipperData(void) +{ + return IM_NEW(ImGuiListClipperData)(); +} +CIMGUI_API void ImGuiListClipperData_destroy(ImGuiListClipperData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiListClipperData_Reset(ImGuiListClipperData* self,ImGuiListClipper* clipper) +{ + return self->Reset(clipper); +} +CIMGUI_API ImGuiNavItemData* ImGuiNavItemData_ImGuiNavItemData(void) +{ + return IM_NEW(ImGuiNavItemData)(); +} +CIMGUI_API void ImGuiNavItemData_destroy(ImGuiNavItemData* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiNavItemData_Clear(ImGuiNavItemData* self) +{ + return self->Clear(); +} +CIMGUI_API ImGuiOldColumnData* ImGuiOldColumnData_ImGuiOldColumnData(void) +{ + return IM_NEW(ImGuiOldColumnData)(); +} +CIMGUI_API void ImGuiOldColumnData_destroy(ImGuiOldColumnData* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiOldColumns* ImGuiOldColumns_ImGuiOldColumns(void) +{ + return IM_NEW(ImGuiOldColumns)(); +} +CIMGUI_API void ImGuiOldColumns_destroy(ImGuiOldColumns* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiViewportP* ImGuiViewportP_ImGuiViewportP(void) +{ + return IM_NEW(ImGuiViewportP)(); +} +CIMGUI_API void ImGuiViewportP_destroy(ImGuiViewportP* self) +{ + IM_DELETE(self); +} +CIMGUI_API void ImGuiViewportP_CalcWorkRectPos(ImVec2 *pOut,ImGuiViewportP* self,const ImVec2 off_min) +{ + *pOut = self->CalcWorkRectPos(off_min); +} +CIMGUI_API void ImGuiViewportP_CalcWorkRectSize(ImVec2 *pOut,ImGuiViewportP* self,const ImVec2 off_min,const ImVec2 off_max) +{ + *pOut = self->CalcWorkRectSize(off_min,off_max); +} +CIMGUI_API void ImGuiViewportP_UpdateWorkRect(ImGuiViewportP* self) +{ + return self->UpdateWorkRect(); +} +CIMGUI_API void ImGuiViewportP_GetMainRect(ImRect *pOut,ImGuiViewportP* self) +{ + *pOut = self->GetMainRect(); +} +CIMGUI_API void ImGuiViewportP_GetWorkRect(ImRect *pOut,ImGuiViewportP* self) +{ + *pOut = self->GetWorkRect(); +} +CIMGUI_API void ImGuiViewportP_GetBuildWorkRect(ImRect *pOut,ImGuiViewportP* self) +{ + *pOut = self->GetBuildWorkRect(); +} +CIMGUI_API ImGuiWindowSettings* ImGuiWindowSettings_ImGuiWindowSettings(void) +{ + return IM_NEW(ImGuiWindowSettings)(); +} +CIMGUI_API void ImGuiWindowSettings_destroy(ImGuiWindowSettings* self) +{ + IM_DELETE(self); +} +CIMGUI_API char* ImGuiWindowSettings_GetName(ImGuiWindowSettings* self) +{ + return self->GetName(); +} +CIMGUI_API ImGuiSettingsHandler* ImGuiSettingsHandler_ImGuiSettingsHandler(void) +{ + return IM_NEW(ImGuiSettingsHandler)(); +} +CIMGUI_API void ImGuiSettingsHandler_destroy(ImGuiSettingsHandler* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiMetricsConfig* ImGuiMetricsConfig_ImGuiMetricsConfig(void) +{ + return IM_NEW(ImGuiMetricsConfig)(); +} +CIMGUI_API void ImGuiMetricsConfig_destroy(ImGuiMetricsConfig* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiStackLevelInfo* ImGuiStackLevelInfo_ImGuiStackLevelInfo(void) +{ + return IM_NEW(ImGuiStackLevelInfo)(); +} +CIMGUI_API void ImGuiStackLevelInfo_destroy(ImGuiStackLevelInfo* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiStackTool* ImGuiStackTool_ImGuiStackTool(void) +{ + return IM_NEW(ImGuiStackTool)(); +} +CIMGUI_API void ImGuiStackTool_destroy(ImGuiStackTool* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiContextHook* ImGuiContextHook_ImGuiContextHook(void) +{ + return IM_NEW(ImGuiContextHook)(); +} +CIMGUI_API void ImGuiContextHook_destroy(ImGuiContextHook* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiContext* ImGuiContext_ImGuiContext(ImFontAtlas* shared_font_atlas) +{ + return IM_NEW(ImGuiContext)(shared_font_atlas); +} +CIMGUI_API void ImGuiContext_destroy(ImGuiContext* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiWindow* ImGuiWindow_ImGuiWindow(ImGuiContext* context,const char* name) +{ + return IM_NEW(ImGuiWindow)(context,name); +} +CIMGUI_API void ImGuiWindow_destroy(ImGuiWindow* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiID ImGuiWindow_GetID_Str(ImGuiWindow* self,const char* str,const char* str_end) +{ + return self->GetID(str,str_end); +} +CIMGUI_API ImGuiID ImGuiWindow_GetID_Ptr(ImGuiWindow* self,const void* ptr) +{ + return self->GetID(ptr); +} +CIMGUI_API ImGuiID ImGuiWindow_GetID_Int(ImGuiWindow* self,int n) +{ + return self->GetID(n); +} +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Str(ImGuiWindow* self,const char* str,const char* str_end) +{ + return self->GetIDNoKeepAlive(str,str_end); +} +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Ptr(ImGuiWindow* self,const void* ptr) +{ + return self->GetIDNoKeepAlive(ptr); +} +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Int(ImGuiWindow* self,int n) +{ + return self->GetIDNoKeepAlive(n); +} +CIMGUI_API ImGuiID ImGuiWindow_GetIDFromRectangle(ImGuiWindow* self,const ImRect r_abs) +{ + return self->GetIDFromRectangle(r_abs); +} +CIMGUI_API void ImGuiWindow_Rect(ImRect *pOut,ImGuiWindow* self) +{ + *pOut = self->Rect(); +} +CIMGUI_API float ImGuiWindow_CalcFontSize(ImGuiWindow* self) +{ + return self->CalcFontSize(); +} +CIMGUI_API float ImGuiWindow_TitleBarHeight(ImGuiWindow* self) +{ + return self->TitleBarHeight(); +} +CIMGUI_API void ImGuiWindow_TitleBarRect(ImRect *pOut,ImGuiWindow* self) +{ + *pOut = self->TitleBarRect(); +} +CIMGUI_API float ImGuiWindow_MenuBarHeight(ImGuiWindow* self) +{ + return self->MenuBarHeight(); +} +CIMGUI_API void ImGuiWindow_MenuBarRect(ImRect *pOut,ImGuiWindow* self) +{ + *pOut = self->MenuBarRect(); +} +CIMGUI_API ImGuiTabItem* ImGuiTabItem_ImGuiTabItem(void) +{ + return IM_NEW(ImGuiTabItem)(); +} +CIMGUI_API void ImGuiTabItem_destroy(ImGuiTabItem* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTabBar* ImGuiTabBar_ImGuiTabBar(void) +{ + return IM_NEW(ImGuiTabBar)(); +} +CIMGUI_API void ImGuiTabBar_destroy(ImGuiTabBar* self) +{ + IM_DELETE(self); +} +CIMGUI_API int ImGuiTabBar_GetTabOrder(ImGuiTabBar* self,const ImGuiTabItem* tab) +{ + return self->GetTabOrder(tab); +} +CIMGUI_API const char* ImGuiTabBar_GetTabName(ImGuiTabBar* self,const ImGuiTabItem* tab) +{ + return self->GetTabName(tab); +} +CIMGUI_API ImGuiTableColumn* ImGuiTableColumn_ImGuiTableColumn(void) +{ + return IM_NEW(ImGuiTableColumn)(); +} +CIMGUI_API void ImGuiTableColumn_destroy(ImGuiTableColumn* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTable* ImGuiTable_ImGuiTable(void) +{ + return IM_NEW(ImGuiTable)(); +} +CIMGUI_API void ImGuiTable_destroy(ImGuiTable* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTableTempData* ImGuiTableTempData_ImGuiTableTempData(void) +{ + return IM_NEW(ImGuiTableTempData)(); +} +CIMGUI_API void ImGuiTableTempData_destroy(ImGuiTableTempData* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableColumnSettings_ImGuiTableColumnSettings(void) +{ + return IM_NEW(ImGuiTableColumnSettings)(); +} +CIMGUI_API void ImGuiTableColumnSettings_destroy(ImGuiTableColumnSettings* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTableSettings* ImGuiTableSettings_ImGuiTableSettings(void) +{ + return IM_NEW(ImGuiTableSettings)(); +} +CIMGUI_API void ImGuiTableSettings_destroy(ImGuiTableSettings* self) +{ + IM_DELETE(self); +} +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableSettings_GetColumnSettings(ImGuiTableSettings* self) +{ + return self->GetColumnSettings(); +} +CIMGUI_API ImGuiWindow* igGetCurrentWindowRead() +{ + return ImGui::GetCurrentWindowRead(); +} +CIMGUI_API ImGuiWindow* igGetCurrentWindow() +{ + return ImGui::GetCurrentWindow(); +} +CIMGUI_API ImGuiWindow* igFindWindowByID(ImGuiID id) +{ + return ImGui::FindWindowByID(id); +} +CIMGUI_API ImGuiWindow* igFindWindowByName(const char* name) +{ + return ImGui::FindWindowByName(name); +} +CIMGUI_API void igUpdateWindowParentAndRootLinks(ImGuiWindow* window,ImGuiWindowFlags flags,ImGuiWindow* parent_window) +{ + return ImGui::UpdateWindowParentAndRootLinks(window,flags,parent_window); +} +CIMGUI_API void igCalcWindowNextAutoFitSize(ImVec2 *pOut,ImGuiWindow* window) +{ + *pOut = ImGui::CalcWindowNextAutoFitSize(window); +} +CIMGUI_API bool igIsWindowChildOf(ImGuiWindow* window,ImGuiWindow* potential_parent,bool popup_hierarchy) +{ + return ImGui::IsWindowChildOf(window,potential_parent,popup_hierarchy); +} +CIMGUI_API bool igIsWindowWithinBeginStackOf(ImGuiWindow* window,ImGuiWindow* potential_parent) +{ + return ImGui::IsWindowWithinBeginStackOf(window,potential_parent); +} +CIMGUI_API bool igIsWindowAbove(ImGuiWindow* potential_above,ImGuiWindow* potential_below) +{ + return ImGui::IsWindowAbove(potential_above,potential_below); +} +CIMGUI_API bool igIsWindowNavFocusable(ImGuiWindow* window) +{ + return ImGui::IsWindowNavFocusable(window); +} +CIMGUI_API void igSetWindowPos_WindowPtr(ImGuiWindow* window,const ImVec2 pos,ImGuiCond cond) +{ + return ImGui::SetWindowPos(window,pos,cond); +} +CIMGUI_API void igSetWindowSize_WindowPtr(ImGuiWindow* window,const ImVec2 size,ImGuiCond cond) +{ + return ImGui::SetWindowSize(window,size,cond); +} +CIMGUI_API void igSetWindowCollapsed_WindowPtr(ImGuiWindow* window,bool collapsed,ImGuiCond cond) +{ + return ImGui::SetWindowCollapsed(window,collapsed,cond); +} +CIMGUI_API void igSetWindowHitTestHole(ImGuiWindow* window,const ImVec2 pos,const ImVec2 size) +{ + return ImGui::SetWindowHitTestHole(window,pos,size); +} +CIMGUI_API void igWindowRectAbsToRel(ImRect *pOut,ImGuiWindow* window,const ImRect r) +{ + *pOut = ImGui::WindowRectAbsToRel(window,r); +} +CIMGUI_API void igWindowRectRelToAbs(ImRect *pOut,ImGuiWindow* window,const ImRect r) +{ + *pOut = ImGui::WindowRectRelToAbs(window,r); +} +CIMGUI_API void igFocusWindow(ImGuiWindow* window) +{ + return ImGui::FocusWindow(window); +} +CIMGUI_API void igFocusTopMostWindowUnderOne(ImGuiWindow* under_this_window,ImGuiWindow* ignore_window) +{ + return ImGui::FocusTopMostWindowUnderOne(under_this_window,ignore_window); +} +CIMGUI_API void igBringWindowToFocusFront(ImGuiWindow* window) +{ + return ImGui::BringWindowToFocusFront(window); +} +CIMGUI_API void igBringWindowToDisplayFront(ImGuiWindow* window) +{ + return ImGui::BringWindowToDisplayFront(window); +} +CIMGUI_API void igBringWindowToDisplayBack(ImGuiWindow* window) +{ + return ImGui::BringWindowToDisplayBack(window); +} +CIMGUI_API void igBringWindowToDisplayBehind(ImGuiWindow* window,ImGuiWindow* above_window) +{ + return ImGui::BringWindowToDisplayBehind(window,above_window); +} +CIMGUI_API int igFindWindowDisplayIndex(ImGuiWindow* window) +{ + return ImGui::FindWindowDisplayIndex(window); +} +CIMGUI_API ImGuiWindow* igFindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window) +{ + return ImGui::FindBottomMostVisibleWindowWithinBeginStack(window); +} +CIMGUI_API void igSetCurrentFont(ImFont* font) +{ + return ImGui::SetCurrentFont(font); +} +CIMGUI_API ImFont* igGetDefaultFont() +{ + return ImGui::GetDefaultFont(); +} +CIMGUI_API ImDrawList* igGetForegroundDrawList_WindowPtr(ImGuiWindow* window) +{ + return ImGui::GetForegroundDrawList(window); +} +CIMGUI_API ImDrawList* igGetBackgroundDrawList_ViewportPtr(ImGuiViewport* viewport) +{ + return ImGui::GetBackgroundDrawList(viewport); +} +CIMGUI_API ImDrawList* igGetForegroundDrawList_ViewportPtr(ImGuiViewport* viewport) +{ + return ImGui::GetForegroundDrawList(viewport); +} +CIMGUI_API void igInitialize(ImGuiContext* context) +{ + return ImGui::Initialize(context); +} +CIMGUI_API void igShutdown(ImGuiContext* context) +{ + return ImGui::Shutdown(context); +} +CIMGUI_API void igUpdateHoveredWindowAndCaptureFlags() +{ + return ImGui::UpdateHoveredWindowAndCaptureFlags(); +} +CIMGUI_API void igStartMouseMovingWindow(ImGuiWindow* window) +{ + return ImGui::StartMouseMovingWindow(window); +} +CIMGUI_API void igUpdateMouseMovingWindowNewFrame() +{ + return ImGui::UpdateMouseMovingWindowNewFrame(); +} +CIMGUI_API void igUpdateMouseMovingWindowEndFrame() +{ + return ImGui::UpdateMouseMovingWindowEndFrame(); +} +CIMGUI_API ImGuiID igAddContextHook(ImGuiContext* context,const ImGuiContextHook* hook) +{ + return ImGui::AddContextHook(context,hook); +} +CIMGUI_API void igRemoveContextHook(ImGuiContext* context,ImGuiID hook_to_remove) +{ + return ImGui::RemoveContextHook(context,hook_to_remove); +} +CIMGUI_API void igCallContextHooks(ImGuiContext* context,ImGuiContextHookType type) +{ + return ImGui::CallContextHooks(context,type); +} +CIMGUI_API void igMarkIniSettingsDirty_Nil() +{ + return ImGui::MarkIniSettingsDirty(); +} +CIMGUI_API void igMarkIniSettingsDirty_WindowPtr(ImGuiWindow* window) +{ + return ImGui::MarkIniSettingsDirty(window); +} +CIMGUI_API void igClearIniSettings() +{ + return ImGui::ClearIniSettings(); +} +CIMGUI_API ImGuiWindowSettings* igCreateNewWindowSettings(const char* name) +{ + return ImGui::CreateNewWindowSettings(name); +} +CIMGUI_API ImGuiWindowSettings* igFindWindowSettings(ImGuiID id) +{ + return ImGui::FindWindowSettings(id); +} +CIMGUI_API ImGuiWindowSettings* igFindOrCreateWindowSettings(const char* name) +{ + return ImGui::FindOrCreateWindowSettings(name); +} +CIMGUI_API ImGuiSettingsHandler* igFindSettingsHandler(const char* type_name) +{ + return ImGui::FindSettingsHandler(type_name); +} +CIMGUI_API void igSetNextWindowScroll(const ImVec2 scroll) +{ + return ImGui::SetNextWindowScroll(scroll); +} +CIMGUI_API void igSetScrollX_WindowPtr(ImGuiWindow* window,float scroll_x) +{ + return ImGui::SetScrollX(window,scroll_x); +} +CIMGUI_API void igSetScrollY_WindowPtr(ImGuiWindow* window,float scroll_y) +{ + return ImGui::SetScrollY(window,scroll_y); +} +CIMGUI_API void igSetScrollFromPosX_WindowPtr(ImGuiWindow* window,float local_x,float center_x_ratio) +{ + return ImGui::SetScrollFromPosX(window,local_x,center_x_ratio); +} +CIMGUI_API void igSetScrollFromPosY_WindowPtr(ImGuiWindow* window,float local_y,float center_y_ratio) +{ + return ImGui::SetScrollFromPosY(window,local_y,center_y_ratio); +} +CIMGUI_API void igScrollToItem(ImGuiScrollFlags flags) +{ + return ImGui::ScrollToItem(flags); +} +CIMGUI_API void igScrollToRect(ImGuiWindow* window,const ImRect rect,ImGuiScrollFlags flags) +{ + return ImGui::ScrollToRect(window,rect,flags); +} +CIMGUI_API void igScrollToRectEx(ImVec2 *pOut,ImGuiWindow* window,const ImRect rect,ImGuiScrollFlags flags) +{ + *pOut = ImGui::ScrollToRectEx(window,rect,flags); +} +CIMGUI_API void igScrollToBringRectIntoView(ImGuiWindow* window,const ImRect rect) +{ + return ImGui::ScrollToBringRectIntoView(window,rect); +} +CIMGUI_API ImGuiID igGetItemID() +{ + return ImGui::GetItemID(); +} +CIMGUI_API ImGuiItemStatusFlags igGetItemStatusFlags() +{ + return ImGui::GetItemStatusFlags(); +} +CIMGUI_API ImGuiItemFlags igGetItemFlags() +{ + return ImGui::GetItemFlags(); +} +CIMGUI_API ImGuiID igGetActiveID() +{ + return ImGui::GetActiveID(); +} +CIMGUI_API ImGuiID igGetFocusID() +{ + return ImGui::GetFocusID(); +} +CIMGUI_API void igSetActiveID(ImGuiID id,ImGuiWindow* window) +{ + return ImGui::SetActiveID(id,window); +} +CIMGUI_API void igSetFocusID(ImGuiID id,ImGuiWindow* window) +{ + return ImGui::SetFocusID(id,window); +} +CIMGUI_API void igClearActiveID() +{ + return ImGui::ClearActiveID(); +} +CIMGUI_API ImGuiID igGetHoveredID() +{ + return ImGui::GetHoveredID(); +} +CIMGUI_API void igSetHoveredID(ImGuiID id) +{ + return ImGui::SetHoveredID(id); +} +CIMGUI_API void igKeepAliveID(ImGuiID id) +{ + return ImGui::KeepAliveID(id); +} +CIMGUI_API void igMarkItemEdited(ImGuiID id) +{ + return ImGui::MarkItemEdited(id); +} +CIMGUI_API void igPushOverrideID(ImGuiID id) +{ + return ImGui::PushOverrideID(id); +} +CIMGUI_API ImGuiID igGetIDWithSeed(const char* str_id_begin,const char* str_id_end,ImGuiID seed) +{ + return ImGui::GetIDWithSeed(str_id_begin,str_id_end,seed); +} +CIMGUI_API void igItemSize_Vec2(const ImVec2 size,float text_baseline_y) +{ + return ImGui::ItemSize(size,text_baseline_y); +} +CIMGUI_API void igItemSize_Rect(const ImRect bb,float text_baseline_y) +{ + return ImGui::ItemSize(bb,text_baseline_y); +} +CIMGUI_API bool igItemAdd(const ImRect bb,ImGuiID id,const ImRect* nav_bb,ImGuiItemFlags extra_flags) +{ + return ImGui::ItemAdd(bb,id,nav_bb,extra_flags); +} +CIMGUI_API bool igItemHoverable(const ImRect bb,ImGuiID id) +{ + return ImGui::ItemHoverable(bb,id); +} +CIMGUI_API bool igIsClippedEx(const ImRect bb,ImGuiID id) +{ + return ImGui::IsClippedEx(bb,id); +} +CIMGUI_API void igSetLastItemData(ImGuiID item_id,ImGuiItemFlags in_flags,ImGuiItemStatusFlags status_flags,const ImRect item_rect) +{ + return ImGui::SetLastItemData(item_id,in_flags,status_flags,item_rect); +} +CIMGUI_API void igCalcItemSize(ImVec2 *pOut,ImVec2 size,float default_w,float default_h) +{ + *pOut = ImGui::CalcItemSize(size,default_w,default_h); +} +CIMGUI_API float igCalcWrapWidthForPos(const ImVec2 pos,float wrap_pos_x) +{ + return ImGui::CalcWrapWidthForPos(pos,wrap_pos_x); +} +CIMGUI_API void igPushMultiItemsWidths(int components,float width_full) +{ + return ImGui::PushMultiItemsWidths(components,width_full); +} +CIMGUI_API bool igIsItemToggledSelection() +{ + return ImGui::IsItemToggledSelection(); +} +CIMGUI_API void igGetContentRegionMaxAbs(ImVec2 *pOut) +{ + *pOut = ImGui::GetContentRegionMaxAbs(); +} +CIMGUI_API void igShrinkWidths(ImGuiShrinkWidthItem* items,int count,float width_excess) +{ + return ImGui::ShrinkWidths(items,count,width_excess); +} +CIMGUI_API void igPushItemFlag(ImGuiItemFlags option,bool enabled) +{ + return ImGui::PushItemFlag(option,enabled); +} +CIMGUI_API void igPopItemFlag() +{ + return ImGui::PopItemFlag(); +} +CIMGUI_API void igLogBegin(ImGuiLogType type,int auto_open_depth) +{ + return ImGui::LogBegin(type,auto_open_depth); +} +CIMGUI_API void igLogToBuffer(int auto_open_depth) +{ + return ImGui::LogToBuffer(auto_open_depth); +} +CIMGUI_API void igLogRenderedText(const ImVec2* ref_pos,const char* text,const char* text_end) +{ + return ImGui::LogRenderedText(ref_pos,text,text_end); +} +CIMGUI_API void igLogSetNextTextDecoration(const char* prefix,const char* suffix) +{ + return ImGui::LogSetNextTextDecoration(prefix,suffix); +} +CIMGUI_API bool igBeginChildEx(const char* name,ImGuiID id,const ImVec2 size_arg,bool border,ImGuiWindowFlags flags) +{ + return ImGui::BeginChildEx(name,id,size_arg,border,flags); +} +CIMGUI_API void igOpenPopupEx(ImGuiID id,ImGuiPopupFlags popup_flags) +{ + return ImGui::OpenPopupEx(id,popup_flags); +} +CIMGUI_API void igClosePopupToLevel(int remaining,bool restore_focus_to_window_under_popup) +{ + return ImGui::ClosePopupToLevel(remaining,restore_focus_to_window_under_popup); +} +CIMGUI_API void igClosePopupsOverWindow(ImGuiWindow* ref_window,bool restore_focus_to_window_under_popup) +{ + return ImGui::ClosePopupsOverWindow(ref_window,restore_focus_to_window_under_popup); +} +CIMGUI_API void igClosePopupsExceptModals() +{ + return ImGui::ClosePopupsExceptModals(); +} +CIMGUI_API bool igIsPopupOpen_ID(ImGuiID id,ImGuiPopupFlags popup_flags) +{ + return ImGui::IsPopupOpen(id,popup_flags); +} +CIMGUI_API bool igBeginPopupEx(ImGuiID id,ImGuiWindowFlags extra_flags) +{ + return ImGui::BeginPopupEx(id,extra_flags); +} +CIMGUI_API void igBeginTooltipEx(ImGuiTooltipFlags tooltip_flags,ImGuiWindowFlags extra_window_flags) +{ + return ImGui::BeginTooltipEx(tooltip_flags,extra_window_flags); +} +CIMGUI_API void igGetPopupAllowedExtentRect(ImRect *pOut,ImGuiWindow* window) +{ + *pOut = ImGui::GetPopupAllowedExtentRect(window); +} +CIMGUI_API ImGuiWindow* igGetTopMostPopupModal() +{ + return ImGui::GetTopMostPopupModal(); +} +CIMGUI_API ImGuiWindow* igGetTopMostAndVisiblePopupModal() +{ + return ImGui::GetTopMostAndVisiblePopupModal(); +} +CIMGUI_API void igFindBestWindowPosForPopup(ImVec2 *pOut,ImGuiWindow* window) +{ + *pOut = ImGui::FindBestWindowPosForPopup(window); +} +CIMGUI_API void igFindBestWindowPosForPopupEx(ImVec2 *pOut,const ImVec2 ref_pos,const ImVec2 size,ImGuiDir* last_dir,const ImRect r_outer,const ImRect r_avoid,ImGuiPopupPositionPolicy policy) +{ + *pOut = ImGui::FindBestWindowPosForPopupEx(ref_pos,size,last_dir,r_outer,r_avoid,policy); +} +CIMGUI_API bool igBeginViewportSideBar(const char* name,ImGuiViewport* viewport,ImGuiDir dir,float size,ImGuiWindowFlags window_flags) +{ + return ImGui::BeginViewportSideBar(name,viewport,dir,size,window_flags); +} +CIMGUI_API bool igBeginMenuEx(const char* label,const char* icon,bool enabled) +{ + return ImGui::BeginMenuEx(label,icon,enabled); +} +CIMGUI_API bool igMenuItemEx(const char* label,const char* icon,const char* shortcut,bool selected,bool enabled) +{ + return ImGui::MenuItemEx(label,icon,shortcut,selected,enabled); +} +CIMGUI_API bool igBeginComboPopup(ImGuiID popup_id,const ImRect bb,ImGuiComboFlags flags) +{ + return ImGui::BeginComboPopup(popup_id,bb,flags); +} +CIMGUI_API bool igBeginComboPreview() +{ + return ImGui::BeginComboPreview(); +} +CIMGUI_API void igEndComboPreview() +{ + return ImGui::EndComboPreview(); +} +CIMGUI_API void igNavInitWindow(ImGuiWindow* window,bool force_reinit) +{ + return ImGui::NavInitWindow(window,force_reinit); +} +CIMGUI_API void igNavInitRequestApplyResult() +{ + return ImGui::NavInitRequestApplyResult(); +} +CIMGUI_API bool igNavMoveRequestButNoResultYet() +{ + return ImGui::NavMoveRequestButNoResultYet(); +} +CIMGUI_API void igNavMoveRequestSubmit(ImGuiDir move_dir,ImGuiDir clip_dir,ImGuiNavMoveFlags move_flags,ImGuiScrollFlags scroll_flags) +{ + return ImGui::NavMoveRequestSubmit(move_dir,clip_dir,move_flags,scroll_flags); +} +CIMGUI_API void igNavMoveRequestForward(ImGuiDir move_dir,ImGuiDir clip_dir,ImGuiNavMoveFlags move_flags,ImGuiScrollFlags scroll_flags) +{ + return ImGui::NavMoveRequestForward(move_dir,clip_dir,move_flags,scroll_flags); +} +CIMGUI_API void igNavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) +{ + return ImGui::NavMoveRequestResolveWithLastItem(result); +} +CIMGUI_API void igNavMoveRequestCancel() +{ + return ImGui::NavMoveRequestCancel(); +} +CIMGUI_API void igNavMoveRequestApplyResult() +{ + return ImGui::NavMoveRequestApplyResult(); +} +CIMGUI_API void igNavMoveRequestTryWrapping(ImGuiWindow* window,ImGuiNavMoveFlags move_flags) +{ + return ImGui::NavMoveRequestTryWrapping(window,move_flags); +} +CIMGUI_API float igGetNavInputAmount(ImGuiNavInput n,ImGuiInputReadMode mode) +{ + return ImGui::GetNavInputAmount(n,mode); +} +CIMGUI_API void igGetNavInputAmount2d(ImVec2 *pOut,ImGuiNavDirSourceFlags dir_sources,ImGuiInputReadMode mode,float slow_factor,float fast_factor) +{ + *pOut = ImGui::GetNavInputAmount2d(dir_sources,mode,slow_factor,fast_factor); +} +CIMGUI_API int igCalcTypematicRepeatAmount(float t0,float t1,float repeat_delay,float repeat_rate) +{ + return ImGui::CalcTypematicRepeatAmount(t0,t1,repeat_delay,repeat_rate); +} +CIMGUI_API void igActivateItem(ImGuiID id) +{ + return ImGui::ActivateItem(id); +} +CIMGUI_API void igSetNavID(ImGuiID id,ImGuiNavLayer nav_layer,ImGuiID focus_scope_id,const ImRect rect_rel) +{ + return ImGui::SetNavID(id,nav_layer,focus_scope_id,rect_rel); +} +CIMGUI_API void igPushFocusScope(ImGuiID id) +{ + return ImGui::PushFocusScope(id); +} +CIMGUI_API void igPopFocusScope() +{ + return ImGui::PopFocusScope(); +} +CIMGUI_API ImGuiID igGetFocusedFocusScope() +{ + return ImGui::GetFocusedFocusScope(); +} +CIMGUI_API ImGuiID igGetFocusScope() +{ + return ImGui::GetFocusScope(); +} +CIMGUI_API void igSetItemUsingMouseWheel() +{ + return ImGui::SetItemUsingMouseWheel(); +} +CIMGUI_API void igSetActiveIdUsingNavAndKeys() +{ + return ImGui::SetActiveIdUsingNavAndKeys(); +} +CIMGUI_API bool igIsActiveIdUsingNavDir(ImGuiDir dir) +{ + return ImGui::IsActiveIdUsingNavDir(dir); +} +CIMGUI_API bool igIsActiveIdUsingNavInput(ImGuiNavInput input) +{ + return ImGui::IsActiveIdUsingNavInput(input); +} +CIMGUI_API bool igIsActiveIdUsingKey(ImGuiKey key) +{ + return ImGui::IsActiveIdUsingKey(key); +} +CIMGUI_API bool igIsMouseDragPastThreshold(ImGuiMouseButton button,float lock_threshold) +{ + return ImGui::IsMouseDragPastThreshold(button,lock_threshold); +} +CIMGUI_API bool igIsKeyPressedMap(ImGuiKey key,bool repeat) +{ + return ImGui::IsKeyPressedMap(key,repeat); +} +CIMGUI_API bool igIsNavInputDown(ImGuiNavInput n) +{ + return ImGui::IsNavInputDown(n); +} +CIMGUI_API bool igIsNavInputTest(ImGuiNavInput n,ImGuiInputReadMode rm) +{ + return ImGui::IsNavInputTest(n,rm); +} +CIMGUI_API ImGuiKeyModFlags igGetMergedKeyModFlags() +{ + return ImGui::GetMergedKeyModFlags(); +} +CIMGUI_API bool igBeginDragDropTargetCustom(const ImRect bb,ImGuiID id) +{ + return ImGui::BeginDragDropTargetCustom(bb,id); +} +CIMGUI_API void igClearDragDrop() +{ + return ImGui::ClearDragDrop(); +} +CIMGUI_API bool igIsDragDropPayloadBeingAccepted() +{ + return ImGui::IsDragDropPayloadBeingAccepted(); +} +CIMGUI_API void igSetWindowClipRectBeforeSetChannel(ImGuiWindow* window,const ImRect clip_rect) +{ + return ImGui::SetWindowClipRectBeforeSetChannel(window,clip_rect); +} +CIMGUI_API void igBeginColumns(const char* str_id,int count,ImGuiOldColumnFlags flags) +{ + return ImGui::BeginColumns(str_id,count,flags); +} +CIMGUI_API void igEndColumns() +{ + return ImGui::EndColumns(); +} +CIMGUI_API void igPushColumnClipRect(int column_index) +{ + return ImGui::PushColumnClipRect(column_index); +} +CIMGUI_API void igPushColumnsBackground() +{ + return ImGui::PushColumnsBackground(); +} +CIMGUI_API void igPopColumnsBackground() +{ + return ImGui::PopColumnsBackground(); +} +CIMGUI_API ImGuiID igGetColumnsID(const char* str_id,int count) +{ + return ImGui::GetColumnsID(str_id,count); +} +CIMGUI_API ImGuiOldColumns* igFindOrCreateColumns(ImGuiWindow* window,ImGuiID id) +{ + return ImGui::FindOrCreateColumns(window,id); +} +CIMGUI_API float igGetColumnOffsetFromNorm(const ImGuiOldColumns* columns,float offset_norm) +{ + return ImGui::GetColumnOffsetFromNorm(columns,offset_norm); +} +CIMGUI_API float igGetColumnNormFromOffset(const ImGuiOldColumns* columns,float offset) +{ + return ImGui::GetColumnNormFromOffset(columns,offset); +} +CIMGUI_API void igTableOpenContextMenu(int column_n) +{ + return ImGui::TableOpenContextMenu(column_n); +} +CIMGUI_API void igTableSetColumnWidth(int column_n,float width) +{ + return ImGui::TableSetColumnWidth(column_n,width); +} +CIMGUI_API void igTableSetColumnSortDirection(int column_n,ImGuiSortDirection sort_direction,bool append_to_sort_specs) +{ + return ImGui::TableSetColumnSortDirection(column_n,sort_direction,append_to_sort_specs); +} +CIMGUI_API int igTableGetHoveredColumn() +{ + return ImGui::TableGetHoveredColumn(); +} +CIMGUI_API float igTableGetHeaderRowHeight() +{ + return ImGui::TableGetHeaderRowHeight(); +} +CIMGUI_API void igTablePushBackgroundChannel() +{ + return ImGui::TablePushBackgroundChannel(); +} +CIMGUI_API void igTablePopBackgroundChannel() +{ + return ImGui::TablePopBackgroundChannel(); +} +CIMGUI_API ImGuiTable* igGetCurrentTable() +{ + return ImGui::GetCurrentTable(); +} +CIMGUI_API ImGuiTable* igTableFindByID(ImGuiID id) +{ + return ImGui::TableFindByID(id); +} +CIMGUI_API bool igBeginTableEx(const char* name,ImGuiID id,int columns_count,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width) +{ + return ImGui::BeginTableEx(name,id,columns_count,flags,outer_size,inner_width); +} +CIMGUI_API void igTableBeginInitMemory(ImGuiTable* table,int columns_count) +{ + return ImGui::TableBeginInitMemory(table,columns_count); +} +CIMGUI_API void igTableBeginApplyRequests(ImGuiTable* table) +{ + return ImGui::TableBeginApplyRequests(table); +} +CIMGUI_API void igTableSetupDrawChannels(ImGuiTable* table) +{ + return ImGui::TableSetupDrawChannels(table); +} +CIMGUI_API void igTableUpdateLayout(ImGuiTable* table) +{ + return ImGui::TableUpdateLayout(table); +} +CIMGUI_API void igTableUpdateBorders(ImGuiTable* table) +{ + return ImGui::TableUpdateBorders(table); +} +CIMGUI_API void igTableUpdateColumnsWeightFromWidth(ImGuiTable* table) +{ + return ImGui::TableUpdateColumnsWeightFromWidth(table); +} +CIMGUI_API void igTableDrawBorders(ImGuiTable* table) +{ + return ImGui::TableDrawBorders(table); +} +CIMGUI_API void igTableDrawContextMenu(ImGuiTable* table) +{ + return ImGui::TableDrawContextMenu(table); +} +CIMGUI_API void igTableMergeDrawChannels(ImGuiTable* table) +{ + return ImGui::TableMergeDrawChannels(table); +} +CIMGUI_API void igTableSortSpecsSanitize(ImGuiTable* table) +{ + return ImGui::TableSortSpecsSanitize(table); +} +CIMGUI_API void igTableSortSpecsBuild(ImGuiTable* table) +{ + return ImGui::TableSortSpecsBuild(table); +} +CIMGUI_API ImGuiSortDirection igTableGetColumnNextSortDirection(ImGuiTableColumn* column) +{ + return ImGui::TableGetColumnNextSortDirection(column); +} +CIMGUI_API void igTableFixColumnSortDirection(ImGuiTable* table,ImGuiTableColumn* column) +{ + return ImGui::TableFixColumnSortDirection(table,column); +} +CIMGUI_API float igTableGetColumnWidthAuto(ImGuiTable* table,ImGuiTableColumn* column) +{ + return ImGui::TableGetColumnWidthAuto(table,column); +} +CIMGUI_API void igTableBeginRow(ImGuiTable* table) +{ + return ImGui::TableBeginRow(table); +} +CIMGUI_API void igTableEndRow(ImGuiTable* table) +{ + return ImGui::TableEndRow(table); +} +CIMGUI_API void igTableBeginCell(ImGuiTable* table,int column_n) +{ + return ImGui::TableBeginCell(table,column_n); +} +CIMGUI_API void igTableEndCell(ImGuiTable* table) +{ + return ImGui::TableEndCell(table); +} +CIMGUI_API void igTableGetCellBgRect(ImRect *pOut,const ImGuiTable* table,int column_n) +{ + *pOut = ImGui::TableGetCellBgRect(table,column_n); +} +CIMGUI_API const char* igTableGetColumnName_TablePtr(const ImGuiTable* table,int column_n) +{ + return ImGui::TableGetColumnName(table,column_n); +} +CIMGUI_API ImGuiID igTableGetColumnResizeID(const ImGuiTable* table,int column_n,int instance_no) +{ + return ImGui::TableGetColumnResizeID(table,column_n,instance_no); +} +CIMGUI_API float igTableGetMaxColumnWidth(const ImGuiTable* table,int column_n) +{ + return ImGui::TableGetMaxColumnWidth(table,column_n); +} +CIMGUI_API void igTableSetColumnWidthAutoSingle(ImGuiTable* table,int column_n) +{ + return ImGui::TableSetColumnWidthAutoSingle(table,column_n); +} +CIMGUI_API void igTableSetColumnWidthAutoAll(ImGuiTable* table) +{ + return ImGui::TableSetColumnWidthAutoAll(table); +} +CIMGUI_API void igTableRemove(ImGuiTable* table) +{ + return ImGui::TableRemove(table); +} +CIMGUI_API void igTableGcCompactTransientBuffers_TablePtr(ImGuiTable* table) +{ + return ImGui::TableGcCompactTransientBuffers(table); +} +CIMGUI_API void igTableGcCompactTransientBuffers_TableTempDataPtr(ImGuiTableTempData* table) +{ + return ImGui::TableGcCompactTransientBuffers(table); +} +CIMGUI_API void igTableGcCompactSettings() +{ + return ImGui::TableGcCompactSettings(); +} +CIMGUI_API void igTableLoadSettings(ImGuiTable* table) +{ + return ImGui::TableLoadSettings(table); +} +CIMGUI_API void igTableSaveSettings(ImGuiTable* table) +{ + return ImGui::TableSaveSettings(table); +} +CIMGUI_API void igTableResetSettings(ImGuiTable* table) +{ + return ImGui::TableResetSettings(table); +} +CIMGUI_API ImGuiTableSettings* igTableGetBoundSettings(ImGuiTable* table) +{ + return ImGui::TableGetBoundSettings(table); +} +CIMGUI_API void igTableSettingsInstallHandler(ImGuiContext* context) +{ + return ImGui::TableSettingsInstallHandler(context); +} +CIMGUI_API ImGuiTableSettings* igTableSettingsCreate(ImGuiID id,int columns_count) +{ + return ImGui::TableSettingsCreate(id,columns_count); +} +CIMGUI_API ImGuiTableSettings* igTableSettingsFindByID(ImGuiID id) +{ + return ImGui::TableSettingsFindByID(id); +} +CIMGUI_API bool igBeginTabBarEx(ImGuiTabBar* tab_bar,const ImRect bb,ImGuiTabBarFlags flags) +{ + return ImGui::BeginTabBarEx(tab_bar,bb,flags); +} +CIMGUI_API ImGuiTabItem* igTabBarFindTabByID(ImGuiTabBar* tab_bar,ImGuiID tab_id) +{ + return ImGui::TabBarFindTabByID(tab_bar,tab_id); +} +CIMGUI_API void igTabBarRemoveTab(ImGuiTabBar* tab_bar,ImGuiID tab_id) +{ + return ImGui::TabBarRemoveTab(tab_bar,tab_id); +} +CIMGUI_API void igTabBarCloseTab(ImGuiTabBar* tab_bar,ImGuiTabItem* tab) +{ + return ImGui::TabBarCloseTab(tab_bar,tab); +} +CIMGUI_API void igTabBarQueueReorder(ImGuiTabBar* tab_bar,const ImGuiTabItem* tab,int offset) +{ + return ImGui::TabBarQueueReorder(tab_bar,tab,offset); +} +CIMGUI_API void igTabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar,const ImGuiTabItem* tab,ImVec2 mouse_pos) +{ + return ImGui::TabBarQueueReorderFromMousePos(tab_bar,tab,mouse_pos); +} +CIMGUI_API bool igTabBarProcessReorder(ImGuiTabBar* tab_bar) +{ + return ImGui::TabBarProcessReorder(tab_bar); +} +CIMGUI_API bool igTabItemEx(ImGuiTabBar* tab_bar,const char* label,bool* p_open,ImGuiTabItemFlags flags) +{ + return ImGui::TabItemEx(tab_bar,label,p_open,flags); +} +CIMGUI_API void igTabItemCalcSize(ImVec2 *pOut,const char* label,bool has_close_button) +{ + *pOut = ImGui::TabItemCalcSize(label,has_close_button); +} +CIMGUI_API void igTabItemBackground(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImU32 col) +{ + return ImGui::TabItemBackground(draw_list,bb,flags,col); +} +CIMGUI_API void igTabItemLabelAndCloseButton(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImVec2 frame_padding,const char* label,ImGuiID tab_id,ImGuiID close_button_id,bool is_contents_visible,bool* out_just_closed,bool* out_text_clipped) +{ + return ImGui::TabItemLabelAndCloseButton(draw_list,bb,flags,frame_padding,label,tab_id,close_button_id,is_contents_visible,out_just_closed,out_text_clipped); +} +CIMGUI_API void igRenderText(ImVec2 pos,const char* text,const char* text_end,bool hide_text_after_hash) +{ + return ImGui::RenderText(pos,text,text_end,hide_text_after_hash); +} +CIMGUI_API void igRenderTextWrapped(ImVec2 pos,const char* text,const char* text_end,float wrap_width) +{ + return ImGui::RenderTextWrapped(pos,text,text_end,wrap_width); +} +CIMGUI_API void igRenderTextClipped(const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect) +{ + return ImGui::RenderTextClipped(pos_min,pos_max,text,text_end,text_size_if_known,align,clip_rect); +} +CIMGUI_API void igRenderTextClippedEx(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect) +{ + return ImGui::RenderTextClippedEx(draw_list,pos_min,pos_max,text,text_end,text_size_if_known,align,clip_rect); +} +CIMGUI_API void igRenderTextEllipsis(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,float clip_max_x,float ellipsis_max_x,const char* text,const char* text_end,const ImVec2* text_size_if_known) +{ + return ImGui::RenderTextEllipsis(draw_list,pos_min,pos_max,clip_max_x,ellipsis_max_x,text,text_end,text_size_if_known); +} +CIMGUI_API void igRenderFrame(ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,bool border,float rounding) +{ + return ImGui::RenderFrame(p_min,p_max,fill_col,border,rounding); +} +CIMGUI_API void igRenderFrameBorder(ImVec2 p_min,ImVec2 p_max,float rounding) +{ + return ImGui::RenderFrameBorder(p_min,p_max,rounding); +} +CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,float grid_step,ImVec2 grid_off,float rounding,ImDrawFlags flags) +{ + return ImGui::RenderColorRectWithAlphaCheckerboard(draw_list,p_min,p_max,fill_col,grid_step,grid_off,rounding,flags); +} +CIMGUI_API void igRenderNavHighlight(const ImRect bb,ImGuiID id,ImGuiNavHighlightFlags flags) +{ + return ImGui::RenderNavHighlight(bb,id,flags); +} +CIMGUI_API const char* igFindRenderedTextEnd(const char* text,const char* text_end) +{ + return ImGui::FindRenderedTextEnd(text,text_end); +} +CIMGUI_API void igRenderArrow(ImDrawList* draw_list,ImVec2 pos,ImU32 col,ImGuiDir dir,float scale) +{ + return ImGui::RenderArrow(draw_list,pos,col,dir,scale); +} +CIMGUI_API void igRenderBullet(ImDrawList* draw_list,ImVec2 pos,ImU32 col) +{ + return ImGui::RenderBullet(draw_list,pos,col); +} +CIMGUI_API void igRenderCheckMark(ImDrawList* draw_list,ImVec2 pos,ImU32 col,float sz) +{ + return ImGui::RenderCheckMark(draw_list,pos,col,sz); +} +CIMGUI_API void igRenderMouseCursor(ImDrawList* draw_list,ImVec2 pos,float scale,ImGuiMouseCursor mouse_cursor,ImU32 col_fill,ImU32 col_border,ImU32 col_shadow) +{ + return ImGui::RenderMouseCursor(draw_list,pos,scale,mouse_cursor,col_fill,col_border,col_shadow); +} +CIMGUI_API void igRenderArrowPointingAt(ImDrawList* draw_list,ImVec2 pos,ImVec2 half_sz,ImGuiDir direction,ImU32 col) +{ + return ImGui::RenderArrowPointingAt(draw_list,pos,half_sz,direction,col); +} +CIMGUI_API void igRenderRectFilledRangeH(ImDrawList* draw_list,const ImRect rect,ImU32 col,float x_start_norm,float x_end_norm,float rounding) +{ + return ImGui::RenderRectFilledRangeH(draw_list,rect,col,x_start_norm,x_end_norm,rounding); +} +CIMGUI_API void igRenderRectFilledWithHole(ImDrawList* draw_list,ImRect outer,ImRect inner,ImU32 col,float rounding) +{ + return ImGui::RenderRectFilledWithHole(draw_list,outer,inner,col,rounding); +} +CIMGUI_API void igTextEx(const char* text,const char* text_end,ImGuiTextFlags flags) +{ + return ImGui::TextEx(text,text_end,flags); +} +CIMGUI_API bool igButtonEx(const char* label,const ImVec2 size_arg,ImGuiButtonFlags flags) +{ + return ImGui::ButtonEx(label,size_arg,flags); +} +CIMGUI_API bool igCloseButton(ImGuiID id,const ImVec2 pos) +{ + return ImGui::CloseButton(id,pos); +} +CIMGUI_API bool igCollapseButton(ImGuiID id,const ImVec2 pos) +{ + return ImGui::CollapseButton(id,pos); +} +CIMGUI_API bool igArrowButtonEx(const char* str_id,ImGuiDir dir,ImVec2 size_arg,ImGuiButtonFlags flags) +{ + return ImGui::ArrowButtonEx(str_id,dir,size_arg,flags); +} +CIMGUI_API void igScrollbar(ImGuiAxis axis) +{ + return ImGui::Scrollbar(axis); +} +CIMGUI_API bool igScrollbarEx(const ImRect bb,ImGuiID id,ImGuiAxis axis,ImS64* p_scroll_v,ImS64 avail_v,ImS64 contents_v,ImDrawFlags flags) +{ + return ImGui::ScrollbarEx(bb,id,axis,p_scroll_v,avail_v,contents_v,flags); +} +CIMGUI_API bool igImageButtonEx(ImGuiID id,ImTextureID texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec2 padding,const ImVec4 bg_col,const ImVec4 tint_col) +{ + return ImGui::ImageButtonEx(id,texture_id,size,uv0,uv1,padding,bg_col,tint_col); +} +CIMGUI_API void igGetWindowScrollbarRect(ImRect *pOut,ImGuiWindow* window,ImGuiAxis axis) +{ + *pOut = ImGui::GetWindowScrollbarRect(window,axis); +} +CIMGUI_API ImGuiID igGetWindowScrollbarID(ImGuiWindow* window,ImGuiAxis axis) +{ + return ImGui::GetWindowScrollbarID(window,axis); +} +CIMGUI_API ImGuiID igGetWindowResizeCornerID(ImGuiWindow* window,int n) +{ + return ImGui::GetWindowResizeCornerID(window,n); +} +CIMGUI_API ImGuiID igGetWindowResizeBorderID(ImGuiWindow* window,ImGuiDir dir) +{ + return ImGui::GetWindowResizeBorderID(window,dir); +} +CIMGUI_API void igSeparatorEx(ImGuiSeparatorFlags flags) +{ + return ImGui::SeparatorEx(flags); +} +CIMGUI_API bool igCheckboxFlags_S64Ptr(const char* label,ImS64* flags,ImS64 flags_value) +{ + return ImGui::CheckboxFlags(label,flags,flags_value); +} +CIMGUI_API bool igCheckboxFlags_U64Ptr(const char* label,ImU64* flags,ImU64 flags_value) +{ + return ImGui::CheckboxFlags(label,flags,flags_value); +} +CIMGUI_API bool igButtonBehavior(const ImRect bb,ImGuiID id,bool* out_hovered,bool* out_held,ImGuiButtonFlags flags) +{ + return ImGui::ButtonBehavior(bb,id,out_hovered,out_held,flags); +} +CIMGUI_API bool igDragBehavior(ImGuiID id,ImGuiDataType data_type,void* p_v,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags) +{ + return ImGui::DragBehavior(id,data_type,p_v,v_speed,p_min,p_max,format,flags); +} +CIMGUI_API bool igSliderBehavior(const ImRect bb,ImGuiID id,ImGuiDataType data_type,void* p_v,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags,ImRect* out_grab_bb) +{ + return ImGui::SliderBehavior(bb,id,data_type,p_v,p_min,p_max,format,flags,out_grab_bb); +} +CIMGUI_API bool igSplitterBehavior(const ImRect bb,ImGuiID id,ImGuiAxis axis,float* size1,float* size2,float min_size1,float min_size2,float hover_extend,float hover_visibility_delay) +{ + return ImGui::SplitterBehavior(bb,id,axis,size1,size2,min_size1,min_size2,hover_extend,hover_visibility_delay); +} +CIMGUI_API bool igTreeNodeBehavior(ImGuiID id,ImGuiTreeNodeFlags flags,const char* label,const char* label_end) +{ + return ImGui::TreeNodeBehavior(id,flags,label,label_end); +} +CIMGUI_API bool igTreeNodeBehaviorIsOpen(ImGuiID id,ImGuiTreeNodeFlags flags) +{ + return ImGui::TreeNodeBehaviorIsOpen(id,flags); +} +CIMGUI_API void igTreePushOverrideID(ImGuiID id) +{ + return ImGui::TreePushOverrideID(id); +} +CIMGUI_API const ImGuiDataTypeInfo* igDataTypeGetInfo(ImGuiDataType data_type) +{ + return ImGui::DataTypeGetInfo(data_type); +} +CIMGUI_API int igDataTypeFormatString(char* buf,int buf_size,ImGuiDataType data_type,const void* p_data,const char* format) +{ + return ImGui::DataTypeFormatString(buf,buf_size,data_type,p_data,format); +} +CIMGUI_API void igDataTypeApplyOp(ImGuiDataType data_type,int op,void* output,const void* arg_1,const void* arg_2) +{ + return ImGui::DataTypeApplyOp(data_type,op,output,arg_1,arg_2); +} +CIMGUI_API bool igDataTypeApplyOpFromText(const char* buf,const char* initial_value_buf,ImGuiDataType data_type,void* p_data,const char* format) +{ + return ImGui::DataTypeApplyOpFromText(buf,initial_value_buf,data_type,p_data,format); +} +CIMGUI_API int igDataTypeCompare(ImGuiDataType data_type,const void* arg_1,const void* arg_2) +{ + return ImGui::DataTypeCompare(data_type,arg_1,arg_2); +} +CIMGUI_API bool igDataTypeClamp(ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max) +{ + return ImGui::DataTypeClamp(data_type,p_data,p_min,p_max); +} +CIMGUI_API bool igInputTextEx(const char* label,const char* hint,char* buf,int buf_size,const ImVec2 size_arg,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data) +{ + return ImGui::InputTextEx(label,hint,buf,buf_size,size_arg,flags,callback,user_data); +} +CIMGUI_API bool igTempInputText(const ImRect bb,ImGuiID id,const char* label,char* buf,int buf_size,ImGuiInputTextFlags flags) +{ + return ImGui::TempInputText(bb,id,label,buf,buf_size,flags); +} +CIMGUI_API bool igTempInputScalar(const ImRect bb,ImGuiID id,const char* label,ImGuiDataType data_type,void* p_data,const char* format,const void* p_clamp_min,const void* p_clamp_max) +{ + return ImGui::TempInputScalar(bb,id,label,data_type,p_data,format,p_clamp_min,p_clamp_max); +} +CIMGUI_API bool igTempInputIsActive(ImGuiID id) +{ + return ImGui::TempInputIsActive(id); +} +CIMGUI_API ImGuiInputTextState* igGetInputTextState(ImGuiID id) +{ + return ImGui::GetInputTextState(id); +} +CIMGUI_API void igColorTooltip(const char* text,const float* col,ImGuiColorEditFlags flags) +{ + return ImGui::ColorTooltip(text,col,flags); +} +CIMGUI_API void igColorEditOptionsPopup(const float* col,ImGuiColorEditFlags flags) +{ + return ImGui::ColorEditOptionsPopup(col,flags); +} +CIMGUI_API void igColorPickerOptionsPopup(const float* ref_col,ImGuiColorEditFlags flags) +{ + return ImGui::ColorPickerOptionsPopup(ref_col,flags); +} +CIMGUI_API int igPlotEx(ImGuiPlotType plot_type,const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 frame_size) +{ + return ImGui::PlotEx(plot_type,label,values_getter,data,values_count,values_offset,overlay_text,scale_min,scale_max,frame_size); +} +CIMGUI_API void igShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,ImVec2 gradient_p0,ImVec2 gradient_p1,ImU32 col0,ImU32 col1) +{ + return ImGui::ShadeVertsLinearColorGradientKeepAlpha(draw_list,vert_start_idx,vert_end_idx,gradient_p0,gradient_p1,col0,col1); +} +CIMGUI_API void igShadeVertsLinearUV(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,bool clamp) +{ + return ImGui::ShadeVertsLinearUV(draw_list,vert_start_idx,vert_end_idx,a,b,uv_a,uv_b,clamp); +} +CIMGUI_API void igGcCompactTransientMiscBuffers() +{ + return ImGui::GcCompactTransientMiscBuffers(); +} +CIMGUI_API void igGcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + return ImGui::GcCompactTransientWindowBuffers(window); +} +CIMGUI_API void igGcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + return ImGui::GcAwakeTransientWindowBuffers(window); +} +CIMGUI_API void igErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback,void* user_data) +{ + return ImGui::ErrorCheckEndFrameRecover(log_callback,user_data); +} +CIMGUI_API void igErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback,void* user_data) +{ + return ImGui::ErrorCheckEndWindowRecover(log_callback,user_data); +} +CIMGUI_API void igDebugDrawItemRect(ImU32 col) +{ + return ImGui::DebugDrawItemRect(col); +} +CIMGUI_API void igDebugStartItemPicker() +{ + return ImGui::DebugStartItemPicker(); +} +CIMGUI_API void igShowFontAtlas(ImFontAtlas* atlas) +{ + return ImGui::ShowFontAtlas(atlas); +} +CIMGUI_API void igDebugHookIdInfo(ImGuiID id,ImGuiDataType data_type,const void* data_id,const void* data_id_end) +{ + return ImGui::DebugHookIdInfo(id,data_type,data_id,data_id_end); +} +CIMGUI_API void igDebugNodeColumns(ImGuiOldColumns* columns) +{ + return ImGui::DebugNodeColumns(columns); +} +CIMGUI_API void igDebugNodeDrawList(ImGuiWindow* window,const ImDrawList* draw_list,const char* label) +{ + return ImGui::DebugNodeDrawList(window,draw_list,label); +} +CIMGUI_API void igDebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list,const ImDrawList* draw_list,const ImDrawCmd* draw_cmd,bool show_mesh,bool show_aabb) +{ + return ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(out_draw_list,draw_list,draw_cmd,show_mesh,show_aabb); +} +CIMGUI_API void igDebugNodeFont(ImFont* font) +{ + return ImGui::DebugNodeFont(font); +} +CIMGUI_API void igDebugNodeStorage(ImGuiStorage* storage,const char* label) +{ + return ImGui::DebugNodeStorage(storage,label); +} +CIMGUI_API void igDebugNodeTabBar(ImGuiTabBar* tab_bar,const char* label) +{ + return ImGui::DebugNodeTabBar(tab_bar,label); +} +CIMGUI_API void igDebugNodeTable(ImGuiTable* table) +{ + return ImGui::DebugNodeTable(table); +} +CIMGUI_API void igDebugNodeTableSettings(ImGuiTableSettings* settings) +{ + return ImGui::DebugNodeTableSettings(settings); +} +CIMGUI_API void igDebugNodeWindow(ImGuiWindow* window,const char* label) +{ + return ImGui::DebugNodeWindow(window,label); +} +CIMGUI_API void igDebugNodeWindowSettings(ImGuiWindowSettings* settings) +{ + return ImGui::DebugNodeWindowSettings(settings); +} +CIMGUI_API void igDebugNodeWindowsList(ImVector_ImGuiWindowPtr* windows,const char* label) +{ + return ImGui::DebugNodeWindowsList(windows,label); +} +CIMGUI_API void igDebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows,int windows_size,ImGuiWindow* parent_in_begin_stack) +{ + return ImGui::DebugNodeWindowsListByBeginStackParent(windows,windows_size,parent_in_begin_stack); +} +CIMGUI_API void igDebugNodeViewport(ImGuiViewportP* viewport) +{ + return ImGui::DebugNodeViewport(viewport); +} +CIMGUI_API void igDebugRenderViewportThumbnail(ImDrawList* draw_list,ImGuiViewportP* viewport,const ImRect bb) +{ + return ImGui::DebugRenderViewportThumbnail(draw_list,viewport,bb); +} +CIMGUI_API const ImFontBuilderIO* igImFontAtlasGetBuilderForStbTruetype() +{ + return ImFontAtlasGetBuilderForStbTruetype(); +} +CIMGUI_API void igImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + return ImFontAtlasBuildInit(atlas); +} +CIMGUI_API void igImFontAtlasBuildSetupFont(ImFontAtlas* atlas,ImFont* font,ImFontConfig* font_config,float ascent,float descent) +{ + return ImFontAtlasBuildSetupFont(atlas,font,font_config,ascent,descent); +} +CIMGUI_API void igImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas,void* stbrp_context_opaque) +{ + return ImFontAtlasBuildPackCustomRects(atlas,stbrp_context_opaque); +} +CIMGUI_API void igImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + return ImFontAtlasBuildFinish(atlas); +} +CIMGUI_API void igImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned char in_marker_pixel_value) +{ + return ImFontAtlasBuildRender8bppRectFromString(atlas,x,y,w,h,in_str,in_marker_char,in_marker_pixel_value); +} +CIMGUI_API void igImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned int in_marker_pixel_value) +{ + return ImFontAtlasBuildRender32bppRectFromString(atlas,x,y,w,h,in_str,in_marker_char,in_marker_pixel_value); +} +CIMGUI_API void igImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256],float in_multiply_factor) +{ + return ImFontAtlasBuildMultiplyCalcLookupTable(out_table,in_multiply_factor); +} +CIMGUI_API void igImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256],unsigned char* pixels,int x,int y,int w,int h,int stride) +{ + return ImFontAtlasBuildMultiplyRectAlpha8(table,pixels,x,y,w,h,stride); +} + + + +/////////////////////////////manual written functions +CIMGUI_API void igLogText(CONST char *fmt, ...) +{ + char buffer[256]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, 256, fmt, args); + va_end(args); + + ImGui::LogText("%s", buffer); +} +CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + buffer->appendfv(fmt, args); + va_end(args); +} + +CIMGUI_API float igGET_FLT_MAX() +{ + return FLT_MAX; +} + +CIMGUI_API float igGET_FLT_MIN() +{ + return FLT_MIN; +} + + +CIMGUI_API ImVector_ImWchar* ImVector_ImWchar_create() +{ + return IM_NEW(ImVector) (); +} + +CIMGUI_API void ImVector_ImWchar_destroy(ImVector_ImWchar* self) +{ + IM_DELETE(self); +} + +CIMGUI_API void ImVector_ImWchar_Init(ImVector_ImWchar* p) +{ + IM_PLACEMENT_NEW(p) ImVector(); +} +CIMGUI_API void ImVector_ImWchar_UnInit(ImVector_ImWchar* p) +{ + p->~ImVector(); +} + + +#ifdef IMGUI_HAS_DOCK + +// NOTE: Some function pointers in the ImGuiPlatformIO structure are not C-compatible because of their +// use of a complex return type. To work around this, we store a custom CimguiStorage object inside +// ImGuiIO::BackendLanguageUserData, which contains C-compatible function pointer variants for these +// functions. When a user function pointer is provided, we hook up the underlying ImGuiPlatformIO +// function pointer to a thunk which accesses the user function pointer through CimguiStorage. + +struct CimguiStorage +{ + void(*Platform_GetWindowPos)(ImGuiViewport* vp, ImVec2* out_pos); + void(*Platform_GetWindowSize)(ImGuiViewport* vp, ImVec2* out_pos); +}; + +// Gets a reference to the CimguiStorage object stored in the current ImGui context's BackendLanguageUserData. +CimguiStorage& GetCimguiStorage() +{ + ImGuiIO& io = ImGui::GetIO(); + if (io.BackendLanguageUserData == NULL) + { + io.BackendLanguageUserData = new CimguiStorage(); + } + + return *(CimguiStorage*)io.BackendLanguageUserData; +} + +// Thunk satisfying the signature of ImGuiPlatformIO::Platform_GetWindowPos. +ImVec2 Platform_GetWindowPos_hook(ImGuiViewport* vp) +{ + ImVec2 pos; + GetCimguiStorage().Platform_GetWindowPos(vp, &pos); + return pos; +}; + +// Fully C-compatible function pointer setter for ImGuiPlatformIO::Platform_GetWindowPos. +CIMGUI_API void ImGuiPlatformIO_Set_Platform_GetWindowPos(ImGuiPlatformIO* platform_io, void(*user_callback)(ImGuiViewport* vp, ImVec2* out_pos)) +{ + CimguiStorage& storage = GetCimguiStorage(); + storage.Platform_GetWindowPos = user_callback; + platform_io->Platform_GetWindowPos = &Platform_GetWindowPos_hook; +} + +// Thunk satisfying the signature of ImGuiPlatformIO::Platform_GetWindowSize. +ImVec2 Platform_GetWindowSize_hook(ImGuiViewport* vp) +{ + ImVec2 size; + GetCimguiStorage().Platform_GetWindowSize(vp, &size); + return size; +}; + +// Fully C-compatible function pointer setter for ImGuiPlatformIO::Platform_GetWindowSize. +CIMGUI_API void ImGuiPlatformIO_Set_Platform_GetWindowSize(ImGuiPlatformIO* platform_io, void(*user_callback)(ImGuiViewport* vp, ImVec2* out_size)) +{ + CimguiStorage& storage = GetCimguiStorage(); + storage.Platform_GetWindowSize = user_callback; + platform_io->Platform_GetWindowSize = &Platform_GetWindowSize_hook; +} + +#endif diff --git a/thirdparty/sokol_imgui/cimgui.h b/thirdparty/sokol_imgui/cimgui.h new file mode 100644 index 0000000..e459e0f --- /dev/null +++ b/thirdparty/sokol_imgui/cimgui.h @@ -0,0 +1,3586 @@ +//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui +//based on imgui.h file version "1.86" from Dear ImGui https://github.com/ocornut/imgui +//with imgui_internal.h api +#ifndef CIMGUI_INCLUDED +#define CIMGUI_INCLUDED +#include +#include +#if defined _WIN32 || defined __CYGWIN__ + #ifdef CIMGUI_NO_EXPORT + #define API + #else + #define API __declspec(dllexport) + #endif +#else + #ifdef __GNUC__ + #define API __attribute__((__visibility__("default"))) + #else + #define API + #endif +#endif + +#if defined __cplusplus + #define EXTERN extern "C" +#else + #include + #include + #define EXTERN extern +#endif + +#define CIMGUI_API EXTERN API +#define CONST const + + +#ifdef _MSC_VER +typedef unsigned __int64 ImU64; +#else +//typedef unsigned long long ImU64; +#endif + + +#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS +typedef struct ImGuiTableColumnSettings ImGuiTableColumnSettings; +typedef struct ImGuiTableCellData ImGuiTableCellData; +typedef struct ImGuiStackTool ImGuiStackTool; +typedef struct ImGuiStackLevelInfo ImGuiStackLevelInfo; +typedef struct ImGuiViewportP ImGuiViewportP; +typedef struct ImGuiListClipperData ImGuiListClipperData; +typedef struct ImGuiListClipperRange ImGuiListClipperRange; +typedef struct ImGuiPtrOrIndex ImGuiPtrOrIndex; +typedef struct ImGuiShrinkWidthItem ImGuiShrinkWidthItem; +typedef struct ImGuiWindowStackData ImGuiWindowStackData; +typedef struct ImGuiComboPreviewData ImGuiComboPreviewData; +typedef struct ImGuiDataTypeTempStorage ImGuiDataTypeTempStorage; +typedef struct ImVec2ih ImVec2ih; +typedef struct ImVec1 ImVec1; +typedef struct StbTexteditRow StbTexteditRow; +typedef struct STB_TexteditState STB_TexteditState; +typedef struct StbUndoState StbUndoState; +typedef struct StbUndoRecord StbUndoRecord; +typedef struct ImGuiWindowSettings ImGuiWindowSettings; +typedef struct ImGuiWindowTempData ImGuiWindowTempData; +typedef struct ImGuiWindow ImGuiWindow; +typedef struct ImGuiTableColumnsSettings ImGuiTableColumnsSettings; +typedef struct ImGuiTableSettings ImGuiTableSettings; +typedef struct ImGuiTableTempData ImGuiTableTempData; +typedef struct ImGuiTableColumn ImGuiTableColumn; +typedef struct ImGuiTable ImGuiTable; +typedef struct ImGuiTabItem ImGuiTabItem; +typedef struct ImGuiTabBar ImGuiTabBar; +typedef struct ImGuiStyleMod ImGuiStyleMod; +typedef struct ImGuiStackSizes ImGuiStackSizes; +typedef struct ImGuiSettingsHandler ImGuiSettingsHandler; +typedef struct ImGuiPopupData ImGuiPopupData; +typedef struct ImGuiOldColumns ImGuiOldColumns; +typedef struct ImGuiOldColumnData ImGuiOldColumnData; +typedef struct ImGuiNextItemData ImGuiNextItemData; +typedef struct ImGuiNextWindowData ImGuiNextWindowData; +typedef struct ImGuiMetricsConfig ImGuiMetricsConfig; +typedef struct ImGuiNavItemData ImGuiNavItemData; +typedef struct ImGuiMenuColumns ImGuiMenuColumns; +typedef struct ImGuiLastItemData ImGuiLastItemData; +typedef struct ImGuiInputTextState ImGuiInputTextState; +typedef struct ImGuiGroupData ImGuiGroupData; +typedef struct ImGuiDataTypeInfo ImGuiDataTypeInfo; +typedef struct ImGuiContextHook ImGuiContextHook; +typedef struct ImGuiColorMod ImGuiColorMod; +typedef struct ImDrawDataBuilder ImDrawDataBuilder; +typedef struct ImRect ImRect; +typedef struct ImBitVector ImBitVector; +typedef struct ImFontAtlasCustomRect ImFontAtlasCustomRect; +typedef struct ImDrawCmdHeader ImDrawCmdHeader; +typedef struct ImGuiStoragePair ImGuiStoragePair; +typedef struct ImGuiTextRange ImGuiTextRange; +typedef struct ImVec4 ImVec4; +typedef struct ImVec2 ImVec2; +typedef struct ImGuiViewport ImGuiViewport; +typedef struct ImGuiTextFilter ImGuiTextFilter; +typedef struct ImGuiTextBuffer ImGuiTextBuffer; +typedef struct ImGuiTableColumnSortSpecs ImGuiTableColumnSortSpecs; +typedef struct ImGuiTableSortSpecs ImGuiTableSortSpecs; +typedef struct ImGuiStyle ImGuiStyle; +typedef struct ImGuiStorage ImGuiStorage; +typedef struct ImGuiSizeCallbackData ImGuiSizeCallbackData; +typedef struct ImGuiPayload ImGuiPayload; +typedef struct ImGuiOnceUponAFrame ImGuiOnceUponAFrame; +typedef struct ImGuiListClipper ImGuiListClipper; +typedef struct ImGuiInputTextCallbackData ImGuiInputTextCallbackData; +typedef struct ImGuiIO ImGuiIO; +typedef struct ImGuiContext ImGuiContext; +typedef struct ImColor ImColor; +typedef struct ImFontGlyphRangesBuilder ImFontGlyphRangesBuilder; +typedef struct ImFontGlyph ImFontGlyph; +typedef struct ImFontConfig ImFontConfig; +typedef struct ImFontBuilderIO ImFontBuilderIO; +typedef struct ImFontAtlas ImFontAtlas; +typedef struct ImFont ImFont; +typedef struct ImDrawVert ImDrawVert; +typedef struct ImDrawListSplitter ImDrawListSplitter; +typedef struct ImDrawListSharedData ImDrawListSharedData; +typedef struct ImDrawList ImDrawList; +typedef struct ImDrawData ImDrawData; +typedef struct ImDrawCmd ImDrawCmd; +typedef struct ImDrawChannel ImDrawChannel; + +struct ImDrawChannel; +struct ImDrawCmd; +struct ImDrawData; +struct ImDrawList; +struct ImDrawListSharedData; +struct ImDrawListSplitter; +struct ImDrawVert; +struct ImFont; +struct ImFontAtlas; +struct ImFontBuilderIO; +struct ImFontConfig; +struct ImFontGlyph; +struct ImFontGlyphRangesBuilder; +struct ImColor; +struct ImGuiContext; +struct ImGuiIO; +struct ImGuiInputTextCallbackData; +struct ImGuiListClipper; +struct ImGuiOnceUponAFrame; +struct ImGuiPayload; +struct ImGuiSizeCallbackData; +struct ImGuiStorage; +struct ImGuiStyle; +struct ImGuiTableSortSpecs; +struct ImGuiTableColumnSortSpecs; +struct ImGuiTextBuffer; +struct ImGuiTextFilter; +struct ImGuiViewport; +typedef int ImGuiCol; +typedef int ImGuiCond; +typedef int ImGuiDataType; +typedef int ImGuiDir; +typedef int ImGuiKey; +typedef int ImGuiNavInput; +typedef int ImGuiMouseButton; +typedef int ImGuiMouseCursor; +typedef int ImGuiSortDirection; +typedef int ImGuiStyleVar; +typedef int ImGuiTableBgTarget; +typedef int ImDrawFlags; +typedef int ImDrawListFlags; +typedef int ImFontAtlasFlags; +typedef int ImGuiBackendFlags; +typedef int ImGuiButtonFlags; +typedef int ImGuiColorEditFlags; +typedef int ImGuiConfigFlags; +typedef int ImGuiComboFlags; +typedef int ImGuiDragDropFlags; +typedef int ImGuiFocusedFlags; +typedef int ImGuiHoveredFlags; +typedef int ImGuiInputTextFlags; +typedef int ImGuiKeyModFlags; +typedef int ImGuiPopupFlags; +typedef int ImGuiSelectableFlags; +typedef int ImGuiSliderFlags; +typedef int ImGuiTabBarFlags; +typedef int ImGuiTabItemFlags; +typedef int ImGuiTableFlags; +typedef int ImGuiTableColumnFlags; +typedef int ImGuiTableRowFlags; +typedef int ImGuiTreeNodeFlags; +typedef int ImGuiViewportFlags; +typedef int ImGuiWindowFlags; +typedef void* ImTextureID; +typedef unsigned short ImDrawIdx; +typedef unsigned int ImGuiID; +typedef signed char ImS8; +typedef unsigned char ImU8; +typedef signed short ImS16; +typedef unsigned short ImU16; +typedef signed int ImS32; +typedef unsigned int ImU32; +typedef int64_t ImS64; +typedef uint64_t ImU64; +typedef unsigned short ImWchar16; +typedef unsigned int ImWchar32; +typedef ImWchar16 ImWchar; +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +struct ImBitVector; +struct ImRect; +struct ImDrawDataBuilder; +struct ImDrawListSharedData; +struct ImGuiColorMod; +struct ImGuiContext; +struct ImGuiContextHook; +struct ImGuiDataTypeInfo; +struct ImGuiGroupData; +struct ImGuiInputTextState; +struct ImGuiLastItemData; +struct ImGuiMenuColumns; +struct ImGuiNavItemData; +struct ImGuiMetricsConfig; +struct ImGuiNextWindowData; +struct ImGuiNextItemData; +struct ImGuiOldColumnData; +struct ImGuiOldColumns; +struct ImGuiPopupData; +struct ImGuiSettingsHandler; +struct ImGuiStackSizes; +struct ImGuiStyleMod; +struct ImGuiTabBar; +struct ImGuiTabItem; +struct ImGuiTable; +struct ImGuiTableColumn; +struct ImGuiTableTempData; +struct ImGuiTableSettings; +struct ImGuiTableColumnsSettings; +struct ImGuiWindow; +struct ImGuiWindowTempData; +struct ImGuiWindowSettings; +typedef int ImGuiLayoutType; +typedef int ImGuiActivateFlags; +typedef int ImGuiItemFlags; +typedef int ImGuiItemStatusFlags; +typedef int ImGuiOldColumnFlags; +typedef int ImGuiNavHighlightFlags; +typedef int ImGuiNavDirSourceFlags; +typedef int ImGuiNavMoveFlags; +typedef int ImGuiNextItemDataFlags; +typedef int ImGuiNextWindowDataFlags; +typedef int ImGuiScrollFlags; +typedef int ImGuiSeparatorFlags; +typedef int ImGuiTextFlags; +typedef int ImGuiTooltipFlags; +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); +extern ImGuiContext* GImGui; +typedef FILE* ImFileHandle; +typedef int ImPoolIdx; +typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); +typedef ImS8 ImGuiTableColumnIdx; +typedef ImU8 ImGuiTableDrawChannelIdx; +typedef struct ImVector{int Size;int Capacity;void* Data;} ImVector; +typedef struct ImVector_ImGuiTableSettings {int Size;int Capacity;ImGuiTableSettings* Data;} ImVector_ImGuiTableSettings; +typedef struct ImChunkStream_ImGuiTableSettings {ImVector_ImGuiTableSettings Buf;} ImChunkStream_ImGuiTableSettings; +typedef struct ImVector_ImGuiWindowSettings {int Size;int Capacity;ImGuiWindowSettings* Data;} ImVector_ImGuiWindowSettings; +typedef struct ImChunkStream_ImGuiWindowSettings {ImVector_ImGuiWindowSettings Buf;} ImChunkStream_ImGuiWindowSettings; +typedef struct ImSpan_ImGuiTableCellData {ImGuiTableCellData* Data;ImGuiTableCellData* DataEnd;} ImSpan_ImGuiTableCellData; +typedef struct ImSpan_ImGuiTableColumn {ImGuiTableColumn* Data;ImGuiTableColumn* DataEnd;} ImSpan_ImGuiTableColumn; +typedef struct ImSpan_ImGuiTableColumnIdx {ImGuiTableColumnIdx* Data;ImGuiTableColumnIdx* DataEnd;} ImSpan_ImGuiTableColumnIdx; +typedef struct ImVector_ImDrawChannel {int Size;int Capacity;ImDrawChannel* Data;} ImVector_ImDrawChannel; +typedef struct ImVector_ImDrawCmd {int Size;int Capacity;ImDrawCmd* Data;} ImVector_ImDrawCmd; +typedef struct ImVector_ImDrawIdx {int Size;int Capacity;ImDrawIdx* Data;} ImVector_ImDrawIdx; +typedef struct ImVector_ImDrawListPtr {int Size;int Capacity;ImDrawList** Data;} ImVector_ImDrawListPtr; +typedef struct ImVector_ImDrawVert {int Size;int Capacity;ImDrawVert* Data;} ImVector_ImDrawVert; +typedef struct ImVector_ImFontPtr {int Size;int Capacity;ImFont** Data;} ImVector_ImFontPtr; +typedef struct ImVector_ImFontAtlasCustomRect {int Size;int Capacity;ImFontAtlasCustomRect* Data;} ImVector_ImFontAtlasCustomRect; +typedef struct ImVector_ImFontConfig {int Size;int Capacity;ImFontConfig* Data;} ImVector_ImFontConfig; +typedef struct ImVector_ImFontGlyph {int Size;int Capacity;ImFontGlyph* Data;} ImVector_ImFontGlyph; +typedef struct ImVector_ImGuiColorMod {int Size;int Capacity;ImGuiColorMod* Data;} ImVector_ImGuiColorMod; +typedef struct ImVector_ImGuiContextHook {int Size;int Capacity;ImGuiContextHook* Data;} ImVector_ImGuiContextHook; +typedef struct ImVector_ImGuiGroupData {int Size;int Capacity;ImGuiGroupData* Data;} ImVector_ImGuiGroupData; +typedef struct ImVector_ImGuiID {int Size;int Capacity;ImGuiID* Data;} ImVector_ImGuiID; +typedef struct ImVector_ImGuiItemFlags {int Size;int Capacity;ImGuiItemFlags* Data;} ImVector_ImGuiItemFlags; +typedef struct ImVector_ImGuiListClipperData {int Size;int Capacity;ImGuiListClipperData* Data;} ImVector_ImGuiListClipperData; +typedef struct ImVector_ImGuiListClipperRange {int Size;int Capacity;ImGuiListClipperRange* Data;} ImVector_ImGuiListClipperRange; +typedef struct ImVector_ImGuiOldColumnData {int Size;int Capacity;ImGuiOldColumnData* Data;} ImVector_ImGuiOldColumnData; +typedef struct ImVector_ImGuiOldColumns {int Size;int Capacity;ImGuiOldColumns* Data;} ImVector_ImGuiOldColumns; +typedef struct ImVector_ImGuiPopupData {int Size;int Capacity;ImGuiPopupData* Data;} ImVector_ImGuiPopupData; +typedef struct ImVector_ImGuiPtrOrIndex {int Size;int Capacity;ImGuiPtrOrIndex* Data;} ImVector_ImGuiPtrOrIndex; +typedef struct ImVector_ImGuiSettingsHandler {int Size;int Capacity;ImGuiSettingsHandler* Data;} ImVector_ImGuiSettingsHandler; +typedef struct ImVector_ImGuiShrinkWidthItem {int Size;int Capacity;ImGuiShrinkWidthItem* Data;} ImVector_ImGuiShrinkWidthItem; +typedef struct ImVector_ImGuiStackLevelInfo {int Size;int Capacity;ImGuiStackLevelInfo* Data;} ImVector_ImGuiStackLevelInfo; +typedef struct ImVector_ImGuiStoragePair {int Size;int Capacity;ImGuiStoragePair* Data;} ImVector_ImGuiStoragePair; +typedef struct ImVector_ImGuiStyleMod {int Size;int Capacity;ImGuiStyleMod* Data;} ImVector_ImGuiStyleMod; +typedef struct ImVector_ImGuiTabItem {int Size;int Capacity;ImGuiTabItem* Data;} ImVector_ImGuiTabItem; +typedef struct ImVector_ImGuiTableColumnSortSpecs {int Size;int Capacity;ImGuiTableColumnSortSpecs* Data;} ImVector_ImGuiTableColumnSortSpecs; +typedef struct ImVector_ImGuiTableTempData {int Size;int Capacity;ImGuiTableTempData* Data;} ImVector_ImGuiTableTempData; +typedef struct ImVector_ImGuiTextRange {int Size;int Capacity;ImGuiTextRange* Data;} ImVector_ImGuiTextRange; +typedef struct ImVector_ImGuiViewportPPtr {int Size;int Capacity;ImGuiViewportP** Data;} ImVector_ImGuiViewportPPtr; +typedef struct ImVector_ImGuiWindowPtr {int Size;int Capacity;ImGuiWindow** Data;} ImVector_ImGuiWindowPtr; +typedef struct ImVector_ImGuiWindowStackData {int Size;int Capacity;ImGuiWindowStackData* Data;} ImVector_ImGuiWindowStackData; +typedef struct ImVector_ImTextureID {int Size;int Capacity;ImTextureID* Data;} ImVector_ImTextureID; +typedef struct ImVector_ImU32 {int Size;int Capacity;ImU32* Data;} ImVector_ImU32; +typedef struct ImVector_ImVec2 {int Size;int Capacity;ImVec2* Data;} ImVector_ImVec2; +typedef struct ImVector_ImVec4 {int Size;int Capacity;ImVec4* Data;} ImVector_ImVec4; +typedef struct ImVector_ImWchar {int Size;int Capacity;ImWchar* Data;} ImVector_ImWchar; +typedef struct ImVector_char {int Size;int Capacity;char* Data;} ImVector_char; +typedef struct ImVector_float {int Size;int Capacity;float* Data;} ImVector_float; +typedef struct ImVector_unsigned_char {int Size;int Capacity;unsigned char* Data;} ImVector_unsigned_char; + +struct ImVec2 +{ + float x, y; +}; +struct ImVec4 +{ + float x, y, z, w; +}; +typedef enum { + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, + ImGuiWindowFlags_NoResize = 1 << 1, + ImGuiWindowFlags_NoMove = 1 << 2, + ImGuiWindowFlags_NoScrollbar = 1 << 3, + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, + ImGuiWindowFlags_NoCollapse = 1 << 5, + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, + ImGuiWindowFlags_NoBackground = 1 << 7, + ImGuiWindowFlags_NoSavedSettings = 1 << 8, + ImGuiWindowFlags_NoMouseInputs = 1 << 9, + ImGuiWindowFlags_MenuBar = 1 << 10, + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, + ImGuiWindowFlags_NoNavInputs = 1 << 18, + ImGuiWindowFlags_NoNavFocus = 1 << 19, + ImGuiWindowFlags_UnsavedDocument = 1 << 20, + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NavFlattened = 1 << 23, + ImGuiWindowFlags_ChildWindow = 1 << 24, + ImGuiWindowFlags_Tooltip = 1 << 25, + ImGuiWindowFlags_Popup = 1 << 26, + ImGuiWindowFlags_Modal = 1 << 27, + ImGuiWindowFlags_ChildMenu = 1 << 28 +}ImGuiWindowFlags_; +typedef enum { + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, + ImGuiInputTextFlags_CharsUppercase = 1 << 2, + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, + ImGuiInputTextFlags_CallbackHistory = 1 << 7, + ImGuiInputTextFlags_CallbackAlways = 1 << 8, + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, + ImGuiInputTextFlags_AllowTabInput = 1 << 10, + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, + ImGuiInputTextFlags_ReadOnly = 1 << 14, + ImGuiInputTextFlags_Password = 1 << 15, + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, + ImGuiInputTextFlags_CharsScientific = 1 << 17, + ImGuiInputTextFlags_CallbackResize = 1 << 18, + ImGuiInputTextFlags_CallbackEdit = 1 << 19 +}ImGuiInputTextFlags_; +typedef enum { + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, + ImGuiTreeNodeFlags_Framed = 1 << 1, + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, + ImGuiTreeNodeFlags_Leaf = 1 << 8, + ImGuiTreeNodeFlags_Bullet = 1 << 9, + ImGuiTreeNodeFlags_FramePadding = 1 << 10, + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog +}ImGuiTreeNodeFlags_; +typedef enum { + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, + ImGuiPopupFlags_MouseButtonRight = 1, + ImGuiPopupFlags_MouseButtonMiddle = 2, + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, + ImGuiPopupFlags_AnyPopupId = 1 << 7, + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel +}ImGuiPopupFlags_; +typedef enum { + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, + ImGuiSelectableFlags_Disabled = 1 << 3, + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 +}ImGuiSelectableFlags_; +typedef enum { + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, + ImGuiComboFlags_HeightSmall = 1 << 1, + ImGuiComboFlags_HeightRegular = 1 << 2, + ImGuiComboFlags_HeightLarge = 1 << 3, + ImGuiComboFlags_HeightLargest = 1 << 4, + ImGuiComboFlags_NoArrowButton = 1 << 5, + ImGuiComboFlags_NoPreview = 1 << 6, + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}ImGuiComboFlags_; +typedef enum { + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, + ImGuiTabBarFlags_NoTooltip = 1 << 5, + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}ImGuiTabBarFlags_; +typedef enum { + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, + ImGuiTabItemFlags_SetSelected = 1 << 1, + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, + ImGuiTabItemFlags_NoPushId = 1 << 3, + ImGuiTabItemFlags_NoTooltip = 1 << 4, + ImGuiTabItemFlags_NoReorder = 1 << 5, + ImGuiTabItemFlags_Leading = 1 << 6, + ImGuiTabItemFlags_Trailing = 1 << 7 +}ImGuiTabItemFlags_; +typedef enum { + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, + ImGuiTableFlags_Reorderable = 1 << 1, + ImGuiTableFlags_Hideable = 1 << 2, + ImGuiTableFlags_Sortable = 1 << 3, + ImGuiTableFlags_NoSavedSettings = 1 << 4, + ImGuiTableFlags_ContextMenuInBody = 1 << 5, + ImGuiTableFlags_RowBg = 1 << 6, + ImGuiTableFlags_BordersInnerH = 1 << 7, + ImGuiTableFlags_BordersOuterH = 1 << 8, + ImGuiTableFlags_BordersInnerV = 1 << 9, + ImGuiTableFlags_BordersOuterV = 1 << 10, + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, + ImGuiTableFlags_NoBordersInBody = 1 << 11, + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, + ImGuiTableFlags_SizingFixedFit = 1 << 13, + ImGuiTableFlags_SizingFixedSame = 2 << 13, + ImGuiTableFlags_SizingStretchProp = 3 << 13, + ImGuiTableFlags_SizingStretchSame = 4 << 13, + ImGuiTableFlags_NoHostExtendX = 1 << 16, + ImGuiTableFlags_NoHostExtendY = 1 << 17, + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, + ImGuiTableFlags_PreciseWidths = 1 << 19, + ImGuiTableFlags_NoClip = 1 << 20, + ImGuiTableFlags_PadOuterX = 1 << 21, + ImGuiTableFlags_NoPadOuterX = 1 << 22, + ImGuiTableFlags_NoPadInnerX = 1 << 23, + ImGuiTableFlags_ScrollX = 1 << 24, + ImGuiTableFlags_ScrollY = 1 << 25, + ImGuiTableFlags_SortMulti = 1 << 26, + ImGuiTableFlags_SortTristate = 1 << 27, + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame +}ImGuiTableFlags_; +typedef enum { + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_Disabled = 1 << 0, + ImGuiTableColumnFlags_DefaultHide = 1 << 1, + ImGuiTableColumnFlags_DefaultSort = 1 << 2, + ImGuiTableColumnFlags_WidthStretch = 1 << 3, + ImGuiTableColumnFlags_WidthFixed = 1 << 4, + ImGuiTableColumnFlags_NoResize = 1 << 5, + ImGuiTableColumnFlags_NoReorder = 1 << 6, + ImGuiTableColumnFlags_NoHide = 1 << 7, + ImGuiTableColumnFlags_NoClip = 1 << 8, + ImGuiTableColumnFlags_NoSort = 1 << 9, + ImGuiTableColumnFlags_NoSortAscending = 1 << 10, + ImGuiTableColumnFlags_NoSortDescending = 1 << 11, + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, + ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, + ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, + ImGuiTableColumnFlags_IndentEnable = 1 << 16, + ImGuiTableColumnFlags_IndentDisable = 1 << 17, + ImGuiTableColumnFlags_IsEnabled = 1 << 24, + ImGuiTableColumnFlags_IsVisible = 1 << 25, + ImGuiTableColumnFlags_IsSorted = 1 << 26, + ImGuiTableColumnFlags_IsHovered = 1 << 27, + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30 +}ImGuiTableColumnFlags_; +typedef enum { + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0 +}ImGuiTableRowFlags_; +typedef enum { + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, + ImGuiTableBgTarget_RowBg1 = 2, + ImGuiTableBgTarget_CellBg = 3 +}ImGuiTableBgTarget_; +typedef enum { + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, + ImGuiFocusedFlags_RootWindow = 1 << 1, + ImGuiFocusedFlags_AnyWindow = 1 << 2, + ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}ImGuiFocusedFlags_; +typedef enum { + ImGuiHoveredFlags_None = 0, + ImGuiHoveredFlags_ChildWindows = 1 << 0, + ImGuiHoveredFlags_RootWindow = 1 << 1, + ImGuiHoveredFlags_AnyWindow = 1 << 2, + ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 8, + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 9, + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}ImGuiHoveredFlags_; +typedef enum { + ImGuiDragDropFlags_None = 0, + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, + ImGuiDragDropFlags_SourceExtern = 1 << 4, + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect +}ImGuiDragDropFlags_; +typedef enum { + ImGuiDataType_S8, + ImGuiDataType_U8, + ImGuiDataType_S16, + ImGuiDataType_U16, + ImGuiDataType_S32, + ImGuiDataType_U32, + ImGuiDataType_S64, + ImGuiDataType_U64, + ImGuiDataType_Float, + ImGuiDataType_Double, + ImGuiDataType_COUNT +}ImGuiDataType_; +typedef enum { + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}ImGuiDir_; +typedef enum { + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, + ImGuiSortDirection_Descending = 2 +}ImGuiSortDirection_; +typedef enum { + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_KeyPadEnter, + ImGuiKey_A, + ImGuiKey_C, + ImGuiKey_V, + ImGuiKey_X, + ImGuiKey_Y, + ImGuiKey_Z, + ImGuiKey_COUNT +}ImGuiKey_; +typedef enum { + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 +}ImGuiKeyModFlags_; +typedef enum { + ImGuiNavInput_Activate, + ImGuiNavInput_Cancel, + ImGuiNavInput_Input, + ImGuiNavInput_Menu, + ImGuiNavInput_DpadLeft, + ImGuiNavInput_DpadRight, + ImGuiNavInput_DpadUp, + ImGuiNavInput_DpadDown, + ImGuiNavInput_LStickLeft, + ImGuiNavInput_LStickRight, + ImGuiNavInput_LStickUp, + ImGuiNavInput_LStickDown, + ImGuiNavInput_FocusPrev, + ImGuiNavInput_FocusNext, + ImGuiNavInput_TweakSlow, + ImGuiNavInput_TweakFast, + ImGuiNavInput_KeyLeft_, + ImGuiNavInput_KeyRight_, + ImGuiNavInput_KeyUp_, + ImGuiNavInput_KeyDown_, + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyLeft_ +}ImGuiNavInput_; +typedef enum { + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, + ImGuiConfigFlags_NoMouse = 1 << 4, + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, + ImGuiConfigFlags_IsSRGB = 1 << 20, + ImGuiConfigFlags_IsTouchScreen = 1 << 21 +}ImGuiConfigFlags_; +typedef enum { + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, + ImGuiBackendFlags_HasMouseCursors = 1 << 1, + ImGuiBackendFlags_HasSetMousePos = 1 << 2, + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 +}ImGuiBackendFlags_; +typedef enum { + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, + ImGuiCol_ChildBg, + ImGuiCol_PopupBg, + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, + ImGuiCol_TableBorderStrong, + ImGuiCol_TableBorderLight, + ImGuiCol_TableRowBg, + ImGuiCol_TableRowBgAlt, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, + ImGuiCol_NavWindowingHighlight, + ImGuiCol_NavWindowingDimBg, + ImGuiCol_ModalWindowDimBg, + ImGuiCol_COUNT +}ImGuiCol_; +typedef enum { + ImGuiStyleVar_Alpha, + ImGuiStyleVar_DisabledAlpha, + ImGuiStyleVar_WindowPadding, + ImGuiStyleVar_WindowRounding, + ImGuiStyleVar_WindowBorderSize, + ImGuiStyleVar_WindowMinSize, + ImGuiStyleVar_WindowTitleAlign, + ImGuiStyleVar_ChildRounding, + ImGuiStyleVar_ChildBorderSize, + ImGuiStyleVar_PopupRounding, + ImGuiStyleVar_PopupBorderSize, + ImGuiStyleVar_FramePadding, + ImGuiStyleVar_FrameRounding, + ImGuiStyleVar_FrameBorderSize, + ImGuiStyleVar_ItemSpacing, + ImGuiStyleVar_ItemInnerSpacing, + ImGuiStyleVar_IndentSpacing, + ImGuiStyleVar_CellPadding, + ImGuiStyleVar_ScrollbarSize, + ImGuiStyleVar_ScrollbarRounding, + ImGuiStyleVar_GrabMinSize, + ImGuiStyleVar_GrabRounding, + ImGuiStyleVar_TabRounding, + ImGuiStyleVar_ButtonTextAlign, + ImGuiStyleVar_SelectableTextAlign, + ImGuiStyleVar_COUNT +}ImGuiStyleVar_; +typedef enum { + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, + ImGuiButtonFlags_MouseButtonRight = 1 << 1, + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft +}ImGuiButtonFlags_; +typedef enum { + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, + ImGuiColorEditFlags_NoPicker = 1 << 2, + ImGuiColorEditFlags_NoOptions = 1 << 3, + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, + ImGuiColorEditFlags_NoInputs = 1 << 5, + ImGuiColorEditFlags_NoTooltip = 1 << 6, + ImGuiColorEditFlags_NoLabel = 1 << 7, + ImGuiColorEditFlags_NoSidePreview = 1 << 8, + ImGuiColorEditFlags_NoDragDrop = 1 << 9, + ImGuiColorEditFlags_NoBorder = 1 << 10, + ImGuiColorEditFlags_AlphaBar = 1 << 16, + ImGuiColorEditFlags_AlphaPreview = 1 << 17, + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, + ImGuiColorEditFlags_HDR = 1 << 19, + ImGuiColorEditFlags_DisplayRGB = 1 << 20, + ImGuiColorEditFlags_DisplayHSV = 1 << 21, + ImGuiColorEditFlags_DisplayHex = 1 << 22, + ImGuiColorEditFlags_Uint8 = 1 << 23, + ImGuiColorEditFlags_Float = 1 << 24, + ImGuiColorEditFlags_PickerHueBar = 1 << 25, + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, + ImGuiColorEditFlags_InputRGB = 1 << 27, + ImGuiColorEditFlags_InputHSV = 1 << 28, + ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV +}ImGuiColorEditFlags_; +typedef enum { + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, + ImGuiSliderFlags_Logarithmic = 1 << 5, + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, + ImGuiSliderFlags_NoInput = 1 << 7, + ImGuiSliderFlags_InvalidMask_ = 0x7000000F +}ImGuiSliderFlags_; +typedef enum { + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}ImGuiMouseButton_; +typedef enum { + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, + ImGuiMouseCursor_ResizeAll, + ImGuiMouseCursor_ResizeNS, + ImGuiMouseCursor_ResizeEW, + ImGuiMouseCursor_ResizeNESW, + ImGuiMouseCursor_ResizeNWSE, + ImGuiMouseCursor_Hand, + ImGuiMouseCursor_NotAllowed, + ImGuiMouseCursor_COUNT +}ImGuiMouseCursor_; +typedef enum { + ImGuiCond_None = 0, + ImGuiCond_Always = 1 << 0, + ImGuiCond_Once = 1 << 1, + ImGuiCond_FirstUseEver = 1 << 2, + ImGuiCond_Appearing = 1 << 3 +}ImGuiCond_; +struct ImGuiStyle +{ + float Alpha; + float DisabledAlpha; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + ImVec2 WindowMinSize; + ImVec2 WindowTitleAlign; + ImGuiDir WindowMenuButtonPosition; + float ChildRounding; + float ChildBorderSize; + float PopupRounding; + float PopupBorderSize; + ImVec2 FramePadding; + float FrameRounding; + float FrameBorderSize; + ImVec2 ItemSpacing; + ImVec2 ItemInnerSpacing; + ImVec2 CellPadding; + ImVec2 TouchExtraPadding; + float IndentSpacing; + float ColumnsMinSpacing; + float ScrollbarSize; + float ScrollbarRounding; + float GrabMinSize; + float GrabRounding; + float LogSliderDeadzone; + float TabRounding; + float TabBorderSize; + float TabMinWidthForCloseButton; + ImGuiDir ColorButtonPosition; + ImVec2 ButtonTextAlign; + ImVec2 SelectableTextAlign; + ImVec2 DisplayWindowPadding; + ImVec2 DisplaySafeAreaPadding; + float MouseCursorScale; + bool AntiAliasedLines; + bool AntiAliasedLinesUseTex; + bool AntiAliasedFill; + float CurveTessellationTol; + float CircleTessellationMaxError; + ImVec4 Colors[ImGuiCol_COUNT]; +}; +struct ImGuiIO +{ + ImGuiConfigFlags ConfigFlags; + ImGuiBackendFlags BackendFlags; + ImVec2 DisplaySize; + float DeltaTime; + float IniSavingRate; + const char* IniFilename; + const char* LogFilename; + float MouseDoubleClickTime; + float MouseDoubleClickMaxDist; + float MouseDragThreshold; + int KeyMap[ImGuiKey_COUNT]; + float KeyRepeatDelay; + float KeyRepeatRate; + void* UserData; + ImFontAtlas*Fonts; + float FontGlobalScale; + bool FontAllowUserScaling; + ImFont* FontDefault; + ImVec2 DisplayFramebufferScale; + bool MouseDrawCursor; + bool ConfigMacOSXBehaviors; + bool ConfigInputTextCursorBlink; + bool ConfigDragClickToInputText; + bool ConfigWindowsResizeFromEdges; + bool ConfigWindowsMoveFromTitleBarOnly; + float ConfigMemoryCompactTimer; + const char* BackendPlatformName; + const char* BackendRendererName; + void* BackendPlatformUserData; + void* BackendRendererUserData; + void* BackendLanguageUserData; + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; + ImVec2 MousePos; + bool MouseDown[5]; + float MouseWheel; + float MouseWheelH; + bool KeyCtrl; + bool KeyShift; + bool KeyAlt; + bool KeySuper; + bool KeysDown[512]; + float NavInputs[ImGuiNavInput_COUNT]; + bool WantCaptureMouse; + bool WantCaptureKeyboard; + bool WantTextInput; + bool WantSetMousePos; + bool WantSaveIniSettings; + bool NavActive; + bool NavVisible; + float Framerate; + int MetricsRenderVertices; + int MetricsRenderIndices; + int MetricsRenderWindows; + int MetricsActiveWindows; + int MetricsActiveAllocations; + ImVec2 MouseDelta; + bool WantCaptureMouseUnlessPopupClose; + ImGuiKeyModFlags KeyMods; + ImGuiKeyModFlags KeyModsPrev; + ImVec2 MousePosPrev; + ImVec2 MouseClickedPos[5]; + double MouseClickedTime[5]; + bool MouseClicked[5]; + bool MouseDoubleClicked[5]; + ImU16 MouseClickedCount[5]; + ImU16 MouseClickedLastCount[5]; + bool MouseReleased[5]; + bool MouseDownOwned[5]; + bool MouseDownOwnedUnlessPopupClose[5]; + float MouseDownDuration[5]; + float MouseDownDurationPrev[5]; + ImVec2 MouseDragMaxDistanceAbs[5]; + float MouseDragMaxDistanceSqr[5]; + float KeysDownDuration[512]; + float KeysDownDurationPrev[512]; + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + float PenPressure; + bool AppFocusLost; + ImWchar16 InputQueueSurrogate; + ImVector_ImWchar InputQueueCharacters; +}; +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; + ImGuiInputTextFlags Flags; + void* UserData; + ImWchar EventChar; + ImGuiKey EventKey; + char* Buf; + int BufTextLen; + int BufSize; + bool BufDirty; + int CursorPos; + int SelectionStart; + int SelectionEnd; +}; +struct ImGuiSizeCallbackData +{ + void* UserData; + ImVec2 Pos; + ImVec2 CurrentSize; + ImVec2 DesiredSize; +}; +struct ImGuiPayload +{ + void* Data; + int DataSize; + ImGuiID SourceId; + ImGuiID SourceParentId; + int DataFrameCount; + char DataType[32 + 1]; + bool Preview; + bool Delivery; +}; +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; + ImS16 ColumnIndex; + ImS16 SortOrder; + ImGuiSortDirection SortDirection : 8; +}; +struct ImGuiTableSortSpecs +{ + const ImGuiTableColumnSortSpecs* Specs; + int SpecsCount; + bool SpecsDirty; +}; +struct ImGuiOnceUponAFrame +{ + int RefFrame; +}; +struct ImGuiTextRange +{ + const char* b; + const char* e; +}; +struct ImGuiTextFilter +{ + char InputBuf[256]; + ImVector_ImGuiTextRange Filters; + int CountGrep; +}; +struct ImGuiTextBuffer +{ + ImVector_char Buf; +}; +struct ImGuiStoragePair +{ + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; +}; +struct ImGuiStorage +{ + ImVector_ImGuiStoragePair Data; +}; +typedef struct ImVector_ImGuiTabBar {int Size;int Capacity;ImGuiTabBar* Data;} ImVector_ImGuiTabBar; +typedef struct ImPool_ImGuiTabBar {ImVector_ImGuiTabBar Buf;ImGuiStorage Map;ImPoolIdx FreeIdx;} ImPool_ImGuiTabBar; +typedef struct ImVector_ImGuiTable {int Size;int Capacity;ImGuiTable* Data;} ImVector_ImGuiTable; +typedef struct ImPool_ImGuiTable {ImVector_ImGuiTable Buf;ImGuiStorage Map;ImPoolIdx FreeIdx;} ImPool_ImGuiTable; +struct ImGuiListClipper +{ + int DisplayStart; + int DisplayEnd; + int ItemsCount; + float ItemsHeight; + float StartPosY; + void* TempData; +}; +struct ImColor +{ + ImVec4 Value; +}; +struct ImDrawCmd +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; + unsigned int IdxOffset; + unsigned int ElemCount; + ImDrawCallback UserCallback; + void* UserCallbackData; +}; +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; +struct ImDrawChannel +{ + ImVector_ImDrawCmd _CmdBuffer; + ImVector_ImDrawIdx _IdxBuffer; +}; +struct ImDrawListSplitter +{ + int _Current; + int _Count; + ImVector_ImDrawChannel _Channels; +}; +typedef enum { + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, + ImDrawFlags_RoundCornersTopLeft = 1 << 4, + ImDrawFlags_RoundCornersTopRight = 1 << 5, + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, + ImDrawFlags_RoundCornersBottomRight = 1 << 7, + ImDrawFlags_RoundCornersNone = 1 << 8, + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone +}ImDrawFlags_; +typedef enum { + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, + ImDrawListFlags_AntiAliasedFill = 1 << 2, + ImDrawListFlags_AllowVtxOffset = 1 << 3 +}ImDrawListFlags_; +struct ImDrawList +{ + ImVector_ImDrawCmd CmdBuffer; + ImVector_ImDrawIdx IdxBuffer; + ImVector_ImDrawVert VtxBuffer; + ImDrawListFlags Flags; + unsigned int _VtxCurrentIdx; + const ImDrawListSharedData* _Data; + const char* _OwnerName; + ImDrawVert* _VtxWritePtr; + ImDrawIdx* _IdxWritePtr; + ImVector_ImVec4 _ClipRectStack; + ImVector_ImTextureID _TextureIdStack; + ImVector_ImVec2 _Path; + ImDrawCmdHeader _CmdHeader; + ImDrawListSplitter _Splitter; + float _FringeScale; +}; +struct ImDrawData +{ + bool Valid; + int CmdListsCount; + int TotalIdxCount; + int TotalVtxCount; + ImDrawList** CmdLists; + ImVec2 DisplayPos; + ImVec2 DisplaySize; + ImVec2 FramebufferScale; +}; +struct ImFontConfig +{ + void* FontData; + int FontDataSize; + bool FontDataOwnedByAtlas; + int FontNo; + float SizePixels; + int OversampleH; + int OversampleV; + bool PixelSnapH; + ImVec2 GlyphExtraSpacing; + ImVec2 GlyphOffset; + const ImWchar* GlyphRanges; + float GlyphMinAdvanceX; + float GlyphMaxAdvanceX; + bool MergeMode; + unsigned int FontBuilderFlags; + float RasterizerMultiply; + ImWchar EllipsisChar; + char Name[40]; + ImFont* DstFont; +}; +struct ImFontGlyph +{ + unsigned int Colored : 1; + unsigned int Visible : 1; + unsigned int Codepoint : 30; + float AdvanceX; + float X0, Y0, X1, Y1; + float U0, V0, U1, V1; +}; +struct ImFontGlyphRangesBuilder +{ + ImVector_ImU32 UsedChars; +}; +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; + unsigned short X, Y; + unsigned int GlyphID; + float GlyphAdvanceX; + ImVec2 GlyphOffset; + ImFont* Font; +}; +typedef enum { + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, + ImFontAtlasFlags_NoMouseCursors = 1 << 1, + ImFontAtlasFlags_NoBakedLines = 1 << 2 +}ImFontAtlasFlags_; +struct ImFontAtlas +{ + ImFontAtlasFlags Flags; + ImTextureID TexID; + int TexDesiredWidth; + int TexGlyphPadding; + bool Locked; + bool TexReady; + bool TexPixelsUseColors; + unsigned char* TexPixelsAlpha8; + unsigned int* TexPixelsRGBA32; + int TexWidth; + int TexHeight; + ImVec2 TexUvScale; + ImVec2 TexUvWhitePixel; + ImVector_ImFontPtr Fonts; + ImVector_ImFontAtlasCustomRect CustomRects; + ImVector_ImFontConfig ConfigData; + ImVec4 TexUvLines[(63) + 1]; + const ImFontBuilderIO* FontBuilderIO; + unsigned int FontBuilderFlags; + int PackIdMouseCursors; + int PackIdLines; +}; +struct ImFont +{ + ImVector_float IndexAdvanceX; + float FallbackAdvanceX; + float FontSize; + ImVector_ImWchar IndexLookup; + ImVector_ImFontGlyph Glyphs; + const ImFontGlyph* FallbackGlyph; + ImFontAtlas* ContainerAtlas; + const ImFontConfig* ConfigData; + short ConfigDataCount; + ImWchar FallbackChar; + ImWchar EllipsisChar; + ImWchar DotChar; + bool DirtyLookupTables; + float Scale; + float Ascent, Descent; + int MetricsTotalSurface; + ImU8 Used4kPagesMap[(0xFFFF +1)/4096/8]; +}; +typedef enum { + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, + ImGuiViewportFlags_OwnedByApp = 1 << 2 +}ImGuiViewportFlags_; +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; + ImVec2 Pos; + ImVec2 Size; + ImVec2 WorkPos; + ImVec2 WorkSize; +}; +struct StbUndoRecord +{ + int where; + int insert_length; + int delete_length; + int char_storage; +}; +struct StbUndoState +{ + StbUndoRecord undo_rec [99]; + ImWchar undo_char[999]; + short undo_point, redo_point; + int undo_char_point, redo_char_point; +}; +struct STB_TexteditState +{ + int cursor; + int select_start; + int select_end; + unsigned char insert_mode; + int row_count_per_page; + unsigned char cursor_at_end_of_line; + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; + StbUndoState undostate; +}; +struct StbTexteditRow +{ + float x0,x1; + float baseline_y_delta; + float ymin,ymax; + int num_chars; +}; +struct ImVec1 +{ + float x; +}; +struct ImVec2ih +{ + short x, y; +}; +struct ImRect +{ + ImVec2 Min; + ImVec2 Max; +}; +struct ImBitVector +{ + ImVector_ImU32 Storage; +}; +struct ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; + ImFont* Font; + float FontSize; + float CurveTessellationTol; + float CircleSegmentMaxError; + ImVec4 ClipRectFullscreen; + ImDrawListFlags InitialFlags; + ImVec2 ArcFastVtx[48]; + float ArcFastRadiusCutoff; + ImU8 CircleSegmentCounts[64]; + const ImVec4* TexUvLines; +}; +struct ImDrawDataBuilder +{ + ImVector_ImDrawListPtr Layers[2]; +}; +typedef enum { + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, + ImGuiItemFlags_ButtonRepeat = 1 << 1, + ImGuiItemFlags_Disabled = 1 << 2, + ImGuiItemFlags_NoNav = 1 << 3, + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, + ImGuiItemFlags_MixedValue = 1 << 6, + ImGuiItemFlags_ReadOnly = 1 << 7, + ImGuiItemFlags_Inputable = 1 << 8 +}ImGuiItemFlags_; +typedef enum { + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_Edited = 1 << 2, + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, + ImGuiItemStatusFlags_Deactivated = 1 << 6, + ImGuiItemStatusFlags_HoveredWindow = 1 << 7, + ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8 +}ImGuiItemStatusFlags_; +typedef enum { + ImGuiInputTextFlags_Multiline = 1 << 26, + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, + ImGuiInputTextFlags_MergedItem = 1 << 28 +}ImGuiInputTextFlagsPrivate_; +typedef enum { + ImGuiButtonFlags_PressedOnClick = 1 << 4, + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, + ImGuiButtonFlags_PressedOnRelease = 1 << 7, + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, + ImGuiButtonFlags_Repeat = 1 << 10, + ImGuiButtonFlags_FlattenChildren = 1 << 11, + ImGuiButtonFlags_AllowItemOverlap = 1 << 12, + ImGuiButtonFlags_DontClosePopups = 1 << 13, + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, + ImGuiButtonFlags_NoNavFocus = 1 << 18, + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease +}ImGuiButtonFlagsPrivate_; +typedef enum { + ImGuiComboFlags_CustomPreview = 1 << 20 +}ImGuiComboFlagsPrivate_; +typedef enum { + ImGuiSliderFlags_Vertical = 1 << 20, + ImGuiSliderFlags_ReadOnly = 1 << 21 +}ImGuiSliderFlagsPrivate_; +typedef enum { + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnNav = 1 << 21, + ImGuiSelectableFlags_SelectOnClick = 1 << 22, + ImGuiSelectableFlags_SelectOnRelease = 1 << 23, + ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, + ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 25, + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26, + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 27 +}ImGuiSelectableFlagsPrivate_; +typedef enum { + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 +}ImGuiTreeNodeFlagsPrivate_; +typedef enum { + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 +}ImGuiSeparatorFlags_; +typedef enum { + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}ImGuiTextFlags_; +typedef enum { + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 +}ImGuiTooltipFlags_; +typedef enum { + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}ImGuiLayoutType_; +typedef enum { + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}ImGuiLogType; +typedef enum { + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}ImGuiAxis; +typedef enum { + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}ImGuiPlotType; +typedef enum { + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Nav, + ImGuiInputSource_Clipboard, + ImGuiInputSource_COUNT +}ImGuiInputSource; +typedef enum { + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}ImGuiInputReadMode; +typedef enum { + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip +}ImGuiPopupPositionPolicy; +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; +}; +struct ImGuiDataTypeInfo +{ + size_t Size; + const char* Name; + const char* PrintFmt; + const char* ScanFmt; +}; +typedef enum { + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID +}ImGuiDataTypePrivate_; +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; +}; +struct ImGuiComboPreviewData +{ + ImRect PreviewRect; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; + float BackupPrevLineTextBaseOffset; + ImGuiLayoutType BackupLayout; +}; +struct ImGuiGroupData +{ + ImGuiID WindowID; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; + bool EmitItem; +}; +struct ImGuiMenuColumns +{ + ImU32 TotalWidth; + ImU32 NextTotalWidth; + ImU16 Spacing; + ImU16 OffsetIcon; + ImU16 OffsetLabel; + ImU16 OffsetShortcut; + ImU16 OffsetMark; + ImU16 Widths[4]; +}; +struct ImGuiInputTextState +{ + ImGuiID ID; + int CurLenW, CurLenA; + ImVector_ImWchar TextW; + ImVector_char TextA; + ImVector_char InitialTextA; + bool TextAIsValid; + int BufCapacityA; + float ScrollX; + STB_TexteditState Stb; + float CursorAnim; + bool CursorFollow; + bool SelectedAllMouseLock; + bool Edited; + ImGuiInputTextFlags Flags; +}; +struct ImGuiPopupData +{ + ImGuiID PopupId; + ImGuiWindow* Window; + ImGuiWindow* SourceWindow; + int OpenFrameCount; + ImGuiID OpenParentId; + ImVec2 OpenPopupPos; + ImVec2 OpenMousePos; +}; +typedef enum { + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7 +}ImGuiNextWindowDataFlags_; +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; + ImVec2 MenuBarOffsetMinVal; +}; +typedef enum { + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1 +}ImGuiNextItemDataFlags_; +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; + ImGuiID FocusScopeId; + ImGuiCond OpenCond; + bool OpenVal; +}; +struct ImGuiLastItemData +{ + ImGuiID ID; + ImGuiItemFlags InFlags; + ImGuiItemStatusFlags StatusFlags; + ImRect Rect; + ImRect NavRect; + ImRect DisplayRect; +}; +struct ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfItemFlagsStack; + short SizeOfBeginPopupStack; + short SizeOfDisabledStack; +}; +struct ImGuiWindowStackData +{ + ImGuiWindow* Window; + ImGuiLastItemData ParentLastItemDataBackup; + ImGuiStackSizes StackSizesOnBegin; +}; +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; +}; +struct ImGuiPtrOrIndex +{ + void* Ptr; + int Index; +}; +struct ImGuiListClipperRange +{ + int Min; + int Max; + bool PosToIndexConvert; + ImS8 PosToIndexOffsetMin; + ImS8 PosToIndexOffsetMax; +}; +struct ImGuiListClipperData +{ + ImGuiListClipper* ListClipper; + float LossynessOffset; + int StepNo; + int ItemsFrozen; + ImVector_ImGuiListClipperRange Ranges; +}; +typedef enum { + ImGuiActivateFlags_None = 0, + ImGuiActivateFlags_PreferInput = 1 << 0, + ImGuiActivateFlags_PreferTweak = 1 << 1, + ImGuiActivateFlags_TryToPreserveState = 1 << 2 +}ImGuiActivateFlags_; +typedef enum { + ImGuiScrollFlags_None = 0, + ImGuiScrollFlags_KeepVisibleEdgeX = 1 << 0, + ImGuiScrollFlags_KeepVisibleEdgeY = 1 << 1, + ImGuiScrollFlags_KeepVisibleCenterX = 1 << 2, + ImGuiScrollFlags_KeepVisibleCenterY = 1 << 3, + ImGuiScrollFlags_AlwaysCenterX = 1 << 4, + ImGuiScrollFlags_AlwaysCenterY = 1 << 5, + ImGuiScrollFlags_NoScrollParent = 1 << 6, + ImGuiScrollFlags_MaskX_ = ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleCenterX | ImGuiScrollFlags_AlwaysCenterX, + ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY +}ImGuiScrollFlags_; +typedef enum { + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}ImGuiNavHighlightFlags_; +typedef enum { + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_RawKeyboard = 1 << 0, + ImGuiNavDirSourceFlags_Keyboard = 1 << 1, + ImGuiNavDirSourceFlags_PadDPad = 1 << 2, + ImGuiNavDirSourceFlags_PadLStick = 1 << 3 +}ImGuiNavDirSourceFlags_; +typedef enum { + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, + ImGuiNavMoveFlags_WrapY = 1 << 3, + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, + ImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6, + ImGuiNavMoveFlags_Forwarded = 1 << 7, + ImGuiNavMoveFlags_DebugNoResult = 1 << 8, + ImGuiNavMoveFlags_FocusApi = 1 << 9, + ImGuiNavMoveFlags_Tabbing = 1 << 10, + ImGuiNavMoveFlags_Activate = 1 << 11, + ImGuiNavMoveFlags_DontSetNavHighlight = 1 << 12 +}ImGuiNavMoveFlags_; +typedef enum { + ImGuiNavLayer_Main = 0, + ImGuiNavLayer_Menu = 1, + ImGuiNavLayer_COUNT +}ImGuiNavLayer; +struct ImGuiNavItemData +{ + ImGuiWindow* Window; + ImGuiID ID; + ImGuiID FocusScopeId; + ImRect RectRel; + ImGuiItemFlags InFlags; + float DistBox; + float DistCenter; + float DistAxial; +}; +typedef enum { + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, + ImGuiOldColumnFlags_NoResize = 1 << 1, + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4 +}ImGuiOldColumnFlags_; +struct ImGuiOldColumnData +{ + float OffsetNorm; + float OffsetNormBeforeResize; + ImGuiOldColumnFlags Flags; + ImRect ClipRect; +}; +struct ImGuiOldColumns +{ + ImGuiID ID; + ImGuiOldColumnFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float OffMinX, OffMaxX; + float LineMinY, LineMaxY; + float HostCursorPosY; + float HostCursorMaxPosX; + ImRect HostInitialClipRect; + ImRect HostBackupClipRect; + ImRect HostBackupParentWorkRect; + ImVector_ImGuiOldColumnData Columns; + ImDrawListSplitter Splitter; +}; +struct ImGuiViewportP +{ + ImGuiViewport _ImGuiViewport; + int DrawListsLastFrame[2]; + ImDrawList* DrawLists[2]; + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + ImVec2 WorkOffsetMin; + ImVec2 WorkOffsetMax; + ImVec2 BuildWorkOffsetMin; + ImVec2 BuildWorkOffsetMax; +}; +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; +}; +struct ImGuiSettingsHandler +{ + const char* TypeName; + ImGuiID TypeHash; + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); + void* UserData; +}; +struct ImGuiMetricsConfig +{ + bool ShowStackTool; + bool ShowWindowsRects; + bool ShowWindowsBeginOrder; + bool ShowTablesRects; + bool ShowDrawCmdMesh; + bool ShowDrawCmdBoundingBoxes; + int ShowWindowsRectsType; + int ShowTablesRectsType; +}; +struct ImGuiStackLevelInfo +{ + ImGuiID ID; + ImS8 QueryFrameCount; + bool QuerySuccess; + char Desc[58]; +}; +struct ImGuiStackTool +{ + int LastActiveFrame; + int StackLevel; + ImGuiID QueryId; + ImVector_ImGuiStackLevelInfo Results; +}; +typedef enum { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }ImGuiContextHookType; +struct ImGuiContextHook +{ + ImGuiID HookId; + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; +}; +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; + float FontSize; + float FontBaseSize; + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + bool WithinFrameScope; + bool WithinFrameScopeWithImplicitWindow; + bool WithinEndChild; + bool GcCompactAll; + bool TestEngineHookItems; + void* TestEngine; + ImVector_ImGuiWindowPtr Windows; + ImVector_ImGuiWindowPtr WindowsFocusOrder; + ImVector_ImGuiWindowPtr WindowsTempSortBuffer; + ImVector_ImGuiWindowStackData CurrentWindowStack; + ImGuiStorage WindowsById; + int WindowsActiveCount; + ImVec2 WindowsHoverPadding; + ImGuiWindow* CurrentWindow; + ImGuiWindow* HoveredWindow; + ImGuiWindow* HoveredWindowUnderMovingWindow; + ImGuiWindow* MovingWindow; + ImGuiWindow* WheelingWindow; + ImVec2 WheelingWindowRefMousePos; + float WheelingWindowTimer; + ImGuiID DebugHookIdInfo; + ImGuiID HoveredId; + ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdUsingMouseWheel; + bool HoveredIdPreviousFrameUsingMouseWheel; + bool HoveredIdDisabled; + float HoveredIdTimer; + float HoveredIdNotActiveTimer; + ImGuiID ActiveId; + ImGuiID ActiveIdIsAlive; + float ActiveIdTimer; + bool ActiveIdIsJustActivated; + bool ActiveIdAllowOverlap; + bool ActiveIdNoClearOnFocusLoss; + bool ActiveIdHasBeenPressedBefore; + bool ActiveIdHasBeenEditedBefore; + bool ActiveIdHasBeenEditedThisFrame; + bool ActiveIdUsingMouseWheel; + ImU32 ActiveIdUsingNavDirMask; + ImU32 ActiveIdUsingNavInputMask; + ImU64 ActiveIdUsingKeyInputMask; + ImVec2 ActiveIdClickOffset; + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; + float LastActiveIdTimer; + ImGuiItemFlags CurrentItemFlags; + ImGuiNextItemData NextItemData; + ImGuiLastItemData LastItemData; + ImGuiNextWindowData NextWindowData; + ImVector_ImGuiColorMod ColorStack; + ImVector_ImGuiStyleMod StyleVarStack; + ImVector_ImFontPtr FontStack; + ImVector_ImGuiID FocusScopeStack; + ImVector_ImGuiItemFlags ItemFlagsStack; + ImVector_ImGuiGroupData GroupStack; + ImVector_ImGuiPopupData OpenPopupStack; + ImVector_ImGuiPopupData BeginPopupStack; + int BeginMenuCount; + ImVector_ImGuiViewportPPtr Viewports; + ImGuiWindow* NavWindow; + ImGuiID NavId; + ImGuiID NavFocusScopeId; + ImGuiID NavActivateId; + ImGuiID NavActivateDownId; + ImGuiID NavActivatePressedId; + ImGuiID NavActivateInputId; + ImGuiActivateFlags NavActivateFlags; + ImGuiID NavJustMovedToId; + ImGuiID NavJustMovedToFocusScopeId; + ImGuiKeyModFlags NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; + ImGuiActivateFlags NavNextActivateFlags; + ImGuiInputSource NavInputSource; + ImGuiNavLayer NavLayer; + bool NavIdIsAlive; + bool NavMousePosDirty; + bool NavDisableHighlight; + bool NavDisableMouseHover; + bool NavAnyRequest; + bool NavInitRequest; + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; + ImRect NavInitResultRectRel; + bool NavMoveSubmitted; + bool NavMoveScoringItems; + bool NavMoveForwardToNextFrame; + ImGuiNavMoveFlags NavMoveFlags; + ImGuiScrollFlags NavMoveScrollFlags; + ImGuiKeyModFlags NavMoveKeyMods; + ImGuiDir NavMoveDir; + ImGuiDir NavMoveDirForDebug; + ImGuiDir NavMoveClipDir; + ImRect NavScoringRect; + ImRect NavScoringNoClipRect; + int NavScoringDebugCount; + int NavTabbingDir; + int NavTabbingCounter; + ImGuiNavItemData NavMoveResultLocal; + ImGuiNavItemData NavMoveResultLocalVisible; + ImGuiNavItemData NavMoveResultOther; + ImGuiNavItemData NavTabbingResultFirst; + ImGuiWindow* NavWindowingTarget; + ImGuiWindow* NavWindowingTargetAnim; + ImGuiWindow* NavWindowingListWindow; + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + float DimBgRatio; + ImGuiMouseCursor MouseCursor; + bool DragDropActive; + bool DragDropWithinSource; + bool DragDropWithinTarget; + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; + ImGuiID DragDropAcceptIdCurr; + ImGuiID DragDropAcceptIdPrev; + int DragDropAcceptFrameCount; + ImGuiID DragDropHoldJustPressedId; + ImVector_unsigned_char DragDropPayloadBufHeap; + unsigned char DragDropPayloadBufLocal[16]; + int ClipperTempDataStacked; + ImVector_ImGuiListClipperData ClipperTempData; + ImGuiTable* CurrentTable; + int TablesTempDataStacked; + ImVector_ImGuiTableTempData TablesTempData; + ImPool_ImGuiTable Tables; + ImVector_float TablesLastTimeActive; + ImVector_ImDrawChannel DrawChannelsTempMergeBuffer; + ImGuiTabBar* CurrentTabBar; + ImPool_ImGuiTabBar TabBars; + ImVector_ImGuiPtrOrIndex CurrentTabBarStack; + ImVector_ImGuiShrinkWidthItem ShrinkWidthBuffer; + ImVec2 MouseLastValidPos; + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; + ImGuiColorEditFlags ColorEditOptions; + float ColorEditLastHue; + float ColorEditLastSat; + ImU32 ColorEditLastColor; + ImVec4 ColorPickerRef; + ImGuiComboPreviewData ComboPreviewData; + float SliderCurrentAccum; + bool SliderCurrentAccumDirty; + bool DragCurrentAccumDirty; + float DragCurrentAccum; + float DragSpeedDefaultRatio; + float ScrollbarClickDeltaToGrabCenter; + float DisabledAlphaBackup; + short DisabledStackSize; + short TooltipOverrideCount; + float TooltipSlowDelay; + ImVector_char ClipboardHandlerData; + ImVector_ImGuiID MenusIdSubmittedThisFrame; + ImVec2 PlatformImePos; + ImVec2 PlatformImeLastPos; + char PlatformLocaleDecimalPoint; + bool SettingsLoaded; + float SettingsDirtyTimer; + ImGuiTextBuffer SettingsIniData; + ImVector_ImGuiSettingsHandler SettingsHandlers; + ImChunkStream_ImGuiWindowSettings SettingsWindows; + ImChunkStream_ImGuiTableSettings SettingsTables; + ImVector_ImGuiContextHook Hooks; + ImGuiID HookIdNext; + bool LogEnabled; + ImGuiLogType LogType; + ImFileHandle LogFile; + ImGuiTextBuffer LogBuffer; + const char* LogNextPrefix; + const char* LogNextSuffix; + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; + bool DebugItemPickerActive; + ImGuiID DebugItemPickerBreakId; + ImGuiMetricsConfig DebugMetricsConfig; + ImGuiStackTool DebugStackTool; + float FramerateSecPerFrame[120]; + int FramerateSecPerFrameIdx; + int FramerateSecPerFrameCount; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024 * 3 + 1]; +}; +struct ImGuiWindowTempData +{ + ImVec2 CursorPos; + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; + ImVec2 CursorMaxPos; + ImVec2 IdealMaxPos; + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; + float PrevLineTextBaseOffset; + ImVec1 Indent; + ImVec1 ColumnsOffset; + ImVec1 GroupOffset; + ImVec2 CursorStartPosLossyness; + ImGuiNavLayer NavLayerCurrent; + short NavLayersActiveMask; + short NavLayersActiveMaskNext; + ImGuiID NavFocusScopeIdCurrent; + bool NavHideHighlightOneFrame; + bool NavHasScroll; + bool MenuBarAppending; + ImVec2 MenuBarOffset; + ImGuiMenuColumns MenuColumns; + int TreeDepth; + ImU32 TreeJumpToParentOnPopMask; + ImVector_ImGuiWindowPtr ChildWindows; + ImGuiStorage* StateStorage; + ImGuiOldColumns* CurrentColumns; + int CurrentTableIdx; + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; + float ItemWidth; + float TextWrapPos; + ImVector_float ItemWidthStack; + ImVector_float TextWrapPosStack; +}; +struct ImGuiWindow +{ + char* Name; + ImGuiID ID; + ImGuiWindowFlags Flags; + ImVec2 Pos; + ImVec2 Size; + ImVec2 SizeFull; + ImVec2 ContentSize; + ImVec2 ContentSizeIdeal; + ImVec2 ContentSizeExplicit; + ImVec2 WindowPadding; + float WindowRounding; + float WindowBorderSize; + int NameBufLen; + ImGuiID MoveId; + ImGuiID ChildId; + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; + ImVec2 ScrollTargetCenterRatio; + ImVec2 ScrollTargetEdgeSnapDist; + ImVec2 ScrollbarSizes; + bool ScrollbarX, ScrollbarY; + bool Active; + bool WasActive; + bool WriteAccessed; + bool Collapsed; + bool WantCollapseToggle; + bool SkipItems; + bool Appearing; + bool Hidden; + bool IsFallbackWindow; + bool IsExplicitChild; + bool HasCloseButton; + signed char ResizeBorderHeld; + short BeginCount; + short BeginOrderWithinParent; + short BeginOrderWithinContext; + short FocusOrder; + ImGuiID PopupId; + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + ImS8 HiddenFramesCanSkipItems; + ImS8 HiddenFramesCannotSkipItems; + ImS8 HiddenFramesForRenderOnly; + ImS8 DisableInputsFrames; + ImGuiCond SetWindowPosAllowFlags : 8; + ImGuiCond SetWindowSizeAllowFlags : 8; + ImGuiCond SetWindowCollapsedAllowFlags : 8; + ImVec2 SetWindowPosVal; + ImVec2 SetWindowPosPivot; + ImVector_ImGuiID IDStack; + ImGuiWindowTempData DC; + ImRect OuterRectClipped; + ImRect InnerRect; + ImRect InnerClipRect; + ImRect WorkRect; + ImRect ParentWorkRect; + ImRect ClipRect; + ImRect ContentRegionRect; + ImVec2ih HitTestHoleSize; + ImVec2ih HitTestHoleOffset; + int LastFrameActive; + float LastTimeActive; + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector_ImGuiOldColumns ColumnsStorage; + float FontWindowScale; + int SettingsOffset; + ImDrawList* DrawList; + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; + ImGuiWindow* ParentWindowInBeginStack; + ImGuiWindow* RootWindow; + ImGuiWindow* RootWindowPopupTree; + ImGuiWindow* RootWindowForTitleBarHighlight; + ImGuiWindow* RootWindowForNav; + ImGuiWindow* NavLastChildNavWindow; + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; + ImRect NavRectRel[ImGuiNavLayer_COUNT]; + int MemoryDrawListIdxCapacity; + int MemoryDrawListVtxCapacity; + bool MemoryCompacted; +}; +typedef enum { + ImGuiTabBarFlags_DockNode = 1 << 20, + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 +}ImGuiTabBarFlagsPrivate_; +typedef enum { + ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, + ImGuiTabItemFlags_NoCloseButton = 1 << 20, + ImGuiTabItemFlags_Button = 1 << 21 +}ImGuiTabItemFlagsPrivate_; +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; + float Offset; + float Width; + float ContentWidth; + ImS32 NameOffset; + ImS16 BeginOrder; + ImS16 IndexDuringLayout; + bool WantClose; +}; +struct ImGuiTabBar +{ + ImVector_ImGuiTabItem Tabs; + ImGuiTabBarFlags Flags; + ImGuiID ID; + ImGuiID SelectedTabId; + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; + float WidthAllTabs; + float WidthAllTabsIdeal; + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + float ScrollingRectMinX; + float ScrollingRectMaxX; + ImGuiID ReorderRequestTabId; + ImS16 ReorderRequestOffset; + ImS8 BeginCount; + bool WantLayout; + bool VisibleTabWasSubmitted; + bool TabsAddedNew; + ImS16 TabsActiveCount; + ImS16 LastTabItemIdx; + float ItemSpacingY; + ImVec2 FramePadding; + ImVec2 BackupCursorPos; + ImGuiTextBuffer TabsNames; +}; +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; + float WidthGiven; + float MinX; + float MaxX; + float WidthRequest; + float WidthAuto; + float StretchWeight; + float InitStretchWeightOrWidth; + ImRect ClipRect; + ImGuiID UserID; + float WorkMinX; + float WorkMaxX; + float ItemWidth; + float ContentMaxXFrozen; + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx IndexWithinEnabledSet; + ImGuiTableColumnIdx PrevEnabledColumn; + ImGuiTableColumnIdx NextEnabledColumn; + ImGuiTableColumnIdx SortOrder; + ImGuiTableDrawChannelIdx DrawChannelCurrent; + ImGuiTableDrawChannelIdx DrawChannelFrozen; + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; + bool IsEnabled; + bool IsUserEnabled; + bool IsUserEnabledNextFrame; + bool IsVisibleX; + bool IsVisibleY; + bool IsRequestOutput; + bool IsSkipItems; + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; + ImU8 AutoFitQueue; + ImU8 CannotSkipItemsQueue; + ImU8 SortDirection : 2; + ImU8 SortDirectionsAvailCount : 2; + ImU8 SortDirectionsAvailMask : 4; + ImU8 SortDirectionsAvailList; +}; +struct ImGuiTableCellData +{ + ImU32 BgColor; + ImGuiTableColumnIdx Column; +}; +struct ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; + ImGuiTableTempData* TempData; + ImSpan_ImGuiTableColumn Columns; + ImSpan_ImGuiTableColumnIdx DisplayOrderToIndex; + ImSpan_ImGuiTableCellData RowCellData; + ImU64 EnabledMaskByDisplayOrder; + ImU64 EnabledMaskByIndex; + ImU64 VisibleMaskByIndex; + ImU64 RequestOutputMaskByIndex; + ImGuiTableFlags SettingsLoadedFlags; + int SettingsOffset; + int LastFrameActive; + int ColumnsCount; + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; + ImS16 InstanceInteracted; + float RowPosY1; + float RowPosY2; + float RowMinHeight; + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; + ImU32 RowBgColor[2]; + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; + float CellPaddingY; + float CellSpacingX1; + float CellSpacingX2; + float LastOuterHeight; + float LastFirstRowHeight; + float InnerWidth; + float ColumnsGivenWidth; + float ColumnsAutoFitWidth; + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; + float RefScale; + ImRect OuterRect; + ImRect InnerRect; + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; + ImRect Bg0ClipRectForDrawCmd; + ImRect Bg2ClipRectForDrawCmd; + ImRect HostClipRect; + ImRect HostBackupInnerClipRect; + ImGuiWindow* OuterWindow; + ImGuiWindow* InnerWindow; + ImGuiTextBuffer ColumnsNames; + ImDrawListSplitter* DrawSplitter; + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector_ImGuiTableColumnSortSpecs SortSpecsMulti; + ImGuiTableSortSpecs SortSpecs; + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; + ImGuiTableColumnIdx ColumnsEnabledFixedCount; + ImGuiTableColumnIdx DeclColumnsCount; + ImGuiTableColumnIdx HoveredColumnBody; + ImGuiTableColumnIdx HoveredColumnBorder; + ImGuiTableColumnIdx AutoFitSingleColumn; + ImGuiTableColumnIdx ResizedColumn; + ImGuiTableColumnIdx LastResizedColumn; + ImGuiTableColumnIdx HeldHeaderColumn; + ImGuiTableColumnIdx ReorderColumn; + ImGuiTableColumnIdx ReorderColumnDir; + ImGuiTableColumnIdx LeftMostEnabledColumn; + ImGuiTableColumnIdx RightMostEnabledColumn; + ImGuiTableColumnIdx LeftMostStretchedColumn; + ImGuiTableColumnIdx RightMostStretchedColumn; + ImGuiTableColumnIdx ContextPopupColumn; + ImGuiTableColumnIdx FreezeRowsRequest; + ImGuiTableColumnIdx FreezeRowsCount; + ImGuiTableColumnIdx FreezeColumnsRequest; + ImGuiTableColumnIdx FreezeColumnsCount; + ImGuiTableColumnIdx RowCellDataCurrent; + ImGuiTableDrawChannelIdx DummyDrawChannel; + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; + bool IsInsideRow; + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; + bool IsContextPopupOpen; + bool IsSettingsRequestLoad; + bool IsSettingsDirty; + bool IsDefaultDisplayOrder; + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; + bool IsDefaultSizingPolicy; + bool MemoryCompacted; + bool HostSkipItems; +}; +struct ImGuiTableTempData +{ + int TableIndex; + float LastTimeActive; + ImVec2 UserOuterSize; + ImDrawListSplitter DrawSplitter; + ImRect HostBackupWorkRect; + ImRect HostBackupParentWorkRect; + ImVec2 HostBackupPrevLineSize; + ImVec2 HostBackupCurrLineSize; + ImVec2 HostBackupCursorMaxPos; + ImVec1 HostBackupColumnsOffset; + float HostBackupItemWidth; + int HostBackupItemWidthStackSize; +}; +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; + ImU8 IsStretch : 1; +}; +struct ImGuiTableSettings +{ + ImGuiID ID; + ImGuiTableFlags SaveFlags; + float RefScale; + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; + bool WantApply; +}; +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; +#else +struct GLFWwindow; +struct SDL_Window; +typedef union SDL_Event SDL_Event; +#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS + +#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS +typedef struct ImGuiStorage::ImGuiStoragePair ImGuiStoragePair; +typedef struct ImGuiTextFilter::ImGuiTextRange ImGuiTextRange; +typedef ImStb::STB_TexteditState STB_TexteditState; +typedef ImStb::StbTexteditRow StbTexteditRow; +typedef ImStb::StbUndoRecord StbUndoRecord; +typedef ImStb::StbUndoState StbUndoState; +typedef ImChunkStream ImChunkStream_ImGuiTableSettings; +typedef ImChunkStream ImChunkStream_ImGuiWindowSettings; +typedef ImPool ImPool_ImGuiTabBar; +typedef ImPool ImPool_ImGuiTable; +typedef ImSpan ImSpan_ImGuiTableCellData; +typedef ImSpan ImSpan_ImGuiTableColumn; +typedef ImSpan ImSpan_ImGuiTableColumnIdx; +typedef ImVector ImVector_ImDrawChannel; +typedef ImVector ImVector_ImDrawCmd; +typedef ImVector ImVector_ImDrawIdx; +typedef ImVector ImVector_ImDrawListPtr; +typedef ImVector ImVector_ImDrawVert; +typedef ImVector ImVector_ImFontPtr; +typedef ImVector ImVector_ImFontAtlasCustomRect; +typedef ImVector ImVector_ImFontConfig; +typedef ImVector ImVector_ImFontGlyph; +typedef ImVector ImVector_ImGuiColorMod; +typedef ImVector ImVector_ImGuiContextHook; +typedef ImVector ImVector_ImGuiGroupData; +typedef ImVector ImVector_ImGuiID; +typedef ImVector ImVector_ImGuiItemFlags; +typedef ImVector ImVector_ImGuiListClipperData; +typedef ImVector ImVector_ImGuiListClipperRange; +typedef ImVector ImVector_ImGuiOldColumnData; +typedef ImVector ImVector_ImGuiOldColumns; +typedef ImVector ImVector_ImGuiPopupData; +typedef ImVector ImVector_ImGuiPtrOrIndex; +typedef ImVector ImVector_ImGuiSettingsHandler; +typedef ImVector ImVector_ImGuiShrinkWidthItem; +typedef ImVector ImVector_ImGuiStackLevelInfo; +typedef ImVector ImVector_ImGuiStoragePair; +typedef ImVector ImVector_ImGuiStyleMod; +typedef ImVector ImVector_ImGuiTabItem; +typedef ImVector ImVector_ImGuiTableColumnSortSpecs; +typedef ImVector ImVector_ImGuiTableTempData; +typedef ImVector ImVector_ImGuiTextRange; +typedef ImVector ImVector_ImGuiViewportPPtr; +typedef ImVector ImVector_ImGuiWindowPtr; +typedef ImVector ImVector_ImGuiWindowStackData; +typedef ImVector ImVector_ImTextureID; +typedef ImVector ImVector_ImU32; +typedef ImVector ImVector_ImVec2; +typedef ImVector ImVector_ImVec4; +typedef ImVector ImVector_ImWchar; +typedef ImVector ImVector_char; +typedef ImVector ImVector_float; +typedef ImVector ImVector_unsigned_char; +#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS +CIMGUI_API ImVec2* ImVec2_ImVec2_Nil(void); +CIMGUI_API void ImVec2_destroy(ImVec2* self); +CIMGUI_API ImVec2* ImVec2_ImVec2_Float(float _x,float _y); +CIMGUI_API ImVec4* ImVec4_ImVec4_Nil(void); +CIMGUI_API void ImVec4_destroy(ImVec4* self); +CIMGUI_API ImVec4* ImVec4_ImVec4_Float(float _x,float _y,float _z,float _w); +CIMGUI_API ImGuiContext* igCreateContext(ImFontAtlas* shared_font_atlas); +CIMGUI_API void igDestroyContext(ImGuiContext* ctx); +CIMGUI_API ImGuiContext* igGetCurrentContext(void); +CIMGUI_API void igSetCurrentContext(ImGuiContext* ctx); +CIMGUI_API ImGuiIO* igGetIO(void); +CIMGUI_API ImGuiStyle* igGetStyle(void); +CIMGUI_API void igNewFrame(void); +CIMGUI_API void igEndFrame(void); +CIMGUI_API void igRender(void); +CIMGUI_API ImDrawData* igGetDrawData(void); +CIMGUI_API void igShowDemoWindow(bool* p_open); +CIMGUI_API void igShowMetricsWindow(bool* p_open); +CIMGUI_API void igShowStackToolWindow(bool* p_open); +CIMGUI_API void igShowAboutWindow(bool* p_open); +CIMGUI_API void igShowStyleEditor(ImGuiStyle* ref); +CIMGUI_API bool igShowStyleSelector(const char* label); +CIMGUI_API void igShowFontSelector(const char* label); +CIMGUI_API void igShowUserGuide(void); +CIMGUI_API const char* igGetVersion(void); +CIMGUI_API void igStyleColorsDark(ImGuiStyle* dst); +CIMGUI_API void igStyleColorsLight(ImGuiStyle* dst); +CIMGUI_API void igStyleColorsClassic(ImGuiStyle* dst); +CIMGUI_API bool igBegin(const char* name,bool* p_open,ImGuiWindowFlags flags); +CIMGUI_API void igEnd(void); +CIMGUI_API bool igBeginChild_Str(const char* str_id,const ImVec2 size,bool border,ImGuiWindowFlags flags); +CIMGUI_API bool igBeginChild_ID(ImGuiID id,const ImVec2 size,bool border,ImGuiWindowFlags flags); +CIMGUI_API void igEndChild(void); +CIMGUI_API bool igIsWindowAppearing(void); +CIMGUI_API bool igIsWindowCollapsed(void); +CIMGUI_API bool igIsWindowFocused(ImGuiFocusedFlags flags); +CIMGUI_API bool igIsWindowHovered(ImGuiHoveredFlags flags); +CIMGUI_API ImDrawList* igGetWindowDrawList(void); +CIMGUI_API void igGetWindowPos(ImVec2 *pOut); +CIMGUI_API void igGetWindowSize(ImVec2 *pOut); +CIMGUI_API float igGetWindowWidth(void); +CIMGUI_API float igGetWindowHeight(void); +CIMGUI_API void igSetNextWindowPos(const ImVec2 pos,ImGuiCond cond,const ImVec2 pivot); +CIMGUI_API void igSetNextWindowSize(const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetNextWindowSizeConstraints(const ImVec2 size_min,const ImVec2 size_max,ImGuiSizeCallback custom_callback,void* custom_callback_data); +CIMGUI_API void igSetNextWindowContentSize(const ImVec2 size); +CIMGUI_API void igSetNextWindowCollapsed(bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetNextWindowFocus(void); +CIMGUI_API void igSetNextWindowBgAlpha(float alpha); +CIMGUI_API void igSetWindowPos_Vec2(const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_Vec2(const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_Bool(bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowFocus_Nil(void); +CIMGUI_API void igSetWindowFontScale(float scale); +CIMGUI_API void igSetWindowPos_Str(const char* name,const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_Str(const char* name,const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_Str(const char* name,bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowFocus_Str(const char* name); +CIMGUI_API void igGetContentRegionAvail(ImVec2 *pOut); +CIMGUI_API void igGetContentRegionMax(ImVec2 *pOut); +CIMGUI_API void igGetWindowContentRegionMin(ImVec2 *pOut); +CIMGUI_API void igGetWindowContentRegionMax(ImVec2 *pOut); +CIMGUI_API float igGetScrollX(void); +CIMGUI_API float igGetScrollY(void); +CIMGUI_API void igSetScrollX_Float(float scroll_x); +CIMGUI_API void igSetScrollY_Float(float scroll_y); +CIMGUI_API float igGetScrollMaxX(void); +CIMGUI_API float igGetScrollMaxY(void); +CIMGUI_API void igSetScrollHereX(float center_x_ratio); +CIMGUI_API void igSetScrollHereY(float center_y_ratio); +CIMGUI_API void igSetScrollFromPosX_Float(float local_x,float center_x_ratio); +CIMGUI_API void igSetScrollFromPosY_Float(float local_y,float center_y_ratio); +CIMGUI_API void igPushFont(ImFont* font); +CIMGUI_API void igPopFont(void); +CIMGUI_API void igPushStyleColor_U32(ImGuiCol idx,ImU32 col); +CIMGUI_API void igPushStyleColor_Vec4(ImGuiCol idx,const ImVec4 col); +CIMGUI_API void igPopStyleColor(int count); +CIMGUI_API void igPushStyleVar_Float(ImGuiStyleVar idx,float val); +CIMGUI_API void igPushStyleVar_Vec2(ImGuiStyleVar idx,const ImVec2 val); +CIMGUI_API void igPopStyleVar(int count); +CIMGUI_API void igPushAllowKeyboardFocus(bool allow_keyboard_focus); +CIMGUI_API void igPopAllowKeyboardFocus(void); +CIMGUI_API void igPushButtonRepeat(bool repeat); +CIMGUI_API void igPopButtonRepeat(void); +CIMGUI_API void igPushItemWidth(float item_width); +CIMGUI_API void igPopItemWidth(void); +CIMGUI_API void igSetNextItemWidth(float item_width); +CIMGUI_API float igCalcItemWidth(void); +CIMGUI_API void igPushTextWrapPos(float wrap_local_pos_x); +CIMGUI_API void igPopTextWrapPos(void); +CIMGUI_API ImFont* igGetFont(void); +CIMGUI_API float igGetFontSize(void); +CIMGUI_API void igGetFontTexUvWhitePixel(ImVec2 *pOut); +CIMGUI_API ImU32 igGetColorU32_Col(ImGuiCol idx,float alpha_mul); +CIMGUI_API ImU32 igGetColorU32_Vec4(const ImVec4 col); +CIMGUI_API ImU32 igGetColorU32_U32(ImU32 col); +CIMGUI_API const ImVec4* igGetStyleColorVec4(ImGuiCol idx); +CIMGUI_API void igSeparator(void); +CIMGUI_API void igSameLine(float offset_from_start_x,float spacing); +CIMGUI_API void igNewLine(void); +CIMGUI_API void igSpacing(void); +CIMGUI_API void igDummy(const ImVec2 size); +CIMGUI_API void igIndent(float indent_w); +CIMGUI_API void igUnindent(float indent_w); +CIMGUI_API void igBeginGroup(void); +CIMGUI_API void igEndGroup(void); +CIMGUI_API void igGetCursorPos(ImVec2 *pOut); +CIMGUI_API float igGetCursorPosX(void); +CIMGUI_API float igGetCursorPosY(void); +CIMGUI_API void igSetCursorPos(const ImVec2 local_pos); +CIMGUI_API void igSetCursorPosX(float local_x); +CIMGUI_API void igSetCursorPosY(float local_y); +CIMGUI_API void igGetCursorStartPos(ImVec2 *pOut); +CIMGUI_API void igGetCursorScreenPos(ImVec2 *pOut); +CIMGUI_API void igSetCursorScreenPos(const ImVec2 pos); +CIMGUI_API void igAlignTextToFramePadding(void); +CIMGUI_API float igGetTextLineHeight(void); +CIMGUI_API float igGetTextLineHeightWithSpacing(void); +CIMGUI_API float igGetFrameHeight(void); +CIMGUI_API float igGetFrameHeightWithSpacing(void); +CIMGUI_API void igPushID_Str(const char* str_id); +CIMGUI_API void igPushID_StrStr(const char* str_id_begin,const char* str_id_end); +CIMGUI_API void igPushID_Ptr(const void* ptr_id); +CIMGUI_API void igPushID_Int(int int_id); +CIMGUI_API void igPopID(void); +CIMGUI_API ImGuiID igGetID_Str(const char* str_id); +CIMGUI_API ImGuiID igGetID_StrStr(const char* str_id_begin,const char* str_id_end); +CIMGUI_API ImGuiID igGetID_Ptr(const void* ptr_id); +CIMGUI_API void igTextUnformatted(const char* text,const char* text_end); +CIMGUI_API void igText(const char* fmt,...); +CIMGUI_API void igTextV(const char* fmt,va_list args); +CIMGUI_API void igTextColored(const ImVec4 col,const char* fmt,...); +CIMGUI_API void igTextColoredV(const ImVec4 col,const char* fmt,va_list args); +CIMGUI_API void igTextDisabled(const char* fmt,...); +CIMGUI_API void igTextDisabledV(const char* fmt,va_list args); +CIMGUI_API void igTextWrapped(const char* fmt,...); +CIMGUI_API void igTextWrappedV(const char* fmt,va_list args); +CIMGUI_API void igLabelText(const char* label,const char* fmt,...); +CIMGUI_API void igLabelTextV(const char* label,const char* fmt,va_list args); +CIMGUI_API void igBulletText(const char* fmt,...); +CIMGUI_API void igBulletTextV(const char* fmt,va_list args); +CIMGUI_API bool igButton(const char* label,const ImVec2 size); +CIMGUI_API bool igSmallButton(const char* label); +CIMGUI_API bool igInvisibleButton(const char* str_id,const ImVec2 size,ImGuiButtonFlags flags); +CIMGUI_API bool igArrowButton(const char* str_id,ImGuiDir dir); +CIMGUI_API void igImage(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec4 tint_col,const ImVec4 border_col); +CIMGUI_API bool igImageButton(ImTextureID user_texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,int frame_padding,const ImVec4 bg_col,const ImVec4 tint_col); +CIMGUI_API bool igCheckbox(const char* label,bool* v); +CIMGUI_API bool igCheckboxFlags_IntPtr(const char* label,int* flags,int flags_value); +CIMGUI_API bool igCheckboxFlags_UintPtr(const char* label,unsigned int* flags,unsigned int flags_value); +CIMGUI_API bool igRadioButton_Bool(const char* label,bool active); +CIMGUI_API bool igRadioButton_IntPtr(const char* label,int* v,int v_button); +CIMGUI_API void igProgressBar(float fraction,const ImVec2 size_arg,const char* overlay); +CIMGUI_API void igBullet(void); +CIMGUI_API bool igBeginCombo(const char* label,const char* preview_value,ImGuiComboFlags flags); +CIMGUI_API void igEndCombo(void); +CIMGUI_API bool igCombo_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int popup_max_height_in_items); +CIMGUI_API bool igCombo_Str(const char* label,int* current_item,const char* items_separated_by_zeros,int popup_max_height_in_items); +CIMGUI_API bool igCombo_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int popup_max_height_in_items); +CIMGUI_API bool igDragFloat(const char* label,float* v,float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat2(const char* label,float v[2],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat3(const char* label,float v[3],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloat4(const char* label,float v[4],float v_speed,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragFloatRange2(const char* label,float* v_current_min,float* v_current_max,float v_speed,float v_min,float v_max,const char* format,const char* format_max,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt(const char* label,int* v,float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt2(const char* label,int v[2],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt3(const char* label,int v[3],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragInt4(const char* label,int v[4],float v_speed,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragIntRange2(const char* label,int* v_current_min,int* v_current_max,float v_speed,int v_min,int v_max,const char* format,const char* format_max,ImGuiSliderFlags flags); +CIMGUI_API bool igDragScalar(const char* label,ImGuiDataType data_type,void* p_data,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igDragScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat(const char* label,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat2(const char* label,float v[2],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat3(const char* label,float v[3],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderFloat4(const char* label,float v[4],float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderAngle(const char* label,float* v_rad,float v_degrees_min,float v_degrees_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt(const char* label,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt2(const char* label,int v[2],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt3(const char* label,int v[3],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderInt4(const char* label,int v[4],int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderFloat(const char* label,const ImVec2 size,float* v,float v_min,float v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderInt(const char* label,const ImVec2 size,int* v,int v_min,int v_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igVSliderScalar(const char* label,const ImVec2 size,ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igInputText(const char* label,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputTextMultiline(const char* label,char* buf,size_t buf_size,const ImVec2 size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputTextWithHint(const char* label,const char* hint,char* buf,size_t buf_size,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igInputFloat(const char* label,float* v,float step,float step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat2(const char* label,float v[2],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat3(const char* label,float v[3],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputFloat4(const char* label,float v[4],const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt(const char* label,int* v,int step,int step_fast,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt2(const char* label,int v[2],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt3(const char* label,int v[3],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputInt4(const char* label,int v[4],ImGuiInputTextFlags flags); +CIMGUI_API bool igInputDouble(const char* label,double* v,double step,double step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputScalar(const char* label,ImGuiDataType data_type,void* p_data,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igInputScalarN(const char* label,ImGuiDataType data_type,void* p_data,int components,const void* p_step,const void* p_step_fast,const char* format,ImGuiInputTextFlags flags); +CIMGUI_API bool igColorEdit3(const char* label,float col[3],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorEdit4(const char* label,float col[4],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorPicker3(const char* label,float col[3],ImGuiColorEditFlags flags); +CIMGUI_API bool igColorPicker4(const char* label,float col[4],ImGuiColorEditFlags flags,const float* ref_col); +CIMGUI_API bool igColorButton(const char* desc_id,const ImVec4 col,ImGuiColorEditFlags flags,ImVec2 size); +CIMGUI_API void igSetColorEditOptions(ImGuiColorEditFlags flags); +CIMGUI_API bool igTreeNode_Str(const char* label); +CIMGUI_API bool igTreeNode_StrStr(const char* str_id,const char* fmt,...); +CIMGUI_API bool igTreeNode_Ptr(const void* ptr_id,const char* fmt,...); +CIMGUI_API bool igTreeNodeV_Str(const char* str_id,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeV_Ptr(const void* ptr_id,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeEx_Str(const char* label,ImGuiTreeNodeFlags flags); +CIMGUI_API bool igTreeNodeEx_StrStr(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,...); +CIMGUI_API bool igTreeNodeEx_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,...); +CIMGUI_API bool igTreeNodeExV_Str(const char* str_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args); +CIMGUI_API bool igTreeNodeExV_Ptr(const void* ptr_id,ImGuiTreeNodeFlags flags,const char* fmt,va_list args); +CIMGUI_API void igTreePush_Str(const char* str_id); +CIMGUI_API void igTreePush_Ptr(const void* ptr_id); +CIMGUI_API void igTreePop(void); +CIMGUI_API float igGetTreeNodeToLabelSpacing(void); +CIMGUI_API bool igCollapsingHeader_TreeNodeFlags(const char* label,ImGuiTreeNodeFlags flags); +CIMGUI_API bool igCollapsingHeader_BoolPtr(const char* label,bool* p_visible,ImGuiTreeNodeFlags flags); +CIMGUI_API void igSetNextItemOpen(bool is_open,ImGuiCond cond); +CIMGUI_API bool igSelectable_Bool(const char* label,bool selected,ImGuiSelectableFlags flags,const ImVec2 size); +CIMGUI_API bool igSelectable_BoolPtr(const char* label,bool* p_selected,ImGuiSelectableFlags flags,const ImVec2 size); +CIMGUI_API bool igBeginListBox(const char* label,const ImVec2 size); +CIMGUI_API void igEndListBox(void); +CIMGUI_API bool igListBox_Str_arr(const char* label,int* current_item,const char* const items[],int items_count,int height_in_items); +CIMGUI_API bool igListBox_FnBoolPtr(const char* label,int* current_item,bool(*items_getter)(void* data,int idx,const char** out_text),void* data,int items_count,int height_in_items); +CIMGUI_API void igPlotLines_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride); +CIMGUI_API void igPlotLines_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size); +CIMGUI_API void igPlotHistogram_FloatPtr(const char* label,const float* values,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size,int stride); +CIMGUI_API void igPlotHistogram_FnFloatPtr(const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 graph_size); +CIMGUI_API void igValue_Bool(const char* prefix,bool b); +CIMGUI_API void igValue_Int(const char* prefix,int v); +CIMGUI_API void igValue_Uint(const char* prefix,unsigned int v); +CIMGUI_API void igValue_Float(const char* prefix,float v,const char* float_format); +CIMGUI_API bool igBeginMenuBar(void); +CIMGUI_API void igEndMenuBar(void); +CIMGUI_API bool igBeginMainMenuBar(void); +CIMGUI_API void igEndMainMenuBar(void); +CIMGUI_API bool igBeginMenu(const char* label,bool enabled); +CIMGUI_API void igEndMenu(void); +CIMGUI_API bool igMenuItem_Bool(const char* label,const char* shortcut,bool selected,bool enabled); +CIMGUI_API bool igMenuItem_BoolPtr(const char* label,const char* shortcut,bool* p_selected,bool enabled); +CIMGUI_API void igBeginTooltip(void); +CIMGUI_API void igEndTooltip(void); +CIMGUI_API void igSetTooltip(const char* fmt,...); +CIMGUI_API void igSetTooltipV(const char* fmt,va_list args); +CIMGUI_API bool igBeginPopup(const char* str_id,ImGuiWindowFlags flags); +CIMGUI_API bool igBeginPopupModal(const char* name,bool* p_open,ImGuiWindowFlags flags); +CIMGUI_API void igEndPopup(void); +CIMGUI_API void igOpenPopup_Str(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igOpenPopup_ID(ImGuiID id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igOpenPopupOnItemClick(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igCloseCurrentPopup(void); +CIMGUI_API bool igBeginPopupContextItem(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupContextWindow(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupContextVoid(const char* str_id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igIsPopupOpen_Str(const char* str_id,ImGuiPopupFlags flags); +CIMGUI_API bool igBeginTable(const char* str_id,int column,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width); +CIMGUI_API void igEndTable(void); +CIMGUI_API void igTableNextRow(ImGuiTableRowFlags row_flags,float min_row_height); +CIMGUI_API bool igTableNextColumn(void); +CIMGUI_API bool igTableSetColumnIndex(int column_n); +CIMGUI_API void igTableSetupColumn(const char* label,ImGuiTableColumnFlags flags,float init_width_or_weight,ImGuiID user_id); +CIMGUI_API void igTableSetupScrollFreeze(int cols,int rows); +CIMGUI_API void igTableHeadersRow(void); +CIMGUI_API void igTableHeader(const char* label); +CIMGUI_API ImGuiTableSortSpecs* igTableGetSortSpecs(void); +CIMGUI_API int igTableGetColumnCount(void); +CIMGUI_API int igTableGetColumnIndex(void); +CIMGUI_API int igTableGetRowIndex(void); +CIMGUI_API const char* igTableGetColumnName_Int(int column_n); +CIMGUI_API ImGuiTableColumnFlags igTableGetColumnFlags(int column_n); +CIMGUI_API void igTableSetColumnEnabled(int column_n,bool v); +CIMGUI_API void igTableSetBgColor(ImGuiTableBgTarget target,ImU32 color,int column_n); +CIMGUI_API void igColumns(int count,const char* id,bool border); +CIMGUI_API void igNextColumn(void); +CIMGUI_API int igGetColumnIndex(void); +CIMGUI_API float igGetColumnWidth(int column_index); +CIMGUI_API void igSetColumnWidth(int column_index,float width); +CIMGUI_API float igGetColumnOffset(int column_index); +CIMGUI_API void igSetColumnOffset(int column_index,float offset_x); +CIMGUI_API int igGetColumnsCount(void); +CIMGUI_API bool igBeginTabBar(const char* str_id,ImGuiTabBarFlags flags); +CIMGUI_API void igEndTabBar(void); +CIMGUI_API bool igBeginTabItem(const char* label,bool* p_open,ImGuiTabItemFlags flags); +CIMGUI_API void igEndTabItem(void); +CIMGUI_API bool igTabItemButton(const char* label,ImGuiTabItemFlags flags); +CIMGUI_API void igSetTabItemClosed(const char* tab_or_docked_window_label); +CIMGUI_API void igLogToTTY(int auto_open_depth); +CIMGUI_API void igLogToFile(int auto_open_depth,const char* filename); +CIMGUI_API void igLogToClipboard(int auto_open_depth); +CIMGUI_API void igLogFinish(void); +CIMGUI_API void igLogButtons(void); +CIMGUI_API void igLogTextV(const char* fmt,va_list args); +CIMGUI_API bool igBeginDragDropSource(ImGuiDragDropFlags flags); +CIMGUI_API bool igSetDragDropPayload(const char* type,const void* data,size_t sz,ImGuiCond cond); +CIMGUI_API void igEndDragDropSource(void); +CIMGUI_API bool igBeginDragDropTarget(void); +CIMGUI_API const ImGuiPayload* igAcceptDragDropPayload(const char* type,ImGuiDragDropFlags flags); +CIMGUI_API void igEndDragDropTarget(void); +CIMGUI_API const ImGuiPayload* igGetDragDropPayload(void); +CIMGUI_API void igBeginDisabled(bool disabled); +CIMGUI_API void igEndDisabled(void); +CIMGUI_API void igPushClipRect(const ImVec2 clip_rect_min,const ImVec2 clip_rect_max,bool intersect_with_current_clip_rect); +CIMGUI_API void igPopClipRect(void); +CIMGUI_API void igSetItemDefaultFocus(void); +CIMGUI_API void igSetKeyboardFocusHere(int offset); +CIMGUI_API bool igIsItemHovered(ImGuiHoveredFlags flags); +CIMGUI_API bool igIsItemActive(void); +CIMGUI_API bool igIsItemFocused(void); +CIMGUI_API bool igIsItemClicked(ImGuiMouseButton mouse_button); +CIMGUI_API bool igIsItemVisible(void); +CIMGUI_API bool igIsItemEdited(void); +CIMGUI_API bool igIsItemActivated(void); +CIMGUI_API bool igIsItemDeactivated(void); +CIMGUI_API bool igIsItemDeactivatedAfterEdit(void); +CIMGUI_API bool igIsItemToggledOpen(void); +CIMGUI_API bool igIsAnyItemHovered(void); +CIMGUI_API bool igIsAnyItemActive(void); +CIMGUI_API bool igIsAnyItemFocused(void); +CIMGUI_API void igGetItemRectMin(ImVec2 *pOut); +CIMGUI_API void igGetItemRectMax(ImVec2 *pOut); +CIMGUI_API void igGetItemRectSize(ImVec2 *pOut); +CIMGUI_API void igSetItemAllowOverlap(void); +CIMGUI_API ImGuiViewport* igGetMainViewport(void); +CIMGUI_API bool igIsRectVisible_Nil(const ImVec2 size); +CIMGUI_API bool igIsRectVisible_Vec2(const ImVec2 rect_min,const ImVec2 rect_max); +CIMGUI_API double igGetTime(void); +CIMGUI_API int igGetFrameCount(void); +CIMGUI_API ImDrawList* igGetBackgroundDrawList_Nil(void); +CIMGUI_API ImDrawList* igGetForegroundDrawList_Nil(void); +CIMGUI_API ImDrawListSharedData* igGetDrawListSharedData(void); +CIMGUI_API const char* igGetStyleColorName(ImGuiCol idx); +CIMGUI_API void igSetStateStorage(ImGuiStorage* storage); +CIMGUI_API ImGuiStorage* igGetStateStorage(void); +CIMGUI_API bool igBeginChildFrame(ImGuiID id,const ImVec2 size,ImGuiWindowFlags flags); +CIMGUI_API void igEndChildFrame(void); +CIMGUI_API void igCalcTextSize(ImVec2 *pOut,const char* text,const char* text_end,bool hide_text_after_double_hash,float wrap_width); +CIMGUI_API void igColorConvertU32ToFloat4(ImVec4 *pOut,ImU32 in); +CIMGUI_API ImU32 igColorConvertFloat4ToU32(const ImVec4 in); +CIMGUI_API void igColorConvertRGBtoHSV(float r,float g,float b,float* out_h,float* out_s,float* out_v); +CIMGUI_API void igColorConvertHSVtoRGB(float h,float s,float v,float* out_r,float* out_g,float* out_b); +CIMGUI_API int igGetKeyIndex(ImGuiKey imgui_key); +CIMGUI_API bool igIsKeyDown(int user_key_index); +CIMGUI_API bool igIsKeyPressed(int user_key_index,bool repeat); +CIMGUI_API bool igIsKeyReleased(int user_key_index); +CIMGUI_API int igGetKeyPressedAmount(int key_index,float repeat_delay,float rate); +CIMGUI_API void igCaptureKeyboardFromApp(bool want_capture_keyboard_value); +CIMGUI_API bool igIsMouseDown(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseClicked(ImGuiMouseButton button,bool repeat); +CIMGUI_API bool igIsMouseReleased(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseDoubleClicked(ImGuiMouseButton button); +CIMGUI_API int igGetMouseClickedCount(ImGuiMouseButton button); +CIMGUI_API bool igIsMouseHoveringRect(const ImVec2 r_min,const ImVec2 r_max,bool clip); +CIMGUI_API bool igIsMousePosValid(const ImVec2* mouse_pos); +CIMGUI_API bool igIsAnyMouseDown(void); +CIMGUI_API void igGetMousePos(ImVec2 *pOut); +CIMGUI_API void igGetMousePosOnOpeningCurrentPopup(ImVec2 *pOut); +CIMGUI_API bool igIsMouseDragging(ImGuiMouseButton button,float lock_threshold); +CIMGUI_API void igGetMouseDragDelta(ImVec2 *pOut,ImGuiMouseButton button,float lock_threshold); +CIMGUI_API void igResetMouseDragDelta(ImGuiMouseButton button); +CIMGUI_API ImGuiMouseCursor igGetMouseCursor(void); +CIMGUI_API void igSetMouseCursor(ImGuiMouseCursor cursor_type); +CIMGUI_API void igCaptureMouseFromApp(bool want_capture_mouse_value); +CIMGUI_API const char* igGetClipboardText(void); +CIMGUI_API void igSetClipboardText(const char* text); +CIMGUI_API void igLoadIniSettingsFromDisk(const char* ini_filename); +CIMGUI_API void igLoadIniSettingsFromMemory(const char* ini_data,size_t ini_size); +CIMGUI_API void igSaveIniSettingsToDisk(const char* ini_filename); +CIMGUI_API const char* igSaveIniSettingsToMemory(size_t* out_ini_size); +CIMGUI_API bool igDebugCheckVersionAndDataLayout(const char* version_str,size_t sz_io,size_t sz_style,size_t sz_vec2,size_t sz_vec4,size_t sz_drawvert,size_t sz_drawidx); +CIMGUI_API void igSetAllocatorFunctions(ImGuiMemAllocFunc alloc_func,ImGuiMemFreeFunc free_func,void* user_data); +CIMGUI_API void igGetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func,ImGuiMemFreeFunc* p_free_func,void** p_user_data); +CIMGUI_API void* igMemAlloc(size_t size); +CIMGUI_API void igMemFree(void* ptr); +CIMGUI_API ImGuiStyle* ImGuiStyle_ImGuiStyle(void); +CIMGUI_API void ImGuiStyle_destroy(ImGuiStyle* self); +CIMGUI_API void ImGuiStyle_ScaleAllSizes(ImGuiStyle* self,float scale_factor); +CIMGUI_API void ImGuiIO_AddInputCharacter(ImGuiIO* self,unsigned int c); +CIMGUI_API void ImGuiIO_AddInputCharacterUTF16(ImGuiIO* self,ImWchar16 c); +CIMGUI_API void ImGuiIO_AddInputCharactersUTF8(ImGuiIO* self,const char* str); +CIMGUI_API void ImGuiIO_AddFocusEvent(ImGuiIO* self,bool focused); +CIMGUI_API void ImGuiIO_ClearInputCharacters(ImGuiIO* self); +CIMGUI_API void ImGuiIO_ClearInputKeys(ImGuiIO* self); +CIMGUI_API ImGuiIO* ImGuiIO_ImGuiIO(void); +CIMGUI_API void ImGuiIO_destroy(ImGuiIO* self); +CIMGUI_API ImGuiInputTextCallbackData* ImGuiInputTextCallbackData_ImGuiInputTextCallbackData(void); +CIMGUI_API void ImGuiInputTextCallbackData_destroy(ImGuiInputTextCallbackData* self); +CIMGUI_API void ImGuiInputTextCallbackData_DeleteChars(ImGuiInputTextCallbackData* self,int pos,int bytes_count); +CIMGUI_API void ImGuiInputTextCallbackData_InsertChars(ImGuiInputTextCallbackData* self,int pos,const char* text,const char* text_end); +CIMGUI_API void ImGuiInputTextCallbackData_SelectAll(ImGuiInputTextCallbackData* self); +CIMGUI_API void ImGuiInputTextCallbackData_ClearSelection(ImGuiInputTextCallbackData* self); +CIMGUI_API bool ImGuiInputTextCallbackData_HasSelection(ImGuiInputTextCallbackData* self); +CIMGUI_API ImGuiPayload* ImGuiPayload_ImGuiPayload(void); +CIMGUI_API void ImGuiPayload_destroy(ImGuiPayload* self); +CIMGUI_API void ImGuiPayload_Clear(ImGuiPayload* self); +CIMGUI_API bool ImGuiPayload_IsDataType(ImGuiPayload* self,const char* type); +CIMGUI_API bool ImGuiPayload_IsPreview(ImGuiPayload* self); +CIMGUI_API bool ImGuiPayload_IsDelivery(ImGuiPayload* self); +CIMGUI_API ImGuiTableColumnSortSpecs* ImGuiTableColumnSortSpecs_ImGuiTableColumnSortSpecs(void); +CIMGUI_API void ImGuiTableColumnSortSpecs_destroy(ImGuiTableColumnSortSpecs* self); +CIMGUI_API ImGuiTableSortSpecs* ImGuiTableSortSpecs_ImGuiTableSortSpecs(void); +CIMGUI_API void ImGuiTableSortSpecs_destroy(ImGuiTableSortSpecs* self); +CIMGUI_API ImGuiOnceUponAFrame* ImGuiOnceUponAFrame_ImGuiOnceUponAFrame(void); +CIMGUI_API void ImGuiOnceUponAFrame_destroy(ImGuiOnceUponAFrame* self); +CIMGUI_API ImGuiTextFilter* ImGuiTextFilter_ImGuiTextFilter(const char* default_filter); +CIMGUI_API void ImGuiTextFilter_destroy(ImGuiTextFilter* self); +CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label,float width); +CIMGUI_API bool ImGuiTextFilter_PassFilter(ImGuiTextFilter* self,const char* text,const char* text_end); +CIMGUI_API void ImGuiTextFilter_Build(ImGuiTextFilter* self); +CIMGUI_API void ImGuiTextFilter_Clear(ImGuiTextFilter* self); +CIMGUI_API bool ImGuiTextFilter_IsActive(ImGuiTextFilter* self); +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Nil(void); +CIMGUI_API void ImGuiTextRange_destroy(ImGuiTextRange* self); +CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Str(const char* _b,const char* _e); +CIMGUI_API bool ImGuiTextRange_empty(ImGuiTextRange* self); +CIMGUI_API void ImGuiTextRange_split(ImGuiTextRange* self,char separator,ImVector_ImGuiTextRange* out); +CIMGUI_API ImGuiTextBuffer* ImGuiTextBuffer_ImGuiTextBuffer(void); +CIMGUI_API void ImGuiTextBuffer_destroy(ImGuiTextBuffer* self); +CIMGUI_API const char* ImGuiTextBuffer_begin(ImGuiTextBuffer* self); +CIMGUI_API const char* ImGuiTextBuffer_end(ImGuiTextBuffer* self); +CIMGUI_API int ImGuiTextBuffer_size(ImGuiTextBuffer* self); +CIMGUI_API bool ImGuiTextBuffer_empty(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_clear(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_reserve(ImGuiTextBuffer* self,int capacity); +CIMGUI_API const char* ImGuiTextBuffer_c_str(ImGuiTextBuffer* self); +CIMGUI_API void ImGuiTextBuffer_append(ImGuiTextBuffer* self,const char* str,const char* str_end); +CIMGUI_API void ImGuiTextBuffer_appendfv(ImGuiTextBuffer* self,const char* fmt,va_list args); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Int(ImGuiID _key,int _val_i); +CIMGUI_API void ImGuiStoragePair_destroy(ImGuiStoragePair* self); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Float(ImGuiID _key,float _val_f); +CIMGUI_API ImGuiStoragePair* ImGuiStoragePair_ImGuiStoragePair_Ptr(ImGuiID _key,void* _val_p); +CIMGUI_API void ImGuiStorage_Clear(ImGuiStorage* self); +CIMGUI_API int ImGuiStorage_GetInt(ImGuiStorage* self,ImGuiID key,int default_val); +CIMGUI_API void ImGuiStorage_SetInt(ImGuiStorage* self,ImGuiID key,int val); +CIMGUI_API bool ImGuiStorage_GetBool(ImGuiStorage* self,ImGuiID key,bool default_val); +CIMGUI_API void ImGuiStorage_SetBool(ImGuiStorage* self,ImGuiID key,bool val); +CIMGUI_API float ImGuiStorage_GetFloat(ImGuiStorage* self,ImGuiID key,float default_val); +CIMGUI_API void ImGuiStorage_SetFloat(ImGuiStorage* self,ImGuiID key,float val); +CIMGUI_API void* ImGuiStorage_GetVoidPtr(ImGuiStorage* self,ImGuiID key); +CIMGUI_API void ImGuiStorage_SetVoidPtr(ImGuiStorage* self,ImGuiID key,void* val); +CIMGUI_API int* ImGuiStorage_GetIntRef(ImGuiStorage* self,ImGuiID key,int default_val); +CIMGUI_API bool* ImGuiStorage_GetBoolRef(ImGuiStorage* self,ImGuiID key,bool default_val); +CIMGUI_API float* ImGuiStorage_GetFloatRef(ImGuiStorage* self,ImGuiID key,float default_val); +CIMGUI_API void** ImGuiStorage_GetVoidPtrRef(ImGuiStorage* self,ImGuiID key,void* default_val); +CIMGUI_API void ImGuiStorage_SetAllInt(ImGuiStorage* self,int val); +CIMGUI_API void ImGuiStorage_BuildSortByKey(ImGuiStorage* self); +CIMGUI_API ImGuiListClipper* ImGuiListClipper_ImGuiListClipper(void); +CIMGUI_API void ImGuiListClipper_destroy(ImGuiListClipper* self); +CIMGUI_API void ImGuiListClipper_Begin(ImGuiListClipper* self,int items_count,float items_height); +CIMGUI_API void ImGuiListClipper_End(ImGuiListClipper* self); +CIMGUI_API bool ImGuiListClipper_Step(ImGuiListClipper* self); +CIMGUI_API void ImGuiListClipper_ForceDisplayRangeByIndices(ImGuiListClipper* self,int item_min,int item_max); +CIMGUI_API ImColor* ImColor_ImColor_Nil(void); +CIMGUI_API void ImColor_destroy(ImColor* self); +CIMGUI_API ImColor* ImColor_ImColor_Int(int r,int g,int b,int a); +CIMGUI_API ImColor* ImColor_ImColor_U32(ImU32 rgba); +CIMGUI_API ImColor* ImColor_ImColor_Float(float r,float g,float b,float a); +CIMGUI_API ImColor* ImColor_ImColor_Vec4(const ImVec4 col); +CIMGUI_API void ImColor_SetHSV(ImColor* self,float h,float s,float v,float a); +CIMGUI_API void ImColor_HSV(ImColor *pOut,float h,float s,float v,float a); +CIMGUI_API ImDrawCmd* ImDrawCmd_ImDrawCmd(void); +CIMGUI_API void ImDrawCmd_destroy(ImDrawCmd* self); +CIMGUI_API ImTextureID ImDrawCmd_GetTexID(ImDrawCmd* self); +CIMGUI_API ImDrawListSplitter* ImDrawListSplitter_ImDrawListSplitter(void); +CIMGUI_API void ImDrawListSplitter_destroy(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_Clear(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_ClearFreeMemory(ImDrawListSplitter* self); +CIMGUI_API void ImDrawListSplitter_Split(ImDrawListSplitter* self,ImDrawList* draw_list,int count); +CIMGUI_API void ImDrawListSplitter_Merge(ImDrawListSplitter* self,ImDrawList* draw_list); +CIMGUI_API void ImDrawListSplitter_SetCurrentChannel(ImDrawListSplitter* self,ImDrawList* draw_list,int channel_idx); +CIMGUI_API ImDrawList* ImDrawList_ImDrawList(const ImDrawListSharedData* shared_data); +CIMGUI_API void ImDrawList_destroy(ImDrawList* self); +CIMGUI_API void ImDrawList_PushClipRect(ImDrawList* self,ImVec2 clip_rect_min,ImVec2 clip_rect_max,bool intersect_with_current_clip_rect); +CIMGUI_API void ImDrawList_PushClipRectFullScreen(ImDrawList* self); +CIMGUI_API void ImDrawList_PopClipRect(ImDrawList* self); +CIMGUI_API void ImDrawList_PushTextureID(ImDrawList* self,ImTextureID texture_id); +CIMGUI_API void ImDrawList_PopTextureID(ImDrawList* self); +CIMGUI_API void ImDrawList_GetClipRectMin(ImVec2 *pOut,ImDrawList* self); +CIMGUI_API void ImDrawList_GetClipRectMax(ImVec2 *pOut,ImDrawList* self); +CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddRect(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_AddRectFilled(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddRectFilledMultiColor(ImDrawList* self,const ImVec2 p_min,const ImVec2 p_max,ImU32 col_upr_left,ImU32 col_upr_right,ImU32 col_bot_right,ImU32 col_bot_left); +CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddQuadFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col); +CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddTriangleFilled(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col); +CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddCircleFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments); +CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddNgonFilled(ImDrawList* self,const ImVec2 center,float radius,ImU32 col,int num_segments); +CIMGUI_API void ImDrawList_AddText_Vec2(ImDrawList* self,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end); +CIMGUI_API void ImDrawList_AddText_FontPtr(ImDrawList* self,const ImFont* font,float font_size,const ImVec2 pos,ImU32 col,const char* text_begin,const char* text_end,float wrap_width,const ImVec4* cpu_fine_clip_rect); +CIMGUI_API void ImDrawList_AddPolyline(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2* points,int num_points,ImU32 col); +CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,ImU32 col,float thickness,int num_segments); +CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,ImU32 col,float thickness,int num_segments); +CIMGUI_API void ImDrawList_AddImage(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col); +CIMGUI_API void ImDrawList_AddImageQuad(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 uv1,const ImVec2 uv2,const ImVec2 uv3,const ImVec2 uv4,ImU32 col); +CIMGUI_API void ImDrawList_AddImageRounded(ImDrawList* self,ImTextureID user_texture_id,const ImVec2 p_min,const ImVec2 p_max,const ImVec2 uv_min,const ImVec2 uv_max,ImU32 col,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_PathClear(ImDrawList* self); +CIMGUI_API void ImDrawList_PathLineTo(ImDrawList* self,const ImVec2 pos); +CIMGUI_API void ImDrawList_PathLineToMergeDuplicate(ImDrawList* self,const ImVec2 pos); +CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col); +CIMGUI_API void ImDrawList_PathStroke(ImDrawList* self,ImU32 col,ImDrawFlags flags,float thickness); +CIMGUI_API void ImDrawList_PathArcTo(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments); +CIMGUI_API void ImDrawList_PathArcToFast(ImDrawList* self,const ImVec2 center,float radius,int a_min_of_12,int a_max_of_12); +CIMGUI_API void ImDrawList_PathBezierCubicCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,int num_segments); +CIMGUI_API void ImDrawList_PathBezierQuadraticCurveTo(ImDrawList* self,const ImVec2 p2,const ImVec2 p3,int num_segments); +CIMGUI_API void ImDrawList_PathRect(ImDrawList* self,const ImVec2 rect_min,const ImVec2 rect_max,float rounding,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddCallback(ImDrawList* self,ImDrawCallback callback,void* callback_data); +CIMGUI_API void ImDrawList_AddDrawCmd(ImDrawList* self); +CIMGUI_API ImDrawList* ImDrawList_CloneOutput(ImDrawList* self); +CIMGUI_API void ImDrawList_ChannelsSplit(ImDrawList* self,int count); +CIMGUI_API void ImDrawList_ChannelsMerge(ImDrawList* self); +CIMGUI_API void ImDrawList_ChannelsSetCurrent(ImDrawList* self,int n); +CIMGUI_API void ImDrawList_PrimReserve(ImDrawList* self,int idx_count,int vtx_count); +CIMGUI_API void ImDrawList_PrimUnreserve(ImDrawList* self,int idx_count,int vtx_count); +CIMGUI_API void ImDrawList_PrimRect(ImDrawList* self,const ImVec2 a,const ImVec2 b,ImU32 col); +CIMGUI_API void ImDrawList_PrimRectUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,ImU32 col); +CIMGUI_API void ImDrawList_PrimQuadUV(ImDrawList* self,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 d,const ImVec2 uv_a,const ImVec2 uv_b,const ImVec2 uv_c,const ImVec2 uv_d,ImU32 col); +CIMGUI_API void ImDrawList_PrimWriteVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col); +CIMGUI_API void ImDrawList_PrimWriteIdx(ImDrawList* self,ImDrawIdx idx); +CIMGUI_API void ImDrawList_PrimVtx(ImDrawList* self,const ImVec2 pos,const ImVec2 uv,ImU32 col); +CIMGUI_API void ImDrawList__ResetForNewFrame(ImDrawList* self); +CIMGUI_API void ImDrawList__ClearFreeMemory(ImDrawList* self); +CIMGUI_API void ImDrawList__PopUnusedDrawCmd(ImDrawList* self); +CIMGUI_API void ImDrawList__TryMergeDrawCmds(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedClipRect(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedTextureID(ImDrawList* self); +CIMGUI_API void ImDrawList__OnChangedVtxOffset(ImDrawList* self); +CIMGUI_API int ImDrawList__CalcCircleAutoSegmentCount(ImDrawList* self,float radius); +CIMGUI_API void ImDrawList__PathArcToFastEx(ImDrawList* self,const ImVec2 center,float radius,int a_min_sample,int a_max_sample,int a_step); +CIMGUI_API void ImDrawList__PathArcToN(ImDrawList* self,const ImVec2 center,float radius,float a_min,float a_max,int num_segments); +CIMGUI_API ImDrawData* ImDrawData_ImDrawData(void); +CIMGUI_API void ImDrawData_destroy(ImDrawData* self); +CIMGUI_API void ImDrawData_Clear(ImDrawData* self); +CIMGUI_API void ImDrawData_DeIndexAllBuffers(ImDrawData* self); +CIMGUI_API void ImDrawData_ScaleClipRects(ImDrawData* self,const ImVec2 fb_scale); +CIMGUI_API ImFontConfig* ImFontConfig_ImFontConfig(void); +CIMGUI_API void ImFontConfig_destroy(ImFontConfig* self); +CIMGUI_API ImFontGlyphRangesBuilder* ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder(void); +CIMGUI_API void ImFontGlyphRangesBuilder_destroy(ImFontGlyphRangesBuilder* self); +CIMGUI_API void ImFontGlyphRangesBuilder_Clear(ImFontGlyphRangesBuilder* self); +CIMGUI_API bool ImFontGlyphRangesBuilder_GetBit(ImFontGlyphRangesBuilder* self,size_t n); +CIMGUI_API void ImFontGlyphRangesBuilder_SetBit(ImFontGlyphRangesBuilder* self,size_t n); +CIMGUI_API void ImFontGlyphRangesBuilder_AddChar(ImFontGlyphRangesBuilder* self,ImWchar c); +CIMGUI_API void ImFontGlyphRangesBuilder_AddText(ImFontGlyphRangesBuilder* self,const char* text,const char* text_end); +CIMGUI_API void ImFontGlyphRangesBuilder_AddRanges(ImFontGlyphRangesBuilder* self,const ImWchar* ranges); +CIMGUI_API void ImFontGlyphRangesBuilder_BuildRanges(ImFontGlyphRangesBuilder* self,ImVector_ImWchar* out_ranges); +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlasCustomRect_ImFontAtlasCustomRect(void); +CIMGUI_API void ImFontAtlasCustomRect_destroy(ImFontAtlasCustomRect* self); +CIMGUI_API bool ImFontAtlasCustomRect_IsPacked(ImFontAtlasCustomRect* self); +CIMGUI_API ImFontAtlas* ImFontAtlas_ImFontAtlas(void); +CIMGUI_API void ImFontAtlas_destroy(ImFontAtlas* self); +CIMGUI_API ImFont* ImFontAtlas_AddFont(ImFontAtlas* self,const ImFontConfig* font_cfg); +CIMGUI_API ImFont* ImFontAtlas_AddFontDefault(ImFontAtlas* self,const ImFontConfig* font_cfg); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromFileTTF(ImFontAtlas* self,const char* filename,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryTTF(ImFontAtlas* self,void* font_data,int font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedTTF(ImFontAtlas* self,const void* compressed_font_data,int compressed_font_size,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API ImFont* ImFontAtlas_AddFontFromMemoryCompressedBase85TTF(ImFontAtlas* self,const char* compressed_font_data_base85,float size_pixels,const ImFontConfig* font_cfg,const ImWchar* glyph_ranges); +CIMGUI_API void ImFontAtlas_ClearInputData(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_ClearTexData(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_ClearFonts(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_Clear(ImFontAtlas* self); +CIMGUI_API bool ImFontAtlas_Build(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_GetTexDataAsAlpha8(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel); +CIMGUI_API void ImFontAtlas_GetTexDataAsRGBA32(ImFontAtlas* self,unsigned char** out_pixels,int* out_width,int* out_height,int* out_bytes_per_pixel); +CIMGUI_API bool ImFontAtlas_IsBuilt(ImFontAtlas* self); +CIMGUI_API void ImFontAtlas_SetTexID(ImFontAtlas* self,ImTextureID id); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesDefault(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesKorean(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesJapanese(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseFull(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesCyrillic(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesThai(ImFontAtlas* self); +CIMGUI_API const ImWchar* ImFontAtlas_GetGlyphRangesVietnamese(ImFontAtlas* self); +CIMGUI_API int ImFontAtlas_AddCustomRectRegular(ImFontAtlas* self,int width,int height); +CIMGUI_API int ImFontAtlas_AddCustomRectFontGlyph(ImFontAtlas* self,ImFont* font,ImWchar id,int width,int height,float advance_x,const ImVec2 offset); +CIMGUI_API ImFontAtlasCustomRect* ImFontAtlas_GetCustomRectByIndex(ImFontAtlas* self,int index); +CIMGUI_API void ImFontAtlas_CalcCustomRectUV(ImFontAtlas* self,const ImFontAtlasCustomRect* rect,ImVec2* out_uv_min,ImVec2* out_uv_max); +CIMGUI_API bool ImFontAtlas_GetMouseCursorTexData(ImFontAtlas* self,ImGuiMouseCursor cursor,ImVec2* out_offset,ImVec2* out_size,ImVec2 out_uv_border[2],ImVec2 out_uv_fill[2]); +CIMGUI_API ImFont* ImFont_ImFont(void); +CIMGUI_API void ImFont_destroy(ImFont* self); +CIMGUI_API const ImFontGlyph* ImFont_FindGlyph(ImFont* self,ImWchar c); +CIMGUI_API const ImFontGlyph* ImFont_FindGlyphNoFallback(ImFont* self,ImWchar c); +CIMGUI_API float ImFont_GetCharAdvance(ImFont* self,ImWchar c); +CIMGUI_API bool ImFont_IsLoaded(ImFont* self); +CIMGUI_API const char* ImFont_GetDebugName(ImFont* self); +CIMGUI_API void ImFont_CalcTextSizeA(ImVec2 *pOut,ImFont* self,float size,float max_width,float wrap_width,const char* text_begin,const char* text_end,const char** remaining); +CIMGUI_API const char* ImFont_CalcWordWrapPositionA(ImFont* self,float scale,const char* text,const char* text_end,float wrap_width); +CIMGUI_API void ImFont_RenderChar(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,ImWchar c); +CIMGUI_API void ImFont_RenderText(ImFont* self,ImDrawList* draw_list,float size,ImVec2 pos,ImU32 col,const ImVec4 clip_rect,const char* text_begin,const char* text_end,float wrap_width,bool cpu_fine_clip); +CIMGUI_API void ImFont_BuildLookupTable(ImFont* self); +CIMGUI_API void ImFont_ClearOutputData(ImFont* self); +CIMGUI_API void ImFont_GrowIndex(ImFont* self,int new_size); +CIMGUI_API void ImFont_AddGlyph(ImFont* self,const ImFontConfig* src_cfg,ImWchar c,float x0,float y0,float x1,float y1,float u0,float v0,float u1,float v1,float advance_x); +CIMGUI_API void ImFont_AddRemapChar(ImFont* self,ImWchar dst,ImWchar src,bool overwrite_dst); +CIMGUI_API void ImFont_SetGlyphVisible(ImFont* self,ImWchar c,bool visible); +CIMGUI_API bool ImFont_IsGlyphRangeUnused(ImFont* self,unsigned int c_begin,unsigned int c_last); +CIMGUI_API ImGuiViewport* ImGuiViewport_ImGuiViewport(void); +CIMGUI_API void ImGuiViewport_destroy(ImGuiViewport* self); +CIMGUI_API void ImGuiViewport_GetCenter(ImVec2 *pOut,ImGuiViewport* self); +CIMGUI_API void ImGuiViewport_GetWorkCenter(ImVec2 *pOut,ImGuiViewport* self); +CIMGUI_API ImGuiID igImHashData(const void* data,size_t data_size,ImU32 seed); +CIMGUI_API ImGuiID igImHashStr(const char* data,size_t data_size,ImU32 seed); +CIMGUI_API void igImQsort(void* base,size_t count,size_t size_of_element,int(*compare_func)(void const*,void const*)); +CIMGUI_API ImU32 igImAlphaBlendColors(ImU32 col_a,ImU32 col_b); +CIMGUI_API bool igImIsPowerOfTwo_Int(int v); +CIMGUI_API bool igImIsPowerOfTwo_U64(ImU64 v); +CIMGUI_API int igImUpperPowerOfTwo(int v); +CIMGUI_API int igImStricmp(const char* str1,const char* str2); +CIMGUI_API int igImStrnicmp(const char* str1,const char* str2,size_t count); +CIMGUI_API void igImStrncpy(char* dst,const char* src,size_t count); +CIMGUI_API char* igImStrdup(const char* str); +CIMGUI_API char* igImStrdupcpy(char* dst,size_t* p_dst_size,const char* str); +CIMGUI_API const char* igImStrchrRange(const char* str_begin,const char* str_end,char c); +CIMGUI_API int igImStrlenW(const ImWchar* str); +CIMGUI_API const char* igImStreolRange(const char* str,const char* str_end); +CIMGUI_API const ImWchar* igImStrbolW(const ImWchar* buf_mid_line,const ImWchar* buf_begin); +CIMGUI_API const char* igImStristr(const char* haystack,const char* haystack_end,const char* needle,const char* needle_end); +CIMGUI_API void igImStrTrimBlanks(char* str); +CIMGUI_API const char* igImStrSkipBlank(const char* str); +CIMGUI_API int igImFormatString(char* buf,size_t buf_size,const char* fmt,...); +CIMGUI_API int igImFormatStringV(char* buf,size_t buf_size,const char* fmt,va_list args); +CIMGUI_API const char* igImParseFormatFindStart(const char* format); +CIMGUI_API const char* igImParseFormatFindEnd(const char* format); +CIMGUI_API const char* igImParseFormatTrimDecorations(const char* format,char* buf,size_t buf_size); +CIMGUI_API int igImParseFormatPrecision(const char* format,int default_value); +CIMGUI_API bool igImCharIsBlankA(char c); +CIMGUI_API bool igImCharIsBlankW(unsigned int c); +CIMGUI_API const char* igImTextCharToUtf8(char out_buf[5],unsigned int c); +CIMGUI_API int igImTextStrToUtf8(char* out_buf,int out_buf_size,const ImWchar* in_text,const ImWchar* in_text_end); +CIMGUI_API int igImTextCharFromUtf8(unsigned int* out_char,const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextStrFromUtf8(ImWchar* out_buf,int out_buf_size,const char* in_text,const char* in_text_end,const char** in_remaining); +CIMGUI_API int igImTextCountCharsFromUtf8(const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextCountUtf8BytesFromChar(const char* in_text,const char* in_text_end); +CIMGUI_API int igImTextCountUtf8BytesFromStr(const ImWchar* in_text,const ImWchar* in_text_end); +CIMGUI_API ImFileHandle igImFileOpen(const char* filename,const char* mode); +CIMGUI_API bool igImFileClose(ImFileHandle file); +CIMGUI_API ImU64 igImFileGetSize(ImFileHandle file); +CIMGUI_API ImU64 igImFileRead(void* data,ImU64 size,ImU64 count,ImFileHandle file); +CIMGUI_API ImU64 igImFileWrite(const void* data,ImU64 size,ImU64 count,ImFileHandle file); +CIMGUI_API void* igImFileLoadToMemory(const char* filename,const char* mode,size_t* out_file_size,int padding_bytes); +CIMGUI_API float igImPow_Float(float x,float y); +CIMGUI_API double igImPow_double(double x,double y); +CIMGUI_API float igImLog_Float(float x); +CIMGUI_API double igImLog_double(double x); +CIMGUI_API int igImAbs_Int(int x); +CIMGUI_API float igImAbs_Float(float x); +CIMGUI_API double igImAbs_double(double x); +CIMGUI_API float igImSign_Float(float x); +CIMGUI_API double igImSign_double(double x); +CIMGUI_API float igImRsqrt_Float(float x); +CIMGUI_API double igImRsqrt_double(double x); +CIMGUI_API void igImMin(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API void igImMax(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API void igImClamp(ImVec2 *pOut,const ImVec2 v,const ImVec2 mn,ImVec2 mx); +CIMGUI_API void igImLerp_Vec2Float(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,float t); +CIMGUI_API void igImLerp_Vec2Vec2(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 t); +CIMGUI_API void igImLerp_Vec4(ImVec4 *pOut,const ImVec4 a,const ImVec4 b,float t); +CIMGUI_API float igImSaturate(float f); +CIMGUI_API float igImLengthSqr_Vec2(const ImVec2 lhs); +CIMGUI_API float igImLengthSqr_Vec4(const ImVec4 lhs); +CIMGUI_API float igImInvLength(const ImVec2 lhs,float fail_value); +CIMGUI_API float igImFloor_Float(float f); +CIMGUI_API float igImFloorSigned(float f); +CIMGUI_API void igImFloor_Vec2(ImVec2 *pOut,const ImVec2 v); +CIMGUI_API int igImModPositive(int a,int b); +CIMGUI_API float igImDot(const ImVec2 a,const ImVec2 b); +CIMGUI_API void igImRotate(ImVec2 *pOut,const ImVec2 v,float cos_a,float sin_a); +CIMGUI_API float igImLinearSweep(float current,float target,float speed); +CIMGUI_API void igImMul(ImVec2 *pOut,const ImVec2 lhs,const ImVec2 rhs); +CIMGUI_API bool igImIsFloatAboveGuaranteedIntegerPrecision(float f); +CIMGUI_API void igImBezierCubicCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,float t); +CIMGUI_API void igImBezierCubicClosestPoint(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,int num_segments); +CIMGUI_API void igImBezierCubicClosestPointCasteljau(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,const ImVec2 p4,const ImVec2 p,float tess_tol); +CIMGUI_API void igImBezierQuadraticCalc(ImVec2 *pOut,const ImVec2 p1,const ImVec2 p2,const ImVec2 p3,float t); +CIMGUI_API void igImLineClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 p); +CIMGUI_API bool igImTriangleContainsPoint(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p); +CIMGUI_API void igImTriangleClosestPoint(ImVec2 *pOut,const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p); +CIMGUI_API void igImTriangleBarycentricCoords(const ImVec2 a,const ImVec2 b,const ImVec2 c,const ImVec2 p,float* out_u,float* out_v,float* out_w); +CIMGUI_API float igImTriangleArea(const ImVec2 a,const ImVec2 b,const ImVec2 c); +CIMGUI_API ImGuiDir igImGetDirQuadrantFromDelta(float dx,float dy); +CIMGUI_API ImVec1* ImVec1_ImVec1_Nil(void); +CIMGUI_API void ImVec1_destroy(ImVec1* self); +CIMGUI_API ImVec1* ImVec1_ImVec1_Float(float _x); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Nil(void); +CIMGUI_API void ImVec2ih_destroy(ImVec2ih* self); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_short(short _x,short _y); +CIMGUI_API ImVec2ih* ImVec2ih_ImVec2ih_Vec2(const ImVec2 rhs); +CIMGUI_API ImRect* ImRect_ImRect_Nil(void); +CIMGUI_API void ImRect_destroy(ImRect* self); +CIMGUI_API ImRect* ImRect_ImRect_Vec2(const ImVec2 min,const ImVec2 max); +CIMGUI_API ImRect* ImRect_ImRect_Vec4(const ImVec4 v); +CIMGUI_API ImRect* ImRect_ImRect_Float(float x1,float y1,float x2,float y2); +CIMGUI_API void ImRect_GetCenter(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetSize(ImVec2 *pOut,ImRect* self); +CIMGUI_API float ImRect_GetWidth(ImRect* self); +CIMGUI_API float ImRect_GetHeight(ImRect* self); +CIMGUI_API float ImRect_GetArea(ImRect* self); +CIMGUI_API void ImRect_GetTL(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetTR(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetBL(ImVec2 *pOut,ImRect* self); +CIMGUI_API void ImRect_GetBR(ImVec2 *pOut,ImRect* self); +CIMGUI_API bool ImRect_Contains_Vec2(ImRect* self,const ImVec2 p); +CIMGUI_API bool ImRect_Contains_Rect(ImRect* self,const ImRect r); +CIMGUI_API bool ImRect_Overlaps(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Add_Vec2(ImRect* self,const ImVec2 p); +CIMGUI_API void ImRect_Add_Rect(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Expand_Float(ImRect* self,const float amount); +CIMGUI_API void ImRect_Expand_Vec2(ImRect* self,const ImVec2 amount); +CIMGUI_API void ImRect_Translate(ImRect* self,const ImVec2 d); +CIMGUI_API void ImRect_TranslateX(ImRect* self,float dx); +CIMGUI_API void ImRect_TranslateY(ImRect* self,float dy); +CIMGUI_API void ImRect_ClipWith(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_ClipWithFull(ImRect* self,const ImRect r); +CIMGUI_API void ImRect_Floor(ImRect* self); +CIMGUI_API bool ImRect_IsInverted(ImRect* self); +CIMGUI_API void ImRect_ToVec4(ImVec4 *pOut,ImRect* self); +CIMGUI_API bool igImBitArrayTestBit(const ImU32* arr,int n); +CIMGUI_API void igImBitArrayClearBit(ImU32* arr,int n); +CIMGUI_API void igImBitArraySetBit(ImU32* arr,int n); +CIMGUI_API void igImBitArraySetBitRange(ImU32* arr,int n,int n2); +CIMGUI_API void ImBitVector_Create(ImBitVector* self,int sz); +CIMGUI_API void ImBitVector_Clear(ImBitVector* self); +CIMGUI_API bool ImBitVector_TestBit(ImBitVector* self,int n); +CIMGUI_API void ImBitVector_SetBit(ImBitVector* self,int n); +CIMGUI_API void ImBitVector_ClearBit(ImBitVector* self,int n); +CIMGUI_API ImDrawListSharedData* ImDrawListSharedData_ImDrawListSharedData(void); +CIMGUI_API void ImDrawListSharedData_destroy(ImDrawListSharedData* self); +CIMGUI_API void ImDrawListSharedData_SetCircleTessellationMaxError(ImDrawListSharedData* self,float max_error); +CIMGUI_API void ImDrawDataBuilder_Clear(ImDrawDataBuilder* self); +CIMGUI_API void ImDrawDataBuilder_ClearFreeMemory(ImDrawDataBuilder* self); +CIMGUI_API int ImDrawDataBuilder_GetDrawListCount(ImDrawDataBuilder* self); +CIMGUI_API void ImDrawDataBuilder_FlattenIntoSingleLayer(ImDrawDataBuilder* self); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Int(ImGuiStyleVar idx,int v); +CIMGUI_API void ImGuiStyleMod_destroy(ImGuiStyleMod* self); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Float(ImGuiStyleVar idx,float v); +CIMGUI_API ImGuiStyleMod* ImGuiStyleMod_ImGuiStyleMod_Vec2(ImGuiStyleVar idx,ImVec2 v); +CIMGUI_API ImGuiComboPreviewData* ImGuiComboPreviewData_ImGuiComboPreviewData(void); +CIMGUI_API void ImGuiComboPreviewData_destroy(ImGuiComboPreviewData* self); +CIMGUI_API ImGuiMenuColumns* ImGuiMenuColumns_ImGuiMenuColumns(void); +CIMGUI_API void ImGuiMenuColumns_destroy(ImGuiMenuColumns* self); +CIMGUI_API void ImGuiMenuColumns_Update(ImGuiMenuColumns* self,float spacing,bool window_reappearing); +CIMGUI_API float ImGuiMenuColumns_DeclColumns(ImGuiMenuColumns* self,float w_icon,float w_label,float w_shortcut,float w_mark); +CIMGUI_API void ImGuiMenuColumns_CalcNextTotalWidth(ImGuiMenuColumns* self,bool update_offsets); +CIMGUI_API ImGuiInputTextState* ImGuiInputTextState_ImGuiInputTextState(void); +CIMGUI_API void ImGuiInputTextState_destroy(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearText(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearFreeMemory(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetUndoAvailCount(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetRedoAvailCount(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_OnKeyPressed(ImGuiInputTextState* self,int key); +CIMGUI_API void ImGuiInputTextState_CursorAnimReset(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_CursorClamp(ImGuiInputTextState* self); +CIMGUI_API bool ImGuiInputTextState_HasSelection(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_ClearSelection(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetCursorPos(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetSelectionStart(ImGuiInputTextState* self); +CIMGUI_API int ImGuiInputTextState_GetSelectionEnd(ImGuiInputTextState* self); +CIMGUI_API void ImGuiInputTextState_SelectAll(ImGuiInputTextState* self); +CIMGUI_API ImGuiPopupData* ImGuiPopupData_ImGuiPopupData(void); +CIMGUI_API void ImGuiPopupData_destroy(ImGuiPopupData* self); +CIMGUI_API ImGuiNextWindowData* ImGuiNextWindowData_ImGuiNextWindowData(void); +CIMGUI_API void ImGuiNextWindowData_destroy(ImGuiNextWindowData* self); +CIMGUI_API void ImGuiNextWindowData_ClearFlags(ImGuiNextWindowData* self); +CIMGUI_API ImGuiNextItemData* ImGuiNextItemData_ImGuiNextItemData(void); +CIMGUI_API void ImGuiNextItemData_destroy(ImGuiNextItemData* self); +CIMGUI_API void ImGuiNextItemData_ClearFlags(ImGuiNextItemData* self); +CIMGUI_API ImGuiLastItemData* ImGuiLastItemData_ImGuiLastItemData(void); +CIMGUI_API void ImGuiLastItemData_destroy(ImGuiLastItemData* self); +CIMGUI_API ImGuiStackSizes* ImGuiStackSizes_ImGuiStackSizes(void); +CIMGUI_API void ImGuiStackSizes_destroy(ImGuiStackSizes* self); +CIMGUI_API void ImGuiStackSizes_SetToCurrentState(ImGuiStackSizes* self); +CIMGUI_API void ImGuiStackSizes_CompareWithCurrentState(ImGuiStackSizes* self); +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Ptr(void* ptr); +CIMGUI_API void ImGuiPtrOrIndex_destroy(ImGuiPtrOrIndex* self); +CIMGUI_API ImGuiPtrOrIndex* ImGuiPtrOrIndex_ImGuiPtrOrIndex_Int(int index); +CIMGUI_API ImGuiListClipperRange ImGuiListClipperRange_FromIndices(int min,int max); +CIMGUI_API ImGuiListClipperRange ImGuiListClipperRange_FromPositions(float y1,float y2,int off_min,int off_max); +CIMGUI_API ImGuiListClipperData* ImGuiListClipperData_ImGuiListClipperData(void); +CIMGUI_API void ImGuiListClipperData_destroy(ImGuiListClipperData* self); +CIMGUI_API void ImGuiListClipperData_Reset(ImGuiListClipperData* self,ImGuiListClipper* clipper); +CIMGUI_API ImGuiNavItemData* ImGuiNavItemData_ImGuiNavItemData(void); +CIMGUI_API void ImGuiNavItemData_destroy(ImGuiNavItemData* self); +CIMGUI_API void ImGuiNavItemData_Clear(ImGuiNavItemData* self); +CIMGUI_API ImGuiOldColumnData* ImGuiOldColumnData_ImGuiOldColumnData(void); +CIMGUI_API void ImGuiOldColumnData_destroy(ImGuiOldColumnData* self); +CIMGUI_API ImGuiOldColumns* ImGuiOldColumns_ImGuiOldColumns(void); +CIMGUI_API void ImGuiOldColumns_destroy(ImGuiOldColumns* self); +CIMGUI_API ImGuiViewportP* ImGuiViewportP_ImGuiViewportP(void); +CIMGUI_API void ImGuiViewportP_destroy(ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_CalcWorkRectPos(ImVec2 *pOut,ImGuiViewportP* self,const ImVec2 off_min); +CIMGUI_API void ImGuiViewportP_CalcWorkRectSize(ImVec2 *pOut,ImGuiViewportP* self,const ImVec2 off_min,const ImVec2 off_max); +CIMGUI_API void ImGuiViewportP_UpdateWorkRect(ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_GetMainRect(ImRect *pOut,ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_GetWorkRect(ImRect *pOut,ImGuiViewportP* self); +CIMGUI_API void ImGuiViewportP_GetBuildWorkRect(ImRect *pOut,ImGuiViewportP* self); +CIMGUI_API ImGuiWindowSettings* ImGuiWindowSettings_ImGuiWindowSettings(void); +CIMGUI_API void ImGuiWindowSettings_destroy(ImGuiWindowSettings* self); +CIMGUI_API char* ImGuiWindowSettings_GetName(ImGuiWindowSettings* self); +CIMGUI_API ImGuiSettingsHandler* ImGuiSettingsHandler_ImGuiSettingsHandler(void); +CIMGUI_API void ImGuiSettingsHandler_destroy(ImGuiSettingsHandler* self); +CIMGUI_API ImGuiMetricsConfig* ImGuiMetricsConfig_ImGuiMetricsConfig(void); +CIMGUI_API void ImGuiMetricsConfig_destroy(ImGuiMetricsConfig* self); +CIMGUI_API ImGuiStackLevelInfo* ImGuiStackLevelInfo_ImGuiStackLevelInfo(void); +CIMGUI_API void ImGuiStackLevelInfo_destroy(ImGuiStackLevelInfo* self); +CIMGUI_API ImGuiStackTool* ImGuiStackTool_ImGuiStackTool(void); +CIMGUI_API void ImGuiStackTool_destroy(ImGuiStackTool* self); +CIMGUI_API ImGuiContextHook* ImGuiContextHook_ImGuiContextHook(void); +CIMGUI_API void ImGuiContextHook_destroy(ImGuiContextHook* self); +CIMGUI_API ImGuiContext* ImGuiContext_ImGuiContext(ImFontAtlas* shared_font_atlas); +CIMGUI_API void ImGuiContext_destroy(ImGuiContext* self); +CIMGUI_API ImGuiWindow* ImGuiWindow_ImGuiWindow(ImGuiContext* context,const char* name); +CIMGUI_API void ImGuiWindow_destroy(ImGuiWindow* self); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Str(ImGuiWindow* self,const char* str,const char* str_end); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Ptr(ImGuiWindow* self,const void* ptr); +CIMGUI_API ImGuiID ImGuiWindow_GetID_Int(ImGuiWindow* self,int n); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Str(ImGuiWindow* self,const char* str,const char* str_end); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Ptr(ImGuiWindow* self,const void* ptr); +CIMGUI_API ImGuiID ImGuiWindow_GetIDNoKeepAlive_Int(ImGuiWindow* self,int n); +CIMGUI_API ImGuiID ImGuiWindow_GetIDFromRectangle(ImGuiWindow* self,const ImRect r_abs); +CIMGUI_API void ImGuiWindow_Rect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_CalcFontSize(ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_TitleBarHeight(ImGuiWindow* self); +CIMGUI_API void ImGuiWindow_TitleBarRect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API float ImGuiWindow_MenuBarHeight(ImGuiWindow* self); +CIMGUI_API void ImGuiWindow_MenuBarRect(ImRect *pOut,ImGuiWindow* self); +CIMGUI_API ImGuiTabItem* ImGuiTabItem_ImGuiTabItem(void); +CIMGUI_API void ImGuiTabItem_destroy(ImGuiTabItem* self); +CIMGUI_API ImGuiTabBar* ImGuiTabBar_ImGuiTabBar(void); +CIMGUI_API void ImGuiTabBar_destroy(ImGuiTabBar* self); +CIMGUI_API int ImGuiTabBar_GetTabOrder(ImGuiTabBar* self,const ImGuiTabItem* tab); +CIMGUI_API const char* ImGuiTabBar_GetTabName(ImGuiTabBar* self,const ImGuiTabItem* tab); +CIMGUI_API ImGuiTableColumn* ImGuiTableColumn_ImGuiTableColumn(void); +CIMGUI_API void ImGuiTableColumn_destroy(ImGuiTableColumn* self); +CIMGUI_API ImGuiTable* ImGuiTable_ImGuiTable(void); +CIMGUI_API void ImGuiTable_destroy(ImGuiTable* self); +CIMGUI_API ImGuiTableTempData* ImGuiTableTempData_ImGuiTableTempData(void); +CIMGUI_API void ImGuiTableTempData_destroy(ImGuiTableTempData* self); +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableColumnSettings_ImGuiTableColumnSettings(void); +CIMGUI_API void ImGuiTableColumnSettings_destroy(ImGuiTableColumnSettings* self); +CIMGUI_API ImGuiTableSettings* ImGuiTableSettings_ImGuiTableSettings(void); +CIMGUI_API void ImGuiTableSettings_destroy(ImGuiTableSettings* self); +CIMGUI_API ImGuiTableColumnSettings* ImGuiTableSettings_GetColumnSettings(ImGuiTableSettings* self); +CIMGUI_API ImGuiWindow* igGetCurrentWindowRead(void); +CIMGUI_API ImGuiWindow* igGetCurrentWindow(void); +CIMGUI_API ImGuiWindow* igFindWindowByID(ImGuiID id); +CIMGUI_API ImGuiWindow* igFindWindowByName(const char* name); +CIMGUI_API void igUpdateWindowParentAndRootLinks(ImGuiWindow* window,ImGuiWindowFlags flags,ImGuiWindow* parent_window); +CIMGUI_API void igCalcWindowNextAutoFitSize(ImVec2 *pOut,ImGuiWindow* window); +CIMGUI_API bool igIsWindowChildOf(ImGuiWindow* window,ImGuiWindow* potential_parent,bool popup_hierarchy); +CIMGUI_API bool igIsWindowWithinBeginStackOf(ImGuiWindow* window,ImGuiWindow* potential_parent); +CIMGUI_API bool igIsWindowAbove(ImGuiWindow* potential_above,ImGuiWindow* potential_below); +CIMGUI_API bool igIsWindowNavFocusable(ImGuiWindow* window); +CIMGUI_API void igSetWindowPos_WindowPtr(ImGuiWindow* window,const ImVec2 pos,ImGuiCond cond); +CIMGUI_API void igSetWindowSize_WindowPtr(ImGuiWindow* window,const ImVec2 size,ImGuiCond cond); +CIMGUI_API void igSetWindowCollapsed_WindowPtr(ImGuiWindow* window,bool collapsed,ImGuiCond cond); +CIMGUI_API void igSetWindowHitTestHole(ImGuiWindow* window,const ImVec2 pos,const ImVec2 size); +CIMGUI_API void igWindowRectAbsToRel(ImRect *pOut,ImGuiWindow* window,const ImRect r); +CIMGUI_API void igWindowRectRelToAbs(ImRect *pOut,ImGuiWindow* window,const ImRect r); +CIMGUI_API void igFocusWindow(ImGuiWindow* window); +CIMGUI_API void igFocusTopMostWindowUnderOne(ImGuiWindow* under_this_window,ImGuiWindow* ignore_window); +CIMGUI_API void igBringWindowToFocusFront(ImGuiWindow* window); +CIMGUI_API void igBringWindowToDisplayFront(ImGuiWindow* window); +CIMGUI_API void igBringWindowToDisplayBack(ImGuiWindow* window); +CIMGUI_API void igBringWindowToDisplayBehind(ImGuiWindow* window,ImGuiWindow* above_window); +CIMGUI_API int igFindWindowDisplayIndex(ImGuiWindow* window); +CIMGUI_API ImGuiWindow* igFindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); +CIMGUI_API void igSetCurrentFont(ImFont* font); +CIMGUI_API ImFont* igGetDefaultFont(void); +CIMGUI_API ImDrawList* igGetForegroundDrawList_WindowPtr(ImGuiWindow* window); +CIMGUI_API ImDrawList* igGetBackgroundDrawList_ViewportPtr(ImGuiViewport* viewport); +CIMGUI_API ImDrawList* igGetForegroundDrawList_ViewportPtr(ImGuiViewport* viewport); +CIMGUI_API void igInitialize(ImGuiContext* context); +CIMGUI_API void igShutdown(ImGuiContext* context); +CIMGUI_API void igUpdateHoveredWindowAndCaptureFlags(void); +CIMGUI_API void igStartMouseMovingWindow(ImGuiWindow* window); +CIMGUI_API void igUpdateMouseMovingWindowNewFrame(void); +CIMGUI_API void igUpdateMouseMovingWindowEndFrame(void); +CIMGUI_API ImGuiID igAddContextHook(ImGuiContext* context,const ImGuiContextHook* hook); +CIMGUI_API void igRemoveContextHook(ImGuiContext* context,ImGuiID hook_to_remove); +CIMGUI_API void igCallContextHooks(ImGuiContext* context,ImGuiContextHookType type); +CIMGUI_API void igMarkIniSettingsDirty_Nil(void); +CIMGUI_API void igMarkIniSettingsDirty_WindowPtr(ImGuiWindow* window); +CIMGUI_API void igClearIniSettings(void); +CIMGUI_API ImGuiWindowSettings* igCreateNewWindowSettings(const char* name); +CIMGUI_API ImGuiWindowSettings* igFindWindowSettings(ImGuiID id); +CIMGUI_API ImGuiWindowSettings* igFindOrCreateWindowSettings(const char* name); +CIMGUI_API ImGuiSettingsHandler* igFindSettingsHandler(const char* type_name); +CIMGUI_API void igSetNextWindowScroll(const ImVec2 scroll); +CIMGUI_API void igSetScrollX_WindowPtr(ImGuiWindow* window,float scroll_x); +CIMGUI_API void igSetScrollY_WindowPtr(ImGuiWindow* window,float scroll_y); +CIMGUI_API void igSetScrollFromPosX_WindowPtr(ImGuiWindow* window,float local_x,float center_x_ratio); +CIMGUI_API void igSetScrollFromPosY_WindowPtr(ImGuiWindow* window,float local_y,float center_y_ratio); +CIMGUI_API void igScrollToItem(ImGuiScrollFlags flags); +CIMGUI_API void igScrollToRect(ImGuiWindow* window,const ImRect rect,ImGuiScrollFlags flags); +CIMGUI_API void igScrollToRectEx(ImVec2 *pOut,ImGuiWindow* window,const ImRect rect,ImGuiScrollFlags flags); +CIMGUI_API void igScrollToBringRectIntoView(ImGuiWindow* window,const ImRect rect); +CIMGUI_API ImGuiID igGetItemID(void); +CIMGUI_API ImGuiItemStatusFlags igGetItemStatusFlags(void); +CIMGUI_API ImGuiItemFlags igGetItemFlags(void); +CIMGUI_API ImGuiID igGetActiveID(void); +CIMGUI_API ImGuiID igGetFocusID(void); +CIMGUI_API void igSetActiveID(ImGuiID id,ImGuiWindow* window); +CIMGUI_API void igSetFocusID(ImGuiID id,ImGuiWindow* window); +CIMGUI_API void igClearActiveID(void); +CIMGUI_API ImGuiID igGetHoveredID(void); +CIMGUI_API void igSetHoveredID(ImGuiID id); +CIMGUI_API void igKeepAliveID(ImGuiID id); +CIMGUI_API void igMarkItemEdited(ImGuiID id); +CIMGUI_API void igPushOverrideID(ImGuiID id); +CIMGUI_API ImGuiID igGetIDWithSeed(const char* str_id_begin,const char* str_id_end,ImGuiID seed); +CIMGUI_API void igItemSize_Vec2(const ImVec2 size,float text_baseline_y); +CIMGUI_API void igItemSize_Rect(const ImRect bb,float text_baseline_y); +CIMGUI_API bool igItemAdd(const ImRect bb,ImGuiID id,const ImRect* nav_bb,ImGuiItemFlags extra_flags); +CIMGUI_API bool igItemHoverable(const ImRect bb,ImGuiID id); +CIMGUI_API bool igIsClippedEx(const ImRect bb,ImGuiID id); +CIMGUI_API void igSetLastItemData(ImGuiID item_id,ImGuiItemFlags in_flags,ImGuiItemStatusFlags status_flags,const ImRect item_rect); +CIMGUI_API void igCalcItemSize(ImVec2 *pOut,ImVec2 size,float default_w,float default_h); +CIMGUI_API float igCalcWrapWidthForPos(const ImVec2 pos,float wrap_pos_x); +CIMGUI_API void igPushMultiItemsWidths(int components,float width_full); +CIMGUI_API bool igIsItemToggledSelection(void); +CIMGUI_API void igGetContentRegionMaxAbs(ImVec2 *pOut); +CIMGUI_API void igShrinkWidths(ImGuiShrinkWidthItem* items,int count,float width_excess); +CIMGUI_API void igPushItemFlag(ImGuiItemFlags option,bool enabled); +CIMGUI_API void igPopItemFlag(void); +CIMGUI_API void igLogBegin(ImGuiLogType type,int auto_open_depth); +CIMGUI_API void igLogToBuffer(int auto_open_depth); +CIMGUI_API void igLogRenderedText(const ImVec2* ref_pos,const char* text,const char* text_end); +CIMGUI_API void igLogSetNextTextDecoration(const char* prefix,const char* suffix); +CIMGUI_API bool igBeginChildEx(const char* name,ImGuiID id,const ImVec2 size_arg,bool border,ImGuiWindowFlags flags); +CIMGUI_API void igOpenPopupEx(ImGuiID id,ImGuiPopupFlags popup_flags); +CIMGUI_API void igClosePopupToLevel(int remaining,bool restore_focus_to_window_under_popup); +CIMGUI_API void igClosePopupsOverWindow(ImGuiWindow* ref_window,bool restore_focus_to_window_under_popup); +CIMGUI_API void igClosePopupsExceptModals(void); +CIMGUI_API bool igIsPopupOpen_ID(ImGuiID id,ImGuiPopupFlags popup_flags); +CIMGUI_API bool igBeginPopupEx(ImGuiID id,ImGuiWindowFlags extra_flags); +CIMGUI_API void igBeginTooltipEx(ImGuiTooltipFlags tooltip_flags,ImGuiWindowFlags extra_window_flags); +CIMGUI_API void igGetPopupAllowedExtentRect(ImRect *pOut,ImGuiWindow* window); +CIMGUI_API ImGuiWindow* igGetTopMostPopupModal(void); +CIMGUI_API ImGuiWindow* igGetTopMostAndVisiblePopupModal(void); +CIMGUI_API void igFindBestWindowPosForPopup(ImVec2 *pOut,ImGuiWindow* window); +CIMGUI_API void igFindBestWindowPosForPopupEx(ImVec2 *pOut,const ImVec2 ref_pos,const ImVec2 size,ImGuiDir* last_dir,const ImRect r_outer,const ImRect r_avoid,ImGuiPopupPositionPolicy policy); +CIMGUI_API bool igBeginViewportSideBar(const char* name,ImGuiViewport* viewport,ImGuiDir dir,float size,ImGuiWindowFlags window_flags); +CIMGUI_API bool igBeginMenuEx(const char* label,const char* icon,bool enabled); +CIMGUI_API bool igMenuItemEx(const char* label,const char* icon,const char* shortcut,bool selected,bool enabled); +CIMGUI_API bool igBeginComboPopup(ImGuiID popup_id,const ImRect bb,ImGuiComboFlags flags); +CIMGUI_API bool igBeginComboPreview(void); +CIMGUI_API void igEndComboPreview(void); +CIMGUI_API void igNavInitWindow(ImGuiWindow* window,bool force_reinit); +CIMGUI_API void igNavInitRequestApplyResult(void); +CIMGUI_API bool igNavMoveRequestButNoResultYet(void); +CIMGUI_API void igNavMoveRequestSubmit(ImGuiDir move_dir,ImGuiDir clip_dir,ImGuiNavMoveFlags move_flags,ImGuiScrollFlags scroll_flags); +CIMGUI_API void igNavMoveRequestForward(ImGuiDir move_dir,ImGuiDir clip_dir,ImGuiNavMoveFlags move_flags,ImGuiScrollFlags scroll_flags); +CIMGUI_API void igNavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); +CIMGUI_API void igNavMoveRequestCancel(void); +CIMGUI_API void igNavMoveRequestApplyResult(void); +CIMGUI_API void igNavMoveRequestTryWrapping(ImGuiWindow* window,ImGuiNavMoveFlags move_flags); +CIMGUI_API float igGetNavInputAmount(ImGuiNavInput n,ImGuiInputReadMode mode); +CIMGUI_API void igGetNavInputAmount2d(ImVec2 *pOut,ImGuiNavDirSourceFlags dir_sources,ImGuiInputReadMode mode,float slow_factor,float fast_factor); +CIMGUI_API int igCalcTypematicRepeatAmount(float t0,float t1,float repeat_delay,float repeat_rate); +CIMGUI_API void igActivateItem(ImGuiID id); +CIMGUI_API void igSetNavID(ImGuiID id,ImGuiNavLayer nav_layer,ImGuiID focus_scope_id,const ImRect rect_rel); +CIMGUI_API void igPushFocusScope(ImGuiID id); +CIMGUI_API void igPopFocusScope(void); +CIMGUI_API ImGuiID igGetFocusedFocusScope(void); +CIMGUI_API ImGuiID igGetFocusScope(void); +CIMGUI_API void igSetItemUsingMouseWheel(void); +CIMGUI_API void igSetActiveIdUsingNavAndKeys(void); +CIMGUI_API bool igIsActiveIdUsingNavDir(ImGuiDir dir); +CIMGUI_API bool igIsActiveIdUsingNavInput(ImGuiNavInput input); +CIMGUI_API bool igIsActiveIdUsingKey(ImGuiKey key); +CIMGUI_API bool igIsMouseDragPastThreshold(ImGuiMouseButton button,float lock_threshold); +CIMGUI_API bool igIsKeyPressedMap(ImGuiKey key,bool repeat); +CIMGUI_API bool igIsNavInputDown(ImGuiNavInput n); +CIMGUI_API bool igIsNavInputTest(ImGuiNavInput n,ImGuiInputReadMode rm); +CIMGUI_API ImGuiKeyModFlags igGetMergedKeyModFlags(void); +CIMGUI_API bool igBeginDragDropTargetCustom(const ImRect bb,ImGuiID id); +CIMGUI_API void igClearDragDrop(void); +CIMGUI_API bool igIsDragDropPayloadBeingAccepted(void); +CIMGUI_API void igSetWindowClipRectBeforeSetChannel(ImGuiWindow* window,const ImRect clip_rect); +CIMGUI_API void igBeginColumns(const char* str_id,int count,ImGuiOldColumnFlags flags); +CIMGUI_API void igEndColumns(void); +CIMGUI_API void igPushColumnClipRect(int column_index); +CIMGUI_API void igPushColumnsBackground(void); +CIMGUI_API void igPopColumnsBackground(void); +CIMGUI_API ImGuiID igGetColumnsID(const char* str_id,int count); +CIMGUI_API ImGuiOldColumns* igFindOrCreateColumns(ImGuiWindow* window,ImGuiID id); +CIMGUI_API float igGetColumnOffsetFromNorm(const ImGuiOldColumns* columns,float offset_norm); +CIMGUI_API float igGetColumnNormFromOffset(const ImGuiOldColumns* columns,float offset); +CIMGUI_API void igTableOpenContextMenu(int column_n); +CIMGUI_API void igTableSetColumnWidth(int column_n,float width); +CIMGUI_API void igTableSetColumnSortDirection(int column_n,ImGuiSortDirection sort_direction,bool append_to_sort_specs); +CIMGUI_API int igTableGetHoveredColumn(void); +CIMGUI_API float igTableGetHeaderRowHeight(void); +CIMGUI_API void igTablePushBackgroundChannel(void); +CIMGUI_API void igTablePopBackgroundChannel(void); +CIMGUI_API ImGuiTable* igGetCurrentTable(void); +CIMGUI_API ImGuiTable* igTableFindByID(ImGuiID id); +CIMGUI_API bool igBeginTableEx(const char* name,ImGuiID id,int columns_count,ImGuiTableFlags flags,const ImVec2 outer_size,float inner_width); +CIMGUI_API void igTableBeginInitMemory(ImGuiTable* table,int columns_count); +CIMGUI_API void igTableBeginApplyRequests(ImGuiTable* table); +CIMGUI_API void igTableSetupDrawChannels(ImGuiTable* table); +CIMGUI_API void igTableUpdateLayout(ImGuiTable* table); +CIMGUI_API void igTableUpdateBorders(ImGuiTable* table); +CIMGUI_API void igTableUpdateColumnsWeightFromWidth(ImGuiTable* table); +CIMGUI_API void igTableDrawBorders(ImGuiTable* table); +CIMGUI_API void igTableDrawContextMenu(ImGuiTable* table); +CIMGUI_API void igTableMergeDrawChannels(ImGuiTable* table); +CIMGUI_API void igTableSortSpecsSanitize(ImGuiTable* table); +CIMGUI_API void igTableSortSpecsBuild(ImGuiTable* table); +CIMGUI_API ImGuiSortDirection igTableGetColumnNextSortDirection(ImGuiTableColumn* column); +CIMGUI_API void igTableFixColumnSortDirection(ImGuiTable* table,ImGuiTableColumn* column); +CIMGUI_API float igTableGetColumnWidthAuto(ImGuiTable* table,ImGuiTableColumn* column); +CIMGUI_API void igTableBeginRow(ImGuiTable* table); +CIMGUI_API void igTableEndRow(ImGuiTable* table); +CIMGUI_API void igTableBeginCell(ImGuiTable* table,int column_n); +CIMGUI_API void igTableEndCell(ImGuiTable* table); +CIMGUI_API void igTableGetCellBgRect(ImRect *pOut,const ImGuiTable* table,int column_n); +CIMGUI_API const char* igTableGetColumnName_TablePtr(const ImGuiTable* table,int column_n); +CIMGUI_API ImGuiID igTableGetColumnResizeID(const ImGuiTable* table,int column_n,int instance_no); +CIMGUI_API float igTableGetMaxColumnWidth(const ImGuiTable* table,int column_n); +CIMGUI_API void igTableSetColumnWidthAutoSingle(ImGuiTable* table,int column_n); +CIMGUI_API void igTableSetColumnWidthAutoAll(ImGuiTable* table); +CIMGUI_API void igTableRemove(ImGuiTable* table); +CIMGUI_API void igTableGcCompactTransientBuffers_TablePtr(ImGuiTable* table); +CIMGUI_API void igTableGcCompactTransientBuffers_TableTempDataPtr(ImGuiTableTempData* table); +CIMGUI_API void igTableGcCompactSettings(void); +CIMGUI_API void igTableLoadSettings(ImGuiTable* table); +CIMGUI_API void igTableSaveSettings(ImGuiTable* table); +CIMGUI_API void igTableResetSettings(ImGuiTable* table); +CIMGUI_API ImGuiTableSettings* igTableGetBoundSettings(ImGuiTable* table); +CIMGUI_API void igTableSettingsInstallHandler(ImGuiContext* context); +CIMGUI_API ImGuiTableSettings* igTableSettingsCreate(ImGuiID id,int columns_count); +CIMGUI_API ImGuiTableSettings* igTableSettingsFindByID(ImGuiID id); +CIMGUI_API bool igBeginTabBarEx(ImGuiTabBar* tab_bar,const ImRect bb,ImGuiTabBarFlags flags); +CIMGUI_API ImGuiTabItem* igTabBarFindTabByID(ImGuiTabBar* tab_bar,ImGuiID tab_id); +CIMGUI_API void igTabBarRemoveTab(ImGuiTabBar* tab_bar,ImGuiID tab_id); +CIMGUI_API void igTabBarCloseTab(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); +CIMGUI_API void igTabBarQueueReorder(ImGuiTabBar* tab_bar,const ImGuiTabItem* tab,int offset); +CIMGUI_API void igTabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar,const ImGuiTabItem* tab,ImVec2 mouse_pos); +CIMGUI_API bool igTabBarProcessReorder(ImGuiTabBar* tab_bar); +CIMGUI_API bool igTabItemEx(ImGuiTabBar* tab_bar,const char* label,bool* p_open,ImGuiTabItemFlags flags); +CIMGUI_API void igTabItemCalcSize(ImVec2 *pOut,const char* label,bool has_close_button); +CIMGUI_API void igTabItemBackground(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImU32 col); +CIMGUI_API void igTabItemLabelAndCloseButton(ImDrawList* draw_list,const ImRect bb,ImGuiTabItemFlags flags,ImVec2 frame_padding,const char* label,ImGuiID tab_id,ImGuiID close_button_id,bool is_contents_visible,bool* out_just_closed,bool* out_text_clipped); +CIMGUI_API void igRenderText(ImVec2 pos,const char* text,const char* text_end,bool hide_text_after_hash); +CIMGUI_API void igRenderTextWrapped(ImVec2 pos,const char* text,const char* text_end,float wrap_width); +CIMGUI_API void igRenderTextClipped(const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect); +CIMGUI_API void igRenderTextClippedEx(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,const char* text,const char* text_end,const ImVec2* text_size_if_known,const ImVec2 align,const ImRect* clip_rect); +CIMGUI_API void igRenderTextEllipsis(ImDrawList* draw_list,const ImVec2 pos_min,const ImVec2 pos_max,float clip_max_x,float ellipsis_max_x,const char* text,const char* text_end,const ImVec2* text_size_if_known); +CIMGUI_API void igRenderFrame(ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,bool border,float rounding); +CIMGUI_API void igRenderFrameBorder(ImVec2 p_min,ImVec2 p_max,float rounding); +CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,float grid_step,ImVec2 grid_off,float rounding,ImDrawFlags flags); +CIMGUI_API void igRenderNavHighlight(const ImRect bb,ImGuiID id,ImGuiNavHighlightFlags flags); +CIMGUI_API const char* igFindRenderedTextEnd(const char* text,const char* text_end); +CIMGUI_API void igRenderArrow(ImDrawList* draw_list,ImVec2 pos,ImU32 col,ImGuiDir dir,float scale); +CIMGUI_API void igRenderBullet(ImDrawList* draw_list,ImVec2 pos,ImU32 col); +CIMGUI_API void igRenderCheckMark(ImDrawList* draw_list,ImVec2 pos,ImU32 col,float sz); +CIMGUI_API void igRenderMouseCursor(ImDrawList* draw_list,ImVec2 pos,float scale,ImGuiMouseCursor mouse_cursor,ImU32 col_fill,ImU32 col_border,ImU32 col_shadow); +CIMGUI_API void igRenderArrowPointingAt(ImDrawList* draw_list,ImVec2 pos,ImVec2 half_sz,ImGuiDir direction,ImU32 col); +CIMGUI_API void igRenderRectFilledRangeH(ImDrawList* draw_list,const ImRect rect,ImU32 col,float x_start_norm,float x_end_norm,float rounding); +CIMGUI_API void igRenderRectFilledWithHole(ImDrawList* draw_list,ImRect outer,ImRect inner,ImU32 col,float rounding); +CIMGUI_API void igTextEx(const char* text,const char* text_end,ImGuiTextFlags flags); +CIMGUI_API bool igButtonEx(const char* label,const ImVec2 size_arg,ImGuiButtonFlags flags); +CIMGUI_API bool igCloseButton(ImGuiID id,const ImVec2 pos); +CIMGUI_API bool igCollapseButton(ImGuiID id,const ImVec2 pos); +CIMGUI_API bool igArrowButtonEx(const char* str_id,ImGuiDir dir,ImVec2 size_arg,ImGuiButtonFlags flags); +CIMGUI_API void igScrollbar(ImGuiAxis axis); +CIMGUI_API bool igScrollbarEx(const ImRect bb,ImGuiID id,ImGuiAxis axis,ImS64* p_scroll_v,ImS64 avail_v,ImS64 contents_v,ImDrawFlags flags); +CIMGUI_API bool igImageButtonEx(ImGuiID id,ImTextureID texture_id,const ImVec2 size,const ImVec2 uv0,const ImVec2 uv1,const ImVec2 padding,const ImVec4 bg_col,const ImVec4 tint_col); +CIMGUI_API void igGetWindowScrollbarRect(ImRect *pOut,ImGuiWindow* window,ImGuiAxis axis); +CIMGUI_API ImGuiID igGetWindowScrollbarID(ImGuiWindow* window,ImGuiAxis axis); +CIMGUI_API ImGuiID igGetWindowResizeCornerID(ImGuiWindow* window,int n); +CIMGUI_API ImGuiID igGetWindowResizeBorderID(ImGuiWindow* window,ImGuiDir dir); +CIMGUI_API void igSeparatorEx(ImGuiSeparatorFlags flags); +CIMGUI_API bool igCheckboxFlags_S64Ptr(const char* label,ImS64* flags,ImS64 flags_value); +CIMGUI_API bool igCheckboxFlags_U64Ptr(const char* label,ImU64* flags,ImU64 flags_value); +CIMGUI_API bool igButtonBehavior(const ImRect bb,ImGuiID id,bool* out_hovered,bool* out_held,ImGuiButtonFlags flags); +CIMGUI_API bool igDragBehavior(ImGuiID id,ImGuiDataType data_type,void* p_v,float v_speed,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags); +CIMGUI_API bool igSliderBehavior(const ImRect bb,ImGuiID id,ImGuiDataType data_type,void* p_v,const void* p_min,const void* p_max,const char* format,ImGuiSliderFlags flags,ImRect* out_grab_bb); +CIMGUI_API bool igSplitterBehavior(const ImRect bb,ImGuiID id,ImGuiAxis axis,float* size1,float* size2,float min_size1,float min_size2,float hover_extend,float hover_visibility_delay); +CIMGUI_API bool igTreeNodeBehavior(ImGuiID id,ImGuiTreeNodeFlags flags,const char* label,const char* label_end); +CIMGUI_API bool igTreeNodeBehaviorIsOpen(ImGuiID id,ImGuiTreeNodeFlags flags); +CIMGUI_API void igTreePushOverrideID(ImGuiID id); +CIMGUI_API const ImGuiDataTypeInfo* igDataTypeGetInfo(ImGuiDataType data_type); +CIMGUI_API int igDataTypeFormatString(char* buf,int buf_size,ImGuiDataType data_type,const void* p_data,const char* format); +CIMGUI_API void igDataTypeApplyOp(ImGuiDataType data_type,int op,void* output,const void* arg_1,const void* arg_2); +CIMGUI_API bool igDataTypeApplyOpFromText(const char* buf,const char* initial_value_buf,ImGuiDataType data_type,void* p_data,const char* format); +CIMGUI_API int igDataTypeCompare(ImGuiDataType data_type,const void* arg_1,const void* arg_2); +CIMGUI_API bool igDataTypeClamp(ImGuiDataType data_type,void* p_data,const void* p_min,const void* p_max); +CIMGUI_API bool igInputTextEx(const char* label,const char* hint,char* buf,int buf_size,const ImVec2 size_arg,ImGuiInputTextFlags flags,ImGuiInputTextCallback callback,void* user_data); +CIMGUI_API bool igTempInputText(const ImRect bb,ImGuiID id,const char* label,char* buf,int buf_size,ImGuiInputTextFlags flags); +CIMGUI_API bool igTempInputScalar(const ImRect bb,ImGuiID id,const char* label,ImGuiDataType data_type,void* p_data,const char* format,const void* p_clamp_min,const void* p_clamp_max); +CIMGUI_API bool igTempInputIsActive(ImGuiID id); +CIMGUI_API ImGuiInputTextState* igGetInputTextState(ImGuiID id); +CIMGUI_API void igColorTooltip(const char* text,const float* col,ImGuiColorEditFlags flags); +CIMGUI_API void igColorEditOptionsPopup(const float* col,ImGuiColorEditFlags flags); +CIMGUI_API void igColorPickerOptionsPopup(const float* ref_col,ImGuiColorEditFlags flags); +CIMGUI_API int igPlotEx(ImGuiPlotType plot_type,const char* label,float(*values_getter)(void* data,int idx),void* data,int values_count,int values_offset,const char* overlay_text,float scale_min,float scale_max,ImVec2 frame_size); +CIMGUI_API void igShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,ImVec2 gradient_p0,ImVec2 gradient_p1,ImU32 col0,ImU32 col1); +CIMGUI_API void igShadeVertsLinearUV(ImDrawList* draw_list,int vert_start_idx,int vert_end_idx,const ImVec2 a,const ImVec2 b,const ImVec2 uv_a,const ImVec2 uv_b,bool clamp); +CIMGUI_API void igGcCompactTransientMiscBuffers(void); +CIMGUI_API void igGcCompactTransientWindowBuffers(ImGuiWindow* window); +CIMGUI_API void igGcAwakeTransientWindowBuffers(ImGuiWindow* window); +CIMGUI_API void igErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback,void* user_data); +CIMGUI_API void igErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback,void* user_data); +CIMGUI_API void igDebugDrawItemRect(ImU32 col); +CIMGUI_API void igDebugStartItemPicker(void); +CIMGUI_API void igShowFontAtlas(ImFontAtlas* atlas); +CIMGUI_API void igDebugHookIdInfo(ImGuiID id,ImGuiDataType data_type,const void* data_id,const void* data_id_end); +CIMGUI_API void igDebugNodeColumns(ImGuiOldColumns* columns); +CIMGUI_API void igDebugNodeDrawList(ImGuiWindow* window,const ImDrawList* draw_list,const char* label); +CIMGUI_API void igDebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list,const ImDrawList* draw_list,const ImDrawCmd* draw_cmd,bool show_mesh,bool show_aabb); +CIMGUI_API void igDebugNodeFont(ImFont* font); +CIMGUI_API void igDebugNodeStorage(ImGuiStorage* storage,const char* label); +CIMGUI_API void igDebugNodeTabBar(ImGuiTabBar* tab_bar,const char* label); +CIMGUI_API void igDebugNodeTable(ImGuiTable* table); +CIMGUI_API void igDebugNodeTableSettings(ImGuiTableSettings* settings); +CIMGUI_API void igDebugNodeWindow(ImGuiWindow* window,const char* label); +CIMGUI_API void igDebugNodeWindowSettings(ImGuiWindowSettings* settings); +CIMGUI_API void igDebugNodeWindowsList(ImVector_ImGuiWindowPtr* windows,const char* label); +CIMGUI_API void igDebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows,int windows_size,ImGuiWindow* parent_in_begin_stack); +CIMGUI_API void igDebugNodeViewport(ImGuiViewportP* viewport); +CIMGUI_API void igDebugRenderViewportThumbnail(ImDrawList* draw_list,ImGuiViewportP* viewport,const ImRect bb); +CIMGUI_API const ImFontBuilderIO* igImFontAtlasGetBuilderForStbTruetype(void); +CIMGUI_API void igImFontAtlasBuildInit(ImFontAtlas* atlas); +CIMGUI_API void igImFontAtlasBuildSetupFont(ImFontAtlas* atlas,ImFont* font,ImFontConfig* font_config,float ascent,float descent); +CIMGUI_API void igImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas,void* stbrp_context_opaque); +CIMGUI_API void igImFontAtlasBuildFinish(ImFontAtlas* atlas); +CIMGUI_API void igImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned char in_marker_pixel_value); +CIMGUI_API void igImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas,int x,int y,int w,int h,const char* in_str,char in_marker_char,unsigned int in_marker_pixel_value); +CIMGUI_API void igImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256],float in_multiply_factor); +CIMGUI_API void igImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256],unsigned char* pixels,int x,int y,int w,int h,int stride); + + +/////////////////////////hand written functions +//no LogTextV +CIMGUI_API void igLogText(CONST char *fmt, ...); +//no appendfV +CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...); +//for getting FLT_MAX in bindings +CIMGUI_API float igGET_FLT_MAX(); +//for getting FLT_MIN in bindings +CIMGUI_API float igGET_FLT_MIN(); + + +CIMGUI_API ImVector_ImWchar* ImVector_ImWchar_create(); +CIMGUI_API void ImVector_ImWchar_destroy(ImVector_ImWchar* self); +CIMGUI_API void ImVector_ImWchar_Init(ImVector_ImWchar* p); +CIMGUI_API void ImVector_ImWchar_UnInit(ImVector_ImWchar* p); + + +#endif //CIMGUI_INCLUDED + + + + diff --git a/thirdparty/sokol_imgui/sokol_imgui.cpp b/thirdparty/sokol_imgui/sokol_imgui.cpp new file mode 100644 index 0000000..5653c56 --- /dev/null +++ b/thirdparty/sokol_imgui/sokol_imgui.cpp @@ -0,0 +1,10 @@ +#define SOKOL_D3D11 1 +#include +#include + +#include +#include +#include "cimgui.h" + +#define SOKOL_IMGUI_IMPL 1 +#include "sokol_imgui.h" diff --git a/thirdparty/sokol_imgui/sokol_imgui.h b/thirdparty/sokol_imgui/sokol_imgui.h new file mode 100644 index 0000000..c2161e6 --- /dev/null +++ b/thirdparty/sokol_imgui/sokol_imgui.h @@ -0,0 +1,2182 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_IMGUI_IMPL) +#define SOKOL_IMGUI_IMPL +#endif +#ifndef SOKOL_IMGUI_INCLUDED +/* + sokol_imgui.h -- drop-in Dear ImGui renderer/event-handler for sokol_gfx.h + + Project URL: https://github.com/floooh/sokol + + Do this: + #define SOKOL_IMPL or + #define SOKOL_IMGUI_IMPL + + before you include this file in *one* C or C++ file to create the + implementation. + + NOTE that the implementation can be compiled either as C++ or as C. + When compiled as C++, sokol_imgui.h will directly call into the + Dear ImGui C++ API. When compiled as C, sokol_imgui.h will call + cimgui.h functions instead. + + NOTE that the formerly separate header sokol_cimgui.h has been + merged into sokol_imgui.h + + The following defines are used by the implementation to select the + platform-specific embedded shader code (these are the same defines as + used by sokol_gfx.h and sokol_app.h): + + SOKOL_GLCORE33 + SOKOL_GLES2 + SOKOL_GLES3 + SOKOL_D3D11 + SOKOL_METAL + SOKOL_WGPU + + Optionally provide the following configuration defines before including the + implementation: + + SOKOL_IMGUI_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) + + Optionally provide the following macros before including the implementation + to override defaults: + + SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) + SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) + SOKOL_FREE(p) - your own free function (default: free(p)) + SOKOL_IMGUI_API_DECL- public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_IMGUI_API_DECL + SOKOL_API_IMPL - public function implementation prefix (default: -) + + If sokol_imgui.h is compiled as a DLL, define the following before + including the declaration or implementation: + + SOKOL_DLL + + On Windows, SOKOL_DLL will define SOKOL_IMGUI_API_DECL as __declspec(dllexport) + or __declspec(dllimport) as needed. + + Include the following headers before sokol_imgui.h (both before including + the declaration and implementation): + + sokol_gfx.h + sokol_app.h (except SOKOL_IMGUI_NO_SOKOL_APP) + + Additionally, include the following headers before including the + implementation: + + If the implementation is compiled as C++: + imgui.h + + If the implementation is compiled as C: + cimgui.h + + + FEATURE OVERVIEW: + ================= + sokol_imgui.h implements the initialization, rendering and event-handling + code for Dear ImGui (https://github.com/ocornut/imgui) on top of + sokol_gfx.h and (optionally) sokol_app.h. + + The sokol_app.h dependency is optional and used for input event handling. + If you only use sokol_gfx.h but not sokol_app.h in your application, + define SOKOL_IMGUI_NO_SOKOL_APP before including the implementation + of sokol_imgui.h, this will remove any dependency to sokol_app.h, but + you must feed input events into Dear ImGui yourself. + + sokol_imgui.h is not thread-safe, all calls must be made from the + same thread where sokol_gfx.h is running. + + HOWTO: + ====== + + --- To initialize sokol-imgui, call: + + simgui_setup(const simgui_desc_t* desc) + + This will initialize Dear ImGui and create sokol-gfx resources + (two buffers for vertices and indices, a font texture and a pipeline- + state-object). + + Use the following simgui_desc_t members to configure behaviour: + + int max_vertices + The maximum number of vertices used for UI rendering, default is 65536. + sokol-imgui will use this to compute the size of the vertex- + and index-buffers allocated via sokol_gfx.h + + sg_pixel_format color_format + The color pixel format of the render pass where the UI + will be rendered. The default is SG_PIXELFORMAT_RGBA8 + + sg_pixel_format depth_format + The depth-buffer pixel format of the render pass where + the UI will be rendered. The default is SG_PIXELFORMAT_DEPTHSTENCIL. + + int sample_count + The MSAA sample-count of the render pass where the UI + will be rendered. The default is 1. + + const char* ini_filename + Sets this path as ImGui::GetIO().IniFilename where ImGui will store + and load UI persistency data. By default this is 0, so that Dear ImGui + will not preserve state between sessions (and also won't do + any filesystem calls). Also see the ImGui functions: + - LoadIniSettingsFromMemory() + - SaveIniSettingsFromMemory() + These functions give you explicit control over loading and saving + UI state while using your own filesystem wrapper functions (in this + case keep simgui_desc.ini_filename zero) + + bool no_default_font + Set this to true if you don't want to use ImGui's default + font. In this case you need to initialize the font + yourself after simgui_setup() is called. + + --- At the start of a frame, call: + + simgui_new_frame(&(simgui_frame_desc_t){.width = ..., .height = ..., .delta_time = ..., .dpi_scale = ...}); + + 'width' and 'height' are the dimensions of the rendering surface, + passed to ImGui::GetIO().DisplaySize. + + 'delta_time' is the frame duration passed to ImGui::GetIO().DeltaTime. + + 'dpi_scale' is the current DPI scale factor, if this is left zero-initialized, + 1.0f will be used instead. Typical values for dpi_scale are >= 1.0f. + + For example, if you're using sokol_app.h and render to the default framebuffer: + + simgui_new_frame(&(simgui_frame_desc_t){ + .width = sapp_width(), + .height = sapp_height(), + .delta_time = sapp_frame_duration(), + .dpi_scale = sapp_dpi_scale() + }); + + --- at the end of the frame, before the sg_end_pass() where you + want to render the UI, call: + + simgui_render() + + This will first call ImGui::Render(), and then render ImGui's draw list + through sokol_gfx.h + + --- if you're using sokol_app.h, from inside the sokol_app.h event callback, + call: + + bool simgui_handle_event(const sapp_event* ev); + + The return value is the value of ImGui::GetIO().WantCaptureKeyboard, + if this is true, you might want to skip keyboard input handling + in your own event handler. + + --- finally, on application shutdown, call + + simgui_shutdown() + + LICENSE + ======= + + zlib/libpng license + + Copyright (c) 2018 Andre Weissflog + + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from the + use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +#define SOKOL_IMGUI_INCLUDED (1) +#include +#include + +#if !defined(SOKOL_GFX_INCLUDED) +#error "Please include sokol_gfx.h before sokol_imgui.h" +#endif +#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) +#error "Please include sokol_app.h before sokol_imgui.h" +#endif + +#if defined(SOKOL_API_DECL) && !defined(SOKOL_IMGUI_API_DECL) +#define SOKOL_IMGUI_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_IMGUI_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMGUI_IMPL) +#define SOKOL_IMGUI_API_DECL __declspec(dllexport) +#elif defined(_WIN32) && defined(SOKOL_DLL) +#define SOKOL_IMGUI_API_DECL __declspec(dllimport) +#else +#define SOKOL_IMGUI_API_DECL extern +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct simgui_desc_t { + int max_vertices; + sg_pixel_format color_format; + sg_pixel_format depth_format; + int sample_count; + const char* ini_filename; + bool no_default_font; + bool disable_hotkeys; /* don't let ImGui handle Ctrl-A,C,V,X,Y,Z */ +} simgui_desc_t; + +typedef struct simgui_frame_desc_t { + int width; + int height; + double delta_time; + float dpi_scale; +} simgui_frame_desc_t; + +SOKOL_IMGUI_API_DECL void simgui_setup(const simgui_desc_t* desc); +SOKOL_IMGUI_API_DECL void simgui_new_frame(const simgui_frame_desc_t* desc); +SOKOL_IMGUI_API_DECL void simgui_render(void); +#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) +SOKOL_IMGUI_API_DECL bool simgui_handle_event(const sapp_event* ev); +#endif +SOKOL_IMGUI_API_DECL void simgui_shutdown(void); + +#ifdef __cplusplus +} /* extern "C" */ + +/* reference-based equivalents for C++ */ +inline void simgui_setup(const simgui_desc_t& desc) { return simgui_setup(&desc); } +inline void simgui_new_frame(const simgui_frame_desc_t& desc) { return simgui_new_frame(&desc); } + +#endif +#endif /* SOKOL_IMGUI_INCLUDED */ + +/*-- IMPLEMENTATION ----------------------------------------------------------*/ +#ifdef SOKOL_IMGUI_IMPL +#define SOKOL_IMGUI_IMPL_INCLUDED (1) + +#if defined(__cplusplus) + #if !defined(IMGUI_VERSION) + #error "Please include imgui.h before the sokol_imgui.h implementation" + #endif +#else + #if !defined(CIMGUI_INCLUDED) + #error "Please include cimgui.h before the sokol_imgui.h implementation" + #endif +#endif + +#include /* offsetof */ +#include /* memset */ + +#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) +#include +#endif + +#ifndef SOKOL_API_IMPL +#define SOKOL_API_IMPL +#endif +#ifndef SOKOL_DEBUG + #ifndef NDEBUG + #define SOKOL_DEBUG (1) + #endif +#endif +#ifndef SOKOL_ASSERT + #include + #define SOKOL_ASSERT(c) assert(c) +#endif +#ifndef SOKOL_MALLOC + #include + #define SOKOL_MALLOC(s) malloc(s) + #define SOKOL_FREE(p) free(p) +#endif +#ifndef _SOKOL_PRIVATE + #if defined(__GNUC__) || defined(__clang__) + #define _SOKOL_PRIVATE __attribute__((unused)) static + #else + #define _SOKOL_PRIVATE static + #endif +#endif + +/* helper macros */ +#define _simgui_def(val, def) (((val) == 0) ? (def) : (val)) + +typedef struct { + ImVec2 disp_size; + uint8_t _pad_8[8]; +} _simgui_vs_params_t; + +#define SIMGUI_MAX_KEY_VALUE (512) // same as ImGuis IO.KeysDown array + +typedef struct { + simgui_desc_t desc; + float cur_dpi_scale; + sg_buffer vbuf; + sg_buffer ibuf; + sg_image img; + sg_shader shd; + sg_pipeline pip; + bool is_osx; // return true if running on OSX (or HTML5 OSX), needed for copy/paste + + sg_range vertices; + sg_range indices; + + #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) + bool btn_down[SAPP_MAX_MOUSEBUTTONS]; + bool btn_up[SAPP_MAX_MOUSEBUTTONS]; + uint8_t keys_down[SIMGUI_MAX_KEY_VALUE]; // bits 0..3 or modifiers, != 0 is key-down + uint8_t keys_up[SIMGUI_MAX_KEY_VALUE]; // same is keys_down + #endif +} _simgui_state_t; +static _simgui_state_t _simgui; + +/* + Embedded source code compiled with: + + sokol-shdc -i simgui.glsl -o simgui.h -l glsl330:glsl100:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b + + (not that for Metal and D3D11 byte code, sokol-shdc must be run + on macOS and Windows) + + @vs vs + uniform vs_params { + vec2 disp_size; + }; + in vec2 position; + in vec2 texcoord0; + in vec4 color0; + out vec2 uv; + out vec4 color; + void main() { + gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0); + uv = texcoord0; + color = color0; + } + @end + + @fs fs + uniform sampler2D tex; + in vec2 uv; + in vec4 color; + out vec4 frag_color; + void main() { + frag_color = texture(tex, uv) * color; + } + @end + + @program simgui vs fs +*/ +#if defined(SOKOL_GLCORE33) +static const char _simgui_vs_source_glsl330[341] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, + 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, + 0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, + 0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79, + 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31, + 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f, + 0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f, + 0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, + 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, + 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, + 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28, + 0x28,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x76,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2d,0x20, + 0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, + 0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e, + 0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20, + 0x3d,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b, + 0x0a,0x7d,0x0a,0x0a,0x00, +}; +static const char _simgui_fs_source_glsl330[169] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, + 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, + 0x74,0x65,0x78,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63, + 0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76, + 0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, + 0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x69,0x6e,0x20,0x76, + 0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64, + 0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72, + 0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75, + 0x72,0x65,0x28,0x74,0x65,0x78,0x2c,0x20,0x75,0x76,0x29,0x20,0x2a,0x20,0x63,0x6f, + 0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +}; +#elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3) +static const char _simgui_vs_source_glsl100[307] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x30,0x30,0x0a,0x0a,0x75,0x6e, + 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x3b,0x0a,0x61,0x74,0x74,0x72,0x69,0x62,0x75, + 0x74,0x65,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x3b,0x0a,0x76,0x61,0x72,0x79,0x69,0x6e,0x67,0x20,0x76,0x65,0x63,0x32,0x20,0x75, + 0x76,0x3b,0x0a,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x20,0x76,0x65,0x63, + 0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x76,0x61,0x72, + 0x79,0x69,0x6e,0x67,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, + 0x0a,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x20,0x76,0x65,0x63,0x34,0x20, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61, + 0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f, + 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x28,0x28, + 0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2e,0x78,0x79,0x29,0x20,0x2d,0x20,0x76,0x65, + 0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28, + 0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30,0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c, + 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20, + 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63, + 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d, + 0x0a,0x0a,0x00, +}; +static const char _simgui_fs_source_glsl100[207] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x30,0x30,0x0a,0x70,0x72,0x65, + 0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d,0x70,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20, + 0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75,0x6e,0x69,0x66, + 0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65, + 0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x79,0x69,0x6e, + 0x67,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b, + 0x0a,0x76,0x61,0x72,0x79,0x69,0x6e,0x67,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76, + 0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64, + 0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c, + 0x5f,0x46,0x72,0x61,0x67,0x44,0x61,0x74,0x61,0x5b,0x30,0x5d,0x20,0x3d,0x20,0x74, + 0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x44,0x28,0x74,0x65,0x78,0x2c,0x20,0x75,0x76, + 0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +}; +#elif defined(SOKOL_METAL) +static const uint8_t _simgui_vs_bytecode_metal_macos[3216] = { + 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, + 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, + 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xef,0xd7,0x24,0x0b,0xf0,0x26,0xba, + 0xcd,0xc3,0x6f,0x48,0x91,0x7a,0x7c,0x38,0xca,0xb8,0xf1,0xb1,0xe3,0xc7,0x99,0x8d, + 0xac,0x39,0x8e,0x2f,0xf8,0xa3,0x19,0x68,0x22,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, + 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x45,0x4e,0x44,0x54,0x37,0x00,0x00, + 0x00,0x56,0x41,0x54,0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x00,0x00,0x80,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03, + 0x00,0x04,0x04,0x06,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54, + 0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x60,0x0b,0x00,0x00, + 0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xd5,0x02,0x00,0x00, + 0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91, + 0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19, + 0x1e,0x04,0x8b,0x62,0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14, + 0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80, + 0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0, + 0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x81,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8, + 0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87, + 0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72, + 0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88, + 0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07, + 0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41, + 0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c, + 0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87, + 0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72, + 0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e, + 0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda, + 0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21, + 0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30, + 0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87, + 0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77, + 0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70, + 0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07, + 0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1, + 0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08, + 0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87, + 0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, + 0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d, + 0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0, + 0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80, + 0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38, + 0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00, + 0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1, + 0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c, + 0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87, + 0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a, + 0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d, + 0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00, + 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x18,0x02,0x01,0x2c,0x40,0x05,0x00, + 0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00,0x89,0x20,0x00,0x00, + 0x1b,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xa4,0x84, + 0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c,0x0b,0x84,0x84,0x4c, + 0x10,0x3c,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x77,0x49,0x53,0x44,0x09, + 0x93,0xcf,0x00,0x48,0x43,0xff,0x0e,0x35,0xf9,0x0f,0x20,0x28,0xc4,0x80,0x87,0x10, + 0x39,0x48,0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02,0x18,0x09,0x05,0x31, + 0x88,0x40,0x08,0xa5,0x98,0x08,0x29,0xb2,0x81,0x80,0x39,0x02,0x30,0xc8,0x81,0x9c, + 0x23,0x00,0x85,0x41,0x84,0x40,0x18,0x46,0x20,0x92,0x11,0x00,0x00,0x00,0x00,0x00, + 0x13,0xb2,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60, + 0x87,0x72,0x68,0x83,0x76,0x08,0x87,0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03, + 0x37,0x88,0x83,0x38,0x70,0x03,0x38,0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07, + 0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71, + 0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80, + 0x07,0x6d,0x90,0x0e,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07, + 0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d, + 0x90,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60, + 0x0e,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e, + 0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71, + 0x60,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40, + 0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07, + 0x7a,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a, + 0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60, + 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07, + 0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78, + 0xa0,0x07,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10, + 0x07,0x79,0x20,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07, + 0x6d,0x60,0x0f,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72, + 0x50,0x07,0x76,0xd0,0x06,0xf6,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20, + 0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07, + 0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d, + 0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60,0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x39,0x00, + 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0xc8,0x02,0x01,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xda, + 0x11,0x00,0xca,0x12,0x18,0x01,0x28,0x88,0x22,0x28,0x84,0x32,0x20,0x1d,0x6b,0x50, + 0x1e,0x82,0x60,0x8c,0x00,0x04,0x41,0x50,0x04,0x03,0x00,0x00,0x79,0x18,0x00,0x00, + 0x16,0x01,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9, + 0xb9,0xb4,0x37,0xb7,0x21,0x46,0x52,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93, + 0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x06,0xd9,0x20,0x08,0x0e, + 0x8e,0xad,0x0c,0x84,0x89,0xc9,0xaa,0x09,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d, + 0x24,0x07,0x46,0xc6,0x25,0x86,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac, + 0x25,0x07,0x46,0xc6,0x25,0x86,0xc6,0x25,0x27,0x65,0x88,0x80,0x10,0x43,0x8c,0x44, + 0x48,0x88,0x64,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e,0x44,0x48,0x84, + 0x64,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56, + 0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x40, + 0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61, + 0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04, + 0x64,0x61,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98, + 0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1, + 0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x61,0x10,0x96,0x26, + 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0xe2,0x16,0x46,0x97,0x66,0x57,0xf6, + 0x45,0xf6,0x56,0x27,0xc6,0x56,0xf6,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44, + 0x40,0x1e,0x92,0x41,0x58,0x9a,0x9c,0xcb,0xd8,0x5b,0x1b,0x5c,0x1a,0x5b,0x99,0x8b, + 0x5b,0x18,0x5d,0x9a,0x5d,0xd9,0x17,0xdb,0x9b,0xdb,0xd9,0x17,0xdb,0x9b,0xdb,0xd9, + 0x17,0x59,0xda,0x5c,0x98,0x18,0x5b,0xd9,0x10,0x01,0x89,0x78,0x06,0x61,0x69,0x72, + 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f, + 0x77,0x69,0x64,0x65,0x5f,0x76,0x65,0x63,0x74,0x6f,0x72,0x73,0x5f,0x64,0x69,0x73, + 0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x62,0x14,0x96,0x26,0xe7,0x62,0x57,0x26,0x47, + 0x57,0x86,0xf7,0xf5,0x56,0x47,0x07,0x57,0x47,0xc7,0xa5,0x6e,0xae,0x4c,0x0e,0x85, + 0xed,0x6d,0xcc,0x0d,0x26,0x85,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d, + 0x1e,0x5c,0xd9,0x97,0x5b,0x58,0x5b,0x19,0x0d,0x33,0xb6,0xb7,0x30,0x3a,0x19,0x32, + 0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x6e,0x61,0x6d,0x65,0x14,0xea,0xec,0x86, + 0x30,0x48,0x85,0x58,0xc8,0x85,0x60,0x48,0x86,0x68,0x5c,0xea,0xe6,0xca,0xe4,0x50, + 0xd8,0xde,0xc6,0xdc,0x62,0x52,0x68,0x98,0xb1,0xbd,0x85,0xd1,0xd1,0xb0,0x18,0x7b, + 0x63,0x7b,0x93,0x1b,0xc2,0x20,0x15,0xc2,0x21,0x17,0xd2,0x21,0x19,0xe2,0x91,0x09, + 0x4b,0x93,0x73,0x81,0x7b,0x9b,0x4b,0xa3,0x4b,0x7b,0x73,0xe3,0x72,0xc6,0xf6,0x05, + 0xf5,0x36,0x97,0x46,0x97,0xf6,0xe6,0x36,0x44,0x41,0xc0,0x00,0xb9,0x90,0x0e,0xc9, + 0x90,0x30,0x18,0x62,0x20,0x1b,0xf2,0x21,0x62,0x40,0x28,0x2c,0x4d,0xce,0xc5,0xae, + 0x4c,0x8e,0xae,0x0c,0xef,0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b, + 0xdb,0xdb,0x58,0x18,0x5d,0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xb3,0xb3, + 0x32,0xb7,0x32,0xb9,0x30,0xba,0x32,0x32,0x14,0x1c,0xb8,0xb7,0xb9,0x34,0xba,0xb4, + 0x37,0x37,0x22,0x3b,0x99,0x2f,0xb3,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x43,0xa8,0x64,0x40,0xc8,0x00,0x29,0x83,0x64,0x48,0x04,0xc4,0x0c,0x90,0x0b, + 0xc1,0x90,0x0c,0x39,0x03,0x6a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28, + 0x39,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x44,0x76,0x32,0x5f,0x66,0x29, + 0x4c,0xe8,0xca,0xf0,0xc6,0xde,0xde,0xe4,0xc8,0x60,0x86,0x50,0x89,0x80,0x90,0x01, + 0x52,0x06,0x89,0x90,0x08,0x48,0x1a,0x20,0x17,0x82,0x21,0x19,0xa2,0x06,0xbc,0xce, + 0xca,0xdc,0xca,0xe4,0xc2,0xe8,0xca,0xc8,0x50,0x6c,0xc6,0xde,0xd8,0xde,0xe4,0x60, + 0x88,0xec,0x68,0xbe,0xcc,0x52,0x68,0x8c,0xbd,0xb1,0xbd,0xc9,0xc1,0x0c,0xa1,0x92, + 0x02,0x21,0x03,0xa4,0x0c,0x92,0x22,0x11,0x10,0x36,0x40,0x2e,0xa4,0x43,0x32,0xa4, + 0x0d,0xa8,0x84,0xa5,0xc9,0xb9,0x88,0xd5,0x99,0x99,0x95,0xc9,0xf1,0x09,0x4b,0x93, + 0x73,0x11,0xab,0x33,0x33,0x2b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x23,0x12,0x96,0x26, + 0xe7,0x22,0x57,0x16,0x46,0x46,0x2a,0x2c,0x4d,0xce,0x65,0x8e,0x4e,0xae,0x6e,0x8c, + 0xee,0x8b,0x2e,0x0f,0xae,0xec,0x2b,0xcd,0xcd,0xec,0x8d,0x09,0x59,0xda,0x1c,0xdc, + 0xd7,0x5c,0x9a,0x5e,0xd9,0x10,0x25,0x19,0x12,0x22,0x19,0x10,0x0c,0x99,0x03,0x46, + 0x61,0x69,0x72,0x2e,0x61,0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x73,0x69,0x7a, + 0x65,0xbc,0xc2,0xd2,0xe4,0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xc2, + 0xd8,0xd2,0xce,0xdc,0xbe,0xe6,0xd2,0xf4,0xca,0x98,0xd8,0xcd,0x7d,0xc1,0x85,0xc9, + 0x85,0xb5,0xcd,0x71,0xf8,0x92,0x99,0x19,0x42,0x06,0xc9,0x81,0xbc,0x01,0x02,0x07, + 0x09,0x81,0x94,0x41,0x32,0x24,0x02,0x12,0x07,0x88,0x1c,0x20,0x74,0x80,0xd4,0x41, + 0x42,0x20,0x76,0x90,0x10,0xc8,0x85,0xdc,0x01,0x92,0x21,0x78,0x30,0x04,0x41,0xd0, + 0x00,0x59,0x03,0xc4,0x0d,0x90,0x3c,0x18,0x62,0x1c,0x00,0x32,0x06,0x88,0x1e,0xf0, + 0x79,0x6b,0x73,0x4b,0x83,0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3, + 0x33,0x95,0xd6,0x06,0xc7,0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34, + 0x44,0x40,0xfa,0x60,0x88,0x81,0xf0,0x01,0xe2,0x07,0x4b,0x30,0xc4,0x40,0xfe,0x00, + 0xf9,0x83,0x25,0x18,0x22,0x00,0xc9,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d, + 0xda,0xe1,0x1d,0xc8,0xa1,0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce, + 0x61,0x1e,0xa6,0x08,0xc1,0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74, + 0x20,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70, + 0x03,0x7b,0x28,0x07,0x79,0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8, + 0x70,0x48,0x07,0x79,0x70,0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73, + 0x28,0x87,0x5f,0xb0,0x87,0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01, + 0x32,0x62,0x0a,0x87,0x74,0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07, + 0x76,0x28,0x87,0x5f,0x78,0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29, + 0x86,0xc2,0x38,0x90,0x44,0x8d,0x50,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c, + 0xe4,0x81,0x1e,0xca,0x01,0x1f,0xa6,0x04,0x7b,0x00,0x00,0x00,0x79,0x18,0x00,0x00, + 0x6d,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88, + 0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6, + 0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce, + 0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8, + 0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48, + 0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11, + 0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e, + 0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89, + 0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b, + 0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37, + 0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78, + 0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81, + 0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1, + 0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c, + 0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39, + 0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc, + 0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58, + 0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87, + 0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f, + 0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e, + 0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66, + 0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b, + 0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0, + 0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e, + 0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc, + 0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3, + 0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07, + 0x7a,0x28,0x07,0x72,0x00,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00, + 0x06,0x50,0x30,0x00,0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x24,0x00,0x00,0x00, + 0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40, + 0x60,0x1c,0x73,0x10,0x83,0x00,0x41,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82, + 0xf0,0x2f,0x80,0x20,0x08,0xc2,0xbf,0x30,0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08, + 0x82,0x20,0x08,0x0e,0x33,0x00,0x24,0x73,0x10,0x18,0x76,0x59,0x34,0x33,0x00,0x04, + 0x63,0x04,0x20,0x08,0x82,0xf8,0x37,0x46,0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00, + 0xe3,0x0d,0x0c,0x66,0x51,0x40,0x2c,0x0a,0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9, + 0x0c,0x32,0x04,0xcb,0x33,0xc8,0x10,0x2c,0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41, + 0x15,0xcc,0x36,0x04,0x83,0x90,0x41,0x40,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x5b,0x86,0x20,0x00,0x85,0x2d,0x83,0x30,0x84,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static const uint8_t _simgui_fs_bytecode_metal_macos[2909] = { + 0x4d,0x54,0x4c,0x42,0x01,0x80,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5d,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, + 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, + 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0x17,0xe5,0xa2,0xb3,0x7d,0x00,0xfc, + 0xde,0x00,0x5f,0xbd,0x79,0x5e,0xd5,0x95,0xff,0xb6,0xf4,0xce,0x41,0x07,0xfb,0x8f, + 0x49,0x6b,0x95,0x79,0x7a,0xd1,0xcf,0x19,0xde,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, + 0x00,0x01,0x00,0x01,0x00,0x45,0x4e,0x44,0x54,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, + 0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17, + 0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x60,0x0a,0x00,0x00,0xff,0xff,0xff, + 0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x95,0x02,0x00,0x00,0x0b,0x82,0x20, + 0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04, + 0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b, + 0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18, + 0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21, + 0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00, + 0x00,0x51,0x18,0x00,0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff, + 0xff,0x01,0x60,0x00,0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07, + 0x7a,0x60,0x87,0x7c,0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72, + 0x68,0x03,0x72,0x48,0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90, + 0x07,0x7a,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc, + 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81, + 0x1d,0xca,0xa1,0x0d,0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d, + 0xd8,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87, + 0x79,0x98,0x87,0x36,0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36, + 0x30,0x07,0x78,0x68,0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c, + 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0, + 0xe1,0x1d,0xd2,0xc1,0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1, + 0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90, + 0x87,0x70,0x68,0x87,0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07, + 0x79,0x68,0x83,0x72,0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36, + 0x60,0x87,0x72,0x08,0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30, + 0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8, + 0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01, + 0x1e,0xda,0x80,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60, + 0x87,0x79,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87, + 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, + 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c, + 0xc8,0xa1,0x0d,0xf4,0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda, + 0xa0,0x1d,0xc2,0x81,0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77, + 0x78,0x87,0x36,0xa0,0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68, + 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6, + 0x81,0x1e,0xc2,0x61,0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61, + 0x1c,0xe8,0xe1,0x1d,0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e, + 0xda,0x60,0x1e,0xd2,0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87, + 0x70,0x30,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74, + 0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e, + 0xde,0xc1,0x1c,0xe8,0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87, + 0x70,0x60,0x87,0x79,0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81, + 0x00,0x16,0xa0,0xda,0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5, + 0x06,0xa3,0x08,0x80,0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00, + 0x00,0x03,0x00,0x00,0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00, + 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, + 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, + 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x70,0x90,0x34,0x45, + 0x94,0x30,0xf9,0x0c,0x80,0x34,0xf4,0xef,0x50,0x13,0x0a,0xc2,0x30,0x82,0x00,0x1c, + 0x25,0x4d,0x11,0x25,0x4c,0xfe,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0xff,0x34, + 0x46,0x00,0x0c,0x22,0x10,0xc1,0x45,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x12,0xc0,0x3c, + 0x0b,0x11,0xfd,0xd3,0x18,0x01,0x30,0x88,0x60,0x08,0xa5,0x10,0x23,0x94,0x43,0x68, + 0x8e,0x20,0x98,0x23,0x00,0x83,0x61,0x04,0x61,0x29,0x48,0x28,0x67,0x28,0xa6,0x00, + 0xb5,0x81,0x80,0x1c,0x58,0x23,0x00,0x00,0x00,0x13,0xb2,0x70,0x48,0x07,0x79,0xb0, + 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x76,0x08,0x87, + 0x71,0x78,0x87,0x79,0xc0,0x87,0x38,0x80,0x03,0x37,0x88,0x83,0x38,0x70,0x03,0x38, + 0xd8,0x70,0x1b,0xe5,0xd0,0x06,0xf0,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, + 0xa0,0x07,0x76,0x40,0x07,0x6d,0x90,0x0e,0x71,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0, + 0x06,0xe9,0x80,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x71,0x60,0x07, + 0x7a,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x6d,0x90,0x0e,0x73,0x20,0x07,0x7a, + 0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x90,0x0e,0x76,0x40,0x07,0x7a,0x60, + 0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0e,0x73,0x20,0x07,0x7a,0x30,0x07, + 0x72,0xa0,0x07,0x73,0x20,0x07,0x6d,0x60,0x0e,0x76,0x40,0x07,0x7a,0x60,0x07,0x74, + 0xa0,0x07,0x76,0x40,0x07,0x6d,0x60,0x0f,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xa0, + 0x07,0x71,0x60,0x07,0x6d,0x60,0x0f,0x72,0x40,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07, + 0x73,0x20,0x07,0x6d,0x60,0x0f,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xa0,0x07,0x73, + 0x20,0x07,0x6d,0x60,0x0f,0x74,0x80,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40, + 0x07,0x6d,0x60,0x0f,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07, + 0x6d,0x60,0x0f,0x79,0x60,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72, + 0x80,0x07,0x6d,0x60,0x0f,0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, + 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x79,0x20,0x07,0x7a,0x20,0x07, + 0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x72,0x50,0x07,0x76, + 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x50, + 0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07,0x7a,0x50,0x07,0x71,0x20,0x07, + 0x6d,0x60,0x0f,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, + 0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x6d,0xe0,0x0e,0x78,0xa0,0x07,0x71,0x60, + 0x07,0x7a,0x30,0x07,0x72,0x30,0x84,0x49,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00, + 0x18,0xc2,0x38,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x64,0x81,0x00,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98,0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26, + 0x47,0xc6,0x04,0x43,0x5a,0x25,0x30,0x02,0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70, + 0xac,0x41,0x79,0x08,0x00,0x79,0x18,0x00,0x00,0xd9,0x00,0x00,0x00,0x1a,0x03,0x4c, + 0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42, + 0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62, + 0x2c,0xc2,0x23,0x2c,0x05,0xd9,0x20,0x08,0x0e,0x8e,0xad,0x0c,0x84,0x89,0xc9,0xaa, + 0x09,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x24,0x07,0x46,0xc6,0x25,0x86,0x06, + 0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x25,0x07,0x46,0xc6,0x25,0x86,0xc6, + 0x25,0x27,0x65,0x88,0xf0,0x10,0x43,0x8c,0x45,0x58,0x8c,0x65,0x60,0xd1,0x54,0x46, + 0x17,0xc6,0x36,0x04,0x79,0x8e,0x45,0x58,0x84,0x65,0xe0,0x16,0x96,0x26,0xe7,0x32, + 0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45, + 0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63, + 0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68, + 0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x61,0x19,0x84,0xa5,0xc9,0xb9, + 0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99, + 0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x91,0xa5,0xcd,0x85,0x89,0xb1, + 0x95,0x0d,0x11,0x9e,0x86,0x61,0x10,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6, + 0x56,0xe6,0xe2,0x16,0x46,0x97,0x66,0x57,0xf6,0x45,0xf6,0x56,0x27,0xc6,0x56,0xf6, + 0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x78,0x1e,0x92,0x41,0x58,0x9a,0x9c, + 0xcb,0xd8,0x5b,0x1b,0x5c,0x1a,0x5b,0x99,0x8b,0x5b,0x18,0x5d,0x9a,0x5d,0xd9,0x17, + 0xdb,0x9b,0xdb,0xd9,0x17,0xdb,0x9b,0xdb,0xd9,0x17,0x59,0xda,0x5c,0x98,0x18,0x5b, + 0xd9,0x10,0xe1,0x89,0x78,0x06,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c, + 0x65,0x2e,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x77,0x69,0x64,0x65,0x5f,0x76,0x65, + 0x63,0x74,0x6f,0x72,0x73,0x5f,0x64,0x69,0x73,0x61,0x62,0x6c,0x65,0x43,0x84,0x67, + 0x62,0x14,0x96,0x26,0xe7,0x22,0x57,0xe6,0x46,0x56,0x26,0xf7,0x45,0x17,0x26,0x77, + 0x56,0x46,0xc7,0x28,0x2c,0x4d,0xce,0x25,0x4c,0xee,0xec,0x8b,0x2e,0x0f,0xae,0xec, + 0xcb,0x2d,0xac,0xad,0x8c,0x86,0x19,0xdb,0x5b,0x18,0x1d,0x0d,0x99,0xb0,0x34,0x39, + 0x97,0x30,0xb9,0xb3,0x2f,0xb7,0xb0,0xb6,0x32,0x2a,0x66,0x72,0x61,0x67,0x5f,0x63, + 0x6f,0x6c,0x6f,0x72,0x43,0x98,0xa7,0x5a,0x86,0xc7,0x7a,0xae,0x07,0x7b,0xb2,0x21, + 0xc2,0xa3,0x51,0x0a,0x4b,0x93,0x73,0x31,0x93,0x0b,0x3b,0x6b,0x2b,0x73,0xa3,0xfb, + 0x4a,0x73,0x83,0xab,0xa3,0xe3,0x52,0x37,0x57,0x26,0x87,0xc2,0xf6,0x36,0xe6,0x06, + 0x93,0x42,0x25,0x2c,0x4d,0xce,0x65,0xac,0xcc,0x8d,0xae,0x4c,0x8e,0x4f,0x58,0x9a, + 0x9c,0x0b,0x5c,0x99,0xdc,0x1c,0x5c,0xd9,0x18,0x5d,0x9a,0x5d,0x19,0x0d,0x33,0xb6, + 0xb7,0x30,0x3a,0x19,0x0a,0x75,0x76,0x43,0xa4,0x65,0x78,0xb8,0xa7,0x7b,0xbc,0xe7, + 0x7b,0xac,0x07,0x0c,0x1e,0xec,0x09,0x03,0x2e,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f, + 0x63,0x6e,0x31,0x29,0x2c,0xc6,0xde,0xd8,0xde,0xe4,0x86,0x48,0x8b,0xf0,0x70,0xcf, + 0x18,0x3c,0xde,0xf3,0x3d,0xd6,0x73,0x3d,0xd8,0x43,0x06,0x5c,0xc2,0xd2,0xe4,0x5c, + 0xe8,0xca,0xf0,0xe8,0xea,0xe4,0xca,0x28,0x85,0xa5,0xc9,0xb9,0xb0,0xbd,0x8d,0x85, + 0xd1,0xa5,0xbd,0xb9,0x7d,0xa5,0xb9,0x91,0x95,0xe1,0x51,0x09,0x4b,0x93,0x73,0x99, + 0x0b,0x6b,0x83,0x63,0x2b,0x23,0x46,0x57,0x86,0x47,0x57,0x27,0x57,0x26,0x43,0xc6, + 0x63,0xc6,0xf6,0x16,0x46,0xc7,0x02,0x32,0x17,0xd6,0x06,0xc7,0x56,0xe6,0xc3,0x81, + 0xae,0x0c,0x6f,0x08,0xb5,0x10,0x8f,0x19,0x3c,0x67,0xb0,0x0c,0x8b,0xf0,0xa0,0xc1, + 0x63,0x3d,0x69,0xf0,0x60,0x8f,0x1a,0x70,0x09,0x4b,0x93,0x73,0x99,0x0b,0x6b,0x83, + 0x63,0x2b,0x93,0xe3,0x31,0x17,0xd6,0x06,0xc7,0x56,0x26,0x47,0x84,0xae,0x0c,0x6f, + 0xaa,0x0d,0x8e,0x4d,0x6e,0x88,0xb4,0x1c,0x0f,0x1b,0x3c,0x67,0xb0,0x0c,0x8b,0xf0, + 0x58,0x4f,0x1b,0x3c,0xd8,0xe3,0x06,0x43,0x90,0x47,0x0c,0x9e,0x32,0x78,0xd6,0xe0, + 0x79,0x83,0x21,0x46,0x02,0x3c,0xdb,0x03,0x07,0x23,0x22,0x76,0x60,0x07,0x7b,0x68, + 0x07,0x37,0x68,0x87,0x77,0x20,0x87,0x7a,0x60,0x87,0x72,0x70,0x03,0x73,0x60,0x87, + 0x70,0x38,0x87,0x79,0x98,0x22,0x04,0xc3,0x08,0x85,0x1d,0xd8,0xc1,0x1e,0xda,0xc1, + 0x0d,0xd2,0x81,0x1c,0xca,0xc1,0x1d,0xe8,0x61,0x4a,0x50,0x8c,0x58,0xc2,0x21,0x1d, + 0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x61,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x4a,0x60, + 0x8c,0xa0,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xd8,0x21,0x1c,0xdc,0xe1,0x1c,0xea,0x21, + 0x1c,0xce,0xa1,0x1c,0x7e,0xc1,0x1e,0xca,0x41,0x1e,0xe6,0x21,0x1d,0xde,0xc1,0x1d, + 0xa6,0x04,0xc8,0x88,0x29,0x1c,0xd2,0x41,0x1e,0xdc,0x60,0x1c,0xde,0xa1,0x1d,0xe0, + 0x21,0x1d,0xd8,0xa1,0x1c,0x7e,0xe1,0x1d,0xe0,0x81,0x1e,0xd2,0xe1,0x1d,0xdc,0x61, + 0x1e,0xa6,0x18,0x0a,0xe3,0x40,0x12,0x35,0x82,0x09,0x87,0x74,0x90,0x07,0x37,0x30, + 0x07,0x79,0x08,0x87,0x73,0x68,0x87,0x72,0x70,0x07,0x7a,0x98,0x12,0xc4,0x01,0x00, + 0x00,0x79,0x18,0x00,0x00,0x6d,0x00,0x00,0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c, + 0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07, + 0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42, + 0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83, + 0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07, + 0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70, + 0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3, + 0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2, + 0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc, + 0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68, + 0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07, + 0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72, + 0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec, + 0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc, + 0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8, + 0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03, + 0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c, + 0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74, + 0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4, + 0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc, + 0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1, + 0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50, + 0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51, + 0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21, + 0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06, + 0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c, + 0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77, + 0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72,0x00,0x00,0x00,0x00,0x71,0x20,0x00, + 0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01,0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f, + 0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e,0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20, + 0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41, + 0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4, + 0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00,0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91, + 0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6,0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static const uint8_t _simgui_vs_bytecode_metal_ios[3200] = { + 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x70,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, + 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, + 0x01,0x00,0x00,0x48,0x41,0x53,0x48,0x20,0x00,0xcb,0xdd,0xe3,0x08,0x7a,0x87,0xef, + 0xdd,0xe0,0x68,0xe7,0xe8,0x6b,0xe6,0xea,0x8b,0x6d,0x4a,0xe0,0x3d,0x6a,0xfe,0xe4, + 0xfe,0x32,0x1d,0xbe,0xb6,0x10,0x11,0xee,0x75,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, + 0x00,0x01,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0x45,0x4e,0x44,0x54,0x37,0x00,0x00, + 0x00,0x56,0x41,0x54,0x54,0x22,0x00,0x03,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x00,0x00,0x80,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x00,0x01,0x80, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x02,0x80,0x56,0x41,0x54,0x59,0x05,0x00,0x03, + 0x00,0x04,0x04,0x06,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54, + 0xde,0xc0,0x17,0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x5c,0x0b,0x00,0x00, + 0xff,0xff,0xff,0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0xd4,0x02,0x00,0x00, + 0x0b,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91, + 0x41,0xc8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19, + 0x1e,0x04,0x8b,0x62,0x80,0x10,0x45,0x02,0x42,0x92,0x0b,0x42,0x84,0x10,0x32,0x14, + 0x38,0x08,0x18,0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80, + 0x0c,0x19,0x21,0x72,0x24,0x07,0xc8,0x08,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0, + 0x01,0x00,0x00,0x00,0x51,0x18,0x00,0x00,0x82,0x00,0x00,0x00,0x1b,0xc8,0x25,0xf8, + 0xff,0xff,0xff,0xff,0x01,0x90,0x80,0x8a,0x18,0x87,0x77,0x90,0x07,0x79,0x28,0x87, + 0x71,0xa0,0x07,0x76,0xc8,0x87,0x36,0x90,0x87,0x77,0xa8,0x07,0x77,0x20,0x87,0x72, + 0x20,0x87,0x36,0x20,0x87,0x74,0xb0,0x87,0x74,0x20,0x87,0x72,0x68,0x83,0x79,0x88, + 0x07,0x79,0xa0,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07, + 0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c,0x00,0x82,0x1c,0xd2,0x61,0x1e,0xc2,0x41, + 0x1c,0xd8,0xa1,0x1c,0xda,0x80,0x1e,0xc2,0x21,0x1d,0xd8,0xa1,0x0d,0xc6,0x21,0x1c, + 0xd8,0x81,0x1d,0xe6,0x01,0x30,0x87,0x70,0x60,0x87,0x79,0x28,0x07,0x80,0x60,0x87, + 0x72,0x98,0x87,0x79,0x68,0x03,0x78,0x90,0x87,0x72,0x18,0x87,0x74,0x98,0x87,0x72, + 0x68,0x03,0x73,0x80,0x87,0x76,0x08,0x07,0x72,0x00,0xcc,0x21,0x1c,0xd8,0x61,0x1e, + 0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0xc0,0x1c,0xe4,0x21,0x1c,0xda,0xa1,0x1c,0xda, + 0x00,0x1e,0xde,0x21,0x1d,0xdc,0x81,0x1e,0xca,0x41,0x1e,0xda,0xa0,0x1c,0xd8,0x21, + 0x1d,0xda,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x06,0x77,0x78,0x87,0x36,0x30, + 0x07,0x79,0x08,0x87,0x76,0x28,0x87,0x36,0x80,0x87,0x77,0x48,0x07,0x77,0xa0,0x87, + 0x72,0x90,0x87,0x36,0x28,0x07,0x76,0x48,0x87,0x76,0x68,0x03,0x77,0x78,0x07,0x77, + 0x68,0x03,0x76,0x28,0x87,0x70,0x30,0x07,0x80,0x70,0x87,0x77,0x68,0x83,0x74,0x70, + 0x07,0x73,0x98,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07, + 0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x40,0x1d,0xea,0xa1, + 0x1d,0xe0,0xa1,0x0d,0xe8,0x21,0x1c,0xc4,0x81,0x1d,0xca,0x61,0x1e,0x00,0x73,0x08, + 0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x77,0x78,0x87,0x36,0x70,0x87,0x70,0x70,0x87, + 0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41, + 0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xe6,0x21,0x1d,0xce,0xc1,0x1d, + 0xca,0x81,0x1c,0xda,0x40,0x1f,0xca,0x41,0x1e,0xde,0x61,0x1e,0xda,0xc0,0x1c,0xe0, + 0xa1,0x0d,0xda,0x21,0x1c,0xe8,0x01,0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x80, + 0x70,0x87,0x77,0x68,0x03,0x7a,0x90,0x87,0x70,0x80,0x07,0x78,0x48,0x07,0x77,0x38, + 0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00, + 0x62,0x1e,0xe8,0x21,0x1c,0xc6,0x61,0x1d,0xda,0x00,0x1e,0xe4,0xe1,0x1d,0xe8,0xa1, + 0x1c,0xc6,0x81,0x1e,0xde,0x41,0x1e,0xda,0x40,0x1c,0xea,0xc1,0x1c,0xcc,0xa1,0x1c, + 0xe4,0xa1,0x0d,0xe6,0x21,0x1d,0xf4,0xa1,0x1c,0x00,0x3c,0x00,0x88,0x7a,0x70,0x87, + 0x79,0x08,0x07,0x73,0x28,0x87,0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a, + 0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xea,0x61,0x1e,0xca,0xa1,0x0d, + 0xe6,0xe1,0x1d,0xcc,0x81,0x1e,0xda,0xc0,0x1c,0xd8,0xe1,0x1d,0xc2,0x81,0x1e,0x00, + 0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x36,0x20,0x02,0x01,0x24,0xc0,0x02,0x54, + 0x00,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x01,0x00,0x00,0x00,0x13,0x84,0x40,0x00, + 0x89,0x20,0x00,0x00,0x1b,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04, + 0x13,0x22,0xa4,0x84,0x04,0x13,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x88,0x8c, + 0x0b,0x84,0x84,0x4c,0x10,0x3c,0x33,0x00,0xc3,0x08,0x02,0x30,0x8c,0x40,0x00,0x77, + 0x49,0x53,0x44,0x09,0x93,0xcf,0x00,0x48,0x43,0xff,0x0e,0x35,0xf9,0x0f,0x20,0x28, + 0xc4,0x80,0x87,0x10,0x39,0x48,0x9a,0x22,0x4a,0x98,0xfc,0x4a,0xfa,0x1f,0x20,0x02, + 0x18,0x09,0x05,0x31,0x88,0x40,0x08,0xa5,0x98,0x08,0x29,0xb2,0x81,0x80,0x39,0x02, + 0x30,0x48,0x81,0x9c,0x23,0x00,0x85,0x41,0x84,0x40,0x18,0x46,0x20,0x92,0x11,0x00, + 0x00,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0,0x03,0x3a,0x68,0x83,0x70, + 0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87,0x79,0xc8,0x03,0x37,0x80, + 0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f,0x7a,0x60,0x07,0x74,0xa0, + 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9,0x10,0x07,0x7a,0x80,0x07, + 0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0,0x07,0x78,0xd0,0x06,0xe9, + 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xe9,0x30, + 0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe9,0x60,0x07, + 0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe6,0x30,0x07,0x72, + 0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xe6,0x60,0x07,0x74,0xa0, + 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x10,0x07,0x76,0xa0,0x07, + 0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20,0x07,0x74,0xa0,0x07,0x73, + 0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20, + 0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78,0xa0,0x07,0x76,0x40,0x07, + 0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a, + 0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07,0x71,0x20,0x07,0x78,0xa0, + 0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07, + 0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60,0x0f,0x71,0x90,0x07,0x72, + 0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07,0x76,0xd0,0x06,0xf6,0x20, + 0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07, + 0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xa0,0x07,0x75, + 0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07,0x74,0xa0,0x07,0x71,0x00, + 0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74,0xd0,0x06,0xee,0x80,0x07, + 0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98,0x03,0x00,0x80,0x00,0x00, + 0x00,0x00,0x00,0x80,0x2c,0x10,0x00,0x00,0x0b,0x00,0x00,0x00,0x32,0x1e,0x98,0x10, + 0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0xda,0x11,0x00,0xca,0x12, + 0x18,0x01,0x28,0x88,0x22,0x28,0x84,0x32,0x20,0x1d,0x4b,0x68,0x0a,0x82,0x31,0x02, + 0x10,0x04,0x41,0x11,0x0c,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x16,0x01,0x00,0x00, + 0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32,0xb9,0xb9,0xb4,0x37,0xb7, + 0x21,0x46,0x52,0x20,0x80,0x82,0x50,0xb9,0x1b,0x43,0x0b,0x93,0xfb,0x9a,0x4b,0xd3, + 0x2b,0x1b,0x62,0x24,0x02,0x22,0x24,0x06,0xd9,0x20,0x08,0x0e,0x8e,0xad,0x0c,0x84, + 0x89,0xc9,0xaa,0x09,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd,0x0d,0x64,0x26,0x07,0x46, + 0xc6,0xc5,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd,0xac,0xac,0x65,0x26,0x07, + 0x46,0xc6,0xc5,0xe6,0x26,0x65,0x88,0x80,0x10,0x43,0x8c,0x44,0x48,0x88,0x64,0x60, + 0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x41,0x8e,0x44,0x48,0x86,0x64,0xe0,0x16,0x96, + 0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42,0x56,0xe6,0xf6,0x26,0xd7, + 0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x12,0x72,0x61,0x69, + 0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66,0x61,0x73,0x74,0x5f,0x6d, + 0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43,0x04,0x64,0x21,0x19,0x84, + 0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9,0x98,0xc9,0x85,0xb5,0x95, + 0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d,0xa1,0x7d,0x95,0xb9,0x85, + 0x89,0xb1,0x95,0x0d,0x11,0x90,0x86,0x61,0x10,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06, + 0x97,0xc6,0x56,0xe6,0xe2,0x16,0x46,0x97,0x66,0x57,0xf6,0x45,0xf6,0x56,0x27,0xc6, + 0x56,0xf6,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44,0x40,0x1e,0x92,0x41,0x58, + 0x9a,0x9c,0xcb,0xd8,0x5b,0x1b,0x5c,0x1a,0x5b,0x99,0x8b,0x5b,0x18,0x5d,0x9a,0x5d, + 0xd9,0x17,0xdb,0x9b,0xdb,0xd9,0x17,0xdb,0x9b,0xdb,0xd9,0x17,0x59,0xda,0x5c,0x98, + 0x18,0x5b,0xd9,0x10,0x01,0x89,0x78,0x06,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70, + 0x69,0x6c,0x65,0x2e,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x77,0x69,0x64,0x65,0x5f, + 0x76,0x65,0x63,0x74,0x6f,0x72,0x73,0x5f,0x64,0x69,0x73,0x61,0x62,0x6c,0x65,0x43, + 0x04,0x64,0x62,0x14,0x96,0x26,0xe7,0x62,0x57,0x26,0x47,0x57,0x86,0xf7,0xf5,0x56, + 0x47,0x07,0x57,0x47,0xc7,0xa5,0x6e,0xae,0x4c,0x0e,0x85,0xed,0x6d,0xcc,0x0d,0x26, + 0x85,0x51,0x58,0x9a,0x9c,0x4b,0x98,0xdc,0xd9,0x17,0x5d,0x1e,0x5c,0xd9,0x97,0x5b, + 0x58,0x5b,0x19,0x0d,0x33,0xb6,0xb7,0x30,0x3a,0x19,0x32,0x61,0x69,0x72,0x2e,0x61, + 0x72,0x67,0x5f,0x6e,0x61,0x6d,0x65,0x14,0xea,0xec,0x86,0x30,0x48,0x85,0x58,0xc8, + 0x85,0x60,0x48,0x86,0x68,0x5c,0xea,0xe6,0xca,0xe4,0x50,0xd8,0xde,0xc6,0xdc,0x62, + 0x52,0x68,0x98,0xb1,0xbd,0x85,0xd1,0xd1,0xb0,0x18,0x7b,0x63,0x7b,0x93,0x1b,0xc2, + 0x20,0x15,0xc2,0x21,0x17,0xd2,0x21,0x19,0xe2,0x91,0x09,0x4b,0x93,0x73,0x81,0x7b, + 0x9b,0x4b,0xa3,0x4b,0x7b,0x73,0xe3,0x72,0xc6,0xf6,0x05,0xf5,0x36,0x97,0x46,0x97, + 0xf6,0xe6,0x36,0x44,0x41,0xc0,0x00,0xb9,0x90,0x0e,0xc9,0x90,0x30,0x18,0x62,0x20, + 0x1b,0xf2,0x21,0x62,0x40,0x28,0x2c,0x4d,0xce,0xc5,0xae,0x4c,0x8e,0xae,0x0c,0xef, + 0x2b,0xcd,0x0d,0xae,0x8e,0x8e,0x52,0x58,0x9a,0x9c,0x0b,0xdb,0xdb,0x58,0x18,0x5d, + 0xda,0x9b,0xdb,0x57,0x9a,0x1b,0x59,0x19,0x1e,0xb3,0xb3,0x32,0xb7,0x32,0xb9,0x30, + 0xba,0x32,0x32,0x14,0x1c,0xb8,0xb7,0xb9,0x34,0xba,0xb4,0x37,0x37,0x22,0x3b,0x99, + 0x2f,0xb3,0x14,0x22,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x43,0xa8,0x64,0x40, + 0xc8,0x00,0x29,0x83,0x64,0x48,0x04,0xc4,0x0c,0x90,0x0b,0xc1,0x90,0x0c,0x39,0x03, + 0x6a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x28,0x39,0x74,0x65,0x78,0x63, + 0x6f,0x6f,0x72,0x64,0x30,0x44,0x76,0x32,0x5f,0x66,0x29,0x4c,0xe8,0xca,0xf0,0xc6, + 0xde,0xde,0xe4,0xc8,0x60,0x86,0x50,0x89,0x80,0x90,0x01,0x52,0x06,0x89,0x90,0x08, + 0x48,0x1a,0x20,0x17,0x82,0x21,0x19,0xa2,0x06,0xbc,0xce,0xca,0xdc,0xca,0xe4,0xc2, + 0xe8,0xca,0xc8,0x50,0x6c,0xc6,0xde,0xd8,0xde,0xe4,0x60,0x88,0xec,0x68,0xbe,0xcc, + 0x52,0x68,0x8c,0xbd,0xb1,0xbd,0xc9,0xc1,0x0c,0xa1,0x92,0x02,0x21,0x03,0xa4,0x0c, + 0x92,0x22,0x11,0x10,0x36,0x40,0x2e,0xa4,0x43,0x32,0xa4,0x0d,0xa8,0x84,0xa5,0xc9, + 0xb9,0x88,0xd5,0x99,0x99,0x95,0xc9,0xf1,0x09,0x4b,0x93,0x73,0x11,0xab,0x33,0x33, + 0x2b,0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x23,0x12,0x96,0x26,0xe7,0x22,0x57,0x16,0x46, + 0x46,0x2a,0x2c,0x4d,0xce,0x65,0x8e,0x4e,0xae,0x6e,0x8c,0xee,0x8b,0x2e,0x0f,0xae, + 0xec,0x2b,0xcd,0xcd,0xec,0x8d,0x09,0x59,0xda,0x1c,0xdc,0xd7,0x5c,0x9a,0x5e,0xd9, + 0x10,0x25,0x19,0x12,0x22,0x19,0x10,0x0c,0x99,0x03,0x46,0x61,0x69,0x72,0x2e,0x61, + 0x72,0x67,0x5f,0x74,0x79,0x70,0x65,0x5f,0x73,0x69,0x7a,0x65,0xbc,0xc2,0xd2,0xe4, + 0x5c,0xc2,0xe4,0xce,0xbe,0xe8,0xf2,0xe0,0xca,0xbe,0xc2,0xd8,0xd2,0xce,0xdc,0xbe, + 0xe6,0xd2,0xf4,0xca,0x98,0xd8,0xcd,0x7d,0xc1,0x85,0xc9,0x85,0xb5,0xcd,0x71,0xf8, + 0x92,0x99,0x19,0x42,0x06,0xc9,0x81,0xbc,0x01,0x02,0x07,0x09,0x81,0x94,0x41,0x32, + 0x24,0x02,0x12,0x07,0x88,0x1c,0x20,0x74,0x80,0xd4,0x41,0x42,0x20,0x76,0x90,0x10, + 0xc8,0x85,0xdc,0x01,0x92,0x21,0x78,0x30,0x04,0x41,0xd0,0x00,0x59,0x03,0xc4,0x0d, + 0x90,0x3c,0x18,0x62,0x1c,0x00,0x32,0x06,0x88,0x1e,0xf0,0x79,0x6b,0x73,0x4b,0x83, + 0x7b,0xa3,0x2b,0x73,0xa3,0x03,0x19,0x43,0x0b,0x93,0xe3,0x33,0x95,0xd6,0x06,0xc7, + 0x56,0x06,0x32,0xb4,0xb2,0x02,0x42,0x25,0x14,0x14,0x34,0x44,0x40,0xfa,0x60,0x88, + 0x81,0xf0,0x01,0xe2,0x07,0x4b,0x30,0xc4,0x40,0xfe,0x00,0xf9,0x83,0x25,0x18,0x22, + 0x00,0xc9,0x88,0x88,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xda,0xe1,0x1d,0xc8,0xa1, + 0x1e,0xd8,0xa1,0x1c,0xdc,0xc0,0x1c,0xd8,0x21,0x1c,0xce,0x61,0x1e,0xa6,0x08,0xc1, + 0x30,0x42,0x61,0x07,0x76,0xb0,0x87,0x76,0x70,0x83,0x74,0x20,0x87,0x72,0x70,0x07, + 0x7a,0x98,0x12,0x14,0x23,0x96,0x70,0x48,0x07,0x79,0x70,0x03,0x7b,0x28,0x07,0x79, + 0x98,0x87,0x74,0x78,0x07,0x77,0x98,0x12,0x18,0x23,0xa8,0x70,0x48,0x07,0x79,0x70, + 0x03,0x76,0x08,0x07,0x77,0x38,0x87,0x7a,0x08,0x87,0x73,0x28,0x87,0x5f,0xb0,0x87, + 0x72,0x90,0x87,0x79,0x48,0x87,0x77,0x70,0x87,0x29,0x01,0x32,0x62,0x0a,0x87,0x74, + 0x90,0x07,0x37,0x18,0x87,0x77,0x68,0x07,0x78,0x48,0x07,0x76,0x28,0x87,0x5f,0x78, + 0x07,0x78,0xa0,0x87,0x74,0x78,0x07,0x77,0x98,0x87,0x29,0x86,0xc2,0x38,0x90,0x44, + 0x8d,0x50,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x81,0x1e,0xca,0x01, + 0x1f,0xa6,0x04,0x7b,0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x6d,0x00,0x00,0x00, + 0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84,0xc3, + 0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed,0x10, + 0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66,0x30, + 0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c,0x03, + 0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07, + 0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90,0x0e, + 0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4,0x1d, + 0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83,0x3b, + 0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14,0x76, + 0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90, + 0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80,0x87, + 0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0,0x0e, + 0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1,0x1c, + 0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d,0xca, + 0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39,0xb8, + 0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc,0x82, + 0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70,0x83, + 0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53,0x0f, + 0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e,0xec, + 0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c,0xdc, + 0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38,0xb0, + 0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x60, + 0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33,0x1e, + 0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4,0xa1, + 0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0,0x43, + 0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3,0x8c, + 0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07,0x72, + 0x00,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x50,0x30,0x00, + 0xd2,0xd0,0x00,0x00,0x61,0x20,0x00,0x00,0x24,0x00,0x00,0x00,0x13,0x04,0x41,0x2c, + 0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0xd4,0x63,0x11,0x40,0x60,0x1c,0x73,0x10, + 0x83,0x00,0x41,0x94,0x33,0x00,0x14,0x63,0x09,0x20,0x08,0x82,0xf0,0x2f,0x80,0x20, + 0x08,0xc2,0xbf,0x30,0x96,0x00,0x82,0x20,0x08,0x82,0x01,0x08,0x82,0x20,0x08,0x0e, + 0x33,0x00,0x24,0x73,0x10,0x18,0x76,0x59,0x34,0x33,0x00,0x04,0x63,0x04,0x20,0x08, + 0x82,0xf8,0x37,0x46,0x00,0x82,0x20,0x08,0x7f,0x33,0x00,0x00,0xe3,0x0d,0x0c,0x66, + 0x51,0x40,0x2c,0x0a,0xe8,0x63,0xc1,0x02,0x1f,0x0b,0x16,0xf9,0x0c,0x32,0x04,0xcb, + 0x33,0xc8,0x10,0x2c,0xd1,0x6c,0xc3,0x52,0x01,0xb3,0x0d,0x41,0x15,0xcc,0x36,0x04, + 0x83,0x90,0x41,0x40,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x5b,0x86,0x20,0x00, + 0x85,0x2d,0x83,0x30,0x84,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static const uint8_t _simgui_fs_bytecode_metal_ios[2893] = { + 0x4d,0x54,0x4c,0x42,0x01,0x00,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4d,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdd,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x70,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6d,0x00,0x00,0x00, + 0x4e,0x41,0x4d,0x45,0x06,0x00,0x6d,0x61,0x69,0x6e,0x30,0x00,0x54,0x59,0x50,0x45, + 0x01,0x00,0x01,0x48,0x41,0x53,0x48,0x20,0x00,0xe9,0x4a,0xc6,0xd1,0xba,0x33,0x39, + 0x67,0xdf,0xcd,0xe3,0x58,0xde,0xd4,0xb8,0x81,0x4c,0x26,0x44,0xbc,0x9d,0x14,0xdc, + 0xa9,0x02,0x93,0x08,0x5a,0xcd,0x66,0x1c,0x30,0x4f,0x46,0x46,0x54,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x45,0x52,0x53,0x08,0x00,0x01,0x00,0x08, + 0x00,0x01,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0x45,0x4e,0x44,0x54,0x04,0x00,0x00, + 0x00,0x45,0x4e,0x44,0x54,0x04,0x00,0x00,0x00,0x45,0x4e,0x44,0x54,0xde,0xc0,0x17, + 0x0b,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x58,0x0a,0x00,0x00,0xff,0xff,0xff, + 0xff,0x42,0x43,0xc0,0xde,0x21,0x0c,0x00,0x00,0x93,0x02,0x00,0x00,0x0b,0x82,0x20, + 0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xc8,0x04, + 0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0c,0x25,0x05,0x08,0x19,0x1e,0x04,0x8b, + 0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0b,0x42,0xa4,0x10,0x32,0x14,0x38,0x08,0x18, + 0x49,0x0a,0x32,0x44,0x24,0x48,0x0a,0x90,0x21,0x23,0xc4,0x52,0x80,0x0c,0x19,0x21, + 0x72,0x24,0x07,0xc8,0x48,0x11,0x62,0xa8,0xa0,0xa8,0x40,0xc6,0xf0,0x01,0x00,0x00, + 0x00,0x51,0x18,0x00,0x00,0x89,0x00,0x00,0x00,0x1b,0xcc,0x25,0xf8,0xff,0xff,0xff, + 0xff,0x01,0x60,0x00,0x09,0xa8,0x88,0x71,0x78,0x07,0x79,0x90,0x87,0x72,0x18,0x07, + 0x7a,0x60,0x87,0x7c,0x68,0x03,0x79,0x78,0x87,0x7a,0x70,0x07,0x72,0x28,0x07,0x72, + 0x68,0x03,0x72,0x48,0x07,0x7b,0x48,0x07,0x72,0x28,0x87,0x36,0x98,0x87,0x78,0x90, + 0x07,0x7a,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xcc, + 0x21,0x1c,0xd8,0x61,0x1e,0xca,0x01,0x20,0xc8,0x21,0x1d,0xe6,0x21,0x1c,0xc4,0x81, + 0x1d,0xca,0xa1,0x0d,0xe8,0x21,0x1c,0xd2,0x81,0x1d,0xda,0x60,0x1c,0xc2,0x81,0x1d, + 0xd8,0x61,0x1e,0x00,0x73,0x08,0x07,0x76,0x98,0x87,0x72,0x00,0x08,0x76,0x28,0x87, + 0x79,0x98,0x87,0x36,0x80,0x07,0x79,0x28,0x87,0x71,0x48,0x87,0x79,0x28,0x87,0x36, + 0x30,0x07,0x78,0x68,0x87,0x70,0x20,0x07,0xc0,0x1c,0xc2,0x81,0x1d,0xe6,0xa1,0x1c, + 0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xcc,0x41,0x1e,0xc2,0xa1,0x1d,0xca,0xa1,0x0d,0xe0, + 0xe1,0x1d,0xd2,0xc1,0x1d,0xe8,0xa1,0x1c,0xe4,0xa1,0x0d,0xca,0x81,0x1d,0xd2,0xa1, + 0x1d,0x00,0x7a,0x90,0x87,0x7a,0x28,0x07,0x60,0x70,0x87,0x77,0x68,0x03,0x73,0x90, + 0x87,0x70,0x68,0x87,0x72,0x68,0x03,0x78,0x78,0x87,0x74,0x70,0x07,0x7a,0x28,0x07, + 0x79,0x68,0x83,0x72,0x60,0x87,0x74,0x68,0x87,0x36,0x70,0x87,0x77,0x70,0x87,0x36, + 0x60,0x87,0x72,0x08,0x07,0x73,0x00,0x08,0x77,0x78,0x87,0x36,0x48,0x07,0x77,0x30, + 0x87,0x79,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74,0x00,0xe8, + 0x41,0x1e,0xea,0xa1,0x1c,0x00,0xc2,0x1d,0xde,0xa1,0x0d,0xd4,0xa1,0x1e,0xda,0x01, + 0x1e,0xda,0x80,0x1e,0xc2,0x41,0x1c,0xd8,0xa1,0x1c,0xe6,0x01,0x30,0x87,0x70,0x60, + 0x87,0x79,0x28,0x07,0x80,0x70,0x87,0x77,0x68,0x03,0x77,0x08,0x07,0x77,0x98,0x87, + 0x36,0x30,0x07,0x78,0x68,0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1, + 0x1e,0xca,0x01,0x20,0xdc,0xe1,0x1d,0xda,0x60,0x1e,0xd2,0xe1,0x1c,0xdc,0xa1,0x1c, + 0xc8,0xa1,0x0d,0xf4,0xa1,0x1c,0xe4,0xe1,0x1d,0xe6,0xa1,0x0d,0xcc,0x01,0x1e,0xda, + 0xa0,0x1d,0xc2,0x81,0x1e,0xd0,0x01,0xa0,0x07,0x79,0xa8,0x87,0x72,0x00,0x08,0x77, + 0x78,0x87,0x36,0xa0,0x07,0x79,0x08,0x07,0x78,0x80,0x87,0x74,0x70,0x87,0x73,0x68, + 0x83,0x76,0x08,0x07,0x7a,0x40,0x07,0x80,0x1e,0xe4,0xa1,0x1e,0xca,0x01,0x20,0xe6, + 0x81,0x1e,0xc2,0x61,0x1c,0xd6,0xa1,0x0d,0xe0,0x41,0x1e,0xde,0x81,0x1e,0xca,0x61, + 0x1c,0xe8,0xe1,0x1d,0xe4,0xa1,0x0d,0xc4,0xa1,0x1e,0xcc,0xc1,0x1c,0xca,0x41,0x1e, + 0xda,0x60,0x1e,0xd2,0x41,0x1f,0xca,0x01,0xc0,0x03,0x80,0xa8,0x07,0x77,0x98,0x87, + 0x70,0x30,0x87,0x72,0x68,0x03,0x73,0x80,0x87,0x36,0x68,0x87,0x70,0xa0,0x07,0x74, + 0x00,0xe8,0x41,0x1e,0xea,0xa1,0x1c,0x00,0xa2,0x1e,0xe6,0xa1,0x1c,0xda,0x60,0x1e, + 0xde,0xc1,0x1c,0xe8,0xa1,0x0d,0xcc,0x81,0x1d,0xde,0x21,0x1c,0xe8,0x01,0x30,0x87, + 0x70,0x60,0x87,0x79,0x28,0x07,0x60,0x83,0x21,0x0c,0xc0,0x02,0x54,0x1b,0x8c,0x81, + 0x00,0x16,0xa0,0xda,0x80,0x10,0xff,0xff,0xff,0xff,0x3f,0x00,0x0c,0x20,0x01,0xd5, + 0x06,0xa3,0x08,0x80,0x05,0xa8,0x36,0x18,0x86,0x00,0x2c,0x40,0x05,0x49,0x18,0x00, + 0x00,0x03,0x00,0x00,0x00,0x13,0x86,0x40,0x18,0x26,0x0c,0x44,0x61,0x00,0x00,0x00, + 0x00,0x89,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85, + 0x04,0x93,0x22,0xa4,0x84,0x04,0x93,0x22,0xe3,0x84,0xa1,0x90,0x14,0x12,0x4c,0x8a, + 0x8c,0x0b,0x84,0xa4,0x4c,0x10,0x48,0x33,0x00,0xc3,0x08,0x04,0x70,0x90,0x34,0x45, + 0x94,0x30,0xf9,0x0c,0x80,0x34,0xf4,0xef,0x50,0x13,0x0a,0xc2,0x30,0x82,0x00,0x1c, + 0x25,0x4d,0x11,0x25,0x4c,0xfe,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0xff,0x34, + 0x46,0x00,0x0c,0x22,0x10,0xc1,0x45,0xd2,0x14,0x51,0xc2,0xe4,0xff,0x12,0xc0,0x3c, + 0x0b,0x11,0xfd,0xd3,0x18,0x01,0x30,0x88,0x60,0x08,0xa5,0x10,0x23,0x94,0x43,0x68, + 0x8e,0x20,0x98,0x23,0x00,0x83,0x61,0x04,0x61,0x29,0x48,0x28,0x67,0x28,0xa6,0x00, + 0xb5,0x81,0x80,0x14,0x58,0x23,0x00,0x00,0x00,0x13,0xa8,0x70,0x48,0x07,0x79,0xb0, + 0x03,0x3a,0x68,0x83,0x70,0x80,0x07,0x78,0x60,0x87,0x72,0x68,0x83,0x74,0x78,0x87, + 0x79,0xc8,0x03,0x37,0x80,0x03,0x37,0x80,0x83,0x0d,0xb7,0x51,0x0e,0x6d,0x00,0x0f, + 0x7a,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xe9, + 0x10,0x07,0x7a,0x80,0x07,0x7a,0x80,0x07,0x6d,0x90,0x0e,0x78,0xa0,0x07,0x78,0xa0, + 0x07,0x78,0xd0,0x06,0xe9,0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07, + 0x76,0xd0,0x06,0xe9,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72, + 0xd0,0x06,0xe9,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0, + 0x06,0xe6,0x30,0x07,0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06, + 0xe6,0x60,0x07,0x74,0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6, + 0x10,0x07,0x76,0xa0,0x07,0x71,0x60,0x07,0x7a,0x10,0x07,0x76,0xd0,0x06,0xf6,0x20, + 0x07,0x74,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x30,0x07, + 0x72,0xa0,0x07,0x73,0x20,0x07,0x7a,0x30,0x07,0x72,0xd0,0x06,0xf6,0x40,0x07,0x78, + 0xa0,0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x60,0x07,0x74,0xa0, + 0x07,0x76,0x40,0x07,0x7a,0x60,0x07,0x74,0xd0,0x06,0xf6,0x90,0x07,0x76,0xa0,0x07, + 0x71,0x20,0x07,0x78,0xa0,0x07,0x71,0x20,0x07,0x78,0xd0,0x06,0xf6,0x10,0x07,0x72, + 0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x7a,0x10,0x07,0x72,0x80,0x07,0x6d,0x60, + 0x0f,0x71,0x90,0x07,0x72,0xa0,0x07,0x72,0x50,0x07,0x76,0xa0,0x07,0x72,0x50,0x07, + 0x76,0xd0,0x06,0xf6,0x20,0x07,0x75,0x60,0x07,0x7a,0x20,0x07,0x75,0x60,0x07,0x7a, + 0x20,0x07,0x75,0x60,0x07,0x6d,0x60,0x0f,0x75,0x10,0x07,0x72,0xa0,0x07,0x75,0x10, + 0x07,0x72,0xa0,0x07,0x75,0x10,0x07,0x72,0xd0,0x06,0xf6,0x10,0x07,0x70,0x20,0x07, + 0x74,0xa0,0x07,0x71,0x00,0x07,0x72,0x40,0x07,0x7a,0x10,0x07,0x70,0x20,0x07,0x74, + 0xd0,0x06,0xee,0x80,0x07,0x7a,0x10,0x07,0x76,0xa0,0x07,0x73,0x20,0x07,0x43,0x98, + 0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x21,0x8c,0x03,0x04,0x80,0x00,0x00, + 0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x32,0x1e,0x98, + 0x10,0x19,0x11,0x4c,0x90,0x8c,0x09,0x26,0x47,0xc6,0x04,0x43,0x5a,0x23,0x00,0x25, + 0x50,0x04,0x85,0x50,0x10,0x65,0x40,0x70,0x2c,0xa1,0x29,0x00,0x00,0x79,0x18,0x00, + 0x00,0xd9,0x00,0x00,0x00,0x1a,0x03,0x4c,0x10,0x97,0x29,0xa2,0x25,0x10,0xab,0x32, + 0xb9,0xb9,0xb4,0x37,0xb7,0x21,0xc6,0x42,0x3c,0x00,0x84,0x50,0xb9,0x1b,0x43,0x0b, + 0x93,0xfb,0x9a,0x4b,0xd3,0x2b,0x1b,0x62,0x2c,0xc3,0x23,0x2c,0x05,0xd9,0x20,0x08, + 0x0e,0x8e,0xad,0x0c,0x84,0x89,0xc9,0xaa,0x09,0xc4,0xae,0x4c,0x6e,0x2e,0xed,0xcd, + 0x0d,0x64,0x26,0x07,0x46,0xc6,0xc5,0xe6,0x06,0x04,0xa5,0xad,0x8c,0x2e,0x8c,0xcd, + 0xac,0xac,0x65,0x26,0x07,0x46,0xc6,0xc5,0xe6,0x26,0x65,0x88,0xf0,0x10,0x43,0x8c, + 0x65,0x58,0x8c,0x45,0x60,0xd1,0x54,0x46,0x17,0xc6,0x36,0x04,0x79,0x8e,0x65,0x58, + 0x84,0x45,0xe0,0x16,0x96,0x26,0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0x42, + 0x56,0xe6,0xf6,0x26,0xd7,0x36,0xf7,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44, + 0x78,0x12,0x72,0x61,0x69,0x72,0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x66, + 0x61,0x73,0x74,0x5f,0x6d,0x61,0x74,0x68,0x5f,0x65,0x6e,0x61,0x62,0x6c,0x65,0x43, + 0x84,0x67,0x21,0x19,0x84,0xa5,0xc9,0xb9,0x8c,0xbd,0xb5,0xc1,0xa5,0xb1,0x95,0xb9, + 0x98,0xc9,0x85,0xb5,0x95,0x89,0xd5,0x99,0x99,0x95,0xc9,0x7d,0x99,0x95,0xd1,0x8d, + 0xa1,0x7d,0x95,0xb9,0x85,0x89,0xb1,0x95,0x0d,0x11,0x9e,0x86,0x61,0x10,0x96,0x26, + 0xe7,0x32,0xf6,0xd6,0x06,0x97,0xc6,0x56,0xe6,0xe2,0x16,0x46,0x97,0x66,0x57,0xf6, + 0x45,0xf6,0x56,0x27,0xc6,0x56,0xf6,0x45,0x96,0x36,0x17,0x26,0xc6,0x56,0x36,0x44, + 0x78,0x1e,0x92,0x41,0x58,0x9a,0x9c,0xcb,0xd8,0x5b,0x1b,0x5c,0x1a,0x5b,0x99,0x8b, + 0x5b,0x18,0x5d,0x9a,0x5d,0xd9,0x17,0xdb,0x9b,0xdb,0xd9,0x17,0xdb,0x9b,0xdb,0xd9, + 0x17,0x59,0xda,0x5c,0x98,0x18,0x5b,0xd9,0x10,0xe1,0x89,0x78,0x06,0x61,0x69,0x72, + 0x2e,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x2e,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f, + 0x77,0x69,0x64,0x65,0x5f,0x76,0x65,0x63,0x74,0x6f,0x72,0x73,0x5f,0x64,0x69,0x73, + 0x61,0x62,0x6c,0x65,0x43,0x84,0x67,0x62,0x14,0x96,0x26,0xe7,0x22,0x57,0xe6,0x46, + 0x56,0x26,0xf7,0x45,0x17,0x26,0x77,0x56,0x46,0xc7,0x28,0x2c,0x4d,0xce,0x25,0x4c, + 0xee,0xec,0x8b,0x2e,0x0f,0xae,0xec,0xcb,0x2d,0xac,0xad,0x8c,0x86,0x19,0xdb,0x5b, + 0x18,0x1d,0x0d,0x99,0xb0,0x34,0x39,0x97,0x30,0xb9,0xb3,0x2f,0xb7,0xb0,0xb6,0x32, + 0x2a,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x43,0x98,0xa7,0x5a,0x84, + 0xc7,0x7a,0xae,0x07,0x7b,0xb2,0x21,0xc2,0xa3,0x51,0x0a,0x4b,0x93,0x73,0x31,0x93, + 0x0b,0x3b,0x6b,0x2b,0x73,0xa3,0xfb,0x4a,0x73,0x83,0xab,0xa3,0xe3,0x52,0x37,0x57, + 0x26,0x87,0xc2,0xf6,0x36,0xe6,0x06,0x93,0x42,0x25,0x2c,0x4d,0xce,0x65,0xac,0xcc, + 0x8d,0xae,0x4c,0x8e,0x4f,0x58,0x9a,0x9c,0x0b,0x5c,0x99,0xdc,0x1c,0x5c,0xd9,0x18, + 0x5d,0x9a,0x5d,0x19,0x0d,0x33,0xb6,0xb7,0x30,0x3a,0x19,0x0a,0x75,0x76,0x43,0xa4, + 0x45,0x78,0xb8,0xa7,0x7b,0xbc,0xe7,0x7b,0xac,0x07,0x0c,0x1e,0xec,0x09,0x03,0x2e, + 0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x2c,0xc6,0xde,0xd8,0xde, + 0xe4,0x86,0x48,0xcb,0xf0,0x70,0xcf,0x18,0x3c,0xde,0xf3,0x3d,0xd6,0x73,0x3d,0xd8, + 0x43,0x06,0x5c,0xc2,0xd2,0xe4,0x5c,0xe8,0xca,0xf0,0xe8,0xea,0xe4,0xca,0x28,0x85, + 0xa5,0xc9,0xb9,0xb0,0xbd,0x8d,0x85,0xd1,0xa5,0xbd,0xb9,0x7d,0xa5,0xb9,0x91,0x95, + 0xe1,0x51,0x09,0x4b,0x93,0x73,0x99,0x0b,0x6b,0x83,0x63,0x2b,0x23,0x46,0x57,0x86, + 0x47,0x57,0x27,0x57,0x26,0x43,0xc6,0x63,0xc6,0xf6,0x16,0x46,0xc7,0x02,0x32,0x17, + 0xd6,0x06,0xc7,0x56,0xe6,0xc3,0x81,0xae,0x0c,0x6f,0x08,0xb5,0x10,0x8f,0x19,0x3c, + 0x67,0xb0,0x08,0xcb,0xf0,0xa0,0xc1,0x63,0x3d,0x69,0xf0,0x60,0x8f,0x1a,0x70,0x09, + 0x4b,0x93,0x73,0x99,0x0b,0x6b,0x83,0x63,0x2b,0x93,0xe3,0x31,0x17,0xd6,0x06,0xc7, + 0x56,0x26,0x47,0x84,0xae,0x0c,0x6f,0xaa,0x0d,0x8e,0x4d,0x6e,0x88,0xb4,0x1c,0x0f, + 0x1b,0x3c,0x67,0xb0,0x08,0xcb,0xf0,0x58,0x4f,0x1b,0x3c,0xd8,0xe3,0x06,0x43,0x90, + 0x47,0x0c,0x9e,0x32,0x78,0xd6,0xe0,0x79,0x83,0x21,0x46,0x02,0x3c,0xdb,0x03,0x07, + 0x23,0x22,0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x77,0x20,0x87,0x7a,0x60, + 0x87,0x72,0x70,0x03,0x73,0x60,0x87,0x70,0x38,0x87,0x79,0x98,0x22,0x04,0xc3,0x08, + 0x85,0x1d,0xd8,0xc1,0x1e,0xda,0xc1,0x0d,0xd2,0x81,0x1c,0xca,0xc1,0x1d,0xe8,0x61, + 0x4a,0x50,0x8c,0x58,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xec,0xa1,0x1c,0xe4,0x61,0x1e, + 0xd2,0xe1,0x1d,0xdc,0x61,0x4a,0x60,0x8c,0xa0,0xc2,0x21,0x1d,0xe4,0xc1,0x0d,0xd8, + 0x21,0x1c,0xdc,0xe1,0x1c,0xea,0x21,0x1c,0xce,0xa1,0x1c,0x7e,0xc1,0x1e,0xca,0x41, + 0x1e,0xe6,0x21,0x1d,0xde,0xc1,0x1d,0xa6,0x04,0xc8,0x88,0x29,0x1c,0xd2,0x41,0x1e, + 0xdc,0x60,0x1c,0xde,0xa1,0x1d,0xe0,0x21,0x1d,0xd8,0xa1,0x1c,0x7e,0xe1,0x1d,0xe0, + 0x81,0x1e,0xd2,0xe1,0x1d,0xdc,0x61,0x1e,0xa6,0x18,0x0a,0xe3,0x40,0x12,0x35,0x82, + 0x09,0x87,0x74,0x90,0x07,0x37,0x30,0x07,0x79,0x08,0x87,0x73,0x68,0x87,0x72,0x70, + 0x07,0x7a,0x98,0x12,0xc4,0x01,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x6d,0x00,0x00, + 0x00,0x33,0x08,0x80,0x1c,0xc4,0xe1,0x1c,0x66,0x14,0x01,0x3d,0x88,0x43,0x38,0x84, + 0xc3,0x8c,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0c,0xe6,0x00,0x0f,0xed, + 0x10,0x0e,0xf4,0x80,0x0e,0x33,0x0c,0x42,0x1e,0xc2,0xc1,0x1d,0xce,0xa1,0x1c,0x66, + 0x30,0x05,0x3d,0x88,0x43,0x38,0x84,0x83,0x1b,0xcc,0x03,0x3d,0xc8,0x43,0x3d,0x8c, + 0x03,0x3d,0xcc,0x78,0x8c,0x74,0x70,0x07,0x7b,0x08,0x07,0x79,0x48,0x87,0x70,0x70, + 0x07,0x7a,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xcc,0x11,0x0e,0xec,0x90, + 0x0e,0xe1,0x30,0x0f,0x6e,0x30,0x0f,0xe3,0xf0,0x0e,0xf0,0x50,0x0e,0x33,0x10,0xc4, + 0x1d,0xde,0x21,0x1c,0xd8,0x21,0x1d,0xc2,0x61,0x1e,0x66,0x30,0x89,0x3b,0xbc,0x83, + 0x3b,0xd0,0x43,0x39,0xb4,0x03,0x3c,0xbc,0x83,0x3c,0x84,0x03,0x3b,0xcc,0xf0,0x14, + 0x76,0x60,0x07,0x7b,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70, + 0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xf8,0x05,0x76,0x78,0x87,0x77,0x80, + 0x87,0x5f,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2c,0xee,0xf0, + 0x0e,0xee,0xe0,0x0e,0xf5,0xc0,0x0e,0xec,0x30,0x03,0x62,0xc8,0xa1,0x1c,0xe4,0xa1, + 0x1c,0xcc,0xa1,0x1c,0xe4,0xa1,0x1c,0xdc,0x61,0x1c,0xca,0x21,0x1c,0xc4,0x81,0x1d, + 0xca,0x61,0x06,0xd6,0x90,0x43,0x39,0xc8,0x43,0x39,0x98,0x43,0x39,0xc8,0x43,0x39, + 0xb8,0xc3,0x38,0x94,0x43,0x38,0x88,0x03,0x3b,0x94,0xc3,0x2f,0xbc,0x83,0x3c,0xfc, + 0x82,0x3b,0xd4,0x03,0x3b,0xb0,0xc3,0x0c,0xc7,0x69,0x87,0x70,0x58,0x87,0x72,0x70, + 0x83,0x74,0x68,0x07,0x78,0x60,0x87,0x74,0x18,0x87,0x74,0xa0,0x87,0x19,0xce,0x53, + 0x0f,0xee,0x00,0x0f,0xf2,0x50,0x0e,0xe4,0x90,0x0e,0xe3,0x40,0x0f,0xe1,0x20,0x0e, + 0xec,0x50,0x0e,0x33,0x20,0x28,0x1d,0xdc,0xc1,0x1e,0xc2,0x41,0x1e,0xd2,0x21,0x1c, + 0xdc,0x81,0x1e,0xdc,0xe0,0x1c,0xe4,0xe1,0x1d,0xea,0x01,0x1e,0x66,0x18,0x51,0x38, + 0xb0,0x43,0x3a,0x9c,0x83,0x3b,0xcc,0x50,0x24,0x76,0x60,0x07,0x7b,0x68,0x07,0x37, + 0x60,0x87,0x77,0x78,0x07,0x78,0x98,0x51,0x4c,0xf4,0x90,0x0f,0xf0,0x50,0x0e,0x33, + 0x1e,0x6a,0x1e,0xca,0x61,0x1c,0xe8,0x21,0x1d,0xde,0xc1,0x1d,0x7e,0x01,0x1e,0xe4, + 0xa1,0x1c,0xcc,0x21,0x1d,0xf0,0x61,0x06,0x54,0x85,0x83,0x38,0xcc,0xc3,0x3b,0xb0, + 0x43,0x3d,0xd0,0x43,0x39,0xfc,0xc2,0x3c,0xe4,0x43,0x3b,0x88,0xc3,0x3b,0xb0,0xc3, + 0x8c,0xc5,0x0a,0x87,0x79,0x98,0x87,0x77,0x18,0x87,0x74,0x08,0x07,0x7a,0x28,0x07, + 0x72,0x00,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0xb0,0x01, + 0x48,0xe4,0x4b,0x00,0xf3,0x2c,0xc4,0x3f,0x11,0xd7,0x44,0x45,0xc4,0x6f,0x0f,0x7e, + 0x85,0x17,0xb7,0x6d,0x00,0x05,0x03,0x20,0x0d,0x0d,0x00,0x00,0x00,0x61,0x20,0x00, + 0x00,0x0c,0x00,0x00,0x00,0x13,0x04,0x41,0x2c,0x10,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0xc4,0x46,0x00,0x48,0x8d,0x00,0xd4,0x00,0x89,0x19,0x00,0x02,0x23,0x00,0x00, + 0x00,0x23,0x06,0x8a,0x10,0x44,0x87,0x91,0x0c,0x05,0x11,0x58,0x90,0xc8,0x67,0xb6, + 0x81,0x08,0x80,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static const char _simgui_vs_source_metal_sim[720] = { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, + 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x32,0x20,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x3b, + 0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63, + 0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, + 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, + 0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, + 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, + 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x70, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62, + 0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x20,0x5b, + 0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x32, + 0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31, + 0x35,0x20,0x22,0x22,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e, + 0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f, + 0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x76, + 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26,0x20,0x5f,0x32,0x33,0x20,0x5b,0x5b, + 0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, + 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, + 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31,0x35,0x20, + 0x22,0x22,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f, + 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28, + 0x28,0x28,0x69,0x6e,0x2e,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x2f,0x20, + 0x5f,0x32,0x33,0x2e,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x29,0x20,0x2d, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x30,0x2e,0x35,0x29,0x29,0x20,0x2a,0x20, + 0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x32,0x2e,0x30,0x2c,0x20,0x2d,0x32,0x2e,0x30, + 0x29,0x2c,0x20,0x30,0x2e,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x23,0x6c, + 0x69,0x6e,0x65,0x20,0x31,0x36,0x20,0x22,0x22,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75, + 0x74,0x2e,0x75,0x76,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x63,0x6f,0x6f, + 0x72,0x64,0x30,0x3b,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31,0x37,0x20,0x22,0x22, + 0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d, + 0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +}; +static const char _simgui_fs_source_metal_sim[470] = { + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d, + 0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f, + 0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20, + 0x75,0x76,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29, + 0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63, + 0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, + 0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20, + 0x31,0x31,0x20,0x22,0x22,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61, + 0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65, + 0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65,0x78,0x20,0x5b,0x5b, + 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61, + 0x6d,0x70,0x6c,0x65,0x72,0x20,0x74,0x65,0x78,0x53,0x6d,0x70,0x6c,0x72,0x20,0x5b, + 0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b, + 0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f, + 0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31, + 0x31,0x20,0x22,0x22,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61, + 0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x2e,0x73,0x61, + 0x6d,0x70,0x6c,0x65,0x28,0x74,0x65,0x78,0x53,0x6d,0x70,0x6c,0x72,0x2c,0x20,0x69, + 0x6e,0x2e,0x75,0x76,0x29,0x20,0x2a,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74, + 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +}; +#elif defined(SOKOL_D3D11) +static const uint8_t _simgui_vs_bytecode_hlsl4[892] = { + 0x44,0x58,0x42,0x43,0x05,0xf8,0x0b,0x1e,0x7a,0x13,0x49,0x07,0x83,0x60,0x2e,0x88, + 0x06,0xfa,0x10,0x2e,0x01,0x00,0x00,0x00,0x7c,0x03,0x00,0x00,0x05,0x00,0x00,0x00, + 0x34,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x60,0x01,0x00,0x00,0xd0,0x01,0x00,0x00, + 0x00,0x03,0x00,0x00,0x52,0x44,0x45,0x46,0xc0,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xfe,0xff, + 0x10,0x81,0x00,0x00,0x98,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0xab,0xab,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x88,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x5f,0x32,0x33,0x5f,0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a, + 0x65,0x00,0xab,0xab,0x01,0x00,0x03,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x20,0x28,0x52, + 0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64,0x65,0x72,0x20,0x43,0x6f, + 0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31,0x00,0x49,0x53,0x47,0x4e, + 0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x50,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x50,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, + 0x4f,0x53,0x47,0x4e,0x68,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x00,0x50,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, + 0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, + 0x00,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0xab,0xab,0xab, + 0x53,0x48,0x44,0x52,0x28,0x01,0x00,0x00,0x40,0x00,0x01,0x00,0x4a,0x00,0x00,0x00, + 0x59,0x00,0x00,0x04,0x46,0x8e,0x20,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x5f,0x00,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x03, + 0x32,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x5f,0x00,0x00,0x03,0xf2,0x10,0x10,0x00, + 0x02,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, + 0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00,0x01,0x00,0x00,0x00,0x67,0x00,0x00,0x04, + 0xf2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00,0x00,0x02, + 0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0x32,0x20,0x10,0x00,0x00,0x00,0x00,0x00, + 0x46,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x00,0x05,0xf2,0x20,0x10,0x00, + 0x01,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x08, + 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00, + 0x46,0x80,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a, + 0x32,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00, + 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x0a,0x32,0x20,0x10,0x00,0x02,0x00,0x00,0x00, + 0x46,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x08, + 0xc2,0x20,0x10,0x00,0x02,0x00,0x00,0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x80,0x3f,0x3e,0x00,0x00,0x01, + 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +static const uint8_t _simgui_fs_bytecode_hlsl4[620] = { + 0x44,0x58,0x42,0x43,0xd1,0x93,0x1f,0x1b,0x9d,0x70,0x90,0xeb,0xc2,0x7c,0x26,0x07, + 0xdf,0x52,0xda,0x49,0x01,0x00,0x00,0x00,0x6c,0x02,0x00,0x00,0x05,0x00,0x00,0x00, + 0x34,0x00,0x00,0x00,0xd4,0x00,0x00,0x00,0x20,0x01,0x00,0x00,0x54,0x01,0x00,0x00, + 0xf0,0x01,0x00,0x00,0x52,0x44,0x45,0x46,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x04,0xff,0xff, + 0x10,0x81,0x00,0x00,0x6d,0x00,0x00,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x5f,0x74,0x65,0x78,0x5f,0x73,0x61,0x6d, + 0x70,0x6c,0x65,0x72,0x00,0x74,0x65,0x78,0x00,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f, + 0x66,0x74,0x20,0x28,0x52,0x29,0x20,0x48,0x4c,0x53,0x4c,0x20,0x53,0x68,0x61,0x64, + 0x65,0x72,0x20,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x20,0x31,0x30,0x2e,0x31, + 0x00,0xab,0xab,0xab,0x49,0x53,0x47,0x4e,0x44,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x38,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x0f,0x00,0x00,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x00,0xab,0xab,0xab, + 0x4f,0x53,0x47,0x4e,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x53,0x56,0x5f,0x54,0x61,0x72,0x67,0x65, + 0x74,0x00,0xab,0xab,0x53,0x48,0x44,0x52,0x94,0x00,0x00,0x00,0x40,0x00,0x00,0x00, + 0x25,0x00,0x00,0x00,0x5a,0x00,0x00,0x03,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00, + 0x58,0x18,0x00,0x04,0x00,0x70,0x10,0x00,0x00,0x00,0x00,0x00,0x55,0x55,0x00,0x00, + 0x62,0x10,0x00,0x03,0x32,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x00,0x03, + 0xf2,0x10,0x10,0x00,0x01,0x00,0x00,0x00,0x65,0x00,0x00,0x03,0xf2,0x20,0x10,0x00, + 0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x02,0x01,0x00,0x00,0x00,0x45,0x00,0x00,0x09, + 0xf2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x10,0x00,0x00,0x00,0x00,0x00, + 0x46,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00, + 0x38,0x00,0x00,0x07,0xf2,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x46,0x0e,0x10,0x00, + 0x00,0x00,0x00,0x00,0x46,0x1e,0x10,0x00,0x01,0x00,0x00,0x00,0x3e,0x00,0x00,0x01, + 0x53,0x54,0x41,0x54,0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +#elif defined(SOKOL_WGPU) +static const uint8_t _simgui_vs_bytecode_wgpu[1868] = { + 0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x34,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x02,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x2a,0x00,0x00,0x00, + 0x2b,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x32,0x00,0x00,0x00, + 0x33,0x00,0x00,0x00,0x07,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x37,0x00,0x02,0x00,0x00,0x00,0xc2,0x01,0x00,0x00,0x01,0x00,0x00,0x00, + 0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65, + 0x73,0x73,0x65,0x64,0x20,0x63,0x6c,0x69,0x65,0x6e,0x74,0x20,0x76,0x75,0x6c,0x6b, + 0x61,0x6e,0x31,0x30,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c, + 0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x63,0x6c,0x69,0x65,0x6e, + 0x74,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c,0x31,0x30,0x30,0x0a,0x2f,0x2f,0x20,0x4f, + 0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64, + 0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2d,0x65,0x6e,0x76,0x20,0x76,0x75,0x6c,0x6b, + 0x61,0x6e,0x31,0x2e,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c, + 0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x74,0x61,0x72,0x67,0x65, + 0x74,0x2d,0x65,0x6e,0x76,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c,0x0a,0x2f,0x2f,0x20, + 0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65, + 0x64,0x20,0x65,0x6e,0x74,0x72,0x79,0x2d,0x70,0x6f,0x69,0x6e,0x74,0x20,0x6d,0x61, + 0x69,0x6e,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31,0x0a,0x00,0x05,0x00,0x04,0x00, + 0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00, + 0x0c,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78, + 0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00, + 0x0c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74, + 0x53,0x69,0x7a,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0c,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61, + 0x6e,0x63,0x65,0x00,0x06,0x00,0x07,0x00,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x43,0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00, + 0x05,0x00,0x03,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00, + 0x13,0x00,0x00,0x00,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00, + 0x05,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d, + 0x73,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x64,0x69,0x73,0x70,0x5f,0x73,0x69,0x7a,0x65,0x00,0x00,0x00,0x05,0x00,0x03,0x00, + 0x17,0x00,0x00,0x00,0x5f,0x32,0x33,0x00,0x05,0x00,0x03,0x00,0x2a,0x00,0x00,0x00, + 0x75,0x76,0x00,0x00,0x05,0x00,0x05,0x00,0x2b,0x00,0x00,0x00,0x74,0x65,0x78,0x63, + 0x6f,0x6f,0x72,0x64,0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2d,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x2f,0x00,0x00,0x00, + 0x63,0x6f,0x6c,0x6f,0x72,0x30,0x00,0x00,0x05,0x00,0x05,0x00,0x32,0x00,0x00,0x00, + 0x67,0x6c,0x5f,0x56,0x65,0x72,0x74,0x65,0x78,0x49,0x44,0x00,0x05,0x00,0x06,0x00, + 0x33,0x00,0x00,0x00,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x49, + 0x44,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0c,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00, + 0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x0c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x13,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x48,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x15,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x2a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x2b,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x2d,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x2f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x05,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x33,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x06,0x00,0x00,0x00, + 0x13,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x15,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x2b,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x1c,0x00,0x04,0x00,0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x0a,0x00,0x00,0x00, + 0x1e,0x00,0x06,0x00,0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00, + 0x0b,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0d,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x0d,0x00,0x00,0x00, + 0x0e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x0f,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0f,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x12,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x12,0x00,0x00,0x00, + 0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1e,0x00,0x03,0x00,0x15,0x00,0x00,0x00, + 0x11,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x15,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x17,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x11,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x3f,0x2c,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x1d,0x00,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x2b,0x00,0x04,0x00,0x07,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x2c,0x00,0x05,0x00,0x11,0x00,0x00,0x00, + 0x21,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x2b,0x00,0x04,0x00, + 0x07,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,0x20,0x00,0x04,0x00, + 0x27,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x29,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x12,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x27,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x2e,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x2e,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00, + 0x31,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x31,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3b,0x00,0x04,0x00, + 0x31,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00, + 0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0xf8,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x01,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x11,0x00,0x00,0x00, + 0x14,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x18,0x00,0x00,0x00, + 0x19,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x88,0x00,0x05,0x00, + 0x11,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x1a,0x00,0x00,0x00, + 0x83,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1b,0x00,0x00,0x00, + 0x1d,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x22,0x00,0x00,0x00, + 0x1e,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x07,0x00,0x00,0x00, + 0x24,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00, + 0x07,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x50,0x00,0x07,0x00,0x08,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x24,0x00,0x00,0x00, + 0x25,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x41,0x00,0x05,0x00, + 0x27,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x3e,0x00,0x03,0x00,0x28,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x08,0x00,0x04,0x00, + 0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x11,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x3e,0x00,0x03,0x00, + 0x2a,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x01,0x00,0x00,0x00, + 0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x08,0x00,0x00,0x00, + 0x30,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x2d,0x00,0x00,0x00, + 0x30,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +static const uint8_t _simgui_fs_bytecode_wgpu[904] = { + 0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x19,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00, + 0x02,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30, + 0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x0f,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x10,0x00,0x03,0x00,0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x03,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x37,0x00,0x02,0x00,0x00,0x00, + 0xc2,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64, + 0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x63,0x6c,0x69, + 0x65,0x6e,0x74,0x20,0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x30,0x30,0x0a,0x2f,0x2f, + 0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73, + 0x65,0x64,0x20,0x63,0x6c,0x69,0x65,0x6e,0x74,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c, + 0x31,0x30,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50, + 0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2d, + 0x65,0x6e,0x76,0x20,0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x2e,0x30,0x0a,0x2f,0x2f, + 0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73, + 0x65,0x64,0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2d,0x65,0x6e,0x76,0x20,0x6f,0x70, + 0x65,0x6e,0x67,0x6c,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65, + 0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x65,0x6e,0x74,0x72,0x79,0x2d, + 0x70,0x6f,0x69,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x0a,0x23,0x6c,0x69,0x6e,0x65, + 0x20,0x31,0x0a,0x00,0x05,0x00,0x04,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e, + 0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x0a,0x00,0x00,0x00,0x66,0x72,0x61,0x67, + 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x05,0x00,0x03,0x00,0x0e,0x00,0x00,0x00, + 0x74,0x65,0x78,0x00,0x05,0x00,0x03,0x00,0x12,0x00,0x00,0x00,0x75,0x76,0x00,0x00, + 0x05,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x63,0x6f,0x6c,0x6f,0x72,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x0e,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x47,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x13,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x04,0x00,0x00,0x00, + 0x03,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x19,0x00,0x09,0x00,0x0b,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1b,0x00,0x03,0x00,0x0c,0x00,0x00,0x00,0x0b,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x0d,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x17,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00, + 0x3b,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x36,0x00,0x05,0x00,0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x08,0x00,0x04,0x00, + 0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x0c,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x3d,0x00,0x04,0x00, + 0x10,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x57,0x00,0x05,0x00, + 0x08,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x00,0x00,0x00, + 0x3d,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x16,0x00,0x00,0x00, + 0x85,0x00,0x05,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x14,0x00,0x00,0x00, + 0x17,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x0a,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00, +}; +#elif defined(SOKOL_DUMMY_BACKEND) +static const char* _simgui_vs_source_dummy = ""; +static const char* _simgui_fs_source_dummy = ""; +#else +#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES2, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" +#endif + +#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) +static void _simgui_set_clipboard(void* user_data, const char* text) { + (void)user_data; + sapp_set_clipboard_string(text); +} + +static const char* _simgui_get_clipboard(void* user_data) { + (void)user_data; + return sapp_get_clipboard_string(); +} +#endif + +#if defined(__EMSCRIPTEN__) && !defined(SOKOL_DUMMY_BACKEND) +EM_JS(int, simgui_js_is_osx, (void), { + if (navigator.userAgent.includes('Macintosh')) { + return 1; + } + else { + return 0; + } +}); +#endif + +static bool _simgui_is_osx(void) { + #if defined(SOKOL_DUMMY_BACKEND) + return false; + #elif defined(__EMSCRIPTEN__) + return simgui_js_is_osx(); + #elif defined(__APPLE__) + return true; + #else + return false; + #endif +} + +SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) { + SOKOL_ASSERT(desc); + memset(&_simgui, 0, sizeof(_simgui)); + _simgui.desc = *desc; + _simgui.desc.max_vertices = _simgui_def(_simgui.desc.max_vertices, 65536); + _simgui.cur_dpi_scale = 1.0f; + #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) + _simgui.is_osx = _simgui_is_osx(); + #endif + /* can keep color_format, depth_format and sample_count as is, + since sokol_gfx.h will do its own default-value handling + */ + + /* allocate an intermediate vertex- and index-buffer */ + SOKOL_ASSERT(_simgui.desc.max_vertices > 0); + _simgui.vertices.size = (size_t)_simgui.desc.max_vertices * sizeof(ImDrawVert); + _simgui.vertices.ptr = SOKOL_MALLOC(_simgui.vertices.size); + SOKOL_ASSERT(_simgui.vertices.ptr); + _simgui.indices.size = (size_t)_simgui.desc.max_vertices * 3 * sizeof(ImDrawIdx); + _simgui.indices.ptr = SOKOL_MALLOC(_simgui.indices.size); + SOKOL_ASSERT(_simgui.indices.ptr); + + /* initialize Dear ImGui */ + #if defined(__cplusplus) + ImGui::CreateContext(); + ImGui::StyleColorsDark(); + ImGuiIO* io = &ImGui::GetIO(); + if (!_simgui.desc.no_default_font) { + ImFontConfig cfg; + cfg.SizePixels = 13.0f * sapp_dpi_scale(); + io->Fonts->AddFontDefault(&cfg)->Scale = 1.0f / sapp_dpi_scale(); + } + #else + igCreateContext(NULL); + igStyleColorsDark(igGetStyle()); + ImGuiIO* io = igGetIO(); + if (!_simgui.desc.no_default_font) { + ImFontAtlas_AddFontDefault(io->Fonts, NULL); + } + #endif + io->IniFilename = _simgui.desc.ini_filename; + io->ConfigMacOSXBehaviors = _simgui_is_osx(); + io->BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; + #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) + io->KeyMap[ImGuiKey_Tab] = SAPP_KEYCODE_TAB; + io->KeyMap[ImGuiKey_LeftArrow] = SAPP_KEYCODE_LEFT; + io->KeyMap[ImGuiKey_RightArrow] = SAPP_KEYCODE_RIGHT; + io->KeyMap[ImGuiKey_UpArrow] = SAPP_KEYCODE_UP; + io->KeyMap[ImGuiKey_DownArrow] = SAPP_KEYCODE_DOWN; + io->KeyMap[ImGuiKey_PageUp] = SAPP_KEYCODE_PAGE_UP; + io->KeyMap[ImGuiKey_PageDown] = SAPP_KEYCODE_PAGE_DOWN; + io->KeyMap[ImGuiKey_Home] = SAPP_KEYCODE_HOME; + io->KeyMap[ImGuiKey_End] = SAPP_KEYCODE_END; + io->KeyMap[ImGuiKey_Delete] = SAPP_KEYCODE_DELETE; + io->KeyMap[ImGuiKey_Backspace] = SAPP_KEYCODE_BACKSPACE; + io->KeyMap[ImGuiKey_Space] = SAPP_KEYCODE_SPACE; + io->KeyMap[ImGuiKey_Enter] = SAPP_KEYCODE_ENTER; + io->KeyMap[ImGuiKey_Escape] = SAPP_KEYCODE_ESCAPE; + if (!_simgui.desc.disable_hotkeys) { + io->KeyMap[ImGuiKey_A] = SAPP_KEYCODE_A; + io->KeyMap[ImGuiKey_C] = SAPP_KEYCODE_C; + io->KeyMap[ImGuiKey_V] = SAPP_KEYCODE_V; + io->KeyMap[ImGuiKey_X] = SAPP_KEYCODE_X; + io->KeyMap[ImGuiKey_Y] = SAPP_KEYCODE_Y; + io->KeyMap[ImGuiKey_Z] = SAPP_KEYCODE_Z; + } + #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) + io->SetClipboardTextFn = _simgui_set_clipboard; + io->GetClipboardTextFn = _simgui_get_clipboard; + #endif + #endif + + /* create sokol-gfx resources */ + sg_push_debug_group("sokol-imgui"); + + /* NOTE: since we're in C++ mode here we can't use C99 designated init */ + sg_buffer_desc vb_desc; + memset(&vb_desc, 0, sizeof(vb_desc)); + vb_desc.usage = SG_USAGE_STREAM; + vb_desc.size = _simgui.vertices.size; + vb_desc.label = "sokol-imgui-vertices"; + _simgui.vbuf = sg_make_buffer(&vb_desc); + + sg_buffer_desc ib_desc; + memset(&ib_desc, 0, sizeof(ib_desc)); + ib_desc.type = SG_BUFFERTYPE_INDEXBUFFER; + ib_desc.usage = SG_USAGE_STREAM; + ib_desc.size = _simgui.indices.size; + ib_desc.label = "sokol-imgui-indices"; + _simgui.ibuf = sg_make_buffer(&ib_desc); + + /* default font texture */ + if (!_simgui.desc.no_default_font) { + unsigned char* font_pixels; + int font_width, font_height; + #if defined(__cplusplus) + io->Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height); + #else + int bytes_per_pixel; + ImFontAtlas_GetTexDataAsRGBA32(io->Fonts, &font_pixels, &font_width, &font_height, &bytes_per_pixel); + #endif + sg_image_desc img_desc; + memset(&img_desc, 0, sizeof(img_desc)); + img_desc.width = font_width; + img_desc.height = font_height; + img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; + img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; + img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; + img_desc.min_filter = SG_FILTER_LINEAR; + img_desc.mag_filter = SG_FILTER_LINEAR; + img_desc.data.subimage[0][0].ptr = font_pixels; + img_desc.data.subimage[0][0].size = (size_t)(font_width * font_height) * sizeof(uint32_t); + img_desc.label = "sokol-imgui-font"; + _simgui.img = sg_make_image(&img_desc); + io->Fonts->TexID = (ImTextureID)(uintptr_t) _simgui.img.id; + } + + /* shader object for using the embedded shader source (or bytecode) */ + sg_shader_desc shd_desc; + memset(&shd_desc, 0, sizeof(shd_desc)); + shd_desc.attrs[0].name = "position"; + shd_desc.attrs[1].name = "texcoord0"; + shd_desc.attrs[2].name = "color0"; + shd_desc.attrs[0].sem_name = "TEXCOORD"; + shd_desc.attrs[0].sem_index = 0; + shd_desc.attrs[1].sem_name = "TEXCOORD"; + shd_desc.attrs[1].sem_index = 1; + shd_desc.attrs[2].sem_name = "TEXCOORD"; + shd_desc.attrs[2].sem_index = 2; + sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; + ub->size = sizeof(_simgui_vs_params_t); + ub->uniforms[0].name = "vs_params"; + ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; + ub->uniforms[0].array_count = 1; + shd_desc.fs.images[0].name = "tex"; + shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; + shd_desc.fs.images[0].sampler_type = SG_SAMPLERTYPE_FLOAT; + shd_desc.label = "sokol-imgui-shader"; + #if defined(SOKOL_GLCORE33) + shd_desc.vs.source = _simgui_vs_source_glsl330; + shd_desc.fs.source = _simgui_fs_source_glsl330; + #elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3) + shd_desc.vs.source = _simgui_vs_source_glsl100; + shd_desc.fs.source = _simgui_fs_source_glsl100; + #elif defined(SOKOL_METAL) + shd_desc.vs.entry = "main0"; + shd_desc.fs.entry = "main0"; + switch (sg_query_backend()) { + case SG_BACKEND_METAL_MACOS: + shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_macos); + shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_macos); + break; + case SG_BACKEND_METAL_IOS: + shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_metal_ios); + shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_metal_ios); + break; + default: + shd_desc.vs.source = _simgui_vs_source_metal_sim; + shd_desc.fs.source = _simgui_fs_source_metal_sim; + break; + } + #elif defined(SOKOL_D3D11) + shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_hlsl4); + shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_hlsl4); + #elif defined(SOKOL_WGPU) + shd_desc.vs.bytecode = SG_RANGE(_simgui_vs_bytecode_wgpu); + shd_desc.fs.bytecode = SG_RANGE(_simgui_fs_bytecode_wgpu); + #else + shd_desc.vs.source = _simgui_vs_source_dummy; + shd_desc.fs.source = _simgui_fs_source_dummy; + #endif + _simgui.shd = sg_make_shader(&shd_desc); + + /* pipeline object for imgui rendering */ + sg_pipeline_desc pip_desc; + memset(&pip_desc, 0, sizeof(pip_desc)); + pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); + { + sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[0]; + attr->offset = offsetof(ImDrawVert, pos); + attr->format = SG_VERTEXFORMAT_FLOAT2; + } + { + sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[1]; + attr->offset = offsetof(ImDrawVert, uv); + attr->format = SG_VERTEXFORMAT_FLOAT2; + } + { + sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[2]; + attr->offset = offsetof(ImDrawVert, col); + attr->format = SG_VERTEXFORMAT_UBYTE4N; + } + pip_desc.shader = _simgui.shd; + pip_desc.index_type = SG_INDEXTYPE_UINT16; + pip_desc.sample_count = _simgui.desc.sample_count; + pip_desc.depth.pixel_format = _simgui.desc.depth_format; + pip_desc.colors[0].pixel_format = _simgui.desc.color_format; + pip_desc.colors[0].write_mask = SG_COLORMASK_RGB; + pip_desc.colors[0].blend.enabled = true; + pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; + pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + pip_desc.label = "sokol-imgui-pipeline"; + _simgui.pip = sg_make_pipeline(&pip_desc); + + sg_pop_debug_group(); +} + +SOKOL_API_IMPL void simgui_shutdown(void) { + #if defined(__cplusplus) + ImGui::DestroyContext(); + #else + igDestroyContext(0); + #endif + /* NOTE: it's valid to call the destroy funcs with SG_INVALID_ID */ + sg_push_debug_group("sokol-imgui"); + sg_destroy_pipeline(_simgui.pip); + sg_destroy_shader(_simgui.shd); + sg_destroy_image(_simgui.img); + sg_destroy_buffer(_simgui.ibuf); + sg_destroy_buffer(_simgui.vbuf); + sg_pop_debug_group(); + SOKOL_ASSERT(_simgui.vertices.ptr); + SOKOL_FREE((void*)_simgui.vertices.ptr); + SOKOL_ASSERT(_simgui.indices.ptr); + SOKOL_FREE((void*)_simgui.indices.ptr); +} + +#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) +_SOKOL_PRIVATE void _simgui_set_imgui_modifiers(ImGuiIO* io, uint32_t mods) { + io->KeyAlt = (mods & SAPP_MODIFIER_ALT) != 0; + io->KeyCtrl = (mods & SAPP_MODIFIER_CTRL) != 0; + io->KeyShift = (mods & SAPP_MODIFIER_SHIFT) != 0; + io->KeySuper = (mods & SAPP_MODIFIER_SUPER) != 0; +} +#endif + +SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) { + SOKOL_ASSERT(desc); + SOKOL_ASSERT(desc->width > 0); + SOKOL_ASSERT(desc->height > 0); + _simgui.cur_dpi_scale = _simgui_def(desc->dpi_scale, 1.0f); + #if defined(__cplusplus) + ImGuiIO* io = &ImGui::GetIO(); + #else + ImGuiIO* io = igGetIO(); + #endif + io->DisplaySize.x = ((float)desc->width) / _simgui.cur_dpi_scale; + io->DisplaySize.y = ((float)desc->height) / _simgui.cur_dpi_scale; + io->DeltaTime = (float)desc->delta_time; + #if !defined(SOKOL_IMGUI_NO_SOKOL_APP) + for (int i = 0; i < SAPP_MAX_MOUSEBUTTONS; i++) { + if (_simgui.btn_down[i]) { + _simgui.btn_down[i] = false; + io->MouseDown[i] = true; + } + else if (_simgui.btn_up[i]) { + _simgui.btn_up[i] = false; + io->MouseDown[i] = false; + } + } + for (int i = 0; i < SIMGUI_MAX_KEY_VALUE; i++) { + if (_simgui.keys_down[i]) { + io->KeysDown[i] = true; + _simgui_set_imgui_modifiers(io, _simgui.keys_down[i]); + _simgui.keys_down[i] = 0; + } + else if (_simgui.keys_up[i]) { + io->KeysDown[i] = false; + _simgui_set_imgui_modifiers(io, _simgui.keys_up[i]); + _simgui.keys_up[i] = 0; + } + } + if (io->WantTextInput && !sapp_keyboard_shown()) { + sapp_show_keyboard(true); + } + if (!io->WantTextInput && sapp_keyboard_shown()) { + sapp_show_keyboard(false); + } + #endif + #if defined(__cplusplus) + ImGui::NewFrame(); + #else + igNewFrame(); + #endif +} + +SOKOL_API_IMPL void simgui_render(void) { + #if defined(__cplusplus) + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + ImGuiIO* io = &ImGui::GetIO(); + #else + igRender(); + ImDrawData* draw_data = igGetDrawData(); + ImGuiIO* io = igGetIO(); + #endif + if (0 == draw_data) { + return; + } + if (draw_data->CmdListsCount == 0) { + return; + } + /* copy vertices and indices into an intermediate buffer so that + they can be updated with a single sg_update_buffer() call each + (sg_append_buffer() has performance problems on some GL platforms), + also keep track of valid number of command lists in case of a + buffer overflow + */ + size_t all_vtx_size = 0; + size_t all_idx_size = 0; + int cmd_list_count = 0; + for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++, cmd_list_count++) { + ImDrawList* cl = draw_data->CmdLists[cl_index]; + const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); + const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); + + /* check for buffer overflow */ + if (((all_vtx_size + vtx_size) > _simgui.vertices.size) || + ((all_idx_size + idx_size) > _simgui.indices.size)) + { + break; + } + + /* copy vertices and indices into common buffers */ + if (vtx_size > 0) { + const ImDrawVert* src_vtx_ptr = cl->VtxBuffer.Data; + void* dst_vtx_ptr = (void*) (((uint8_t*)_simgui.vertices.ptr) + all_vtx_size); + memcpy(dst_vtx_ptr, src_vtx_ptr, vtx_size); + } + if (idx_size > 0) { + const ImDrawIdx* src_idx_ptr = cl->IdxBuffer.Data; + void* dst_idx_ptr = (void*) (((uint8_t*)_simgui.indices.ptr) + all_idx_size); + memcpy(dst_idx_ptr, src_idx_ptr, idx_size); + } + all_vtx_size += vtx_size; + all_idx_size += idx_size; + } + if (0 == cmd_list_count) { + return; + } + + /* update the sokol-gfx vertex- and index-buffer */ + sg_push_debug_group("sokol-imgui"); + if (all_vtx_size > 0) { + sg_range vtx_data = _simgui.vertices; + vtx_data.size = all_vtx_size; + sg_update_buffer(_simgui.vbuf, &vtx_data); + } + if (all_idx_size > 0) { + sg_range idx_data = _simgui.indices; + idx_data.size = all_idx_size; + sg_update_buffer(_simgui.ibuf, &idx_data); + } + + /* render the ImGui command list */ + const float dpi_scale = _simgui.cur_dpi_scale; + const int fb_width = (int) (io->DisplaySize.x * dpi_scale); + const int fb_height = (int) (io->DisplaySize.y * dpi_scale); + sg_apply_viewport(0, 0, fb_width, fb_height, true); + sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); + + sg_apply_pipeline(_simgui.pip); + _simgui_vs_params_t vs_params; + memset((void*)&vs_params, 0, sizeof(vs_params)); + vs_params.disp_size.x = io->DisplaySize.x; + vs_params.disp_size.y = io->DisplaySize.y; + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); + sg_bindings bind; + memset((void*)&bind, 0, sizeof(bind)); + bind.vertex_buffers[0] = _simgui.vbuf; + bind.index_buffer = _simgui.ibuf; + ImTextureID tex_id = io->Fonts->TexID; + bind.fs_images[0].id = (uint32_t)(uintptr_t)tex_id; + int vb_offset = 0; + int ib_offset = 0; + for (int cl_index = 0; cl_index < cmd_list_count; cl_index++) { + const ImDrawList* cl = draw_data->CmdLists[cl_index]; + + bind.vertex_buffer_offsets[0] = vb_offset; + bind.index_buffer_offset = ib_offset; + sg_apply_bindings(&bind); + + #if defined(__cplusplus) + const int num_cmds = cl->CmdBuffer.size(); + #else + const int num_cmds = cl->CmdBuffer.Size; + #endif + uint32_t vtx_offset = 0; + for (int cmd_index = 0; cmd_index < num_cmds; cmd_index++) { + ImDrawCmd* pcmd = &cl->CmdBuffer.Data[cmd_index]; + if (pcmd->UserCallback) { + pcmd->UserCallback(cl, pcmd); + // need to re-apply all state after calling a user callback + sg_apply_viewport(0, 0, fb_width, fb_height, true); + sg_apply_pipeline(_simgui.pip); + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(vs_params)); + sg_apply_bindings(&bind); + } + else { + if ((tex_id != pcmd->TextureId) || (vtx_offset != pcmd->VtxOffset)) { + tex_id = pcmd->TextureId; + vtx_offset = pcmd->VtxOffset; + bind.fs_images[0].id = (uint32_t)(uintptr_t)tex_id; + bind.vertex_buffer_offsets[0] = vb_offset + (int)(pcmd->VtxOffset * sizeof(ImDrawVert)); + sg_apply_bindings(&bind); + } + const int scissor_x = (int) (pcmd->ClipRect.x * dpi_scale); + const int scissor_y = (int) (pcmd->ClipRect.y * dpi_scale); + const int scissor_w = (int) ((pcmd->ClipRect.z - pcmd->ClipRect.x) * dpi_scale); + const int scissor_h = (int) ((pcmd->ClipRect.w - pcmd->ClipRect.y) * dpi_scale); + sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); + sg_draw((int)pcmd->IdxOffset, (int)pcmd->ElemCount, 1); + } + } + #if defined(__cplusplus) + const size_t vtx_size = cl->VtxBuffer.size() * sizeof(ImDrawVert); + const size_t idx_size = cl->IdxBuffer.size() * sizeof(ImDrawIdx); + #else + const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert); + const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx); + #endif + vb_offset += (int)vtx_size; + ib_offset += (int)idx_size; + } + sg_apply_viewport(0, 0, fb_width, fb_height, true); + sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); + sg_pop_debug_group(); +} + +#if !defined(SOKOL_IMGUI_NO_SOKOL_APP) +_SOKOL_PRIVATE bool _simgui_is_ctrl(uint32_t modifiers) { + if (_simgui.is_osx) { + return 0 != (modifiers & SAPP_MODIFIER_SUPER); + } + else { + return 0 != (modifiers & SAPP_MODIFIER_CTRL); + } +} + +SOKOL_API_IMPL bool simgui_handle_event(const sapp_event* ev) { + const float dpi_scale = _simgui.cur_dpi_scale; + #if defined(__cplusplus) + ImGuiIO* io = &ImGui::GetIO(); + #else + ImGuiIO* io = igGetIO(); + #endif + _simgui_set_imgui_modifiers(io, ev->modifiers); + switch (ev->type) { + case SAPP_EVENTTYPE_MOUSE_DOWN: + io->MousePos.x = ev->mouse_x / dpi_scale; + io->MousePos.y = ev->mouse_y / dpi_scale; + if (ev->mouse_button < 3) { + _simgui.btn_down[ev->mouse_button] = true; + } + break; + case SAPP_EVENTTYPE_MOUSE_UP: + io->MousePos.x = ev->mouse_x / dpi_scale; + io->MousePos.y = ev->mouse_y / dpi_scale; + if (ev->mouse_button < 3) { + _simgui.btn_up[ev->mouse_button] = true; + } + break; + case SAPP_EVENTTYPE_MOUSE_MOVE: + io->MousePos.x = ev->mouse_x / dpi_scale; + io->MousePos.y = ev->mouse_y / dpi_scale; + break; + case SAPP_EVENTTYPE_MOUSE_ENTER: + case SAPP_EVENTTYPE_MOUSE_LEAVE: + for (int i = 0; i < 3; i++) { + _simgui.btn_down[i] = false; + _simgui.btn_up[i] = false; + io->MouseDown[i] = false; + } + break; + case SAPP_EVENTTYPE_MOUSE_SCROLL: + io->MouseWheelH = ev->scroll_x; + io->MouseWheel = ev->scroll_y; + break; + case SAPP_EVENTTYPE_TOUCHES_BEGAN: + _simgui.btn_down[0] = true; + io->MousePos.x = ev->touches[0].pos_x / dpi_scale; + io->MousePos.y = ev->touches[0].pos_y / dpi_scale; + break; + case SAPP_EVENTTYPE_TOUCHES_MOVED: + io->MousePos.x = ev->touches[0].pos_x / dpi_scale; + io->MousePos.y = ev->touches[0].pos_y / dpi_scale; + break; + case SAPP_EVENTTYPE_TOUCHES_ENDED: + _simgui.btn_up[0] = true; + io->MousePos.x = ev->touches[0].pos_x / dpi_scale; + io->MousePos.y = ev->touches[0].pos_y / dpi_scale; + break; + case SAPP_EVENTTYPE_TOUCHES_CANCELLED: + _simgui.btn_up[0] = _simgui.btn_down[0] = false; + break; + case SAPP_EVENTTYPE_KEY_DOWN: + /* intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED */ + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { + break; + } + /* on web platform, don't forward Ctrl-X, Ctrl-V to the browser */ + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { + sapp_consume_event(); + } + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { + sapp_consume_event(); + } + _simgui.keys_down[ev->key_code] = 0x80 | (uint8_t)ev->modifiers; + break; + case SAPP_EVENTTYPE_KEY_UP: + /* intercept Ctrl-V, this is handled via EVENTTYPE_CLIPBOARD_PASTED */ + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_V)) { + break; + } + /* on web platform, don't forward Ctrl-X, Ctrl-V to the browser */ + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_X)) { + sapp_consume_event(); + } + if (_simgui_is_ctrl(ev->modifiers) && (ev->key_code == SAPP_KEYCODE_C)) { + sapp_consume_event(); + } + _simgui.keys_up[ev->key_code] = 0x80 | (uint8_t)ev->modifiers; + break; + case SAPP_EVENTTYPE_CHAR: + /* on some platforms, special keys may be reported as + characters, which may confuse some ImGui widgets, + drop those, also don't forward characters if some + modifiers have been pressed + */ + if ((ev->char_code >= 32) && + (ev->char_code != 127) && + (0 == (ev->modifiers & (SAPP_MODIFIER_ALT|SAPP_MODIFIER_CTRL|SAPP_MODIFIER_SUPER)))) + { + #if defined(__cplusplus) + io->AddInputCharacter((ImWchar)ev->char_code); + #else + ImGuiIO_AddInputCharacter(io, (ImWchar)ev->char_code); + #endif + } + break; + case SAPP_EVENTTYPE_CLIPBOARD_PASTED: + /* simulate a Ctrl-V key down/up */ + _simgui.keys_down[SAPP_KEYCODE_V] = _simgui.keys_up[SAPP_KEYCODE_V] = + (uint8_t) (0x80 | (_simgui.is_osx ? SAPP_MODIFIER_SUPER:SAPP_MODIFIER_CTRL)); + break; + default: + break; + } + return io->WantCaptureKeyboard || io->WantCaptureMouse; +} +#endif + +#endif /* SOKOL_IMPL */ diff --git a/thirdparty/stb_image/CMakeLists.txt b/thirdparty/stb_image/CMakeLists.txt new file mode 100644 index 0000000..68777a9 --- /dev/null +++ b/thirdparty/stb_image/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(stb_image + stb_image.hxx + stb_image.cxx +) + +target_include_directories(stb_image PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(stb_image PROPERTIES FOLDER "thirdparty") \ No newline at end of file diff --git a/thirdparty/stb_image/stb_image.cxx b/thirdparty/stb_image/stb_image.cxx new file mode 100644 index 0000000..978412a --- /dev/null +++ b/thirdparty/stb_image/stb_image.cxx @@ -0,0 +1,2 @@ +#define STB_IMAGE_IMPLEMENTATION 1 +#include "stb_image.hxx" diff --git a/thirdparty/stb_image/stb_image.hxx b/thirdparty/stb_image/stb_image.hxx new file mode 100644 index 0000000..303f2c9 --- /dev/null +++ b/thirdparty/stb_image/stb_image.hxx @@ -0,0 +1,7890 @@ +/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ \ No newline at end of file diff --git a/thirdparty/tinyexr/CMakeLists.txt b/thirdparty/tinyexr/CMakeLists.txt new file mode 100644 index 0000000..d173f5c --- /dev/null +++ b/thirdparty/tinyexr/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(tinyexr + tinyexr.hxx + tinyexr.cxx +) + +target_include_directories(tinyexr PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(tinyexr PROPERTIES FOLDER "thirdparty") \ No newline at end of file diff --git a/thirdparty/tinyexr/tinyexr.cxx b/thirdparty/tinyexr/tinyexr.cxx new file mode 100644 index 0000000..5ee19a2 --- /dev/null +++ b/thirdparty/tinyexr/tinyexr.cxx @@ -0,0 +1,2 @@ +#define TINYEXR_IMPLEMENTATION 1 +#include "tinyexr.hxx" \ No newline at end of file diff --git a/thirdparty/tinyexr/tinyexr.hxx b/thirdparty/tinyexr/tinyexr.hxx new file mode 100644 index 0000000..bfaf963 --- /dev/null +++ b/thirdparty/tinyexr/tinyexr.hxx @@ -0,0 +1,14980 @@ +#ifndef TINYEXR_H_ +#define TINYEXR_H_ +/* +Copyright (c) 2014 - 2020, Syoyo Fujita and many contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Syoyo Fujita nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TinyEXR contains some OpenEXR code, which is licensed under ------------ + +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Industrial Light & Magic nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +// End of OpenEXR license ------------------------------------------------- + + +// +// +// Do this: +// #define TINYEXR_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the +// implementation. +// +// // i.e. it should look like this: +// #include ... +// #include ... +// #include ... +// #define TINYEXR_IMPLEMENTATION +// #include "tinyexr.h" +// +// + +#include // for size_t +#include // guess stdint.h is available(C99) + +#ifdef __cplusplus +extern "C" { +#endif + +// Use embedded miniz or not to decode ZIP format pixel. Linking with zlib +// required if this flas is 0. +#ifndef TINYEXR_USE_MINIZ +#define TINYEXR_USE_MINIZ (1) +#endif + +// Disable PIZ comporession when applying cpplint. +#ifndef TINYEXR_USE_PIZ +#define TINYEXR_USE_PIZ (1) +#endif + +#ifndef TINYEXR_USE_ZFP +#define TINYEXR_USE_ZFP (0) // TinyEXR extension. +// http://computation.llnl.gov/projects/floating-point-compression +#endif + +#ifndef TINYEXR_USE_THREAD +#define TINYEXR_USE_THREAD (0) // No threaded loading. +// http://computation.llnl.gov/projects/floating-point-compression +#endif + +#ifndef TINYEXR_USE_OPENMP +#ifdef _OPENMP +#define TINYEXR_USE_OPENMP (1) +#else +#define TINYEXR_USE_OPENMP (0) +#endif +#endif + +#define TINYEXR_SUCCESS (0) +#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1) +#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2) +#define TINYEXR_ERROR_INVALID_ARGUMENT (-3) +#define TINYEXR_ERROR_INVALID_DATA (-4) +#define TINYEXR_ERROR_INVALID_FILE (-5) +#define TINYEXR_ERROR_INVALID_PARAMETER (-6) +#define TINYEXR_ERROR_CANT_OPEN_FILE (-7) +#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8) +#define TINYEXR_ERROR_INVALID_HEADER (-9) +#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10) +#define TINYEXR_ERROR_CANT_WRITE_FILE (-11) +#define TINYEXR_ERROR_SERIALZATION_FAILED (-12) +#define TINYEXR_ERROR_LAYER_NOT_FOUND (-13) + +// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf } + +// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2 +#define TINYEXR_PIXELTYPE_UINT (0) +#define TINYEXR_PIXELTYPE_HALF (1) +#define TINYEXR_PIXELTYPE_FLOAT (2) + +#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024) +#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128) + +#define TINYEXR_COMPRESSIONTYPE_NONE (0) +#define TINYEXR_COMPRESSIONTYPE_RLE (1) +#define TINYEXR_COMPRESSIONTYPE_ZIPS (2) +#define TINYEXR_COMPRESSIONTYPE_ZIP (3) +#define TINYEXR_COMPRESSIONTYPE_PIZ (4) +#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension + +#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0) +#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1) +#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2) + +#define TINYEXR_TILE_ONE_LEVEL (0) +#define TINYEXR_TILE_MIPMAP_LEVELS (1) +#define TINYEXR_TILE_RIPMAP_LEVELS (2) + +#define TINYEXR_TILE_ROUND_DOWN (0) +#define TINYEXR_TILE_ROUND_UP (1) + +typedef struct _EXRVersion { + int version; // this must be 2 + // tile format image; + // not zero for only a single-part "normal" tiled file (according to spec.) + int tiled; + int long_name; // long name attribute + // deep image(EXR 2.0); + // for a multi-part file, indicates that at least one part is of type deep* (according to spec.) + int non_image; + int multipart; // multi-part(EXR 2.0) +} EXRVersion; + +typedef struct _EXRAttribute { + char name[256]; // name and type are up to 255 chars long. + char type[256]; + unsigned char *value; // uint8_t* + int size; + int pad0; +} EXRAttribute; + +typedef struct _EXRChannelInfo { + char name[256]; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} EXRChannelInfo; + +typedef struct _EXRTile { + int offset_x; + int offset_y; + int level_x; + int level_y; + + int width; // actual width in a tile. + int height; // actual height int a tile. + + unsigned char **images; // image[channels][pixels] +} EXRTile; + +typedef struct _EXRBox2i { + int min_x; + int min_y; + int max_x; + int max_y; +} EXRBox2i; + +typedef struct _EXRHeader { + float pixel_aspect_ratio; + int line_order; + EXRBox2i data_window; + EXRBox2i display_window; + float screen_window_center[2]; + float screen_window_width; + + int chunk_count; + + // Properties for tiled format(`tiledesc`). + int tiled; + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + int long_name; + // for a single-part file, agree with the version field bit 11 + // for a multi-part file, it is consistent with the type of part + int non_image; + int multipart; + unsigned int header_len; + + // Custom attributes(exludes required attributes(e.g. `channels`, + // `compression`, etc) + int num_custom_attributes; + EXRAttribute *custom_attributes; // array of EXRAttribute. size = + // `num_custom_attributes`. + + EXRChannelInfo *channels; // [num_channels] + + int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for + // each channel. This is overwritten with `requested_pixel_types` when + // loading. + int num_channels; + + int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*) + int *requested_pixel_types; // Filled initially by + // ParseEXRHeaderFrom(Meomory|File), then users + // can edit it(only valid for HALF pixel type + // channel) + // name attribute required for multipart files; + // must be unique and non empty (according to spec.); + // use EXRSetNameAttr for setting value; + // max 255 character allowed - excluding terminating zero + char name[256]; +} EXRHeader; + +typedef struct _EXRMultiPartHeader { + int num_headers; + EXRHeader *headers; + +} EXRMultiPartHeader; + +typedef struct _EXRImage { + EXRTile *tiles; // Tiled pixel data. The application must reconstruct image + // from tiles manually. NULL if scanline format. + struct _EXRImage* next_level; // NULL if scanline format or image is the last level. + int level_x; // x level index + int level_y; // y level index + + unsigned char **images; // image[channels][pixels]. NULL if tiled format. + + int width; + int height; + int num_channels; + + // Properties for tile format. + int num_tiles; + +} EXRImage; + +typedef struct _EXRMultiPartImage { + int num_images; + EXRImage *images; + +} EXRMultiPartImage; + +typedef struct _DeepImage { + const char **channel_names; + float ***image; // image[channels][scanlines][samples] + int **offset_table; // offset_table[scanline][offsets] + int num_channels; + int width; + int height; + int pad0; +} DeepImage; + +// @deprecated { For backward compatibility. Not recommended to use. } +// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel +// alpha) or RGB(A) channels. +// Application must free image data as returned by `out_rgba` +// Result image format is: float x RGBA x width x hight +// Returns negative value and may set error string in `err` when there's an +// error +extern int LoadEXR(float **out_rgba, int *width, int *height, + const char *filename, const char **err); + +// Loads single-frame OpenEXR image by specifying layer name. Assume EXR image +// contains A(single channel alpha) or RGB(A) channels. Application must free +// image data as returned by `out_rgba` Result image format is: float x RGBA x +// width x hight Returns negative value and may set error string in `err` when +// there's an error When the specified layer name is not found in the EXR file, +// the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`. +extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height, + const char *filename, const char *layer_name, + const char **err); + +// +// Get layer infos from EXR file. +// +// @param[out] layer_names List of layer names. Application must free memory +// after using this. +// @param[out] num_layers The number of layers +// @param[out] err Error string(will be filled when the function returns error +// code). Free it using FreeEXRErrorMessage after using this value. +// +// @return TINYEXR_SUCCEES upon success. +// +extern int EXRLayers(const char *filename, const char **layer_names[], + int *num_layers, const char **err); + +// @deprecated { to be removed. } +// Simple wrapper API for ParseEXRHeaderFromFile. +// checking given file is a EXR file(by just look up header) +// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for +// others +extern int IsEXR(const char *filename); + +// @deprecated { to be removed. } +// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. +// components must be 1(Grayscale), 3(RGB) or 4(RGBA). +// Input image format is: `float x width x height`, or `float x RGB(A) x width x +// hight` +// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero +// value. +// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. +// Use ZIP compression by default. +// Returns negative value and may set error string in `err` when there's an +// error +extern int SaveEXR(const float *data, const int width, const int height, + const int components, const int save_as_fp16, + const char *filename, const char **err); + +// Returns the number of resolution levels of the image (including the base) +extern int EXRNumLevels(const EXRImage* exr_image); + +// Initialize EXRHeader struct +extern void InitEXRHeader(EXRHeader *exr_header); + +// Set name attribute of EXRHeader struct (it makes a copy) +extern void EXRSetNameAttr(EXRHeader *exr_header, const char* name); + +// Initialize EXRImage struct +extern void InitEXRImage(EXRImage *exr_image); + +// Frees internal data of EXRHeader struct +extern int FreeEXRHeader(EXRHeader *exr_header); + +// Frees internal data of EXRImage struct +extern int FreeEXRImage(EXRImage *exr_image); + +// Frees error message +extern void FreeEXRErrorMessage(const char *msg); + +// Parse EXR version header of a file. +extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename); + +// Parse EXR version header from memory-mapped EXR data. +extern int ParseEXRVersionFromMemory(EXRVersion *version, + const unsigned char *memory, size_t size); + +// Parse single-part OpenEXR header from a file and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, + const char *filename, const char **err); + +// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromMemory(EXRHeader *header, + const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err); + +// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*` +// array. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const char *filename, + const char **err); + +// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*` +// array +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const unsigned char *memory, + size_t size, const char **err); + +// Loads single-part OpenEXR image from a file. +// Application must setup `ParseEXRHeaderFromFile` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, + const char *filename, const char **err); + +// Loads single-part OpenEXR image from a memory. +// Application must setup `EXRHeader` with +// `ParseEXRHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, + const unsigned char *memory, + const size_t size, const char **err); + +// Loads multi-part OpenEXR image from a file. +// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this +// function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromFile(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const char *filename, + const char **err); + +// Loads multi-part OpenEXR image from a memory. +// Application must setup `EXRHeader*` array with +// `ParseEXRMultipartHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromMemory(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a file. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int SaveEXRImageToFile(const EXRImage *image, + const EXRHeader *exr_header, const char *filename, + const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// Return the number of bytes if success. +// Return zero and will set error string in `err` when there's an +// error. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern size_t SaveEXRImageToMemory(const EXRImage *image, + const EXRHeader *exr_header, + unsigned char **memory, const char **err); + +// Saves multi-channel, multi-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// File global attributes (eg. display_window) must be set in the first header. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int SaveEXRMultipartImageToFile(const EXRImage *images, + const EXRHeader **exr_headers, + unsigned int num_parts, + const char *filename, const char **err); + +// Saves multi-channel, multi-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// File global attributes (eg. display_window) must be set in the first header. +// Return the number of bytes if success. +// Return zero and will set error string in `err` when there's an +// error. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern size_t SaveEXRMultipartImageToMemory(const EXRImage *images, + const EXRHeader **exr_headers, + unsigned int num_parts, + unsigned char **memory, const char **err); +// Loads single-frame OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadDeepEXR(DeepImage *out_image, const char *filename, + const char **err); + +// NOT YET IMPLEMENTED: +// Saves single-frame OpenEXR deep image. +// Returns negative value and may set error string in `err` when there's an +// error +// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename, +// const char **err); + +// NOT YET IMPLEMENTED: +// Loads multi-part OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const +// char *filename, +// const char **err); + +// For emscripten. +// Loads single-frame OpenEXR image from memory. Assume EXR image contains +// RGB(A) channels. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err); + +#ifdef __cplusplus +} +#endif + +#endif // TINYEXR_H_ + +#ifdef TINYEXR_IMPLEMENTATION +#ifndef TINYEXR_IMPLEMENTATION_DEFINED +#define TINYEXR_IMPLEMENTATION_DEFINED + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include // for UTF-8 + +#endif + +#include +#include +#include +#include +#include +#include + +// #include // debug + +#include +#include +#include +#include + +// https://stackoverflow.com/questions/5047971/how-do-i-check-for-c11-support +#if __cplusplus > 199711L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define TINYEXR_HAS_CXX11 (1) +// C++11 +#include + +#if TINYEXR_USE_THREAD +#include +#include +#endif + +#endif // __cplusplus > 199711L + +#if TINYEXR_USE_OPENMP +#include +#endif + +#if TINYEXR_USE_MINIZ +#else +// Issue #46. Please include your own zlib-compatible API header before +// including `tinyexr.h` +//#include "zlib.h" +#endif + +#if TINYEXR_USE_ZFP + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +#include "zfp.h" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +namespace tinyexr { + +#if __cplusplus > 199711L +// C++11 +typedef uint64_t tinyexr_uint64; +typedef int64_t tinyexr_int64; +#else +// Although `long long` is not a standard type pre C++11, assume it is defined +// as a compiler's extension. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif +typedef unsigned long long tinyexr_uint64; +typedef long long tinyexr_int64; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#endif + +#if TINYEXR_USE_MINIZ + +namespace miniz { + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wundef" + +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" +#endif + +#if __has_warning("-Wmacro-redefined") +#pragma clang diagnostic ignored "-Wmacro-redefined" +#endif + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#if __has_warning("-Wtautological-constant-compare") +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#endif + +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif + +#endif + +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP + reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: + http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the + archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO + (see the list below for more macros). + + * Change History + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major + release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug + (thanks kahmyong.moon@hp.com) which could cause locate files to not find + files. This bug + would only have occurred in earlier versions if you explicitly used this + flag, OR if you used mz_zip_extract_archive_file_to_heap() or + mz_zip_add_mem_to_archive_file_in_place() + (which used this flag). If you can't switch to v1.15 but want to fix + this bug, just remove the uses of this flag from both helper funcs (and of + course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when + pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract + compressed data from directory entries, to account for weird zipfiles which + contain zero-size compressed data on dir entries. + Hopefully this fix won't cause any issues on weird zip archives, + because it assumes the low 16-bits of zip external attributes are DOS + attributes (which I believe they always are in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the + internal attributes, just the filename and external attributes + - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed + - Added cmake support for Linux builds which builds all the examples, + tested with clang v3.3 and gcc v4.6. + - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti + - Merged MZ_FORCEINLINE fix from hdeanclark + - Fix include before config #ifdef, thanks emil.brink + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping + (super useful for OpenGL apps), and explicit control over the compression + level (so you can + set it to 1 for real-time compression). + - Merged in some compiler fixes from paulharris's github repro. + - Retested this build under Windows (VS 2010, including static analysis), + tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG + file. + - Modified example2 to help test the + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix + possible src file fclose() leak if alignment bytes+local header file write + faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): + Was pushing the wrong central dir header offset, appears harmless in this + release, but it became a problem in the zip64 branch + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, + #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix + mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and + re-ran a randomized regression test on ~500k files. + - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze + (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, + which I purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and + tested Linux executables. The codeblocks workspace is compatible with + Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app + derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on + ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level + functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the + MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which + are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple + minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce + Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput + now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 + vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved + compression perf. issues on some file types. + - Refactored the compression code for better readability and + maintainability. + - Added level 10 compression level (L10 has slightly better ratio than + level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, + and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. + It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is + implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB + (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory + allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough + functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly + routines. + Supports raw deflate streams or standard zlib streams with adler-32 + checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or + zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing + and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, + originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in + mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file + information, read files from + existing archives, create new archives, append new files to existing + archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, + on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a + disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const + char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an + archive, the entire central + directory is located and read as-is into memory, and subsequent file access + only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a + loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one + example) can be used to identify + multiple versions of the same file in an archive. This function uses a + simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using + mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer + immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The + central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file + data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, + the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives + written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is + to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, + const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 + comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be + appended to. + Note the appending is done in-place and is not an atomic operation, so if + something goes wrong + during the operation it's possible the archive could be left without a + central directory (although the local + file headers and file data will be fine, so the archive will be + recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, + cloning only those bits you want to + preserve into a new archive using using the + mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and + rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or + heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using + mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an + updated central directory to the + original archive. (This is basically what + mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this + method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle + unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, + either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then + include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your + target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before + including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be + able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +//#include + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be +// CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on +// stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able +// to get the current time, or +// get/set file times, and the C run-time funcs that get/set times won't be +// called. +// The current downside is the times written to your archives will be from 1979. +#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive +// API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression +// API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent +// conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom +// user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's +// which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and +// tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc +// on Linux +#define MINIZ_NO_TIME +#endif + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +//#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient +// integer loads and stores from unaligned addresses. +//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \ + 0 // disable to suppress compiler warnings +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ + defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ + defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are +// reasonably fast (and don't involve compiler generated calls to helper +// functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some +// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// mz_free() internally uses the MZ_FREE() macro (which by default calls free() +// unless you've modified the MZ_MALLOC macro) to release a block allocated from +// the heap. +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with +// ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with +// ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: +// items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, + size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The +// other values are for advanced use (refer to the zlib docs). +enum { + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best +// possible compression (not zlib compatible, and may be very slow), +// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s { + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func + zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been +// optimized purely for performance, not ratio. +// (This special func. is currently only enabled when +// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with +// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no +// header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as +// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input +// and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or +// MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not +// available, and/or there's more output to be written but the output buffer +// is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been +// written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or +// output buffers are empty. (Fill up the input buffer or free up some output +// space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by deflate(), assuming flush is set to only +// MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on +// failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that +// controls the window size and whether or not the stream has been wrapped with +// a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or +// -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the +// input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output +// buffers are both sized large enough to decompress the entire stream in a +// single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside +// what's already in the input buffer, and that the output buffer is large +// enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or +// there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes +// have been written. For zlib streams, the adler-32 of the decompressed data +// has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is +// empty but the inflater needs more input to continue, or if the output +// buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when +// using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on +// failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the +// error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used +// as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you +// use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// An attempt to work around MSVC's spammy "warning C4127: conditional +// expression is constant" message. +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum { + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct { + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct mz_zip_archive_tag { + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is +// 0 this function returns the number of bytes needed to fully store the +// filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and +// modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive +// file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient +// in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the +// archive's filename so it can be reopened for writing. If the file can't be +// reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be +// growable using the realloc callback (which defaults to realloc unless you've +// overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's +// user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what +// you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record +// the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a +// forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records +// the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no +// recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by +// the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive +// struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be +// valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if +// mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) +// appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and +// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the +// input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available +// beyond the end of the supplied input buffer. If clear, the input buffer +// contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large +// enough to hold the entire decompressed stream. If clear, the output buffer is +// at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the +// decompressed bytes. +enum { + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data +// to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must call mz_free() on the returned block when it's no longer +// needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block +// in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes +// written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an +// internal 32KB buffer, and a user provided callback function will be called to +// flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum { + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) \ + do { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function +// actually needed for decompression. All the other functions are just +// high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any +// desired higher level decompression API. In the limit case, it can be called +// once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum { + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct { + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], + m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag { + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, + m_check_adler32, m_dist, m_counter, m_num_extra, + m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], + m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly +// slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain +// the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes +// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap +// compression), 4095=Huffman+LZ (slowest/best compression). +enum { + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before +// the deflate data, and the Adler-32 of the source data at the end. Otherwise, +// you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even +// when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more +// efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's +// initialization time to the minimum, but the output may vary from run to run +// given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +// The low 12 bits are reserved to control the max # of hash probes per +// dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum { + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against +// the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in +// memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be +// 1, 2, 3, or 4. +// The image pitch in bytes per scanline will be w*num_chans. The leftmost +// pixel on the top scanline is stored first in memory. +// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL +// If flip is true, the image will be flipped on the Y axis (useful for OpenGL +// apps). +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must mz_free() the returned heap block (which will typically be +// larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write +// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, + void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The +// above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +enum { + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed +// output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum { + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +// The low-level tdefl functions below may be used directly if the above helper +// functions aren't flexible enough. The low-level functions don't make any heap +// allocations, unlike the above helper functions. +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct { + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, + m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, + m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, + m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not +// dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified +// callback. In this case, the user should call the tdefl_compress_buffer() API +// for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() +// API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, +// etc.) +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer +// as possible, and writing as much compressed data to the specified output +// buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a +// non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't +// defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be +// much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, +// MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want +// the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +//#include +//#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C +// implementation that balances processor cache usage against speed": +// http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { + static const mz_uint32 s_crc32[16] = { + 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, + 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; +} + +void mz_free(void *p) { MZ_FREE(p); } + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +static void def_free_func(void *opaque, void *address) { + (void)opaque, (void)address; + MZ_FREE(address); +} +// static void *def_realloc_func(void *opaque, void *address, size_t items, +// size_t size) { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +//} + +const char *mz_version(void) { return MZ_VERSION; } + +int mz_deflateInit(mz_streamp pStream, int level) { + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, + MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy) { + tdefl_compressor *pComp; + mz_uint comp_flags = + TDEFL_COMPUTE_ADLER32 | + tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || + ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, + sizeof(tdefl_compressor)); + if (!pComp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) { + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || + (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, + ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) { + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || + (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == + TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, + pStream->next_in, &in_bytes, pStream->next_out, + &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) { + mz_status = MZ_STREAM_ERROR; + break; + } else if (defl_status == TDEFL_STATUS_DONE) { + mz_status = MZ_STREAM_END; + break; + } else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { + if ((flush) || (pStream->total_in != orig_total_in) || + (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty + // tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, + 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level) { + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + return mz_compress2(pDest, pDest_len, pSource, source_len, + MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) { + return mz_deflateBound(NULL, source_len); +} + +typedef struct { + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) { + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, + sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) { + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) { + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) { + // MZ_FINISH on the first call implies that the input and output buffers are + // large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, + pStream->next_out, pStream->next_out, &out_bytes, + decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && + (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; + } + + for (;;) { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress( + &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, + pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some + // uncompressed data left in the output dictionary - + // oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress + // without supplying more input or by setting flush + // to MZ_FINISH. + else if (flush == MZ_FINISH) { + // The output buffer MUST be large to hold the remaining uncompressed data + // when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's + // at least 1 more byte on the way. If there's no more room left in the + // output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || + (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR + : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) { + static struct { + int m_err; + const char *m_pDesc; + } s_error_descs[] = {{MZ_OK, ""}, + {MZ_STREAM_END, "stream end"}, + {MZ_NEED_DICT, "need dictionary"}, + {MZ_ERRNO, "file error"}, + {MZ_STREAM_ERROR, "stream error"}, + {MZ_DATA_ERROR, "data error"}, + {MZ_MEM_ERROR, "out of memory"}, + {MZ_BUF_ERROR, "buf error"}, + {MZ_VERSION_ERROR, "version error"}, + {MZ_PARAM_ERROR, "parameter error"}}; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all +// compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do { \ + for (;;) { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt +// to read beyond the input buf, then something is wrong with the input because +// the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of +// the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) \ + do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for (;;) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes +// remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode +// the next Huffman code (and absolutely no more). It works by trying to fully +// decode a +// Huffman code by using whatever bits are currently present in the bit buffer. +// If this fails, it reads another byte, and tries again until it succeeds or +// until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex +// than you would initially expect because the zlib API expects the decompressor +// to never read +// beyond the final byte of the deflate stream. (In other words, when this macro +// wants to read another byte from the input, it REALLY needs another byte in +// order to fully +// decode the next Huffman code.) Handling this properly is particularly +// important on raw deflate (non-zlib) streams, which aren't followed by a byte +// aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ + (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \ + 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags) { + static const int s_length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0, 0, 0}; + static const int s_dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const mz_uint8 s_length_dezigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static const int s_min_table_sizes[3] = {257, 1, 4}; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = + pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = + pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) + ? (size_t)-1 + : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, + dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer + // is large enough to hold the entire output file (in which case it doesn't + // matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || + (pOut_buf_next < pOut_buf_start)) { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || + (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || + ((out_buf_size_mask + 1) < + (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != + (mz_uint)(0xFFFF ^ + (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } else { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), + (size_t)(pIn_buf_end - pIn_buf_cur)), + counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } else if (r->m_type == 3) { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } else { + if (r->m_type == 1) { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + } else { + for (counter = 0; counter < 3; counter++) { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], + total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; + sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { + mz_uint rev_code = 0, l, cur_code, + code_size = pTable->m_code_size[sym_index]; + if (!code_size) continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == + (tree_cur = pTable->m_look_up[rev_code & + (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = + (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) { + for (counter = 0; + counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, + (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, + r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, + r->m_len_codes + r->m_table_sizes[0], + r->m_table_sizes[1]); + } + } + for (;;) { + mz_uint8 *pSrc; + for (;;) { + if (((pIn_buf_end - pIn_buf_cur) < 4) || + ((pOut_buf_end - pOut_buf_cur) < 2)) { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) break; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } else { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { + while (counter--) { + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = + pOut_buf_start[(dist_from_out_buf_start++ - dist) & + out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) { + if (counter) { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & + (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && + (status >= 0)) { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, + s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && + (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && + (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) { + size_t src_buf_size = src_buf_len - src_buf_ofs, + dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress( + &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, + (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = + tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, + (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED + : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (;;) { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, + dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = + tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, + &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && + (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression +// API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, + 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, + 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, + 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, + 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 285}; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted +// values. +typedef struct { + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, + tdefl_sym_freq *pSyms0, + tdefl_sym_freq *pSyms1) { + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = + pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, +// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) { + while (root >= 0 && (int)A[root].m_key == dpth) { + used++; + root--; + } + while (avbl > used) { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, + int code_list_len, + int max_code_size) { + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, + int table_len, int code_size_limit, + int static_table) { + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } else { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], + *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, + code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ + d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = \ + (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) { + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, + rle_repeat_count, packed_code_sizes_index; + mz_uint8 + code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], + num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, + sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = + (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } else if (++rle_repeat_count == 6) { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { + TDEFL_RLE_PREV_CODE_SIZE(); + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes + [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS( + d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; + packed_code_sizes_index < num_packed_code_sizes;) { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], + "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) { + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ + MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + + if (flags & 1) { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], + d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], + num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + if (flags & 1) { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + if (match_dist < 512) { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } else { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && + // MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) { + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = + ((d->m_pPut_buf_func == NULL) && + ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) + ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) + : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = + tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output + // buffer and send a raw block instead. + if (((use_raw_block) || + ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= + d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) { + TDEFL_PUT_BITS( + d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], + 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed + // block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) { + if (flush == TDEFL_FINISH) { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } else { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { + if (d->m_pPut_buf_func) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } else if (pOutput_buf_start == d->m_output_buf) { + int bytes_to_copy = (int)MZ_MIN( + (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, + bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } else { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), + s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; + probe_len = 32; + do { + } while ( + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + if (!probe_len) { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } else if ((probe_len = ((mz_uint)(p - s) * 2) + + (mz_uint)(*(const mz_uint8 *)p == + *(const mz_uint8 *)q)) > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == + max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && \ + (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) break; + if (probe_len > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) { + // Faster, minimally featured LZRW1-style match+parse loop with better + // register utilization. Intended for applications where raw throughput is + // valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, + lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, + total_lz_bytes = d->m_total_lz_bytes, + num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = + (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, + MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = + (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & + TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= + dict_size) && + ((*(const mz_uint32 *)(d->m_dict + + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & + 0xFFFFFF) == first_trigram)) { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { + } while ((TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || + ((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U))) { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } else { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 1) && + (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - + TDEFL_MIN_MATCH_LEN]]++; + } + } else { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, + mz_uint8 lit) { + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, + mz_uint match_len, + mz_uint match_dist) { + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && + (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) { + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to + // TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK, + ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } else { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << (TDEFL_LZ_HASH_SHIFT * 2)) ^ + (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + c) & + (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = + MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = + d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) { + if (d->m_dict[cur_pos + cur_match_len] != c) break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } else { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, + d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U)) || + (cur_pos == cur_match_dist) || + ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) { + if (cur_match_len > d->m_saved_match_len) { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } else { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } else if (!cur_match_dist) + tdefl_record_literal(d, + d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || + (cur_match_len >= 128)) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = + MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output + // buffer. + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && + (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= + d->m_total_lz_bytes) || + (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { + if (d->m_pIn_buf_size) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, + d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, + d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE + : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush) { + if (!d) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == + ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || + (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || + (pIn_buf_size && *pIn_buf_size && !pIn_buf) || + (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | + TDEFL_RLE_MATCHES)) == 0)) { + if (!tdefl_compress_fast(d)) return d->m_prev_return_status; + } else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && + (pIn_buf)) + d->m_adler32 = + (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, + d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && + (!d->m_output_flush_remaining)) { + if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush) { + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = + d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = + d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == + TDEFL_STATUS_OKAY); + succeeded = + succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == + TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct { + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, + void *pUser) { + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) return MZ_FALSE; + do { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, + 128, 256, 512, 768, 1500}; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we +// want a bit more compression and it's fine if throughput to fall off a cliff +// on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy) { + mz_uint comp_flags = + s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | + ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif // MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public +// domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +// This is actually a modification of Alex's original code so PNG files +// generated by this function pass pngcheck. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip) { + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was + // defined. + static const mz_uint s_tdefl_png_num_probes[11] = { + 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + tdefl_compressor *pComp = + (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { + MZ_FREE(pComp); + return NULL; + } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init( + pComp, tdefl_output_buffer_putter, &out_buf, + s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, + (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, + bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != + TDEFL_STATUS_DONE) { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + // write real header + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41] = {0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x0d, + 0x49, + 0x48, + 0x44, + 0x52, + 0, + 0, + (mz_uint8)(w >> 8), + (mz_uint8)w, + 0, + 0, + (mz_uint8)(h >> 8), + (mz_uint8)h, + 8, + chans[num_chans], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (mz_uint8)(*pLen_out >> 24), + (mz_uint8)(*pLen_out >> 16), + (mz_uint8)(*pLen_out >> 8), + (mz_uint8)*pLen_out, + 0x49, + 0x44, + 0x41, + 0x54}; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter( + "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, + *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out) { + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we + // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's + // where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, + pLen_out, 6, MZ_FALSE); +} + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS +#error "No arvhive APIs" + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE *mz_fopen(const char *pFilename, const char *pMode) { + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#else +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler +// alignment and platform endian issues, miniz.c doesn't use structs for any of +// this stuff. +enum { + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct { + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag { + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ + (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ + ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, + mz_zip_array *pArray) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t min_new_capacity, + mz_uint growing) { + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, + pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_capacity, + mz_uint growing) { + if (new_capacity > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_size, + mz_uint growing) { + if (new_size > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t n) { + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, + mz_zip_array *pArray, + const void *pElements, + size_t n) { + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, + pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, + mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef MINIZ_NO_TIME + (void)pFilename; + *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 + // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, + time_t modified_time) { + struct utimbuf t; + t.actime = access_time; + t.modtime = modified_time; + return !utime(pFilename, &t); +} +#endif // #ifndef MINIZ_NO_TIME +#endif // #ifndef MINIZ_NO_STDIO + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, + mz_uint32 flags) { + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool +mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, + mz_uint l_index, mz_uint r_index) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), + r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central +// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), +// but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename( + mz_zip_archive *pZip) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) { + int child, root = start; + for (;;) { + if ((child = (root << 1) + 1) >= size) break; + child += + (((child + 1) < size) && + (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + start--; + } + + end = size - 1; + while (end > 0) { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) { + if ((child = (root << 1) + 1) >= end) break; + child += + (((child + 1) < end) && + mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, + mz_uint32 flags) { + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = + ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first + // 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end + // towards the beginning. + cur_file_ofs = + MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) { + int i, + n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; + if (i >= 0) { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= + (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && + ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < + pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) { + mz_uint i, n; + + // Read the entire central directory into a heap block, and allocate another + // heap block to hold the unsorted central dir file record offsets, and + // another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, + MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, + pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + + if (sort_central_dir) { + if (!mz_zip_array_resize(pZip, + &pZip->m_pState->m_sorted_central_dir_offsets, + pZip->m_total_files, MZ_FALSE)) + return MZ_FALSE; + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, + pZip->m_pState->m_central_dir.m_p, + cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some + // basic sanity checking on each record, and check for zip64 entries (which + // are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || + (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + i) = + (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, + mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && + (decomp_size != comp_size)) || + (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || + (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > + n) + return MZ_FALSE; + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags) { + if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) + ? 0 + : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags) { + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags) { + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh( + mz_zip_archive *pZip, mz_uint file_index) { + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint filename_len, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + // Bugfix: This code was also checking if the internal attribute was non-zero, + // which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the + // low 16-bits, so check for the DOS directory flag and ignore the source OS + // ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) return MZ_TRUE; + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = + mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), + MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + n); + pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + if (filename_buf_size) pFilename[0] = '\0'; + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, + const char *pB, + mz_uint len, + mz_uint flags) { + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare( + const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, + mz_uint r_len) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) { + int m = (l + h) >> 1, file_index = pIndices[m], + comp = + mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, + file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags) { + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && + (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); + if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = + (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) continue; + if (comment_len) { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), + file_comment_len = + MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || + (!mz_zip_reader_string_equal(pComment, pFile_comment, + file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { + int ofs = filename_len - 1; + do { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || + (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && + (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size) { + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, + out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size + : file_stat.m_uncomp_size; + if (buf_size < needed_size) return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input + // buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else if (pUser_read_buf) { + // Use a user provided read buffer. + if (!user_read_buf_size) return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } else { + // Temporarily allocate a read buffer. + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do { + size_t in_buf_size, + out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | + (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, pUser_read_buf, + user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags) { + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, + buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags) { + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) *pSize = 0; + if (!p) return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == + (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, + flags)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, + out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input + // buffer. + if (pZip->m_pState->m_pMem) { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else { + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, + (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } else { + while (comp_remaining) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32( + file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } else { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else { + do { + mz_uint8 *pWrite_buf_cur = + (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, + out_buf_size = + TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, + comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != + out_buf_size) { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || + (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && + (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, + flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, + const void *pBuf, size_t n) { + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, + mz_uint flags) { + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) return MZ_FALSE; + status = mz_zip_reader_extract_to_callback( + pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags) { + int file_index = + mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || + (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || + ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || + ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc( + pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size) { + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, + size_to_reserve_at_beginning))) { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning) { + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max + // size + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) { +#ifdef MINIZ_NO_STDIO + pFilename; + return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + if (!pFilename) return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == + (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is + // NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } else if (pState->m_pMem) { + // Archive lives in a memory block. Assume it's from the heap that we can + // resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the + // user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory + // location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags) { + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, + level_and_flags, 0, 0); +} + +typedef struct { + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, + void *pUser) { + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, + pState->m_cur_archive_file_ofs, pBuf, + len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, + mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, + mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir( + mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, + mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, + mz_uint32 ext_attributes) { + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || + (((mz_uint64)pState->m_central_dir.m_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header( + pZip, central_dir_header, filename_size, extra_size, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, + dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, + filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, + extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, + comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, + ¢ral_dir_ofs, 1))) { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { + // Basic ZIP archive filename validity checks: Valid filenames cannot start + // with a forward slash, cannot contain a drive letter, and cannot use + // DOS-style backward slashes. + if (*pArchive_name == '/') return MZ_FALSE; + while (*pArchive_name) { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment( + mz_zip_archive *pZip) { + mz_uint32 n; + if (!pZip->m_file_offset_alignment) return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & + (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, + mz_uint64 cur_file_ofs, mz_uint32 n) { + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32) { + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = + ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || + (!pArchive_name) || ((comment_size) && (!pComment)) || + (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; + time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an + // allocation fails the file remains unmodified. (A good idea if we're doing + // an in-place modification.) + if ((!mz_zip_array_ensure_room( + pZip, &pState->m_central_dir, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || + (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + uncomp_crc32 = + (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, + buf_size) != buf_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; + } else if (buf_size) { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != + TDEFL_STATUS_DONE)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, + comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || + ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) level = 0; + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = + pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) { + while (uncomp_remaining) { + mz_uint n = + (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || + (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, + n) != n)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = + (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } else { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for (;;) { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, + (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32( + uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer( + pComp, pRead_buf, in_buf_size, + uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) { + result = MZ_TRUE; + break; + } else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index) { + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == + (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > + 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, + pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, + num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = + n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, + (size_t)MZ_MAX(sizeof(mz_uint32) * 4, + MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, + comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) { + n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, + local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back( + pZip, &pState->m_central_dir, + pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || + ((pZip->m_archive_size + pState->m_central_dir.m_size + + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, + pState->m_central_dir.m_p, + (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, + pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, + sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize) { + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || + ((comment_size) && (!pComment)) || + ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } else { + // Append to an existing archive. + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = + mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, + pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid + // central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; + if ((!status) && (created_new_archive)) { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint flags) { + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, + flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ + +// ---------------------- end of miniz ---------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +} // namespace miniz +#else + +// Reuse MINIZ_LITTE_ENDIAN macro + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#endif // TINYEXR_USE_MINIZ + +// static bool IsBigEndian(void) { +// union { +// unsigned int i; +// char c[4]; +// } bint = {0x01020304}; +// +// return bint.c[0] == 1; +//} + +static void SetErrorMessage(const std::string &msg, const char **err) { + if (err) { +#ifdef _WIN32 + (*err) = _strdup(msg.c_str()); +#else + (*err) = strdup(msg.c_str()); +#endif + } +} + +static const int kEXRVersionSize = 8; + +static void cpy2(unsigned short *dst_val, const unsigned short *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; +} + +static void swap2(unsigned short *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned short tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[1]; + dst[1] = src[0]; +#endif +} + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +static void cpy4(int *dst_val, const int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(unsigned int *dst_val, const unsigned int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(float *dst_val, const float *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +static void swap4(unsigned int *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +static void swap4(int *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +static void swap4(float *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + float tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +#if 0 +static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} +#endif + +static void swap8(tinyexr::tinyexr_uint64 *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + tinyexr::tinyexr_uint64 tmp = (*val); + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; +#endif +} + +// https://gist.github.com/rygorous/2156668 +// Reuse MINIZ_LITTLE_ENDIAN flag from miniz. +union FP32 { + unsigned int u; + float f; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 23; + unsigned int Exponent : 8; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 8; + unsigned int Mantissa : 23; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +union FP16 { + unsigned short u; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 10; + unsigned int Exponent : 5; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 5; + unsigned int Mantissa : 10; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +static FP32 half_to_float(FP16 h) { + static const FP32 magic = {113 << 23}; + static const unsigned int shifted_exp = 0x7c00 + << 13; // exponent mask after shift + FP32 o; + + o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits + unsigned int exp_ = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp_ == shifted_exp) // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + else if (exp_ == 0) // Zero/Denormal? + { + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // renormalize + } + + o.u |= (h.u & 0x8000U) << 16U; // sign bit + return o; +} + +static FP16 float_to_half_full(FP32 f) { + FP16 o = {0}; + + // Based on ISPC reference code (with minor modifications) + if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow) + o.s.Exponent = 0; + else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set) + { + o.s.Exponent = 31; + o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf + } else // Normalized number + { + // Exponent unbias the single, then bias the halfp + int newexp = f.s.Exponent - 127 + 15; + if (newexp >= 31) // Overflow, return signed infinity + o.s.Exponent = 31; + else if (newexp <= 0) // Underflow + { + if ((14 - newexp) <= 24) // Mantissa might be non-zero + { + unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit + o.s.Mantissa = mant >> (14 - newexp); + if ((mant >> (13 - newexp)) & 1) // Check for rounding + o.u++; // Round, might overflow into exp bit, but this is OK + } + } else { + o.s.Exponent = static_cast(newexp); + o.s.Mantissa = f.s.Mantissa >> 13; + if (f.s.Mantissa & 0x1000) // Check for rounding + o.u++; // Round, might overflow to inf, this is OK + } + } + + o.s.Sign = f.s.Sign; + return o; +} + +// NOTE: From OpenEXR code +// #define IMF_INCREASING_Y 0 +// #define IMF_DECREASING_Y 1 +// #define IMF_RAMDOM_Y 2 +// +// #define IMF_NO_COMPRESSION 0 +// #define IMF_RLE_COMPRESSION 1 +// #define IMF_ZIPS_COMPRESSION 2 +// #define IMF_ZIP_COMPRESSION 3 +// #define IMF_PIZ_COMPRESSION 4 +// #define IMF_PXR24_COMPRESSION 5 +// #define IMF_B44_COMPRESSION 6 +// #define IMF_B44A_COMPRESSION 7 + +#ifdef __clang__ +#pragma clang diagnostic push + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif + +static const char *ReadString(std::string *s, const char *ptr, size_t len) { + // Read untile NULL(\0). + const char *p = ptr; + const char *q = ptr; + while ((size_t(q - ptr) < len) && (*q) != 0) { + q++; + } + + if (size_t(q - ptr) >= len) { + (*s) = std::string(); + return NULL; + } + + (*s) = std::string(p, q); + + return q + 1; // skip '\0' +} + +static bool ReadAttribute(std::string *name, std::string *type, + std::vector *data, size_t *marker_size, + const char *marker, size_t size) { + size_t name_len = strnlen(marker, size); + if (name_len == size) { + // String does not have a terminating character. + return false; + } + *name = std::string(marker, name_len); + + marker += name_len + 1; + size -= name_len + 1; + + size_t type_len = strnlen(marker, size); + if (type_len == size) { + return false; + } + *type = std::string(marker, type_len); + + marker += type_len + 1; + size -= type_len + 1; + + if (size < sizeof(uint32_t)) { + return false; + } + + uint32_t data_len; + memcpy(&data_len, marker, sizeof(uint32_t)); + tinyexr::swap4(reinterpret_cast(&data_len)); + + if (data_len == 0) { + if ((*type).compare("string") == 0) { + // Accept empty string attribute. + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t); + + data->resize(1); + (*data)[0] = '\0'; + + return true; + } else { + return false; + } + } + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + if (size < data_len) { + return false; + } + + data->resize(static_cast(data_len)); + memcpy(&data->at(0), marker, static_cast(data_len)); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len; + return true; +} + +static void WriteAttributeToMemory(std::vector *out, + const char *name, const char *type, + const unsigned char *data, int len) { + out->insert(out->end(), name, name + strlen(name) + 1); + out->insert(out->end(), type, type + strlen(type) + 1); + + int outLen = len; + tinyexr::swap4(&outLen); + out->insert(out->end(), reinterpret_cast(&outLen), + reinterpret_cast(&outLen) + sizeof(int)); + out->insert(out->end(), data, data + len); +} + +typedef struct { + std::string name; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} ChannelInfo; + +typedef struct { + int min_x; + int min_y; + int max_x; + int max_y; +} Box2iInfo; + +struct HeaderInfo { + std::vector channels; + std::vector attributes; + + Box2iInfo data_window; + int line_order; + Box2iInfo display_window; + float screen_window_center[2]; + float screen_window_width; + float pixel_aspect_ratio; + + int chunk_count; + + // Tiled format + int tiled; // Non-zero if the part is tiled. + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + unsigned int header_len; + + int compression_type; + + // required for multi-part or non-image files + std::string name; + // required for multi-part or non-image files + std::string type; + + void clear() { + channels.clear(); + attributes.clear(); + + data_window.min_x = 0; + data_window.min_y = 0; + data_window.max_x = 0; + data_window.max_y = 0; + line_order = 0; + display_window.min_x = 0; + display_window.min_y = 0; + display_window.max_x = 0; + display_window.max_y = 0; + screen_window_center[0] = 0.0f; + screen_window_center[1] = 0.0f; + screen_window_width = 0.0f; + pixel_aspect_ratio = 0.0f; + + chunk_count = 0; + + // Tiled format + tiled = 0; + tile_size_x = 0; + tile_size_y = 0; + tile_level_mode = 0; + tile_rounding_mode = 0; + + header_len = 0; + compression_type = 0; + + name.clear(); + type.clear(); + } +}; + +static bool ReadChannelInfo(std::vector &channels, + const std::vector &data) { + const char *p = reinterpret_cast(&data.at(0)); + + for (;;) { + if ((*p) == 0) { + break; + } + ChannelInfo info; + + tinyexr_int64 data_len = static_cast(data.size()) - + (p - reinterpret_cast(data.data())); + if (data_len < 0) { + return false; + } + + p = ReadString(&info.name, p, size_t(data_len)); + if ((p == NULL) && (info.name.empty())) { + // Buffer overrun. Issue #51. + return false; + } + + const unsigned char *data_end = + reinterpret_cast(p) + 16; + if (data_end >= (data.data() + data.size())) { + return false; + } + + memcpy(&info.pixel_type, p, sizeof(int)); + p += 4; + info.p_linear = static_cast(p[0]); // uchar + p += 1 + 3; // reserved: uchar[3] + memcpy(&info.x_sampling, p, sizeof(int)); // int + p += 4; + memcpy(&info.y_sampling, p, sizeof(int)); // int + p += 4; + + tinyexr::swap4(&info.pixel_type); + tinyexr::swap4(&info.x_sampling); + tinyexr::swap4(&info.y_sampling); + + channels.push_back(info); + } + + return true; +} + +static void WriteChannelInfo(std::vector &data, + const std::vector &channels) { + size_t sz = 0; + + // Calculate total size. + for (size_t c = 0; c < channels.size(); c++) { + sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0 + sz += 16; // 4 * int + } + data.resize(sz + 1); + + unsigned char *p = &data.at(0); + + for (size_t c = 0; c < channels.size(); c++) { + memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str())); + p += strlen(channels[c].name.c_str()); + (*p) = '\0'; + p++; + + int pixel_type = channels[c].pixel_type; + int x_sampling = channels[c].x_sampling; + int y_sampling = channels[c].y_sampling; + tinyexr::swap4(&pixel_type); + tinyexr::swap4(&x_sampling); + tinyexr::swap4(&y_sampling); + + memcpy(p, &pixel_type, sizeof(int)); + p += sizeof(int); + + (*p) = channels[c].p_linear; + p += 4; + + memcpy(p, &x_sampling, sizeof(int)); + p += sizeof(int); + + memcpy(p, &y_sampling, sizeof(int)); + p += sizeof(int); + } + + (*p) = '\0'; +} + +static void CompressZip(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + +#if TINYEXR_USE_MINIZ + // + // Compress the data using miniz + // + + miniz::mz_ulong outSize = miniz::mz_compressBound(src_size); + int ret = miniz::mz_compress( + dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == miniz::MZ_OK); + (void)ret; + + compressedSize = outSize; +#else + uLong outSize = compressBound(static_cast(src_size)); + int ret = compress(dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == Z_OK); + + compressedSize = outSize; +#endif + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressZip(unsigned char *dst, + unsigned long *uncompressed_size /* inout */, + const unsigned char *src, unsigned long src_size) { + if ((*uncompressed_size) == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + std::vector tmpBuf(*uncompressed_size); + +#if TINYEXR_USE_MINIZ + int ret = + miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (miniz::MZ_OK != ret) { + return false; + } +#else + int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (Z_OK != ret) { + return false; + } +#endif + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size); + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (*uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + (*uncompressed_size); + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +// RLE code from OpenEXR -------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +const int MIN_RUN_LENGTH = 3; +const int MAX_RUN_LENGTH = 127; + +// +// Compress an array of bytes, using run-length encoding, +// and return the length of the compressed data. +// + +static int rleCompress(int inLength, const char in[], signed char out[]) { + const char *inEnd = in + inLength; + const char *runStart = in; + const char *runEnd = in + 1; + signed char *outWrite = out; + + while (runStart < inEnd) { + while (runEnd < inEnd && *runStart == *runEnd && + runEnd - runStart - 1 < MAX_RUN_LENGTH) { + ++runEnd; + } + + if (runEnd - runStart >= MIN_RUN_LENGTH) { + // + // Compressible run + // + + *outWrite++ = static_cast(runEnd - runStart) - 1; + *outWrite++ = *(reinterpret_cast(runStart)); + runStart = runEnd; + } else { + // + // Uncompressable run + // + + while (runEnd < inEnd && + ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) || + (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) && + runEnd - runStart < MAX_RUN_LENGTH) { + ++runEnd; + } + + *outWrite++ = static_cast(runStart - runEnd); + + while (runStart < runEnd) { + *outWrite++ = *(reinterpret_cast(runStart++)); + } + } + + ++runEnd; + } + + return static_cast(outWrite - out); +} + +// +// Uncompress an array of bytes compressed with rleCompress(). +// Returns the length of the oncompressed data, or 0 if the +// length of the uncompressed data would be more than maxLength. +// + +static int rleUncompress(int inLength, int maxLength, const signed char in[], + char out[]) { + char *outStart = out; + + while (inLength > 0) { + if (*in < 0) { + int count = -(static_cast(*in++)); + inLength -= count + 1; + + // Fixes #116: Add bounds check to in buffer. + if ((0 > (maxLength -= count)) || (inLength < 0)) return 0; + + memcpy(out, in, count); + out += count; + in += count; + } else { + int count = *in++; + inLength -= 2; + + if (0 > (maxLength -= count + 1)) return 0; + + memset(out, *reinterpret_cast(in), count + 1); + out += count + 1; + + in++; + } + } + + return static_cast(out - outStart); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// End of RLE code from OpenEXR ----------------------------------- + +static void CompressRle(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + + // outSize will be (srcSiz * 3) / 2 at max. + int outSize = rleCompress(static_cast(src_size), + reinterpret_cast(&tmpBuf.at(0)), + reinterpret_cast(dst)); + assert(outSize > 0); + + compressedSize = static_cast(outSize); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressRle(unsigned char *dst, + const unsigned long uncompressed_size, + const unsigned char *src, unsigned long src_size) { + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + + // Workaround for issue #112. + // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`. + if (src_size <= 2) { + return false; + } + + std::vector tmpBuf(uncompressed_size); + + int ret = rleUncompress(static_cast(src_size), + static_cast(uncompressed_size), + reinterpret_cast(src), + reinterpret_cast(&tmpBuf.at(0))); + if (ret != static_cast(uncompressed_size)) { + return false; + } + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + uncompressed_size; + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + uncompressed_size; + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +#if TINYEXR_USE_PIZ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif + +#endif + +// +// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp +// +// ----------------------------------------------------------------- +// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC) +// (3 clause BSD license) +// + +struct PIZChannelData { + unsigned short *start; + unsigned short *end; + int nx; + int ny; + int ys; + int size; +}; + +//----------------------------------------------------------------------------- +// +// 16-bit Haar Wavelet encoding and decoding +// +// The source code in this file is derived from the encoding +// and decoding routines written by Christian Rouet for his +// PIZ image file format. +// +//----------------------------------------------------------------------------- + +// +// Wavelet basis functions without modulo arithmetic; they produce +// the best compression ratios when the wavelet-transformed data are +// Huffman-encoded, but the wavelet transform works only for 14-bit +// data (untransformed data values must be less than (1 << 14)). +// + +inline void wenc14(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + short as = static_cast(a); + short bs = static_cast(b); + + short ms = (as + bs) >> 1; + short ds = as - bs; + + l = static_cast(ms); + h = static_cast(ds); +} + +inline void wdec14(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + short ls = static_cast(l); + short hs = static_cast(h); + + int hi = hs; + int ai = ls + (hi & 1) + (hi >> 1); + + short as = static_cast(ai); + short bs = static_cast(ai - hi); + + a = static_cast(as); + b = static_cast(bs); +} + +// +// Wavelet basis functions with modulo arithmetic; they work with full +// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't +// compress the data quite as well. +// + +const int NBITS = 16; +const int A_OFFSET = 1 << (NBITS - 1); +const int M_OFFSET = 1 << (NBITS - 1); +const int MOD_MASK = (1 << NBITS) - 1; + +inline void wenc16(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + int ao = (a + A_OFFSET) & MOD_MASK; + int m = ((ao + b) >> 1); + int d = ao - b; + + if (d < 0) m = (m + M_OFFSET) & MOD_MASK; + + d &= MOD_MASK; + + l = static_cast(m); + h = static_cast(d); +} + +inline void wdec16(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + int m = l; + int d = h; + int bb = (m - (d >> 1)) & MOD_MASK; + int aa = (d + bb - A_OFFSET) & MOD_MASK; + b = static_cast(bb); + a = static_cast(aa); +} + +// +// 2D Wavelet encoding: +// + +static void wav2Encode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; // == 1 << level + int p2 = 2; // == 1 << (level+1) + + // + // Hierarchical loop on smaller dimension n + // + + while (p2 <= n) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet encoding + // + + if (w14) { + wenc14(*px, *p01, i00, i01); + wenc14(*p10, *p11, i10, i11); + wenc14(i00, i10, *px, *p10); + wenc14(i01, i11, *p01, *p11); + } else { + wenc16(*px, *p01, i00, i01); + wenc16(*p10, *p11, i10, i11); + wenc16(i00, i10, *px, *p10); + wenc16(i01, i11, *p01, *p11); + } + } + + // + // Encode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wenc14(*px, *p10, i00, *p10); + else + wenc16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Encode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wenc14(*px, *p01, i00, *p01); + else + wenc16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p = p2; + p2 <<= 1; + } +} + +// +// 2D Wavelet decoding: +// + +static void wav2Decode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; + int p2; + + // + // Search max level + // + + while (p <= n) p <<= 1; + + p >>= 1; + p2 = p; + p >>= 1; + + // + // Hierarchical loop on smaller dimension n + // + + while (p >= 1) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet decoding + // + + if (w14) { + wdec14(*px, *p10, i00, i10); + wdec14(*p01, *p11, i01, i11); + wdec14(i00, i01, *px, *p01); + wdec14(i10, i11, *p10, *p11); + } else { + wdec16(*px, *p10, i00, i10); + wdec16(*p01, *p11, i01, i11); + wdec16(i00, i01, *px, *p01); + wdec16(i10, i11, *p10, *p11); + } + } + + // + // Decode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wdec14(*px, *p10, i00, *p10); + else + wdec16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Decode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wdec14(*px, *p01, i00, *p01); + else + wdec16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p2 = p; + p >>= 1; + } +} + +//----------------------------------------------------------------------------- +// +// 16-bit Huffman compression and decompression. +// +// The source code in this file is derived from the 8-bit +// Huffman compression and decompression routines written +// by Christian Rouet for his PIZ image file format. +// +//----------------------------------------------------------------------------- + +// Adds some modification for tinyexr. + +const int HUF_ENCBITS = 16; // literal (value) bit length +const int HUF_DECBITS = 14; // decoding bit size (>= 8) + +const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size +const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size +const int HUF_DECMASK = HUF_DECSIZE - 1; + +struct HufDec { // short code long code + //------------------------------- + unsigned int len : 8; // code length 0 + unsigned int lit : 24; // lit p size + unsigned int *p; // 0 lits +}; + +inline long long hufLength(long long code) { return code & 63; } + +inline long long hufCode(long long code) { return code >> 6; } + +inline void outputBits(int nBits, long long bits, long long &c, int &lc, + char *&out) { + c <<= nBits; + lc += nBits; + + c |= bits; + + while (lc >= 8) *out++ = static_cast((c >> (lc -= 8))); +} + +inline long long getBits(int nBits, long long &c, int &lc, const char *&in) { + while (lc < nBits) { + c = (c << 8) | *(reinterpret_cast(in++)); + lc += 8; + } + + lc -= nBits; + return (c >> lc) & ((1 << nBits) - 1); +} + +// +// ENCODING TABLE BUILDING & (UN)PACKING +// + +// +// Build a "canonical" Huffman code table: +// - for each (uncompressed) symbol, hcode contains the length +// of the corresponding code (in the compressed data) +// - canonical codes are computed and stored in hcode +// - the rules for constructing canonical codes are as follows: +// * shorter codes (if filled with zeroes to the right) +// have a numerically higher value than longer codes +// * for codes with the same length, numerical values +// increase with numerical symbol values +// - because the canonical code table can be constructed from +// symbol lengths alone, the code table can be transmitted +// without sending the actual code values +// - see http://www.compressconsult.com/huffman/ +// + +static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) { + long long n[59]; + + // + // For each i from 0 through 58, count the + // number of different codes of length i, and + // store the count in n[i]. + // + + for (int i = 0; i <= 58; ++i) n[i] = 0; + + for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1; + + // + // For each i from 58 through 1, compute the + // numerically lowest code with length i, and + // store that code in n[i]. + // + + long long c = 0; + + for (int i = 58; i > 0; --i) { + long long nc = ((c + n[i]) >> 1); + n[i] = c; + c = nc; + } + + // + // hcode[i] contains the length, l, of the + // code for symbol i. Assign the next available + // code of length l to the symbol and store both + // l and the code in hcode[i]. + // + + for (int i = 0; i < HUF_ENCSIZE; ++i) { + int l = static_cast(hcode[i]); + + if (l > 0) hcode[i] = l | (n[l]++ << 6); + } +} + +// +// Compute Huffman codes (based on frq input) and store them in frq: +// - code structure is : [63:lsb - 6:msb] | [5-0: bit length]; +// - max code length is 58 bits; +// - codes outside the range [im-iM] have a null length (unused values); +// - original frequencies are destroyed; +// - encoding tables are used by hufEncode() and hufBuildDecTable(); +// + +struct FHeapCompare { + bool operator()(long long *a, long long *b) { return *a > *b; } +}; + +static void hufBuildEncTable( + long long *frq, // io: input frequencies [HUF_ENCSIZE], output table + int *im, // o: min frq index + int *iM) // o: max frq index +{ + // + // This function assumes that when it is called, array frq + // indicates the frequency of all possible symbols in the data + // that are to be Huffman-encoded. (frq[i] contains the number + // of occurrences of symbol i in the data.) + // + // The loop below does three things: + // + // 1) Finds the minimum and maximum indices that point + // to non-zero entries in frq: + // + // frq[im] != 0, and frq[i] == 0 for all i < im + // frq[iM] != 0, and frq[i] == 0 for all i > iM + // + // 2) Fills array fHeap with pointers to all non-zero + // entries in frq. + // + // 3) Initializes array hlink such that hlink[i] == i + // for all array entries. + // + + std::vector hlink(HUF_ENCSIZE); + std::vector fHeap(HUF_ENCSIZE); + + *im = 0; + + while (!frq[*im]) (*im)++; + + int nf = 0; + + for (int i = *im; i < HUF_ENCSIZE; i++) { + hlink[i] = i; + + if (frq[i]) { + fHeap[nf] = &frq[i]; + nf++; + *iM = i; + } + } + + // + // Add a pseudo-symbol, with a frequency count of 1, to frq; + // adjust the fHeap and hlink array accordingly. Function + // hufEncode() uses the pseudo-symbol for run-length encoding. + // + + (*iM)++; + frq[*iM] = 1; + fHeap[nf] = &frq[*iM]; + nf++; + + // + // Build an array, scode, such that scode[i] contains the number + // of bits assigned to symbol i. Conceptually this is done by + // constructing a tree whose leaves are the symbols with non-zero + // frequency: + // + // Make a heap that contains all symbols with a non-zero frequency, + // with the least frequent symbol on top. + // + // Repeat until only one symbol is left on the heap: + // + // Take the two least frequent symbols off the top of the heap. + // Create a new node that has first two nodes as children, and + // whose frequency is the sum of the frequencies of the first + // two nodes. Put the new node back into the heap. + // + // The last node left on the heap is the root of the tree. For each + // leaf node, the distance between the root and the leaf is the length + // of the code for the corresponding symbol. + // + // The loop below doesn't actually build the tree; instead we compute + // the distances of the leaves from the root on the fly. When a new + // node is added to the heap, then that node's descendants are linked + // into a single linear list that starts at the new node, and the code + // lengths of the descendants (that is, their distance from the root + // of the tree) are incremented by one. + // + + std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + std::vector scode(HUF_ENCSIZE); + memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE); + + while (nf > 1) { + // + // Find the indices, mm and m, of the two smallest non-zero frq + // values in fHeap, add the smallest frq to the second-smallest + // frq, and remove the smallest frq value from fHeap. + // + + int mm = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + --nf; + + int m = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + frq[m] += frq[mm]; + std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + // + // The entries in scode are linked into lists with the + // entries in hlink serving as "next" pointers and with + // the end of a list marked by hlink[j] == j. + // + // Traverse the lists that start at scode[m] and scode[mm]. + // For each element visited, increment the length of the + // corresponding code by one bit. (If we visit scode[j] + // during the traversal, then the code for symbol j becomes + // one bit longer.) + // + // Merge the lists that start at scode[m] and scode[mm] + // into a single list that starts at scode[m]. + // + + // + // Add a bit to all codes in the first list. + // + + for (int j = m;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) { + // + // Merge the two lists. + // + + hlink[j] = mm; + break; + } + } + + // + // Add a bit to all codes in the second list + // + + for (int j = mm;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) break; + } + } + + // + // Build a canonical Huffman code table, replacing the code + // lengths in scode with (code, code length) pairs. Copy the + // code table from scode into frq. + // + + hufCanonicalCodeTable(scode.data()); + memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE); +} + +// +// Pack an encoding table: +// - only code lengths, not actual codes, are stored +// - runs of zeroes are compressed as follows: +// +// unpacked packed +// -------------------------------- +// 1 zero 0 (6 bits) +// 2 zeroes 59 +// 3 zeroes 60 +// 4 zeroes 61 +// 5 zeroes 62 +// n zeroes (6 or more) 63 n-6 (6 + 8 bits) +// + +const int SHORT_ZEROCODE_RUN = 59; +const int LONG_ZEROCODE_RUN = 63; +const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN; +const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN; + +static void hufPackEncTable( + const long long *hcode, // i : encoding table [HUF_ENCSIZE] + int im, // i : min hcode index + int iM, // i : max hcode index + char **pcode) // o: ptr to packed table (updated) +{ + char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + int l = hufLength(hcode[im]); + + if (l == 0) { + int zerun = 1; + + while ((im < iM) && (zerun < LONGEST_LONG_RUN)) { + if (hufLength(hcode[im + 1]) > 0) break; + im++; + zerun++; + } + + if (zerun >= 2) { + if (zerun >= SHORTEST_LONG_RUN) { + outputBits(6, LONG_ZEROCODE_RUN, c, lc, p); + outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p); + } else { + outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p); + } + continue; + } + } + + outputBits(6, l, c, lc, p); + } + + if (lc > 0) *p++ = (unsigned char)(c << (8 - lc)); + + *pcode = p; +} + +// +// Unpack an encoding table packed by hufPackEncTable(): +// + +static bool hufUnpackEncTable( + const char **pcode, // io: ptr to packed table (updated) + int ni, // i : input size (in bytes) + int im, // i : min hcode index + int iM, // i : max hcode index + long long *hcode) // o: encoding table [HUF_ENCSIZE] +{ + memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE); + + const char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + if (p - *pcode >= ni) { + return false; + } + + long long l = hcode[im] = getBits(6, c, lc, p); // code length + + if (l == (long long)LONG_ZEROCODE_RUN) { + if (p - *pcode > ni) { + return false; + } + + int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } else if (l >= (long long)SHORT_ZEROCODE_RUN) { + int zerun = l - SHORT_ZEROCODE_RUN + 2; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } + } + + *pcode = const_cast(p); + + hufCanonicalCodeTable(hcode); + + return true; +} + +// +// DECODING TABLE BUILDING +// + +// +// Clear a newly allocated decoding table so that it contains only zeroes. +// + +static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + hdecod[i].len = 0; + hdecod[i].lit = 0; + hdecod[i].p = NULL; + } + // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE); +} + +// +// Build a decoding hash table based on the encoding table hcode: +// - short codes (<= HUF_DECBITS) are resolved with a single table access; +// - long code entry allocations are not optimized, because long codes are +// unfrequent; +// - decoding tables are used by hufDecode(); +// + +static bool hufBuildDecTable(const long long *hcode, // i : encoding table + int im, // i : min index in hcode + int iM, // i : max index in hcode + HufDec *hdecod) // o: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + // + // Init hashtable & loop on all codes. + // Assumes that hufClearDecTable(hdecod) has already been called. + // + + for (; im <= iM; im++) { + long long c = hufCode(hcode[im]); + int l = hufLength(hcode[im]); + + if (c >> l) { + // + // Error: c is supposed to be an l-bit code, + // but c contains a value that is greater + // than the largest l-bit number. + // + + // invalidTableEntry(); + return false; + } + + if (l > HUF_DECBITS) { + // + // Long code: add a secondary entry + // + + HufDec *pl = hdecod + (c >> (l - HUF_DECBITS)); + + if (pl->len) { + // + // Error: a short code has already + // been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->lit++; + + if (pl->p) { + unsigned int *p = pl->p; + pl->p = new unsigned int[pl->lit]; + + for (unsigned int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i]; + + delete[] p; + } else { + pl->p = new unsigned int[1]; + } + + pl->p[pl->lit - 1] = im; + } else if (l) { + // + // Short code: init all primary entries + // + + HufDec *pl = hdecod + (c << (HUF_DECBITS - l)); + + for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) { + if (pl->len || pl->p) { + // + // Error: a short code or a long code has + // already been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->len = l; + pl->lit = im; + } + } + } + + return true; +} + +// +// Free the long code entries of a decoding table built by hufBuildDecTable() +// + +static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + if (hdecod[i].p) { + delete[] hdecod[i].p; + hdecod[i].p = 0; + } + } +} + +// +// ENCODING +// + +inline void outputCode(long long code, long long &c, int &lc, char *&out) { + outputBits(hufLength(code), hufCode(code), c, lc, out); +} + +inline void sendCode(long long sCode, int runCount, long long runCode, + long long &c, int &lc, char *&out) { + // + // Output a run of runCount instances of the symbol sCount. + // Output the symbols explicitly, or if that is shorter, output + // the sCode symbol once followed by a runCode symbol and runCount + // expressed as an 8-bit number. + // + + if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) { + outputCode(sCode, c, lc, out); + outputCode(runCode, c, lc, out); + outputBits(8, runCount, c, lc, out); + } else { + while (runCount-- >= 0) outputCode(sCode, c, lc, out); + } +} + +// +// Encode (compress) ni values based on the Huffman encoding table hcode: +// + +static int hufEncode // return: output size (in bits) + (const long long *hcode, // i : encoding table + const unsigned short *in, // i : uncompressed input buffer + const int ni, // i : input buffer size (in bytes) + int rlc, // i : rl code + char *out) // o: compressed output buffer +{ + char *outStart = out; + long long c = 0; // bits not yet written to out + int lc = 0; // number of valid bits in c (LSB) + int s = in[0]; + int cs = 0; + + // + // Loop on input values + // + + for (int i = 1; i < ni; i++) { + // + // Count same values or send code + // + + if (s == in[i] && cs < 255) { + cs++; + } else { + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + cs = 0; + } + + s = in[i]; + } + + // + // Send remaining code + // + + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + + if (lc) *out = (c << (8 - lc)) & 0xff; + + return (out - outStart) * 8 + lc; +} + +// +// DECODING +// + +// +// In order to force the compiler to inline them, +// getChar() and getCode() are implemented as macros +// instead of "inline" functions. +// + +#define getChar(c, lc, in) \ + { \ + c = (c << 8) | *(unsigned char *)(in++); \ + lc += 8; \ + } + +#if 0 +#define getCode(po, rlc, c, lc, in, out, ob, oe) \ + { \ + if (po == rlc) { \ + if (lc < 8) getChar(c, lc, in); \ + \ + lc -= 8; \ + \ + unsigned char cs = (c >> lc); \ + \ + if (out + cs > oe) return false; \ + \ + /* TinyEXR issue 78 */ \ + unsigned short s = out[-1]; \ + \ + while (cs-- > 0) *out++ = s; \ + } else if (out < oe) { \ + *out++ = po; \ + } else { \ + return false; \ + } \ + } +#else +static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in, + const char *in_end, unsigned short *&out, + const unsigned short *ob, const unsigned short *oe) { + (void)ob; + if (po == rlc) { + if (lc < 8) { + /* TinyEXR issue 78 */ + if ((in + 1) >= in_end) { + return false; + } + + getChar(c, lc, in); + } + + lc -= 8; + + unsigned char cs = (c >> lc); + + if (out + cs > oe) return false; + + // Bounds check for safety + // Issue 100. + if ((out - 1) < ob) return false; + unsigned short s = out[-1]; + + while (cs-- > 0) *out++ = s; + } else if (out < oe) { + *out++ = po; + } else { + return false; + } + return true; +} +#endif + +// +// Decode (uncompress) ni bits based on encoding & decoding tables: +// + +static bool hufDecode(const long long *hcode, // i : encoding table + const HufDec *hdecod, // i : decoding table + const char *in, // i : compressed input buffer + int ni, // i : input size (in bits) + int rlc, // i : run-length code + int no, // i : expected output size (in bytes) + unsigned short *out) // o: uncompressed output buffer +{ + long long c = 0; + int lc = 0; + unsigned short *outb = out; // begin + unsigned short *oe = out + no; // end + const char *ie = in + (ni + 7) / 8; // input byte size + + // + // Loop on input bytes + // + + while (in < ie) { + getChar(c, lc, in); + + // + // Access decoding table + // + + while (lc >= HUF_DECBITS) { + const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK]; + + if (pl.len) { + // + // Get short code + // + + lc -= pl.len; + // std::cout << "lit = " << pl.lit << std::endl; + // std::cout << "rlc = " << rlc << std::endl; + // std::cout << "c = " << c << std::endl; + // std::cout << "lc = " << lc << std::endl; + // std::cout << "in = " << in << std::endl; + // std::cout << "out = " << out << std::endl; + // std::cout << "oe = " << oe << std::endl; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + if (!pl.p) { + return false; + } + // invalidCode(); // wrong code + + // + // Search long code + // + + unsigned int j; + + for (j = 0; j < pl.lit; j++) { + int l = hufLength(hcode[pl.p[j]]); + + while (lc < l && in < ie) // get more bits + getChar(c, lc, in); + + if (lc >= l) { + if (hufCode(hcode[pl.p[j]]) == + ((c >> (lc - l)) & (((long long)(1) << l) - 1))) { + // + // Found : get long code + // + + lc -= l; + if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + break; + } + } + } + + if (j == pl.lit) { + return false; + // invalidCode(); // Not found + } + } + } + } + + // + // Get remaining (short) codes + // + + int i = (8 - ni) & 7; + c >>= i; + lc -= i; + + while (lc > 0) { + const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK]; + + if (pl.len) { + lc -= pl.len; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + return false; + // invalidCode(); // wrong (long) code + } + } + + if (out - outb != no) { + return false; + } + // notEnoughData (); + + return true; +} + +static void countFrequencies(std::vector &freq, + const unsigned short data[/*n*/], int n) { + for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0; + + for (int i = 0; i < n; ++i) ++freq[data[i]]; +} + +static void writeUInt(char buf[4], unsigned int i) { + unsigned char *b = (unsigned char *)buf; + + b[0] = i; + b[1] = i >> 8; + b[2] = i >> 16; + b[3] = i >> 24; +} + +static unsigned int readUInt(const char buf[4]) { + const unsigned char *b = (const unsigned char *)buf; + + return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) | + ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000); +} + +// +// EXTERNAL INTERFACE +// + +static int hufCompress(const unsigned short raw[], int nRaw, + char compressed[]) { + if (nRaw == 0) return 0; + + std::vector freq(HUF_ENCSIZE); + + countFrequencies(freq, raw, nRaw); + + int im = 0; + int iM = 0; + hufBuildEncTable(freq.data(), &im, &iM); + + char *tableStart = compressed + 20; + char *tableEnd = tableStart; + hufPackEncTable(freq.data(), im, iM, &tableEnd); + int tableLength = tableEnd - tableStart; + + char *dataStart = tableEnd; + int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart); + int data_length = (nBits + 7) / 8; + + writeUInt(compressed, im); + writeUInt(compressed + 4, iM); + writeUInt(compressed + 8, tableLength); + writeUInt(compressed + 12, nBits); + writeUInt(compressed + 16, 0); // room for future extensions + + return dataStart + data_length - compressed; +} + +static bool hufUncompress(const char compressed[], int nCompressed, + std::vector *raw) { + if (nCompressed == 0) { + if (raw->size() != 0) return false; + + return false; + } + + int im = readUInt(compressed); + int iM = readUInt(compressed + 4); + // int tableLength = readUInt (compressed + 8); + int nBits = readUInt(compressed + 12); + + if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false; + + const char *ptr = compressed + 20; + + // + // Fast decoder needs at least 2x64-bits of compressed data, and + // needs to be run-able on this platform. Otherwise, fall back + // to the original decoder + // + + // if (FastHufDecoder::enabled() && nBits > 128) + //{ + // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM); + // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw); + //} + // else + { + std::vector freq(HUF_ENCSIZE); + std::vector hdec(HUF_DECSIZE); + + hufClearDecTable(&hdec.at(0)); + + hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM, + &freq.at(0)); + + { + if (nBits > 8 * (nCompressed - (ptr - compressed))) { + return false; + } + + hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0)); + hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(), + raw->data()); + } + // catch (...) + //{ + // hufFreeDecTable (hdec); + // throw; + //} + + hufFreeDecTable(&hdec.at(0)); + } + + return true; +} + +// +// Functions to compress the range of values in the pixel data +// + +const int USHORT_RANGE = (1 << 16); +const int BITMAP_SIZE = (USHORT_RANGE >> 3); + +static void bitmapFromData(const unsigned short data[/*nData*/], int nData, + unsigned char bitmap[BITMAP_SIZE], + unsigned short &minNonZero, + unsigned short &maxNonZero) { + for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0; + + for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7)); + + bitmap[0] &= ~1; // zero is not explicitly stored in + // the bitmap; we assume that the + // data always contain zeroes + minNonZero = BITMAP_SIZE - 1; + maxNonZero = 0; + + for (int i = 0; i < BITMAP_SIZE; ++i) { + if (bitmap[i]) { + if (minNonZero > i) minNonZero = i; + if (maxNonZero < i) maxNonZero = i; + } + } +} + +static unsigned short forwardLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) + lut[i] = k++; + else + lut[i] = 0; + } + + return k - 1; // maximum value stored in lut[], +} // i.e. number of ones in bitmap minus 1 + +static unsigned short reverseLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i; + } + + int n = k - 1; + + while (k < USHORT_RANGE) lut[k++] = 0; + + return n; // maximum k where lut[k] is non-zero, +} // i.e. number of ones in bitmap minus 1 + +static void applyLut(const unsigned short lut[USHORT_RANGE], + unsigned short data[/*nData*/], int nData) { + for (int i = 0; i < nData; ++i) data[i] = lut[data[i]]; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, + const unsigned char *inPtr, size_t inSize, + const std::vector &channelInfo, + int data_width, int num_lines) { + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + // Assume `inSize` is multiple of 2 or 4. + std::vector tmpBuffer(inSize / sizeof(unsigned short)); + + std::vector channelData(channelInfo.size()); + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t c = 0; c < channelData.size(); c++) { + PIZChannelData &cd = channelData[c]; + + cd.start = tmpBufferEnd; + cd.end = cd.start; + + cd.nx = data_width; + cd.ny = num_lines; + // cd.ys = c.channel().ySampling; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + cd.size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += cd.nx * cd.ny * cd.size; + } + + const unsigned char *ptr = inPtr; + for (int y = 0; y < num_lines; ++y) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(cd.end, ptr, n * sizeof(unsigned short)); + ptr += n * sizeof(unsigned short); + cd.end += n; + } + } + + bitmapFromData(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), + bitmap.data(), minNonZero, maxNonZero); + + std::vector lut(USHORT_RANGE); + unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data()); + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBuffer.size())); + + // + // Store range compression info in _outBuffer + // + + char *buf = reinterpret_cast(outPtr); + + memcpy(buf, &minNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + memcpy(buf, &maxNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + + if (minNonZero <= maxNonZero) { + memcpy(buf, reinterpret_cast(&bitmap[0] + minNonZero), + maxNonZero - minNonZero + 1); + buf += maxNonZero - minNonZero + 1; + } + + // + // Apply wavelet encoding + // + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Apply Huffman encoding; append the result to _outBuffer + // + + // length header(4byte), then huff data. Initialize length header with zero, + // then later fill it by `length`. + char *lengthPtr = buf; + int zero = 0; + memcpy(buf, &zero, sizeof(int)); + buf += sizeof(int); + + int length = + hufCompress(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), buf); + memcpy(lengthPtr, &length, sizeof(int)); + + (*outSize) = static_cast( + (reinterpret_cast(buf) - outPtr) + + static_cast(length)); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if ((*outSize) >= inSize) { + (*outSize) = static_cast(inSize); + memcpy(outPtr, inPtr, inSize); + } + return true; +} + +static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, + size_t tmpBufSize, size_t inLen, int num_channels, + const EXRChannelInfo *channels, int data_width, + int num_lines) { + if (inLen == tmpBufSize) { + // Data is not compressed(Issue 40). + memcpy(outPtr, inPtr, inLen); + return true; + } + + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + memset(bitmap.data(), 0, BITMAP_SIZE); + + const unsigned char *ptr = inPtr; + // minNonZero = *(reinterpret_cast(ptr)); + tinyexr::cpy2(&minNonZero, reinterpret_cast(ptr)); + // maxNonZero = *(reinterpret_cast(ptr + 2)); + tinyexr::cpy2(&maxNonZero, reinterpret_cast(ptr + 2)); + ptr += 4; + + if (maxNonZero >= BITMAP_SIZE) { + return false; + } + + if (minNonZero <= maxNonZero) { + memcpy(reinterpret_cast(&bitmap[0] + minNonZero), ptr, + maxNonZero - minNonZero + 1); + ptr += maxNonZero - minNonZero + 1; + } + + std::vector lut(USHORT_RANGE); + memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE); + unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data()); + + // + // Huffman decoding + // + + int length; + + // length = *(reinterpret_cast(ptr)); + tinyexr::cpy4(&length, reinterpret_cast(ptr)); + ptr += sizeof(int); + + if (size_t((ptr - inPtr) + length) > inLen) { + return false; + } + + std::vector tmpBuffer(tmpBufSize); + hufUncompress(reinterpret_cast(ptr), length, &tmpBuffer); + + // + // Wavelet decoding + // + + std::vector channelData(static_cast(num_channels)); + + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t i = 0; i < static_cast(num_channels); ++i) { + const EXRChannelInfo &chan = channels[i]; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + channelData[i].start = tmpBufferEnd; + channelData[i].end = channelData[i].start; + channelData[i].nx = data_width; + channelData[i].ny = num_lines; + // channelData[i].ys = 1; + channelData[i].size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size; + } + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Expand the pixel data to their original range + // + + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBufSize)); + + for (int y = 0; y < num_lines; y++) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(outPtr, cd.end, static_cast(n * sizeof(unsigned short))); + outPtr += n * sizeof(unsigned short); + cd.end += n; + } + } + + return true; +} +#endif // TINYEXR_USE_PIZ + +#if TINYEXR_USE_ZFP + +struct ZFPCompressionParam { + double rate; + unsigned int precision; + unsigned int __pad0; + double tolerance; + int type; // TINYEXR_ZFP_COMPRESSIONTYPE_* + unsigned int __pad1; + + ZFPCompressionParam() { + type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE; + rate = 2.0; + precision = 0; + tolerance = 0.0; + } +}; + +static bool FindZFPCompressionParam(ZFPCompressionParam *param, + const EXRAttribute *attributes, + int num_attributes, std::string *err) { + bool foundType = false; + + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionType") == 0)) { + if (attributes[i].size == 1) { + param->type = static_cast(attributes[i].value[0]); + foundType = true; + break; + } else { + if (err) { + (*err) += + "zfpCompressionType attribute must be uchar(1 byte) type.\n"; + } + return false; + } + } + } + + if (!foundType) { + if (err) { + (*err) += "`zfpCompressionType` attribute not found.\n"; + } + return false; + } + + if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) && + (attributes[i].size == 8)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionRate` attribute not found.\n"; + } + + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) && + (attributes[i].size == 4)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionPrecision` attribute not found.\n"; + } + + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) && + (attributes[i].size == 8)) { + param->tolerance = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionTolerance` attribute not found.\n"; + } + } else { + if (err) { + (*err) += "Unknown value specified for `zfpCompressionType`.\n"; + } + } + + return false; +} + +// Assume pixel format is FLOAT for all channels. +static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, + size_t num_channels, const unsigned char *src, + unsigned long src_size, + const ZFPCompressionParam ¶m) { + size_t uncompressed_size = + size_t(dst_width) * size_t(dst_num_lines) * num_channels; + + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + } + + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((dst_width % 4) == 0); + assert((dst_num_lines % 4) == 0); + + if ((size_t(dst_width) & 3U) || (size_t(dst_num_lines) & 3U)) { + return false; + } + + field = + zfp_field_2d(reinterpret_cast(const_cast(src)), + zfp_type_float, static_cast(dst_width), + static_cast(dst_num_lines) * + static_cast(num_channels)); + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimension */ 2, + /* write random access */ 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + std::vector buf(buf_size); + memcpy(&buf.at(0), src, src_size); + + bitstream *stream = stream_open(&buf.at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_stream_rewind(zfp); + + size_t image_size = size_t(dst_width) * size_t(dst_num_lines); + + for (size_t c = 0; c < size_t(num_channels); c++) { + // decompress 4x4 pixel block. + for (size_t y = 0; y < size_t(dst_num_lines); y += 4) { + for (size_t x = 0; x < size_t(dst_width); x += 4) { + float fblock[16]; + zfp_decode_block_float_2(zfp, fblock); + for (size_t j = 0; j < 4; j++) { + for (size_t i = 0; i < 4; i++) { + dst[c * image_size + ((y + j) * size_t(dst_width) + (x + i))] = + fblock[j * 4 + i]; + } + } + } + } + } + + zfp_field_free(field); + zfp_stream_close(zfp); + stream_close(stream); + + return true; +} + +// Assume pixel format is FLOAT for all channels. +static bool CompressZfp(std::vector *outBuf, + unsigned int *outSize, const float *inPtr, int width, + int num_lines, int num_channels, + const ZFPCompressionParam ¶m) { + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((width % 4) == 0); + assert((num_lines % 4) == 0); + + if ((size_t(width) & 3U) || (size_t(num_lines) & 3U)) { + return false; + } + + // create input array. + field = zfp_field_2d(reinterpret_cast(const_cast(inPtr)), + zfp_type_float, static_cast(width), + static_cast(num_lines * num_channels)); + + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + + outBuf->resize(buf_size); + + bitstream *stream = stream_open(&outBuf->at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_field_free(field); + + size_t image_size = size_t(width) * size_t(num_lines); + + for (size_t c = 0; c < size_t(num_channels); c++) { + // compress 4x4 pixel block. + for (size_t y = 0; y < size_t(num_lines); y += 4) { + for (size_t x = 0; x < size_t(width); x += 4) { + float fblock[16]; + for (size_t j = 0; j < 4; j++) { + for (size_t i = 0; i < 4; i++) { + fblock[j * 4 + i] = + inPtr[c * image_size + ((y + j) * size_t(width) + (x + i))]; + } + } + zfp_encode_block_float_2(zfp, fblock); + } + } + } + + zfp_stream_flush(zfp); + (*outSize) = static_cast(zfp_stream_compressed_size(zfp)); + + zfp_stream_close(zfp); + + return true; +} + +#endif + +// +// ----------------------------------------------------------------- +// + +// heuristics +#define TINYEXR_DIMENSION_THRESHOLD (1024 * 8192) + +// TODO(syoyo): Refactor function arguments. +static bool DecodePixelData(/* out */ unsigned char **out_images, + const int *requested_pixel_types, + const unsigned char *data_ptr, size_t data_len, + int compression_type, int line_order, int width, + int height, int x_stride, int y, int line_no, + int num_lines, size_t pixel_data_size, + size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ +#if TINYEXR_USE_PIZ + if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) { + // Invalid input #90 + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast( + static_cast(width * num_lines) * pixel_data_size)); + size_t tmpBufLen = outBuf.size(); + + bool ret = tinyexr::DecompressPiz( + reinterpret_cast(&outBuf.at(0)), data_ptr, tmpBufLen, + data_len, static_cast(num_channels), channels, width, num_lines); + + if (!ret) { + return false; + } + + // For PIZ_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + FP16 hf; + + // hf.u = line_ptr[u]; + // use `cpy` to avoid unaligned memory access when compiler's + // optimization is on. + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + image += offset; + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast(&outBuf.at( + v * pixel_data_size * static_cast(x_stride) + + channel_offset_list[c] * static_cast(x_stride))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + } + } +#else + assert(0 && "PIZ is enabled in this build"); + return false; +#endif + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS || + compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + assert(dstLen > 0); + if (!tinyexr::DecompressZip( + reinterpret_cast(&outBuf.at(0)), &dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For ZIP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + image += offset; + + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + if (dstLen == 0) { + return false; + } + + if (!tinyexr::DecompressRle( + reinterpret_cast(&outBuf.at(0)), dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For RLE_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + std::string e; + if (!tinyexr::FindZFPCompressionParam(&zfp_compression_param, attributes, + int(num_attributes), &e)) { + // This code path should not be reachable. + assert(0); + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = outBuf.size(); + assert(dstLen > 0); + tinyexr::DecompressZfp(reinterpret_cast(&outBuf.at(0)), width, + num_lines, num_channels, data_ptr, + static_cast(data_len), + zfp_compression_param); + + // For ZFP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } +#else + (void)attributes; + (void)num_attributes; + (void)num_channels; + assert(0); + return false; +#endif + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + for (size_t c = 0; c < num_channels; c++) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + const unsigned short *line_ptr = + reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + outLine[u] = hf.u; + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // address may not be aliged. use byte-wise copy for safety.#76 + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + tinyexr::FP32 f32 = half_to_float(hf); + + outLine[u] = f32.f; + } + } else { + assert(0); + return false; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + const float *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + const unsigned int *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + unsigned int *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + if (reinterpret_cast(line_ptr + u) >= + (data_ptr + data_len)) { + // Corrupsed data? + return false; + } + + unsigned int val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } + } + } + } + + return true; +} + +static bool DecodeTiledPixelData( + unsigned char **out_images, int *width, int *height, + const int *requested_pixel_types, const unsigned char *data_ptr, + size_t data_len, int compression_type, int line_order, int data_width, + int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x, + int tile_size_y, size_t pixel_data_size, size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + // Here, data_width and data_height are the dimensions of the current (sub)level. + if (tile_size_x * tile_offset_x > data_width || + tile_size_y * tile_offset_y > data_height) { + return false; + } + + // Compute actual image size in a tile. + if ((tile_offset_x + 1) * tile_size_x >= data_width) { + (*width) = data_width - (tile_offset_x * tile_size_x); + } else { + (*width) = tile_size_x; + } + + if ((tile_offset_y + 1) * tile_size_y >= data_height) { + (*height) = data_height - (tile_offset_y * tile_size_y); + } else { + (*height) = tile_size_y; + } + + // Image size = tile size. + return DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len, + compression_type, line_order, (*width), tile_size_y, + /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0, + (*height), pixel_data_size, num_attributes, attributes, + num_channels, channels, channel_offset_list); +} + +static bool ComputeChannelLayout(std::vector *channel_offset_list, + int *pixel_data_size, size_t *channel_offset, + int num_channels, + const EXRChannelInfo *channels) { + channel_offset_list->resize(static_cast(num_channels)); + + (*pixel_data_size) = 0; + (*channel_offset) = 0; + + for (size_t c = 0; c < static_cast(num_channels); c++) { + (*channel_offset_list)[c] = (*channel_offset); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + (*pixel_data_size) += sizeof(unsigned short); + (*channel_offset) += sizeof(unsigned short); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + (*pixel_data_size) += sizeof(float); + (*channel_offset) += sizeof(float); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + (*pixel_data_size) += sizeof(unsigned int); + (*channel_offset) += sizeof(unsigned int); + } else { + // ??? + return false; + } + } + return true; +} + +static unsigned char **AllocateImage(int num_channels, + const EXRChannelInfo *channels, + const int *requested_pixel_types, + int data_width, int data_height) { + unsigned char **images = + reinterpret_cast(static_cast( + malloc(sizeof(float *) * static_cast(num_channels)))); + + for (size_t c = 0; c < static_cast(num_channels); c++) { + size_t data_len = + static_cast(data_width) * static_cast(data_height); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + // pixel_data_size += sizeof(unsigned short); + // channel_offset += sizeof(unsigned short); + // Alloc internal image for half type. + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + images[c] = + reinterpret_cast(static_cast( + malloc(sizeof(unsigned short) * data_len))); + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else { + assert(0); + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + // pixel_data_size += sizeof(float); + // channel_offset += sizeof(float); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + // pixel_data_size += sizeof(unsigned int); + // channel_offset += sizeof(unsigned int); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(unsigned int) * data_len))); + } else { + assert(0); + } + } + + return images; +} + +#ifdef _WIN32 +static inline std::wstring UTF8ToWchar(const std::string &str) { + int wstr_size = + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), NULL, 0); + std::wstring wstr(wstr_size, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0], + (int)wstr.size()); + return wstr; +} +#endif + + +static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, + const EXRVersion *version, std::string *err, + const unsigned char *buf, size_t size) { + const char *marker = reinterpret_cast(&buf[0]); + + if (empty_header) { + (*empty_header) = false; + } + + if (version->multipart) { + if (size > 0 && marker[0] == '\0') { + // End of header list. + if (empty_header) { + (*empty_header) = true; + } + return TINYEXR_SUCCESS; + } + } + + // According to the spec, the header of every OpenEXR file must contain at + // least the following attributes: + // + // channels chlist + // compression compression + // dataWindow box2i + // displayWindow box2i + // lineOrder lineOrder + // pixelAspectRatio float + // screenWindowCenter v2f + // screenWindowWidth float + bool has_channels = false; + bool has_compression = false; + bool has_data_window = false; + bool has_display_window = false; + bool has_line_order = false; + bool has_pixel_aspect_ratio = false; + bool has_screen_window_center = false; + bool has_screen_window_width = false; + bool has_name = false; + bool has_type = false; + + info->name.clear(); + info->type.clear(); + + info->data_window.min_x = 0; + info->data_window.min_y = 0; + info->data_window.max_x = 0; + info->data_window.max_y = 0; + info->line_order = 0; // @fixme + info->display_window.min_x = 0; + info->display_window.min_y = 0; + info->display_window.max_x = 0; + info->display_window.max_y = 0; + info->screen_window_center[0] = 0.0f; + info->screen_window_center[1] = 0.0f; + info->screen_window_width = -1.0f; + info->pixel_aspect_ratio = -1.0f; + + info->tiled = 0; + info->tile_size_x = -1; + info->tile_size_y = -1; + info->tile_level_mode = -1; + info->tile_rounding_mode = -1; + + info->attributes.clear(); + + // Read attributes + size_t orig_size = size; + for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) { + if (0 == size) { + if (err) { + (*err) += "Insufficient data size for attributes.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + if (err) { + (*err) += "Failed to read attribute.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + // For a multipart file, the version field 9th bit is 0. + if ((version->tiled || version->multipart || version->non_image) && attr_name.compare("tiles") == 0) { + unsigned int x_size, y_size; + unsigned char tile_mode; + assert(data.size() == 9); + memcpy(&x_size, &data.at(0), sizeof(int)); + memcpy(&y_size, &data.at(4), sizeof(int)); + tile_mode = data[8]; + tinyexr::swap4(&x_size); + tinyexr::swap4(&y_size); + + if (x_size > static_cast(std::numeric_limits::max()) || + y_size > static_cast(std::numeric_limits::max())) { + if (err) { + (*err) = "Tile sizes were invalid."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + info->tile_size_x = static_cast(x_size); + info->tile_size_y = static_cast(y_size); + + // mode = levelMode + roundingMode * 16 + info->tile_level_mode = tile_mode & 0x3; + info->tile_rounding_mode = (tile_mode >> 4) & 0x1; + info->tiled = 1; + } else if (attr_name.compare("compression") == 0) { + bool ok = false; + if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { + ok = true; + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + ok = true; +#else + if (err) { + (*err) = "PIZ compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + ok = true; +#else + if (err) { + (*err) = "ZFP compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (!ok) { + if (err) { + (*err) = "Unknown compression type."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + info->compression_type = static_cast(data[0]); + has_compression = true; + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!ReadChannelInfo(info->channels, data)) { + if (err) { + (*err) += "Failed to parse channel info.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (info->channels.size() < 1) { + if (err) { + (*err) += "# of channels is zero.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + has_channels = true; + + } else if (attr_name.compare("dataWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->data_window.min_x, &data.at(0), sizeof(int)); + memcpy(&info->data_window.min_y, &data.at(4), sizeof(int)); + memcpy(&info->data_window.max_x, &data.at(8), sizeof(int)); + memcpy(&info->data_window.max_y, &data.at(12), sizeof(int)); + tinyexr::swap4(&info->data_window.min_x); + tinyexr::swap4(&info->data_window.min_y); + tinyexr::swap4(&info->data_window.max_x); + tinyexr::swap4(&info->data_window.max_y); + has_data_window = true; + } + } else if (attr_name.compare("displayWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->display_window.min_x, &data.at(0), sizeof(int)); + memcpy(&info->display_window.min_y, &data.at(4), sizeof(int)); + memcpy(&info->display_window.max_x, &data.at(8), sizeof(int)); + memcpy(&info->display_window.max_y, &data.at(12), sizeof(int)); + tinyexr::swap4(&info->display_window.min_x); + tinyexr::swap4(&info->display_window.min_y); + tinyexr::swap4(&info->display_window.max_x); + tinyexr::swap4(&info->display_window.max_y); + + has_display_window = true; + } + } else if (attr_name.compare("lineOrder") == 0) { + if (data.size() >= 1) { + info->line_order = static_cast(data[0]); + has_line_order = true; + } + } else if (attr_name.compare("pixelAspectRatio") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); + tinyexr::swap4(&info->pixel_aspect_ratio); + has_pixel_aspect_ratio = true; + } + } else if (attr_name.compare("screenWindowCenter") == 0) { + if (data.size() >= 8) { + memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); + memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); + tinyexr::swap4(&info->screen_window_center[0]); + tinyexr::swap4(&info->screen_window_center[1]); + has_screen_window_center = true; + } + } else if (attr_name.compare("screenWindowWidth") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); + tinyexr::swap4(&info->screen_window_width); + + has_screen_window_width = true; + } + } else if (attr_name.compare("chunkCount") == 0) { + if (data.size() >= sizeof(int)) { + memcpy(&info->chunk_count, &data.at(0), sizeof(int)); + tinyexr::swap4(&info->chunk_count); + } + } else if (attr_name.compare("name") == 0) { + if (!data.empty() && data[0]) { + data.push_back(0); + size_t len = strlen(reinterpret_cast(&data[0])); + info->name.resize(len); + info->name.assign(reinterpret_cast(&data[0]), len); + has_name = true; + } + } else if (attr_name.compare("type") == 0) { + if (!data.empty() && data[0]) { + data.push_back(0); + size_t len = strlen(reinterpret_cast(&data[0])); + info->type.resize(len); + info->type.assign(reinterpret_cast(&data[0]), len); + has_type = true; + } + } else { + // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES) + if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + EXRAttribute attrib; +#ifdef _MSC_VER + strncpy_s(attrib.name, attr_name.c_str(), 255); + strncpy_s(attrib.type, attr_type.c_str(), 255); +#else + strncpy(attrib.name, attr_name.c_str(), 255); + strncpy(attrib.type, attr_type.c_str(), 255); +#endif + attrib.name[255] = '\0'; + attrib.type[255] = '\0'; + attrib.size = static_cast(data.size()); + attrib.value = static_cast(malloc(data.size())); + memcpy(reinterpret_cast(attrib.value), &data.at(0), + data.size()); + info->attributes.push_back(attrib); + } + } + } + + // Check if required attributes exist + { + std::stringstream ss_err; + + if (!has_compression) { + ss_err << "\"compression\" attribute not found in the header." + << std::endl; + } + + if (!has_channels) { + ss_err << "\"channels\" attribute not found in the header." << std::endl; + } + + if (!has_line_order) { + ss_err << "\"lineOrder\" attribute not found in the header." << std::endl; + } + + if (!has_display_window) { + ss_err << "\"displayWindow\" attribute not found in the header." + << std::endl; + } + + if (!has_data_window) { + ss_err << "\"dataWindow\" attribute not found in the header or invalid." + << std::endl; + } + + if (!has_pixel_aspect_ratio) { + ss_err << "\"pixelAspectRatio\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_width) { + ss_err << "\"screenWindowWidth\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_center) { + ss_err << "\"screenWindowCenter\" attribute not found in the header." + << std::endl; + } + + if (version->multipart || version->non_image) { + if (!has_name) { + ss_err << "\"name\" attribute not found in the header." + << std::endl; + } + if (!has_type) { + ss_err << "\"type\" attribute not found in the header." + << std::endl; + } + } + + if (!(ss_err.str().empty())) { + if (err) { + (*err) += ss_err.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + } + + info->header_len = static_cast(orig_size - size); + + return TINYEXR_SUCCESS; +} + +// C++ HeaderInfo to C EXRHeader conversion. +static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { + exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio; + exr_header->screen_window_center[0] = info.screen_window_center[0]; + exr_header->screen_window_center[1] = info.screen_window_center[1]; + exr_header->screen_window_width = info.screen_window_width; + exr_header->chunk_count = info.chunk_count; + exr_header->display_window.min_x = info.display_window.min_x; + exr_header->display_window.min_y = info.display_window.min_y; + exr_header->display_window.max_x = info.display_window.max_x; + exr_header->display_window.max_y = info.display_window.max_y; + exr_header->data_window.min_x = info.data_window.min_x; + exr_header->data_window.min_y = info.data_window.min_y; + exr_header->data_window.max_x = info.data_window.max_x; + exr_header->data_window.max_y = info.data_window.max_y; + exr_header->line_order = info.line_order; + exr_header->compression_type = info.compression_type; + exr_header->tiled = info.tiled; + exr_header->tile_size_x = info.tile_size_x; + exr_header->tile_size_y = info.tile_size_y; + exr_header->tile_level_mode = info.tile_level_mode; + exr_header->tile_rounding_mode = info.tile_rounding_mode; + + EXRSetNameAttr(exr_header, info.name.c_str()); + + if (!info.type.empty()) { + if (info.type == "scanlineimage") { + assert(!exr_header->tiled); + } else if (info.type == "tiledimage") { + assert(exr_header->tiled); + } else if (info.type == "deeptile") { + exr_header->non_image = 1; + assert(exr_header->tiled); + } else if (info.type == "deepscanline") { + exr_header->non_image = 1; + assert(!exr_header->tiled); + } else { + assert(false); + } + } + + exr_header->num_channels = static_cast(info.channels.size()); + + exr_header->channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { +#ifdef _MSC_VER + strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#else + strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#endif + // manually add '\0' for safety. + exr_header->channels[c].name[255] = '\0'; + + exr_header->channels[c].pixel_type = info.channels[c].pixel_type; + exr_header->channels[c].p_linear = info.channels[c].p_linear; + exr_header->channels[c].x_sampling = info.channels[c].x_sampling; + exr_header->channels[c].y_sampling = info.channels[c].y_sampling; + } + + exr_header->pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->pixel_types[c] = info.channels[c].pixel_type; + } + + // Initially fill with values of `pixel_types` + exr_header->requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->requested_pixel_types[c] = info.channels[c].pixel_type; + } + + exr_header->num_custom_attributes = static_cast(info.attributes.size()); + + if (exr_header->num_custom_attributes > 0) { + // TODO(syoyo): Report warning when # of attributes exceeds + // `TINYEXR_MAX_CUSTOM_ATTRIBUTES` + if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES; + } + + exr_header->custom_attributes = static_cast(malloc( + sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes))); + + for (size_t i = 0; i < info.attributes.size(); i++) { + memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, + 256); + memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, + 256); + exr_header->custom_attributes[i].size = info.attributes[i].size; + // Just copy pointer + exr_header->custom_attributes[i].value = info.attributes[i].value; + } + + } else { + exr_header->custom_attributes = NULL; + } + + exr_header->header_len = info.header_len; +} + +struct OffsetData { + OffsetData() : num_x_levels(0), num_y_levels(0) {} + std::vector > > offsets; + int num_x_levels; + int num_y_levels; +}; + +int LevelIndex(int lx, int ly, int tile_level_mode, int num_x_levels) { + switch (tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + return 0; + + case TINYEXR_TILE_MIPMAP_LEVELS: + return lx; + + case TINYEXR_TILE_RIPMAP_LEVELS: + return lx + ly * num_x_levels; + + default: + assert(false); + } + return 0; +} + +static int LevelSize(int toplevel_size, int level, int tile_rounding_mode) { + assert(level >= 0); + + int b = (int)(1u << (unsigned)level); + int level_size = toplevel_size / b; + + if (tile_rounding_mode == TINYEXR_TILE_ROUND_UP && level_size * b < toplevel_size) + level_size += 1; + + return std::max(level_size, 1); +} + +static int DecodeTiledLevel(EXRImage* exr_image, const EXRHeader* exr_header, + const OffsetData& offset_data, + const std::vector& channel_offset_list, + int pixel_data_size, + const unsigned char* head, const size_t size, + std::string* err) { + int num_channels = exr_header->num_channels; + + int level_index = LevelIndex(exr_image->level_x, exr_image->level_y, exr_header->tile_level_mode, offset_data.num_x_levels); + int num_y_tiles = (int)offset_data.offsets[level_index].size(); + assert(num_y_tiles); + int num_x_tiles = (int)offset_data.offsets[level_index][0].size(); + assert(num_x_tiles); + int num_tiles = num_x_tiles * num_y_tiles; + + int err_code = TINYEXR_SUCCESS; + + enum { + EF_SUCCESS = 0, + EF_INVALID_DATA = 1, + EF_INSUFFICIENT_DATA = 2, + EF_FAILED_TO_DECODE = 4 + }; +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic error_flag(EF_SUCCESS); +#else + unsigned error_flag(EF_SUCCESS); +#endif + + // Although the spec says : "...the data window is subdivided into an array of smaller rectangles...", + // the IlmImf library allows the dimensions of the tile to be larger (or equal) than the dimensions of the data window. +#if 0 + if ((exr_header->tile_size_x > exr_image->width || exr_header->tile_size_y > exr_image->height) && + exr_image->level_x == 0 && exr_image->level_y == 0) { + if (err) { + (*err) += "Failed to decode tile data.\n"; + } + err_code = TINYEXR_ERROR_INVALID_DATA; + } +#endif + exr_image->tiles = static_cast( + calloc(sizeof(EXRTile), static_cast(num_tiles))); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic tile_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_tiles)) { + num_threads = int(num_tiles); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() + { + int tile_idx = 0; + while ((tile_idx = tile_count++) < num_tiles) { + +#else +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int tile_idx = 0; tile_idx < num_tiles; tile_idx++) { +#endif + // Allocate memory for each tile. + exr_image->tiles[tile_idx].images = tinyexr::AllocateImage( + num_channels, exr_header->channels, + exr_header->requested_pixel_types, exr_header->tile_size_x, + exr_header->tile_size_y); + + int x_tile = tile_idx % num_x_tiles; + int y_tile = tile_idx / num_x_tiles; + // 16 byte: tile coordinates + // 4 byte : data size + // ~ : data(uncompressed or compressed) + tinyexr::tinyexr_uint64 offset = offset_data.offsets[level_index][y_tile][x_tile]; + if (offset + sizeof(int) * 5 > size) { + // Insufficient data size. + error_flag |= EF_INSUFFICIENT_DATA; + continue; + } + + size_t data_size = + size_t(size - (offset + sizeof(int) * 5)); + const unsigned char* data_ptr = + reinterpret_cast(head + offset); + + int tile_coordinates[4]; + memcpy(tile_coordinates, data_ptr, sizeof(int) * 4); + tinyexr::swap4(&tile_coordinates[0]); + tinyexr::swap4(&tile_coordinates[1]); + tinyexr::swap4(&tile_coordinates[2]); + tinyexr::swap4(&tile_coordinates[3]); + + if (tile_coordinates[2] != exr_image->level_x) { + // Invalid data. + error_flag |= EF_INVALID_DATA; + continue; + } + if (tile_coordinates[3] != exr_image->level_y) { + // Invalid data. + error_flag |= EF_INVALID_DATA; + continue; + } + + int data_len; + memcpy(&data_len, data_ptr + 16, + sizeof(int)); // 16 = sizeof(tile_coordinates) + tinyexr::swap4(&data_len); + + if (data_len < 2 || size_t(data_len) > data_size) { + // Insufficient data size. + error_flag |= EF_INSUFFICIENT_DATA; + continue; + } + + // Move to data addr: 20 = 16 + 4; + data_ptr += 20; + bool ret = tinyexr::DecodeTiledPixelData( + exr_image->tiles[tile_idx].images, + &(exr_image->tiles[tile_idx].width), + &(exr_image->tiles[tile_idx].height), + exr_header->requested_pixel_types, data_ptr, + static_cast(data_len), exr_header->compression_type, + exr_header->line_order, + exr_image->width, exr_image->height, + tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x, + exr_header->tile_size_y, static_cast(pixel_data_size), + static_cast(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), + exr_header->channels, channel_offset_list); + + if (!ret) { + // Failed to decode tile data. + error_flag |= EF_FAILED_TO_DECODE; + } + + exr_image->tiles[tile_idx].offset_x = tile_coordinates[0]; + exr_image->tiles[tile_idx].offset_y = tile_coordinates[1]; + exr_image->tiles[tile_idx].level_x = tile_coordinates[2]; + exr_image->tiles[tile_idx].level_y = tile_coordinates[3]; + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } // num_thread loop + + for (auto& t : workers) { + t.join(); + } + +#else + } // parallel for +#endif + + // Even in the event of an error, the reserved memory may be freed. + exr_image->num_channels = num_channels; + exr_image->num_tiles = static_cast(num_tiles); + + if (error_flag) err_code = TINYEXR_ERROR_INVALID_DATA; + if (err) { + if (error_flag & EF_INSUFFICIENT_DATA) { + (*err) += "Insufficient data length.\n"; + } + if (error_flag & EF_FAILED_TO_DECODE) { + (*err) += "Failed to decode tile data.\n"; + } + } + return err_code; +} + +static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, + const OffsetData& offset_data, + const unsigned char *head, const size_t size, + std::string *err) { + int num_channels = exr_header->num_channels; + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + if (!FindZFPCompressionParam(&zfp_compression_param, + exr_header->custom_attributes, + int(exr_header->num_custom_attributes), err)) { + return TINYEXR_ERROR_INVALID_HEADER; + } +#endif + } + + if (exr_header->data_window.max_x < exr_header->data_window.min_x || + exr_header->data_window.max_y < exr_header->data_window.min_y) { + if (err) { + (*err) += "Invalid data window.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + int data_width = + exr_header->data_window.max_x - exr_header->data_window.min_x + 1; + int data_height = + exr_header->data_window.max_y - exr_header->data_window.min_y + 1; + + // Do not allow too large data_width and data_height. header invalid? + { + if ((data_width > TINYEXR_DIMENSION_THRESHOLD) || (data_height > TINYEXR_DIMENSION_THRESHOLD)) { + if (err) { + std::stringstream ss; + ss << "data_with or data_height too large. data_width: " << data_width + << ", " + << "data_height = " << data_height << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + if (exr_header->tiled) { + if ((exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) || (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD)) { + if (err) { + std::stringstream ss; + ss << "tile with or tile height too large. tile width: " << exr_header->tile_size_x + << ", " + << "tile height = " << exr_header->tile_size_y << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + + const std::vector& offsets = offset_data.offsets[0][0]; + size_t num_blocks = offsets.size(); + + std::vector channel_offset_list; + int pixel_data_size = 0; + size_t channel_offset = 0; + if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, + &channel_offset, num_channels, + exr_header->channels)) { + if (err) { + (*err) += "Failed to compute channel layout.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); +#else + bool invalid_data(false); +#endif + + if (exr_header->tiled) { + // value check + if (exr_header->tile_size_x < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + + if (exr_header->tile_size_y < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + if (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) { + EXRImage* level_image = NULL; + for (int level = 0; level < offset_data.num_x_levels; ++level) { + if (!level_image) { + level_image = exr_image; + } else { + level_image->next_level = new EXRImage; + InitEXRImage(level_image->next_level); + level_image = level_image->next_level; + } + level_image->width = + LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level, exr_header->tile_rounding_mode); + level_image->height = + LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level, exr_header->tile_rounding_mode); + level_image->level_x = level; + level_image->level_y = level; + + int ret = DecodeTiledLevel(level_image, exr_header, + offset_data, + channel_offset_list, + pixel_data_size, + head, size, + err); + if (ret != TINYEXR_SUCCESS) return ret; + } + } else { + EXRImage* level_image = NULL; + for (int level_y = 0; level_y < offset_data.num_y_levels; ++level_y) + for (int level_x = 0; level_x < offset_data.num_x_levels; ++level_x) { + if (!level_image) { + level_image = exr_image; + } else { + level_image->next_level = new EXRImage; + InitEXRImage(level_image->next_level); + level_image = level_image->next_level; + } + + level_image->width = + LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level_x, exr_header->tile_rounding_mode); + level_image->height = + LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level_y, exr_header->tile_rounding_mode); + level_image->level_x = level_x; + level_image->level_y = level_y; + + int ret = DecodeTiledLevel(level_image, exr_header, + offset_data, + channel_offset_list, + pixel_data_size, + head, size, + err); + if (ret != TINYEXR_SUCCESS) return ret; + } + } + } else { // scanline format + // Don't allow too large image(256GB * pixel_data_size or more). Workaround + // for #104. + size_t total_data_len = + size_t(data_width) * size_t(data_height) * size_t(num_channels); + const bool total_data_len_overflown = + sizeof(void *) == 8 ? (total_data_len >= 0x4000000000) : false; + if ((total_data_len == 0) || total_data_len_overflown) { + if (err) { + std::stringstream ss; + ss << "Image data size is zero or too large: width = " << data_width + << ", height = " << data_height << ", channels = " << num_channels + << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + + exr_image->images = tinyexr::AllocateImage( + num_channels, exr_header->channels, exr_header->requested_pixel_types, + data_width, data_height); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic y_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_blocks)) { + num_threads = int(num_blocks); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int y = 0; + while ((y = y_count++) < int(num_blocks)) { + +#else + +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int y = 0; y < static_cast(num_blocks); y++) { + +#endif + size_t y_idx = static_cast(y); + + if (offsets[y_idx] + sizeof(int) * 2 > size) { + invalid_data = true; + } else { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed or compressed) + size_t data_size = + size_t(size - (offsets[y_idx] + sizeof(int) * 2)); + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y_idx]); + + int line_no; + memcpy(&line_no, data_ptr, sizeof(int)); + int data_len; + memcpy(&data_len, data_ptr + 4, sizeof(int)); + tinyexr::swap4(&line_no); + tinyexr::swap4(&data_len); + + if (size_t(data_len) > data_size) { + invalid_data = true; + + } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) { + // Too large value. Assume this is invalid + // 2**20 = 1048576 = heuristic value. + invalid_data = true; + } else if (data_len == 0) { + // TODO(syoyo): May be ok to raise the threshold for example + // `data_len < 4` + invalid_data = true; + } else { + // line_no may be negative. + int end_line_no = (std::min)(line_no + num_scanline_blocks, + (exr_header->data_window.max_y + 1)); + + int num_lines = end_line_no - line_no; + + if (num_lines <= 0) { + invalid_data = true; + } else { + // Move to data addr: 8 = 4 + 4; + data_ptr += 8; + + // Adjust line_no with data_window.bmin.y + + // overflow check + tinyexr_int64 lno = + static_cast(line_no) - + static_cast(exr_header->data_window.min_y); + if (lno > std::numeric_limits::max()) { + line_no = -1; // invalid + } else if (lno < -std::numeric_limits::max()) { + line_no = -1; // invalid + } else { + line_no -= exr_header->data_window.min_y; + } + + if (line_no < 0) { + invalid_data = true; + } else { + if (!tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, + data_ptr, static_cast(data_len), + exr_header->compression_type, exr_header->line_order, + data_width, data_height, data_width, y, line_no, + num_lines, static_cast(pixel_data_size), + static_cast( + exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), + exr_header->channels, channel_offset_list)) { + invalid_data = true; + } + } + } + } + } + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + } + + if (invalid_data) { + if (err) { + std::stringstream ss; + (*err) += "Invalid data found when decoding pixels.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + // Overwrite `pixel_type` with `requested_pixel_type`. + { + for (int c = 0; c < exr_header->num_channels; c++) { + exr_header->pixel_types[c] = exr_header->requested_pixel_types[c]; + } + } + + { + exr_image->num_channels = num_channels; + + exr_image->width = data_width; + exr_image->height = data_height; + } + + return TINYEXR_SUCCESS; +} + +static bool ReconstructLineOffsets( + std::vector *offsets, size_t n, + const unsigned char *head, const unsigned char *marker, const size_t size) { + assert(head < marker); + assert(offsets->size() == n); + + for (size_t i = 0; i < n; i++) { + size_t offset = static_cast(marker - head); + // Offset should not exceed whole EXR file/data size. + if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) { + return false; + } + + int y; + unsigned int data_len; + + memcpy(&y, marker, sizeof(int)); + memcpy(&data_len, marker + 4, sizeof(unsigned int)); + + if (data_len >= size) { + return false; + } + + tinyexr::swap4(&y); + tinyexr::swap4(&data_len); + + (*offsets)[i] = offset; + + marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len) + } + + return true; +} + + +static int FloorLog2(unsigned x) { + // + // For x > 0, floorLog2(y) returns floor(log(x)/log(2)). + // + int y = 0; + while (x > 1) { + y += 1; + x >>= 1u; + } + return y; +} + + +static int CeilLog2(unsigned x) { + // + // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)). + // + int y = 0; + int r = 0; + while (x > 1) { + if (x & 1) + r = 1; + + y += 1; + x >>= 1u; + } + return y + r; +} + +static int RoundLog2(int x, int tile_rounding_mode) { + return (tile_rounding_mode == TINYEXR_TILE_ROUND_DOWN) ? FloorLog2(static_cast(x)) : CeilLog2(static_cast(x)); +} + +static int CalculateNumXLevels(const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + + int num = 0; + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + num = 1; + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + int h = max_y - min_y + 1; + num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1; + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + num = RoundLog2(w, exr_header->tile_rounding_mode) + 1; + } + break; + + default: + + assert(false); + } + + return num; +} + +static int CalculateNumYLevels(const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + int num = 0; + + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + num = 1; + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + int h = max_y - min_y + 1; + num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1; + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + { + int h = max_y - min_y + 1; + num = RoundLog2(h, exr_header->tile_rounding_mode) + 1; + } + break; + + default: + + assert(false); + } + + return num; +} + +static void CalculateNumTiles(std::vector& numTiles, + int toplevel_size, + int size, + int tile_rounding_mode) { + for (unsigned i = 0; i < numTiles.size(); i++) { + int l = LevelSize(toplevel_size, i, tile_rounding_mode); + assert(l <= std::numeric_limits::max() - size + 1); + + numTiles[i] = (l + size - 1) / size; + } +} + +static void PrecalculateTileInfo(std::vector& num_x_tiles, + std::vector& num_y_tiles, + const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + + int num_x_levels = CalculateNumXLevels(exr_header); + int num_y_levels = CalculateNumYLevels(exr_header); + + num_x_tiles.resize(num_x_levels); + num_y_tiles.resize(num_y_levels); + + CalculateNumTiles(num_x_tiles, + max_x - min_x + 1, + exr_header->tile_size_x, + exr_header->tile_rounding_mode); + + CalculateNumTiles(num_y_tiles, + max_y - min_y + 1, + exr_header->tile_size_y, + exr_header->tile_rounding_mode); +} + +static void InitSingleResolutionOffsets(OffsetData& offset_data, size_t num_blocks) { + offset_data.offsets.resize(1); + offset_data.offsets[0].resize(1); + offset_data.offsets[0][0].resize(num_blocks); + offset_data.num_x_levels = 1; + offset_data.num_y_levels = 1; +} + +// Return sum of tile blocks. +static int InitTileOffsets(OffsetData& offset_data, + const EXRHeader* exr_header, + const std::vector& num_x_tiles, + const std::vector& num_y_tiles) { + int num_tile_blocks = 0; + offset_data.num_x_levels = static_cast(num_x_tiles.size()); + offset_data.num_y_levels = static_cast(num_y_tiles.size()); + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + case TINYEXR_TILE_MIPMAP_LEVELS: + assert(offset_data.num_x_levels == offset_data.num_y_levels); + offset_data.offsets.resize(offset_data.num_x_levels); + + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + offset_data.offsets[l].resize(num_y_tiles[l]); + + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + offset_data.offsets[l][dy].resize(num_x_tiles[l]); + num_tile_blocks += num_x_tiles[l]; + } + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + offset_data.offsets.resize(static_cast(offset_data.num_x_levels) * static_cast(offset_data.num_y_levels)); + + for (int ly = 0; ly < offset_data.num_y_levels; ++ly) { + for (int lx = 0; lx < offset_data.num_x_levels; ++lx) { + int l = ly * offset_data.num_x_levels + lx; + offset_data.offsets[l].resize(num_y_tiles[ly]); + + for (size_t dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + offset_data.offsets[l][dy].resize(num_x_tiles[lx]); + num_tile_blocks += num_x_tiles[lx]; + } + } + } + break; + + default: + assert(false); + } + return num_tile_blocks; +} + +static bool IsAnyOffsetsAreInvalid(const OffsetData& offset_data) { + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) + if (reinterpret_cast(offset_data.offsets[l][dy][dx]) <= 0) + return true; + + return false; +} + +static bool isValidTile(const EXRHeader* exr_header, + const OffsetData& offset_data, + int dx, int dy, int lx, int ly) { + if (lx < 0 || ly < 0 || dx < 0 || dy < 0) return false; + int num_x_levels = offset_data.num_x_levels; + int num_y_levels = offset_data.num_y_levels; + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + if (lx == 0 && + ly == 0 && + offset_data.offsets.size() > 0 && + offset_data.offsets[0].size() > static_cast(dy) && + offset_data.offsets[0][dy].size() > static_cast(dx)) { + return true; + } + + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + if (lx < num_x_levels && + ly < num_y_levels && + offset_data.offsets.size() > static_cast(lx) && + offset_data.offsets[lx].size() > static_cast(dy) && + offset_data.offsets[lx][dy].size() > static_cast(dx)) { + return true; + } + + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + { + size_t idx = static_cast(lx) + static_cast(ly)* static_cast(num_x_levels); + if (lx < num_x_levels && + ly < num_y_levels && + (offset_data.offsets.size() > idx) && + offset_data.offsets[idx].size() > static_cast(dy) && + offset_data.offsets[idx][dy].size() > static_cast(dx)) { + return true; + } + } + + break; + + default: + + return false; + } + + return false; +} + +static void ReconstructTileOffsets(OffsetData& offset_data, + const EXRHeader* exr_header, + const unsigned char* head, const unsigned char* marker, const size_t size, + bool isMultiPartFile, + bool isDeep) { + int numXLevels = offset_data.num_x_levels; + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 tileOffset = marker - head; + + if (isMultiPartFile) { + //int partNumber; + marker += sizeof(int); + } + + int tileX; + memcpy(&tileX, marker, sizeof(int)); + tinyexr::swap4(&tileX); + marker += sizeof(int); + + int tileY; + memcpy(&tileY, marker, sizeof(int)); + tinyexr::swap4(&tileY); + marker += sizeof(int); + + int levelX; + memcpy(&levelX, marker, sizeof(int)); + tinyexr::swap4(&levelX); + marker += sizeof(int); + + int levelY; + memcpy(&levelY, marker, sizeof(int)); + tinyexr::swap4(&levelY); + marker += sizeof(int); + + if (isDeep) { + tinyexr::tinyexr_int64 packed_offset_table_size; + memcpy(&packed_offset_table_size, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&packed_offset_table_size)); + marker += sizeof(tinyexr::tinyexr_int64); + + tinyexr::tinyexr_int64 packed_sample_size; + memcpy(&packed_sample_size, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&packed_sample_size)); + marker += sizeof(tinyexr::tinyexr_int64); + + // next Int64 is unpacked sample size - skip that too + marker += packed_offset_table_size + packed_sample_size + 8; + + } else { + + int dataSize; + memcpy(&dataSize, marker, sizeof(int)); + tinyexr::swap4(&dataSize); + marker += sizeof(int); + marker += dataSize; + } + + if (!isValidTile(exr_header, offset_data, + tileX, tileY, levelX, levelY)) + return; + + int level_idx = LevelIndex(levelX, levelY, exr_header->tile_level_mode, numXLevels); + offset_data.offsets[level_idx][tileY][tileX] = tileOffset; + } + } + } +} + +// marker output is also +static int ReadOffsets(OffsetData& offset_data, + const unsigned char* head, + const unsigned char*& marker, + const size_t size, + const char** err) { + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 offset; + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + offset_data.offsets[l][dy][dx] = offset; + } + } + } + return TINYEXR_SUCCESS; +} + +static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *head, + const unsigned char *marker, const size_t size, + const char **err) { + if (exr_image == NULL || exr_header == NULL || head == NULL || + marker == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + } + + if (exr_header->data_window.max_x < exr_header->data_window.min_x || + exr_header->data_window.max_x - exr_header->data_window.min_x == + std::numeric_limits::max()) { + // Issue 63 + tinyexr::SetErrorMessage("Invalid data width value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + int data_width = + exr_header->data_window.max_x - exr_header->data_window.min_x + 1; + + if (exr_header->data_window.max_y < exr_header->data_window.min_y || + exr_header->data_window.max_y - exr_header->data_window.min_y == + std::numeric_limits::max()) { + tinyexr::SetErrorMessage("Invalid data height value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + int data_height = + exr_header->data_window.max_y - exr_header->data_window.min_y + 1; + + // Do not allow too large data_width and data_height. header invalid? + { + if (data_width > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("data width too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + if (data_height > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("data height too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + if (exr_header->tiled) { + if (exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("tile width too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + if (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("tile height too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + // Read offset tables. + OffsetData offset_data; + size_t num_blocks = 0; + // For a multi-resolution image, the size of the offset table will be calculated from the other attributes of the header. + // If chunk_count > 0 then chunk_count must be equal to the calculated tile count. + if (exr_header->tiled) { + { + std::vector num_x_tiles, num_y_tiles; + PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header); + num_blocks = InitTileOffsets(offset_data, exr_header, num_x_tiles, num_y_tiles); + if (exr_header->chunk_count > 0) { + if (exr_header->chunk_count != num_blocks) { + tinyexr::SetErrorMessage("Invalid offset table size.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + + int ret = ReadOffsets(offset_data, head, marker, size, err); + if (ret != TINYEXR_SUCCESS) return ret; + if (IsAnyOffsetsAreInvalid(offset_data)) { + ReconstructTileOffsets(offset_data, exr_header, + head, marker, size, + exr_header->multipart, exr_header->non_image); + } + } else if (exr_header->chunk_count > 0) { + // Use `chunkCount` attribute. + num_blocks = static_cast(exr_header->chunk_count); + InitSingleResolutionOffsets(offset_data, num_blocks); + } else { + num_blocks = static_cast(data_height) / + static_cast(num_scanline_blocks); + if (num_blocks * static_cast(num_scanline_blocks) < + static_cast(data_height)) { + num_blocks++; + } + + InitSingleResolutionOffsets(offset_data, num_blocks); + } + + if (!exr_header->tiled) { + std::vector& offsets = offset_data.offsets[0][0]; + for (size_t y = 0; y < num_blocks; y++) { + tinyexr::tinyexr_uint64 offset; + // Issue #81 + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + offsets[y] = offset; + } + + // If line offsets are invalid, we try to reconstruct it. + // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details. + for (size_t y = 0; y < num_blocks; y++) { + if (offsets[y] <= 0) { + // TODO(syoyo) Report as warning? + // if (err) { + // stringstream ss; + // ss << "Incomplete lineOffsets." << std::endl; + // (*err) += ss.str(); + //} + bool ret = + ReconstructLineOffsets(&offsets, num_blocks, head, marker, size); + if (ret) { + // OK + break; + } else { + tinyexr::SetErrorMessage( + "Cannot reconstruct lineOffset table in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + } + + { + std::string e; + int ret = DecodeChunk(exr_image, exr_header, offset_data, head, size, &e); + + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + +#if 1 + FreeEXRImage(exr_image); +#else + // release memory(if exists) + if ((exr_header->num_channels > 0) && exr_image && exr_image->images) { + for (size_t c = 0; c < size_t(exr_header->num_channels); c++) { + if (exr_image->images[c]) { + free(exr_image->images[c]); + exr_image->images[c] = NULL; + } + } + free(exr_image->images); + exr_image->images = NULL; + } +#endif + } + + return ret; + } +} + +static void GetLayers(const EXRHeader &exr_header, + std::vector &layer_names) { + // Naive implementation + // Group channels by layers + // go over all channel names, split by periods + // collect unique names + layer_names.clear(); + for (int c = 0; c < exr_header.num_channels; c++) { + std::string full_name(exr_header.channels[c].name); + const size_t pos = full_name.find_last_of('.'); + if (pos != std::string::npos && pos != 0 && pos + 1 < full_name.size()) { + full_name.erase(pos); + if (std::find(layer_names.begin(), layer_names.end(), full_name) == + layer_names.end()) + layer_names.push_back(full_name); + } + } +} + +struct LayerChannel { + explicit LayerChannel(size_t i, std::string n) : index(i), name(n) {} + size_t index; + std::string name; +}; + +static void ChannelsInLayer(const EXRHeader &exr_header, + const std::string layer_name, + std::vector &channels) { + channels.clear(); + for (int c = 0; c < exr_header.num_channels; c++) { + std::string ch_name(exr_header.channels[c].name); + if (layer_name.empty()) { + const size_t pos = ch_name.find_last_of('.'); + if (pos != std::string::npos && pos < ch_name.size()) { + ch_name = ch_name.substr(pos + 1); + } + } else { + const size_t pos = ch_name.find(layer_name + '.'); + if (pos == std::string::npos) continue; + if (pos == 0) { + ch_name = ch_name.substr(layer_name.size() + 1); + } + } + LayerChannel ch(size_t(c), ch_name); + channels.push_back(ch); + } +} + +} // namespace tinyexr + +int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, + const char **err) { + EXRVersion exr_version; + EXRHeader exr_header; + InitEXRHeader(&exr_header); + + { + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Invalid EXR header.", err); + return ret; + } + + if (exr_version.multipart || exr_version.non_image) { + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); + return TINYEXR_ERROR_INVALID_DATA; // @fixme. + } + } + + int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + + std::vector layer_vec; + tinyexr::GetLayers(exr_header, layer_vec); + + (*num_layers) = int(layer_vec.size()); + (*layer_names) = static_cast( + malloc(sizeof(const char *) * static_cast(layer_vec.size()))); + for (size_t c = 0; c < static_cast(layer_vec.size()); c++) { +#ifdef _MSC_VER + (*layer_names)[c] = _strdup(layer_vec[c].c_str()); +#else + (*layer_names)[c] = strdup(layer_vec[c].c_str()); +#endif + } + + FreeEXRHeader(&exr_header); + return TINYEXR_SUCCESS; +} + +int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, + const char **err) { + return LoadEXRWithLayer(out_rgba, width, height, filename, + /* layername */ NULL, err); +} + +int LoadEXRWithLayer(float **out_rgba, int *width, int *height, + const char *filename, const char *layername, + const char **err) { + if (out_rgba == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + InitEXRHeader(&exr_header); + InitEXRImage(&exr_image); + + { + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + std::stringstream ss; + ss << "Failed to open EXR file or read version info from EXR file. code(" + << ret << ")"; + tinyexr::SetErrorMessage(ss.str(), err); + return ret; + } + + if (exr_version.multipart || exr_version.non_image) { + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); + return TINYEXR_ERROR_INVALID_DATA; // @fixme. + } + } + + { + int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + // TODO: Probably limit loading to layers (channels) selected by layer index + { + int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + + std::vector layer_names; + tinyexr::GetLayers(exr_header, layer_names); + + std::vector channels; + tinyexr::ChannelsInLayer( + exr_header, layername == NULL ? "" : std::string(layername), channels); + + if (channels.size() < 1) { + tinyexr::SetErrorMessage("Layer Not Found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_LAYER_NOT_FOUND; + } + + size_t ch_count = channels.size() < 4 ? channels.size() : 4; + for (size_t c = 0; c < ch_count; c++) { + const tinyexr::LayerChannel &ch = channels[c]; + + if (ch.name == "R") { + idxR = int(ch.index); + } else if (ch.name == "G") { + idxG = int(ch.index); + } else if (ch.name == "B") { + idxB = int(ch.index); + } else if (ch.name == "A") { + idxA = int(ch.index); + } + } + + if (channels.size() == 1) { + int chIdx = int(channels.front().index); + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = exr_image.tiles[it].offset_x * + static_cast(exr_header.tile_size_x) + + i; + const int jj = exr_image.tiles[it].offset_y * + static_cast(exr_header.tile_size_y) + + j; + const int idx = ii + jj * static_cast(exr_image.width); + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[chIdx][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = + reinterpret_cast(exr_image.images)[chIdx][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + } else { + // Assume RGB(A) + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int IsEXR(const char *filename) { + EXRVersion exr_version; + + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_header == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument. `memory` or `exr_header` argument is null in " + "ParseEXRHeaderFromMemory()", + err); + + // Invalid argument + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Insufficient header/data size.\n", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + if (err && !err_str.empty()) { + tinyexr::SetErrorMessage(err_str, err); + } + } + + ConvertHeader(exr_header, info); + + exr_header->multipart = version->multipart ? 1 : 0; + exr_header->non_image = version->non_image ? 1 : 0; + + return ret; +} + +int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err) { + if (out_rgba == NULL || memory == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + + InitEXRHeader(&exr_header); + + int ret = ParseEXRVersionFromMemory(&exr_version, memory, size); + if (ret != TINYEXR_SUCCESS) { + std::stringstream ss; + ss << "Failed to parse EXR version. code(" << ret << ")"; + tinyexr::SetErrorMessage(ss.str(), err); + return ret; + } + + ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + InitEXRImage(&exr_image); + ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + for (int c = 0; c < exr_header.num_channels; c++) { + if (strcmp(exr_header.channels[c].name, "R") == 0) { + idxR = c; + } else if (strcmp(exr_header.channels[c].name, "G") == 0) { + idxG = c; + } else if (strcmp(exr_header.channels[c].name, "B") == 0) { + idxB = c; + } else if (strcmp(exr_header.channels[c].name, "A") == 0) { + idxA = c; + } + } + + // TODO(syoyo): Refactor removing same code as used in LoadEXR(). + if (exr_header.num_channels == 1) { + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[0][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + + } else { + // TODO(syoyo): Support non RGBA image. + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + // TODO(syoyo): return wfopen_s erro code + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize < 16) { + tinyexr::SetErrorMessage("File size too short " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize, + err); +} + +int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *memory, const size_t size, + const char **err) { + if (exr_image == NULL || memory == NULL || + (size < tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + const unsigned char *head = memory; + const unsigned char *marker = reinterpret_cast( + memory + exr_header->header_len + + 8); // +8 for magic number + version header. + return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size, + err); +} + +namespace tinyexr +{ + +// out_data must be allocated initially with the block-header size +// of the current image(-part) type +static bool EncodePixelData(/* out */ std::vector& out_data, + const unsigned char* const* images, + const int* requested_pixel_types, + int compression_type, + int line_order, + int width, // for tiled : tile.width + int height, // for tiled : header.tile_size_y + int x_stride, // for tiled : header.tile_size_x + int line_no, // for tiled : 0 + int num_lines, // for tiled : tile.height + size_t pixel_data_size, + const std::vector& channels, + const std::vector& channel_offset_list, + const void* compression_param = 0) // zfp compression param +{ + size_t buf_size = static_cast(width) * + static_cast(num_lines) * + static_cast(pixel_data_size); + //int last2bit = (buf_size & 3); + // buf_size must be multiple of four + //if(last2bit) buf_size += 4 - last2bit; + std::vector buf(buf_size); + + size_t start_y = static_cast(line_no); + for (size_t c = 0; c < channels.size(); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + tinyexr::FP16 h16; + h16.u = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::FP32 f32 = half_to_float(h16); + + tinyexr::swap4(&f32.f); + + // line_ptr[x] = f32.f; + tinyexr::cpy4(line_ptr + x, &(f32.f)); + } + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + unsigned short val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap2(&val); + + // line_ptr[x] = val; + tinyexr::cpy2(line_ptr + x, &val); + } + } + } else { + assert(0); + } + + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + tinyexr::FP32 f32; + f32.f = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::FP16 h16; + h16 = float_to_half_full(f32); + + tinyexr::swap2(reinterpret_cast(&h16.u)); + + // line_ptr[x] = h16.u; + tinyexr::cpy2(line_ptr + x, &(h16.u)); + } + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + float val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap4(&val); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } else { + assert(0); + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned int *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * static_cast(width))); + for (int x = 0; x < width; x++) { + unsigned int val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap4(&val); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } + } + + if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed) + out_data.insert(out_data.end(), buf.begin(), buf.end()); + + } else if ((compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#if TINYEXR_USE_MINIZ + std::vector block(tinyexr::miniz::mz_compressBound( + static_cast(buf.size()))); +#else + std::vector block( + compressBound(static_cast(buf.size()))); +#endif + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressZip(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = static_cast(outSize); // truncate + + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // (buf.size() * 3) / 2 would be enough. + std::vector block((buf.size() * 3) / 2); + + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressRle(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = static_cast(outSize); // truncate + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + unsigned int bufLen = + 8192 + static_cast( + 2 * static_cast( + buf.size())); // @fixme { compute good bound. } + std::vector block(bufLen); + unsigned int outSize = static_cast(block.size()); + + CompressPiz(&block.at(0), &outSize, + reinterpret_cast(&buf.at(0)), + buf.size(), channels, width, num_lines); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = outSize; + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + +#else + assert(0); +#endif + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + const ZFPCompressionParam* zfp_compression_param = reinterpret_cast(compression_param); + std::vector block; + unsigned int outSize; + + tinyexr::CompressZfp( + &block, &outSize, reinterpret_cast(&buf.at(0)), + width, num_lines, static_cast(channels.size()), *zfp_compression_param); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = outSize; + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + +#else + assert(0); +#endif + } else { + assert(0); + return false; + } + + return true; +} + +static int EncodeTiledLevel(const EXRImage* level_image, const EXRHeader* exr_header, + const std::vector& channels, + std::vector >& data_list, + size_t start_index, // for data_list + int num_x_tiles, int num_y_tiles, + const std::vector& channel_offset_list, + int pixel_data_size, + const void* compression_param, // must be set if zfp compression is enabled + std::string* err) { + int num_tiles = num_x_tiles * num_y_tiles; + assert(num_tiles == level_image->num_tiles); + + if ((exr_header->tile_size_x > level_image->width || exr_header->tile_size_y > level_image->height) && + level_image->level_x == 0 && level_image->level_y == 0) { + if (err) { + (*err) += "Failed to encode tile data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); +#else + bool invalid_data(false); +#endif + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic tile_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_tiles)) { + num_threads = int(num_tiles); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int i = 0; + while ((i = tile_count++) < num_tiles) { + +#else + // Use signed int since some OpenMP compiler doesn't allow unsigned type for + // `parallel for` +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < num_tiles; i++) { + +#endif + size_t tile_idx = static_cast(i); + size_t data_idx = tile_idx + start_index; + + int x_tile = i % num_x_tiles; + int y_tile = i / num_x_tiles; + + EXRTile& tile = level_image->tiles[tile_idx]; + + const unsigned char* const* images = + static_cast(tile.images); + + data_list[data_idx].resize(5*sizeof(int)); + size_t data_header_size = data_list[data_idx].size(); + bool ret = EncodePixelData(data_list[data_idx], + images, + exr_header->requested_pixel_types, + exr_header->compression_type, + 0, // increasing y + tile.width, + exr_header->tile_size_y, + exr_header->tile_size_x, + 0, + tile.height, + pixel_data_size, + channels, + channel_offset_list, + compression_param); + if (!ret) { + invalid_data = true; + continue; + } + assert(data_list[data_idx].size() > data_header_size); + int data_len = static_cast(data_list[data_idx].size() - data_header_size); + //tileX, tileY, levelX, levelY // pixel_data_size(int) + memcpy(&data_list[data_idx][0], &x_tile, sizeof(int)); + memcpy(&data_list[data_idx][4], &y_tile, sizeof(int)); + memcpy(&data_list[data_idx][8], &level_image->level_x, sizeof(int)); + memcpy(&data_list[data_idx][12], &level_image->level_y, sizeof(int)); + memcpy(&data_list[data_idx][16], &data_len, sizeof(int)); + + swap4(reinterpret_cast(&data_list[data_idx][0])); + swap4(reinterpret_cast(&data_list[data_idx][4])); + swap4(reinterpret_cast(&data_list[data_idx][8])); + swap4(reinterpret_cast(&data_list[data_idx][12])); + swap4(reinterpret_cast(&data_list[data_idx][16])); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } +})); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + + if (invalid_data) { + if (err) { + (*err) += "Failed to encode tile data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + return TINYEXR_SUCCESS; +} + +static int NumScanlines(int compression_type) { + int num_scanlines = 1; + if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanlines = 16; + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanlines = 32; + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanlines = 16; + } + return num_scanlines; +} + +static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header, + const std::vector& channels, + int num_blocks, + tinyexr_uint64 chunk_offset, // starting offset of current chunk + bool is_multipart, + OffsetData& offset_data, // output block offsets, must be initialized + std::vector >& data_list, // output + tinyexr_uint64& total_size, // output: ending offset of current chunk + std::string* err) { + int num_scanlines = NumScanlines(exr_header->compression_type); + + data_list.resize(num_blocks); + + std::vector channel_offset_list( + static_cast(exr_header->num_channels)); + + int pixel_data_size = 0; + { + size_t channel_offset = 0; + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + channel_offset_list[c] = channel_offset; + if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + pixel_data_size += sizeof(unsigned short); + channel_offset += sizeof(unsigned short); + } else if (exr_header->requested_pixel_types[c] == + TINYEXR_PIXELTYPE_FLOAT) { + pixel_data_size += sizeof(float); + channel_offset += sizeof(float); + } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { + pixel_data_size += sizeof(unsigned int); + channel_offset += sizeof(unsigned int); + } else { + assert(0); + } + } + } + + const void* compression_param = 0; +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + + // Use ZFP compression parameter from custom attributes(if such a parameter + // exists) + { + std::string e; + bool ret = tinyexr::FindZFPCompressionParam( + &zfp_compression_param, exr_header->custom_attributes, + exr_header->num_custom_attributes, &e); + + if (!ret) { + // Use predefined compression parameter. + zfp_compression_param.type = 0; + zfp_compression_param.rate = 2; + } + compression_param = &zfp_compression_param; + } +#endif + + tinyexr_uint64 offset = chunk_offset; + tinyexr_uint64 doffset = is_multipart ? 4u : 0u; + + if (exr_image->tiles) { + const EXRImage* level_image = exr_image; + size_t block_idx = 0; + tinyexr::tinyexr_uint64 block_data_size = 0; + int num_levels = (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ? + offset_data.num_x_levels : (offset_data.num_x_levels * offset_data.num_y_levels); + for (int level_index = 0; level_index < num_levels; ++level_index) { + if (!level_image) { + if (err) { + (*err) += "Invalid number of tiled levels for EncodeChunk\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + int level_index_from_image = LevelIndex(level_image->level_x, level_image->level_y, + exr_header->tile_level_mode, offset_data.num_x_levels); + if (level_index_from_image != level_index) { + if (err) { + (*err) += "Incorrect level ordering in tiled image\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + int num_y_tiles = (int)offset_data.offsets[level_index].size(); + assert(num_y_tiles); + int num_x_tiles = (int)offset_data.offsets[level_index][0].size(); + assert(num_x_tiles); + + std::string e; + int ret = EncodeTiledLevel(level_image, + exr_header, + channels, + data_list, + block_idx, + num_x_tiles, + num_y_tiles, + channel_offset_list, + pixel_data_size, + compression_param, + &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty() && err) { + (*err) += e; + } + return ret; + } + + for (size_t j = 0; j < static_cast(num_y_tiles); ++j) + for (size_t i = 0; i < static_cast(num_x_tiles); ++i) { + offset_data.offsets[level_index][j][i] = offset; + swap8(reinterpret_cast(&offset_data.offsets[level_index][j][i])); + offset += data_list[block_idx].size() + doffset; + block_data_size += data_list[block_idx].size(); + ++block_idx; + } + level_image = level_image->next_level; + } + assert(block_idx == num_blocks); + total_size = offset; + } else { // scanlines + std::vector& offsets = offset_data.offsets[0][0]; + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); + std::vector workers; + std::atomic block_count(0); + + int num_threads = std::min(std::max(1, int(std::thread::hardware_concurrency())), num_blocks); + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int i = 0; + while ((i = block_count++) < num_blocks) { + +#else + bool invalid_data(false); +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < num_blocks; i++) { + +#endif + int start_y = num_scanlines * i; + int end_Y = (std::min)(num_scanlines * (i + 1), exr_image->height); + int num_lines = end_Y - start_y; + + const unsigned char* const* images = + static_cast(exr_image->images); + + data_list[i].resize(2*sizeof(int)); + size_t data_header_size = data_list[i].size(); + + bool ret = EncodePixelData(data_list[i], + images, + exr_header->requested_pixel_types, + exr_header->compression_type, + 0, // increasing y + exr_image->width, + exr_image->height, + exr_image->width, + start_y, + num_lines, + pixel_data_size, + channels, + channel_offset_list, + compression_param); + if (!ret) { + invalid_data = true; + continue; // "break" cannot be used with OpenMP + } + assert(data_list[i].size() > data_header_size); + int data_len = static_cast(data_list[i].size() - data_header_size); + memcpy(&data_list[i][0], &start_y, sizeof(int)); + memcpy(&data_list[i][4], &data_len, sizeof(int)); + + swap4(reinterpret_cast(&data_list[i][0])); + swap4(reinterpret_cast(&data_list[i][4])); +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + + if (invalid_data) { + if (err) { + (*err) += "Failed to encode scanline data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + for (size_t i = 0; i < static_cast(num_blocks); i++) { + offsets[i] = offset; + tinyexr::swap8(reinterpret_cast(&offsets[i])); + offset += data_list[i].size() + doffset; + } + + total_size = static_cast(offset); + } + return TINYEXR_SUCCESS; +} + +// can save a single or multi-part image (no deep* formats) +static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + unsigned char** memory_out, const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || + memory_out == NULL) { + SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } + { + for (unsigned int i = 0; i < num_parts; ++i) { + if (exr_headers[i]->compression_type < 0) { + SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } +#if !TINYEXR_USE_PIZ + if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + SetErrorMessage("PIZ compression is not supported in this build", + err); + return 0; + } +#endif +#if !TINYEXR_USE_ZFP + if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + SetErrorMessage("ZFP compression is not supported in this build", + err); + return 0; + } +#else + for (int c = 0; c < exr_header->num_channels; ++c) { + if (exr_headers[i]->requested_pixel_types[c] != TINYEXR_PIXELTYPE_FLOAT) { + SetErrorMessage("Pixel type must be FLOAT for ZFP compression", + err); + return 0; + } + } +#endif + } + } + + std::vector memory; + + // Header + { + const char header[] = { 0x76, 0x2f, 0x31, 0x01 }; + memory.insert(memory.end(), header, header + 4); + } + + // Version + // using value from the first header + int long_name = exr_headers[0]->long_name; + { + char marker[] = { 2, 0, 0, 0 }; + /* @todo + if (exr_header->non_image) { + marker[1] |= 0x8; + } + */ + // tiled + if (num_parts == 1 && exr_images[0].tiles) { + marker[1] |= 0x2; + } + // long_name + if (long_name) { + marker[1] |= 0x4; + } + // multipart + if (num_parts > 1) { + marker[1] |= 0x10; + } + memory.insert(memory.end(), marker, marker + 4); + } + + int total_chunk_count = 0; + std::vector chunk_count(num_parts); + std::vector offset_data(num_parts); + for (unsigned int i = 0; i < num_parts; ++i) { + if (!exr_images[i].tiles) { + int num_scanlines = NumScanlines(exr_headers[i]->compression_type); + chunk_count[i] = + (exr_images[i].height + num_scanlines - 1) / num_scanlines; + InitSingleResolutionOffsets(offset_data[i], chunk_count[i]); + total_chunk_count += chunk_count[i]; + } else { + { + std::vector num_x_tiles, num_y_tiles; + PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]); + chunk_count[i] = + InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles); + total_chunk_count += chunk_count[i]; + } + } + } + // Write attributes to memory buffer. + std::vector< std::vector > channels(num_parts); + { + std::set partnames; + for (unsigned int i = 0; i < num_parts; ++i) { + //channels + { + std::vector data; + + for (int c = 0; c < exr_headers[i]->num_channels; c++) { + tinyexr::ChannelInfo info; + info.p_linear = 0; + info.pixel_type = exr_headers[i]->requested_pixel_types[c]; + info.x_sampling = 1; + info.y_sampling = 1; + info.name = std::string(exr_headers[i]->channels[c].name); + channels[i].push_back(info); + } + + tinyexr::WriteChannelInfo(data, channels[i]); + + tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0), + static_cast(data.size())); + } + + { + int comp = exr_headers[i]->compression_type; + swap4(&comp); + WriteAttributeToMemory( + &memory, "compression", "compression", + reinterpret_cast(&comp), 1); + } + + { + int data[4] = { 0, 0, exr_images[i].width - 1, exr_images[i].height - 1 }; + swap4(&data[0]); + swap4(&data[1]); + swap4(&data[2]); + swap4(&data[3]); + WriteAttributeToMemory( + &memory, "dataWindow", "box2i", + reinterpret_cast(data), sizeof(int) * 4); + + int data0[4] = { 0, 0, exr_images[0].width - 1, exr_images[0].height - 1 }; + swap4(&data0[0]); + swap4(&data0[1]); + swap4(&data0[2]); + swap4(&data0[3]); + // Note: must be the same across parts (currently, using value from the first header) + WriteAttributeToMemory( + &memory, "displayWindow", "box2i", + reinterpret_cast(data0), sizeof(int) * 4); + } + + { + unsigned char line_order = 0; // @fixme { read line_order from EXRHeader } + WriteAttributeToMemory(&memory, "lineOrder", "lineOrder", + &line_order, 1); + } + + { + // Note: must be the same across parts + float aspectRatio = 1.0f; + swap4(&aspectRatio); + WriteAttributeToMemory( + &memory, "pixelAspectRatio", "float", + reinterpret_cast(&aspectRatio), sizeof(float)); + } + + { + float center[2] = { 0.0f, 0.0f }; + swap4(¢er[0]); + swap4(¢er[1]); + WriteAttributeToMemory( + &memory, "screenWindowCenter", "v2f", + reinterpret_cast(center), 2 * sizeof(float)); + } + + { + float w = 1.0f; + swap4(&w); + WriteAttributeToMemory(&memory, "screenWindowWidth", "float", + reinterpret_cast(&w), + sizeof(float)); + } + + if (exr_images[i].tiles) { + unsigned char tile_mode = static_cast(exr_headers[i]->tile_level_mode & 0x3); + if (exr_headers[i]->tile_rounding_mode) tile_mode |= (1u << 4u); + //unsigned char data[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned int datai[3] = { 0, 0, 0 }; + unsigned char* data = reinterpret_cast(&datai[0]); + datai[0] = static_cast(exr_headers[i]->tile_size_x); + datai[1] = static_cast(exr_headers[i]->tile_size_y); + data[8] = tile_mode; + swap4(reinterpret_cast(&data[0])); + swap4(reinterpret_cast(&data[4])); + WriteAttributeToMemory( + &memory, "tiles", "tiledesc", + reinterpret_cast(data), 9); + } + + // must be present for multi-part files - according to spec. + if (num_parts > 1) { + // name + { + size_t len = 0; + if ((len = strlen(exr_headers[i]->name)) > 0) { + partnames.insert(std::string(exr_headers[i]->name)); + if (partnames.size() != i + 1) { + SetErrorMessage("'name' attributes must be unique for a multi-part file", err); + return 0; + } + WriteAttributeToMemory( + &memory, "name", "string", + reinterpret_cast(exr_headers[i]->name), + static_cast(len)); + } else { + SetErrorMessage("Invalid 'name' attribute for a multi-part file", err); + return 0; + } + } + // type + { + const char* type = "scanlineimage"; + if (exr_images[i].tiles) type = "tiledimage"; + WriteAttributeToMemory( + &memory, "type", "string", + reinterpret_cast(type), + static_cast(strlen(type))); + } + // chunkCount + { + WriteAttributeToMemory( + &memory, "chunkCount", "int", + reinterpret_cast(&chunk_count[i]), + 4); + } + } + + // Custom attributes + if (exr_headers[i]->num_custom_attributes > 0) { + for (int j = 0; j < exr_headers[i]->num_custom_attributes; j++) { + tinyexr::WriteAttributeToMemory( + &memory, exr_headers[i]->custom_attributes[j].name, + exr_headers[i]->custom_attributes[j].type, + reinterpret_cast( + exr_headers[i]->custom_attributes[j].value), + exr_headers[i]->custom_attributes[j].size); + } + } + + { // end of header + memory.push_back(0); + } + } + } + if (num_parts > 1) { + // end of header list + memory.push_back(0); + } + + tinyexr_uint64 chunk_offset = memory.size() + size_t(total_chunk_count) * sizeof(tinyexr_uint64); + + tinyexr_uint64 total_size = 0; + std::vector< std::vector< std::vector > > data_lists(num_parts); + for (unsigned int i = 0; i < num_parts; ++i) { + std::string e; + int ret = EncodeChunk(&exr_images[i], exr_headers[i], + channels[i], + chunk_count[i], + // starting offset of current chunk after part-number + chunk_offset, + num_parts > 1, + offset_data[i], // output: block offsets, must be initialized + data_lists[i], // output + total_size, // output + &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + return 0; + } + chunk_offset = total_size; + } + + // Allocating required memory + if (total_size == 0) { // something went wrong + tinyexr::SetErrorMessage("Output memory size is zero", err); + return 0; + } + (*memory_out) = static_cast(malloc(total_size)); + + // Writing header + memcpy((*memory_out), &memory[0], memory.size()); + unsigned char* memory_ptr = *memory_out + memory.size(); + size_t sum = memory.size(); + + // Writing offset data for chunks + for (unsigned int i = 0; i < num_parts; ++i) { + if (exr_images[i].tiles) { + const EXRImage* level_image = &exr_images[i]; + int num_levels = (exr_headers[i]->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ? + offset_data[i].num_x_levels : (offset_data[i].num_x_levels * offset_data[i].num_y_levels); + for (int level_index = 0; level_index < num_levels; ++level_index) { + for (size_t j = 0; j < offset_data[i].offsets[level_index].size(); ++j) { + size_t num_bytes = sizeof(tinyexr_uint64) * offset_data[i].offsets[level_index][j].size(); + sum += num_bytes; + assert(sum <= total_size); + memcpy(memory_ptr, + reinterpret_cast(&offset_data[i].offsets[level_index][j][0]), + num_bytes); + memory_ptr += num_bytes; + } + level_image = level_image->next_level; + } + } else { + size_t num_bytes = sizeof(tinyexr::tinyexr_uint64) * static_cast(chunk_count[i]); + sum += num_bytes; + assert(sum <= total_size); + std::vector& offsets = offset_data[i].offsets[0][0]; + memcpy(memory_ptr, reinterpret_cast(&offsets[0]), num_bytes); + memory_ptr += num_bytes; + } + } + + // Writing chunk data + for (unsigned int i = 0; i < num_parts; ++i) { + for (size_t j = 0; j < static_cast(chunk_count[i]); ++j) { + if (num_parts > 1) { + sum += 4; + assert(sum <= total_size); + unsigned int part_number = i; + swap4(&part_number); + memcpy(memory_ptr, &part_number, 4); + memory_ptr += 4; + } + sum += data_lists[i][j].size(); + assert(sum <= total_size); + memcpy(memory_ptr, &data_lists[i][j][0], data_lists[i][j].size()); + memory_ptr += data_lists[i][j].size(); + } + } + assert(sum == total_size); + return total_size; // OK +} + +} // tinyexr + +size_t SaveEXRImageToMemory(const EXRImage* exr_image, + const EXRHeader* exr_header, + unsigned char** memory_out, const char** err) { + return tinyexr::SaveEXRNPartImageToMemory(exr_image, &exr_header, 1, memory_out, err); +} + +int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL || filename == NULL || + exr_header->compression_type < 0) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#if !TINYEXR_USE_PIZ + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + +#if !TINYEXR_USE_ZFP + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "wb"); +#endif +#else + fp = fopen(filename, "wb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + unsigned char *mem = NULL; + size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err); + if (mem_size == 0) { + return TINYEXR_ERROR_SERIALZATION_FAILED; + } + + size_t written_size = 0; + if ((mem_size > 0) && mem) { + written_size = fwrite(mem, 1, mem_size, fp); + } + free(mem); + + fclose(fp); + + if (written_size != mem_size) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + return TINYEXR_SUCCESS; +} + +size_t SaveEXRMultipartImageToMemory(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + unsigned char** memory_out, const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts < 2 || + memory_out == NULL) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } + return tinyexr::SaveEXRNPartImageToMemory(exr_images, exr_headers, num_parts, memory_out, err); +} + +int SaveEXRMultipartImageToFile(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + const char* filename, + const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts < 2) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRMultipartImageToFile", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "wb"); +#endif +#else + fp = fopen(filename, "wb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + unsigned char *mem = NULL; + size_t mem_size = SaveEXRMultipartImageToMemory(exr_images, exr_headers, num_parts, &mem, err); + if (mem_size == 0) { + return TINYEXR_ERROR_SERIALZATION_FAILED; + } + + size_t written_size = 0; + if ((mem_size > 0) && mem) { + written_size = fwrite(mem, 1, mem_size, fp); + } + free(mem); + + fclose(fp); + + if (written_size != mem_size) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + return TINYEXR_SUCCESS; +} + +int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { + if (deep_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + FILE *fp = fopen(filename, "rb"); + if (!fp) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#endif + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize == 0) { + fclose(fp); + tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + (void)ret; + } + fclose(fp); + + const char *head = &buf[0]; + const char *marker = &buf[0]; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + tinyexr::SetErrorMessage("Invalid magic number", err); + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + // Version, scanline. + { + // ver 2.0, scanline, deep bit on(0x800) + // must be [2, 0, 0, 0] + if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) { + tinyexr::SetErrorMessage("Unsupported version or scanline", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + marker += 4; + } + + int dx = -1; + int dy = -1; + int dw = -1; + int dh = -1; + int num_scanline_blocks = 1; // 16 for ZIP compression. + int compression_type = -1; + int num_channels = -1; + std::vector channels; + + // Read attributes + size_t size = filesize - tinyexr::kEXRVersionSize; + for (;;) { + if (0 == size) { + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + marker++; + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + std::stringstream ss; + ss << "Failed to parse attribute\n"; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + if (attr_name.compare("compression") == 0) { + compression_type = data[0]; + if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) { + std::stringstream ss; + ss << "Unsupported compression type : " << compression_type; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!tinyexr::ReadChannelInfo(channels, data)) { + tinyexr::SetErrorMessage("Failed to parse channel info", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + num_channels = static_cast(channels.size()); + + if (num_channels < 1) { + tinyexr::SetErrorMessage("Invalid channels format", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + } else if (attr_name.compare("dataWindow") == 0) { + memcpy(&dx, &data.at(0), sizeof(int)); + memcpy(&dy, &data.at(4), sizeof(int)); + memcpy(&dw, &data.at(8), sizeof(int)); + memcpy(&dh, &data.at(12), sizeof(int)); + tinyexr::swap4(&dx); + tinyexr::swap4(&dy); + tinyexr::swap4(&dw); + tinyexr::swap4(&dh); + + } else if (attr_name.compare("displayWindow") == 0) { + int x; + int y; + int w; + int h; + memcpy(&x, &data.at(0), sizeof(int)); + memcpy(&y, &data.at(4), sizeof(int)); + memcpy(&w, &data.at(8), sizeof(int)); + memcpy(&h, &data.at(12), sizeof(int)); + tinyexr::swap4(&x); + tinyexr::swap4(&y); + tinyexr::swap4(&w); + tinyexr::swap4(&h); + } + } + + assert(dx >= 0); + assert(dy >= 0); + assert(dw >= 0); + assert(dh >= 0); + assert(num_channels >= 1); + + int data_width = dw - dx + 1; + int data_height = dh - dy + 1; + + std::vector image( + static_cast(data_width * data_height * 4)); // 4 = RGBA + + // Read offset tables. + int num_blocks = data_height / num_scanline_blocks; + if (num_blocks * num_scanline_blocks < data_height) { + num_blocks++; + } + + std::vector offsets(static_cast(num_blocks)); + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + tinyexr::tinyexr_int64 offset; + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&offset)); + marker += sizeof(tinyexr::tinyexr_int64); // = 8 + offsets[y] = offset; + } + +#if TINYEXR_USE_PIZ + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) || + (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) { +#else + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#endif + // OK + } else { + tinyexr::SetErrorMessage("Unsupported compression format", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + deep_image->image = static_cast( + malloc(sizeof(float **) * static_cast(num_channels))); + for (int c = 0; c < num_channels; c++) { + deep_image->image[c] = static_cast( + malloc(sizeof(float *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + } + } + + deep_image->offset_table = static_cast( + malloc(sizeof(int *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + deep_image->offset_table[y] = static_cast( + malloc(sizeof(int) * static_cast(data_width))); + } + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y]); + + // int: y coordinate + // int64: packed size of pixel offset table + // int64: packed size of sample data + // int64: unpacked size of sample data + // compressed pixel offset table + // compressed sample data + int line_no; + tinyexr::tinyexr_int64 packedOffsetTableSize; + tinyexr::tinyexr_int64 packedSampleDataSize; + tinyexr::tinyexr_int64 unpackedSampleDataSize; + memcpy(&line_no, data_ptr, sizeof(int)); + memcpy(&packedOffsetTableSize, data_ptr + 4, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&packedSampleDataSize, data_ptr + 12, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&unpackedSampleDataSize, data_ptr + 20, + sizeof(tinyexr::tinyexr_int64)); + + tinyexr::swap4(&line_no); + tinyexr::swap8( + reinterpret_cast(&packedOffsetTableSize)); + tinyexr::swap8( + reinterpret_cast(&packedSampleDataSize)); + tinyexr::swap8( + reinterpret_cast(&unpackedSampleDataSize)); + + std::vector pixelOffsetTable(static_cast(data_width)); + + // decode pixel offset table. + { + unsigned long dstLen = + static_cast(pixelOffsetTable.size() * sizeof(int)); + if (!tinyexr::DecompressZip( + reinterpret_cast(&pixelOffsetTable.at(0)), + &dstLen, data_ptr + 28, + static_cast(packedOffsetTableSize))) { + return false; + } + + assert(dstLen == pixelOffsetTable.size() * sizeof(int)); + for (size_t i = 0; i < static_cast(data_width); i++) { + deep_image->offset_table[y][i] = pixelOffsetTable[i]; + } + } + + std::vector sample_data( + static_cast(unpackedSampleDataSize)); + + // decode sample data. + { + unsigned long dstLen = static_cast(unpackedSampleDataSize); + if (dstLen) { + if (!tinyexr::DecompressZip( + reinterpret_cast(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast(packedSampleDataSize))) { + return false; + } + assert(dstLen == static_cast(unpackedSampleDataSize)); + } + } + + // decode sample + int sampleSize = -1; + std::vector channel_offset_list(static_cast(num_channels)); + { + int channel_offset = 0; + for (size_t i = 0; i < static_cast(num_channels); i++) { + channel_offset_list[i] = channel_offset; + if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT + channel_offset += 4; + } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half + channel_offset += 2; + } else if (channels[i].pixel_type == + TINYEXR_PIXELTYPE_FLOAT) { // float + channel_offset += 4; + } else { + assert(0); + } + } + sampleSize = channel_offset; + } + assert(sampleSize >= 2); + + assert(static_cast( + pixelOffsetTable[static_cast(data_width - 1)] * + sampleSize) == sample_data.size()); + int samples_per_line = static_cast(sample_data.size()) / sampleSize; + + // + // Alloc memory + // + + // + // pixel data is stored as image[channels][pixel_samples] + // + { + tinyexr::tinyexr_uint64 data_offset = 0; + for (size_t c = 0; c < static_cast(num_channels); c++) { + deep_image->image[c][y] = static_cast( + malloc(sizeof(float) * static_cast(samples_per_line))); + + if (channels[c].pixel_type == 0) { // UINT + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + unsigned int ui; + unsigned int *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(int))); + tinyexr::cpy4(&ui, src_ptr); + deep_image->image[c][y][x] = static_cast(ui); // @fixme + } + data_offset += + sizeof(unsigned int) * static_cast(samples_per_line); + } else if (channels[c].pixel_type == 1) { // half + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + tinyexr::FP16 f16; + const unsigned short *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(short))); + tinyexr::cpy2(&(f16.u), src_ptr); + tinyexr::FP32 f32 = half_to_float(f16); + deep_image->image[c][y][x] = f32.f; + } + data_offset += sizeof(short) * static_cast(samples_per_line); + } else { // float + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + float f; + const float *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(float))); + tinyexr::cpy4(&f, src_ptr); + deep_image->image[c][y][x] = f; + } + data_offset += sizeof(float) * static_cast(samples_per_line); + } + } + } + } // y + + deep_image->width = data_width; + deep_image->height = data_height; + + deep_image->channel_names = static_cast( + malloc(sizeof(const char *) * static_cast(num_channels))); + for (size_t c = 0; c < static_cast(num_channels); c++) { +#ifdef _WIN32 + deep_image->channel_names[c] = _strdup(channels[c].name.c_str()); +#else + deep_image->channel_names[c] = strdup(channels[c].name.c_str()); +#endif + } + deep_image->num_channels = num_channels; + + return TINYEXR_SUCCESS; +} + +void InitEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return; + } + + exr_image->width = 0; + exr_image->height = 0; + exr_image->num_channels = 0; + + exr_image->images = NULL; + exr_image->tiles = NULL; + exr_image->next_level = NULL; + exr_image->level_x = 0; + exr_image->level_y = 0; + + exr_image->num_tiles = 0; +} + +void FreeEXRErrorMessage(const char *msg) { + if (msg) { + free(reinterpret_cast(const_cast(msg))); + } + return; +} + +void InitEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return; + } + + memset(exr_header, 0, sizeof(EXRHeader)); +} + +int FreeEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->channels) { + free(exr_header->channels); + } + + if (exr_header->pixel_types) { + free(exr_header->pixel_types); + } + + if (exr_header->requested_pixel_types) { + free(exr_header->requested_pixel_types); + } + + for (int i = 0; i < exr_header->num_custom_attributes; i++) { + if (exr_header->custom_attributes[i].value) { + free(exr_header->custom_attributes[i].value); + } + } + + if (exr_header->custom_attributes) { + free(exr_header->custom_attributes); + } + + EXRSetNameAttr(exr_header, NULL); + + return TINYEXR_SUCCESS; +} + +void EXRSetNameAttr(EXRHeader* exr_header, const char* name) { + if (exr_header == NULL) { + return; + } + memset(exr_header->name, 0, 256); + if (name != NULL) { + size_t len = std::min(strlen(name), (size_t)255); + if (len) { + memcpy(exr_header->name, name, len); + } + } +} + +int EXRNumLevels(const EXRImage* exr_image) { + if (exr_image == NULL) return 0; + if(exr_image->images) return 1; // scanlines + int levels = 1; + const EXRImage* level_image = exr_image; + while((level_image = level_image->next_level)) ++levels; + return levels; +} + +int FreeEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_image->next_level) { + FreeEXRImage(exr_image->next_level); + delete exr_image->next_level; + } + + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->images && exr_image->images[i]) { + free(exr_image->images[i]); + } + } + + if (exr_image->images) { + free(exr_image->images); + } + + if (exr_image->tiles) { + for (int tid = 0; tid < exr_image->num_tiles; tid++) { + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) { + free(exr_image->tiles[tid].images[i]); + } + } + if (exr_image->tiles[tid].images) { + free(exr_image->tiles[tid].images); + } + } + free(exr_image->tiles); + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_header == NULL || exr_version == NULL || filename == NULL) { + tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_INVALID_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("fread() error on " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize, + err); +} + +int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, + int *num_headers, + const EXRVersion *exr_version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_headers == NULL || num_headers == NULL || + exr_version == NULL) { + // Invalid argument + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Data size too short", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + std::vector infos; + + for (;;) { + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + bool empty_header = false; + int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str, + marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage(err_str, err); + return ret; + } + + if (empty_header) { + marker += 1; // skip '\0' + break; + } + + // `chunkCount` must exist in the header. + if (info.chunk_count == 0) { + tinyexr::SetErrorMessage( + "`chunkCount' attribute is not found in the header.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + infos.push_back(info); + + // move to next header. + marker += info.header_len; + size -= info.header_len; + } + + // allocate memory for EXRHeader and create array of EXRHeader pointers. + (*exr_headers) = + static_cast(malloc(sizeof(EXRHeader *) * infos.size())); + for (size_t i = 0; i < infos.size(); i++) { + EXRHeader *exr_header = static_cast(malloc(sizeof(EXRHeader))); + memset(exr_header, 0, sizeof(EXRHeader)); + + ConvertHeader(exr_header, infos[i]); + + exr_header->multipart = exr_version->multipart ? 1 : 0; + + (*exr_headers)[i] = exr_header; + } + + (*num_headers) = static_cast(infos.size()); + + return TINYEXR_SUCCESS; +} + +int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, + const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_headers == NULL || num_headers == NULL || exr_version == NULL || + filename == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromFile()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_INVALID_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRMultipartHeaderFromMemory( + exr_headers, num_headers, exr_version, &buf.at(0), filesize, err); +} + +int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, + size_t size) { + if (version == NULL || memory == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + version->tiled = false; + version->long_name = false; + version->non_image = false; + version->multipart = false; + + // Parse version header. + { + // must be 2 + if (marker[0] != 2) { + return TINYEXR_ERROR_INVALID_EXR_VERSION; + } + + if (version == NULL) { + return TINYEXR_SUCCESS; // May OK + } + + version->version = 2; + + if (marker[1] & 0x2) { // 9th bit + version->tiled = true; + } + if (marker[1] & 0x4) { // 10th bit + version->long_name = true; + } + if (marker[1] & 0x8) { // 11th bit + version->non_image = true; // (deep image) + } + if (marker[1] & 0x10) { // 12th bit + version->multipart = true; + } + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) { + if (filename == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t err = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (err != 0) { + // TODO(syoyo): return wfopen_s erro code + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t file_size; + // Compute size + fseek(fp, 0, SEEK_END); + file_size = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (file_size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + unsigned char buf[tinyexr::kEXRVersionSize]; + size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp); + fclose(fp); + + if (ret != tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize); +} + +int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || + memory == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromMemory()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + // compute total header size. + size_t total_header_size = 0; + for (unsigned int i = 0; i < num_parts; i++) { + if (exr_headers[i]->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + total_header_size += exr_headers[i]->header_len; + } + + const char *marker = reinterpret_cast( + memory + total_header_size + 4 + + 4); // +8 for magic number and version header. + + marker += 1; // Skip empty header. + + // NOTE 1: + // In multipart image, There is 'part number' before chunk data. + // 4 byte : part number + // 4+ : chunk + // + // NOTE 2: + // EXR spec says 'part number' is 'unsigned long' but actually this is + // 'unsigned int(4 bytes)' in OpenEXR implementation... + // http://www.openexr.com/openexrfilelayout.pdf + + // Load chunk offset table. + std::vector chunk_offset_table_list; + chunk_offset_table_list.reserve(num_parts); + for (size_t i = 0; i < static_cast(num_parts); i++) { + chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1); + tinyexr::OffsetData& offset_data = chunk_offset_table_list.back(); + if (!exr_headers[i]->tiled || exr_headers[i]->tile_level_mode == TINYEXR_TILE_ONE_LEVEL) { + tinyexr::InitSingleResolutionOffsets(offset_data, exr_headers[i]->chunk_count); + std::vector& offset_table = offset_data.offsets[0][0]; + + for (size_t c = 0; c < offset_table.size(); c++) { + tinyexr::tinyexr_uint64 offset; + memcpy(&offset, marker, 8); + tinyexr::swap8(&offset); + + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + + offset_table[c] = offset + 4; // +4 to skip 'part number' + marker += 8; + } + } else { + { + std::vector num_x_tiles, num_y_tiles; + tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]); + int num_blocks = InitTileOffsets(offset_data, exr_headers[i], num_x_tiles, num_y_tiles); + if (num_blocks != exr_headers[i]->chunk_count) { + tinyexr::SetErrorMessage("Invalid offset table size.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 offset; + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + offset_data.offsets[l][dy][dx] = offset + 4; // +4 to skip 'part number' + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + } + } + } + } + } + + // Decode image. + for (size_t i = 0; i < static_cast(num_parts); i++) { + tinyexr::OffsetData &offset_data = chunk_offset_table_list[i]; + + // First check 'part number' is identitical to 'i' + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + + const unsigned char *part_number_addr = + memory + offset_data.offsets[l][dy][dx] - 4; // -4 to move to 'part number' field. + unsigned int part_no; + memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4 + tinyexr::swap4(&part_no); + + if (part_no != i) { + tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + std::string e; + int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_data, + memory, size, &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + return ret; + } + } + + return TINYEXR_SUCCESS; +} + +int LoadEXRMultipartImageFromFile(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, const char *filename, + const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts, + &buf.at(0), filesize, err); +} + +int SaveEXR(const float *data, int width, int height, int components, + const int save_as_fp16, const char *outfilename, const char **err) { + if ((components == 1) || components == 3 || components == 4) { + // OK + } else { + std::stringstream ss; + ss << "Unsupported component value : " << components << std::endl; + + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRHeader header; + InitEXRHeader(&header); + + if ((width < 16) && (height < 16)) { + // No compression for small image. + header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE; + } else { + header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; + } + + EXRImage image; + InitEXRImage(&image); + + image.num_channels = components; + + std::vector images[4]; + + if (components == 1) { + images[0].resize(static_cast(width * height)); + memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); + } else { + images[0].resize(static_cast(width * height)); + images[1].resize(static_cast(width * height)); + images[2].resize(static_cast(width * height)); + images[3].resize(static_cast(width * height)); + + // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers + for (size_t i = 0; i < static_cast(width * height); i++) { + images[0][i] = data[static_cast(components) * i + 0]; + images[1][i] = data[static_cast(components) * i + 1]; + images[2][i] = data[static_cast(components) * i + 2]; + if (components == 4) { + images[3][i] = data[static_cast(components) * i + 3]; + } + } + } + + float *image_ptr[4] = {0, 0, 0, 0}; + if (components == 4) { + image_ptr[0] = &(images[3].at(0)); // A + image_ptr[1] = &(images[2].at(0)); // B + image_ptr[2] = &(images[1].at(0)); // G + image_ptr[3] = &(images[0].at(0)); // R + } else if (components == 3) { + image_ptr[0] = &(images[2].at(0)); // B + image_ptr[1] = &(images[1].at(0)); // G + image_ptr[2] = &(images[0].at(0)); // R + } else if (components == 1) { + image_ptr[0] = &(images[0].at(0)); // A + } + + image.images = reinterpret_cast(image_ptr); + image.width = width; + image.height = height; + + header.num_channels = components; + header.channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(header.num_channels))); + // Must be (A)BGR order, since most of EXR viewers expect this channel order. + if (components == 4) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); + strncpy_s(header.channels[1].name, "B", 255); + strncpy_s(header.channels[2].name, "G", 255); + strncpy_s(header.channels[3].name, "R", 255); +#else + strncpy(header.channels[0].name, "A", 255); + strncpy(header.channels[1].name, "B", 255); + strncpy(header.channels[2].name, "G", 255); + strncpy(header.channels[3].name, "R", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + header.channels[1].name[strlen("B")] = '\0'; + header.channels[2].name[strlen("G")] = '\0'; + header.channels[3].name[strlen("R")] = '\0'; + } else if (components == 3) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "B", 255); + strncpy_s(header.channels[1].name, "G", 255); + strncpy_s(header.channels[2].name, "R", 255); +#else + strncpy(header.channels[0].name, "B", 255); + strncpy(header.channels[1].name, "G", 255); + strncpy(header.channels[2].name, "R", 255); +#endif + header.channels[0].name[strlen("B")] = '\0'; + header.channels[1].name[strlen("G")] = '\0'; + header.channels[2].name[strlen("R")] = '\0'; + } else { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); +#else + strncpy(header.channels[0].name, "A", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + } + + header.pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + header.requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + for (int i = 0; i < header.num_channels; i++) { + header.pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image + + if (save_as_fp16 > 0) { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format + } else { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. + // no precision reduction) + } + } + + int ret = SaveEXRImageToFile(&image, &header, outfilename, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + free(header.channels); + free(header.pixel_types); + free(header.requested_pixel_types); + + return ret; +} + +#ifdef __clang__ +// zero-as-null-ppinter-constant +#pragma clang diagnostic pop +#endif + +#endif // TINYEXR_IMPLEMENTATION_DEFINED +#endif // TINYEXR_IMPLEMENTATION \ No newline at end of file diff --git a/thirdparty/tinyobjloader/CMakeLists.txt b/thirdparty/tinyobjloader/CMakeLists.txt new file mode 100644 index 0000000..674e265 --- /dev/null +++ b/thirdparty/tinyobjloader/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(tiny_obj_loader + tiny_obj_loader.hxx + tiny_obj_loader.cxx +) + +target_include_directories(tiny_obj_loader PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +set_target_properties(tiny_obj_loader PROPERTIES FOLDER "thirdparty") diff --git a/thirdparty/tinyobjloader/tiny_obj_loader.cxx b/thirdparty/tinyobjloader/tiny_obj_loader.cxx new file mode 100644 index 0000000..6b8d131 --- /dev/null +++ b/thirdparty/tinyobjloader/tiny_obj_loader.cxx @@ -0,0 +1,2 @@ +#define TINYOBJLOADER_IMPLEMENTATION 1 +#include "tiny_obj_loader.hxx" diff --git a/thirdparty/tinyobjloader/tiny_obj_loader.hxx b/thirdparty/tinyobjloader/tiny_obj_loader.hxx new file mode 100644 index 0000000..4712c7d --- /dev/null +++ b/thirdparty/tinyobjloader/tiny_obj_loader.hxx @@ -0,0 +1,3351 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-Present, Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 2.0.0 : Add new object oriented API. 1.x API is still provided. +// * Support line primitive. +// * Support points primitive. +// * Support multiple search path for .mtl(v1 API). +// * Support vertex weight `vw`(as an tinyobj extension) +// * Support escaped whitespece in mtllib +// * Add robust triangulation using Mapbox earcut(TINYOBJLOADER_USE_MAPBOX_EARCUT). +// version 1.4.0 : Modifed ParseTextureNameAndOption API +// version 1.3.1 : Make ParseTextureNameAndOption API public +// version 1.3.0 : Separate warning and error message(breaking API of LoadObj) +// version 1.2.3 : Added color space extension('-colorspace') to tex opts. +// version 1.2.2 : Parse multiple group names. +// version 1.2.1 : Added initial support for line('l') primitive(PR #178) +// version 1.2.0 : Hardened implementation(#175) +// version 1.1.1 : Support smoothing groups(#162) +// version 1.1.0 : Support parsing vertex color(#144) +// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) +// version 1.0.7 : Support multiple tex options(#126) +// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124) +// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43) +// version 1.0.4 : Support multiple filenames for 'mtllib'(#112) +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// TODO(syoyo): Better C++11 detection for older compiler +#if __cplusplus > 199711L +#define TINYOBJ_OVERRIDE override +#else +#define TINYOBJ_OVERRIDE +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#pragma clang diagnostic ignored "-Wpadded" + +#endif + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost real_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right +// +// TinyObjLoader extension. +// +// -colorspace SPACE # Color space of the texture. e.g. +// 'sRGB` or 'linear' +// + +#ifdef TINYOBJLOADER_USE_DOUBLE +//#pragma message "using double" +typedef double real_t; +#else +//#pragma message "using float" +typedef float real_t; +#endif + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +struct texture_option_t { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + real_t sharpness; // -boost (default 1.0?) + real_t brightness; // base_value in -mm option (default 0) + real_t contrast; // gain_value in -mm option (default 1) + real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) + real_t scale[3]; // -s u [v [w]] (default 1 1 1) + real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) + int texture_resolution; // -texres resolution (No default value in the spec. + // We'll use -1) + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + real_t bump_multiplier; // -bm (for bump maps only, default 1.0) + + // extension + std::string colorspace; // Explicitly specify color space of stored texel + // value. Usually `sRGB` or `linear` (default empty). +}; + +struct material_t { + std::string name; + + real_t ambient[3]; + real_t diffuse[3] = {1.0f, 1.0f, 1.0f}; + real_t specular[3] = {1.0f, 1.0f, 1.0f}; + real_t transmittance[3] = {1.0f, 1.0f, 1.0f}; + real_t emission[3] = {0.0f, 0.0f, 0.0f}; + real_t shininess; + real_t ior; // index of refraction + real_t dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, map_Bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + std::string reflection_texname; // refl + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + texture_option_t reflection_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + real_t roughness; // [0, 1] default 0 + real_t metallic; // [0, 1] default 0 + real_t sheen; // [0, 1] default 0 + real_t clearcoat_thickness; // [0, 1] default 0 + real_t clearcoat_roughness; // [0, 1] default 0 + real_t anisotropy; // aniso. [0, 1] default 0 + real_t anisotropy_rotation; // anisor. [0, 1] default 0 + real_t pad0; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; + +#ifdef TINY_OBJ_LOADER_PYTHON_BINDING + // For pybind11 + std::array GetDiffuse() { + std::array values; + values[0] = double(diffuse[0]); + values[1] = double(diffuse[1]); + values[2] = double(diffuse[2]); + + return values; + } + + std::array GetSpecular() { + std::array values; + values[0] = double(specular[0]); + values[1] = double(specular[1]); + values[2] = double(specular[2]); + + return values; + } + + std::array GetTransmittance() { + std::array values; + values[0] = double(transmittance[0]); + values[1] = double(transmittance[1]); + values[2] = double(transmittance[2]); + + return values; + } + + std::array GetEmission() { + std::array values; + values[0] = double(emission[0]); + values[1] = double(emission[1]); + values[2] = double(emission[2]); + + return values; + } + + std::array GetAmbient() { + std::array values; + values[0] = double(ambient[0]); + values[1] = double(ambient[1]); + values[2] = double(ambient[2]); + + return values; + } + + void SetDiffuse(std::array& a) { + diffuse[0] = real_t(a[0]); + diffuse[1] = real_t(a[1]); + diffuse[2] = real_t(a[2]); + } + + void SetAmbient(std::array& a) { + ambient[0] = real_t(a[0]); + ambient[1] = real_t(a[1]); + ambient[2] = real_t(a[2]); + } + + void SetSpecular(std::array& a) { + specular[0] = real_t(a[0]); + specular[1] = real_t(a[1]); + specular[2] = real_t(a[2]); + } + + void SetTransmittance(std::array& a) { + transmittance[0] = real_t(a[0]); + transmittance[1] = real_t(a[1]); + transmittance[2] = real_t(a[2]); + } + + std::string GetCustomParameter(const std::string& key) { + std::map::const_iterator it = unknown_parameter.find(key); + + if (it != unknown_parameter.end()) { + return it->second; + } + return std::string(); + } + +#endif +}; + +struct tag_t { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +}; + +struct joint_and_weight_t { + int joint_id; + real_t weight; +}; + +struct skin_weight_t { + int vertex_id; // Corresponding vertex index in `attrib_t::vertices`. + // Compared to `index_t`, this index must be positive and + // start with 0(does not allow relative indexing) + std::vector weightValues; +}; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +struct index_t { + int vertex_index; + int normal_index; + int texcoord_index; +}; + +struct mesh_t { + std::vector indices; + std::vector num_face_vertices; // The number of vertices per + // face. 3 = triangle, 4 = quad, + // ... Up to 255 vertices per face. + std::vector material_ids; // per-face material ID + std::vector smoothing_group_ids; // per-face smoothing group + // ID(0 = off. positive value + // = group id) + std::vector tags; // SubD tag +}; + +// struct path_t { +// std::vector indices; // pairs of indices for lines +//}; + +struct lines_t { + // Linear flattened indices. + std::vector indices; // indices for vertices(poly lines) + std::vector num_line_vertices; // The number of vertices per line. +}; + +struct points_t { + std::vector indices; // indices for points +}; + +struct shape_t { + std::string name; + mesh_t mesh; + lines_t lines; + points_t points; +}; + +// Vertex attributes +struct attrib_t { + std::vector vertices; // 'v'(xyz) + + // For backward compatibility, we store vertex weight in separate array. + std::vector vertex_weights; // 'v'(w) + std::vector normals; // 'vn' + std::vector texcoords; // 'vt'(uv) + + // For backward compatibility, we store texture coordinate 'w' in separate + // array. + std::vector texcoord_ws; // 'vt'(w) + std::vector colors; // extension: vertex colors + + // + // TinyObj extension. + // + + // NOTE(syoyo): array index is based on the appearance order. + // To get a corresponding skin weight for a specific vertex id `vid`, + // Need to reconstruct a look up table: `skin_weight_t::vertex_id` == `vid` + // (e.g. using std::map, std::unordered_map) + std::vector skin_weights; + + attrib_t() { + } + + // + // For pybind11 + // + const std::vector& GetVertices() const { + return vertices; + } + + const std::vector& GetVertexWeights() const { + return vertex_weights; + } +}; + +struct callback_t { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void* user_data, real_t x, real_t y, real_t z, real_t w); + void (*normal_cb)(void* user_data, real_t x, real_t y, real_t z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void* user_data, real_t x, real_t y, real_t z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void* user_data, index_t* indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void* user_data, const char* name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void* user_data, const material_t* materials, int num_materials); + // There may be multiple group names + void (*group_cb)(void* user_data, const char** names, int num_names); + void (*object_cb)(void* user_data, const char* name); + + callback_t() + : vertex_cb(NULL) + , normal_cb(NULL) + , texcoord_cb(NULL) + , index_cb(NULL) + , usemtl_cb(NULL) + , mtllib_cb(NULL) + , group_cb(NULL) + , object_cb(NULL) { + } +}; + +class MaterialReader { + public: + MaterialReader() { + } + virtual ~MaterialReader(); + + virtual bool operator()(const std::string& matId, std::vector* materials, std::map* matMap, std::string* warn, std::string* err) = 0; +}; + +/// +/// Read .mtl from a file. +/// +class MaterialFileReader : public MaterialReader { + public: + // Path could contain separator(';' in Windows, ':' in Posix) + explicit MaterialFileReader(const std::string& mtl_basedir) + : m_mtlBaseDir(mtl_basedir) { + } + virtual ~MaterialFileReader() TINYOBJ_OVERRIDE { + } + virtual bool operator()(const std::string& matId, std::vector* materials, std::map* matMap, std::string* warn, std::string* err) TINYOBJ_OVERRIDE; + + private: + std::string m_mtlBaseDir; +}; + +/// +/// Read .mtl from a stream. +/// +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream& inStream) + : m_inStream(inStream) { + } + virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE { + } + virtual bool operator()(const std::string& matId, std::vector* materials, std::map* matMap, std::string* warn, std::string* err) TINYOBJ_OVERRIDE; + + private: + std::istream& m_inStream; +}; + +// v2 API +struct ObjReaderConfig { + bool triangulate; // triangulate polygon? + + // Currently not used. + // "simple" or empty: Create triangle fan + // "earcut": Use the algorithm based on Ear clipping + std::string triangulation_method; + + /// Parse vertex color. + /// If vertex color is not present, its filled with default value. + /// false = no vertex color + /// This will increase memory of parsed .obj + bool vertex_color; + + /// + /// Search path to .mtl file. + /// Default = "" = search from the same directory of .obj file. + /// Valid only when loading .obj from a file. + /// + std::string mtl_search_path; + + ObjReaderConfig() + : triangulate(true) + , triangulation_method("simple") + , vertex_color(true) { + } +}; + +/// +/// Wavefront .obj reader class(v2 API) +/// +class ObjReader { + public: + ObjReader() + : valid_(false) { + } + ~ObjReader() { + } + + /// + /// Load .obj and .mtl from a file. + /// + /// @param[in] filename wavefront .obj filename + /// @param[in] config Reader configuration + /// + bool ParseFromFile(const std::string& filename, const std::string& customMataterials, const ObjReaderConfig& config = ObjReaderConfig()); + + /// + /// Parse .obj from a text string. + /// Need to supply .mtl text string by `mtl_text`. + /// This function ignores `mtllib` line in .obj text. + /// + /// @param[in] obj_text wavefront .obj filename + /// @param[in] mtl_text wavefront .mtl filename + /// @param[in] config Reader configuration + /// + bool ParseFromString(const std::string& obj_text, const std::string& mtl_text, const ObjReaderConfig& config = ObjReaderConfig()); + + /// + /// .obj was loaded or parsed correctly. + /// + bool Valid() const { + return valid_; + } + + const attrib_t& GetAttrib() const { + return attrib_; + } + + const std::vector& GetShapes() const { + return shapes_; + } + + const std::vector& GetMaterials() const { + return materials_; + } + + /// + /// Warning message(may be filled after `Load` or `Parse`) + /// + const std::string& Warning() const { + return warning_; + } + + /// + /// Error message(filled when `Load` or `Parse` failed) + /// + const std::string& Error() const { + return error_; + } + + private: + bool valid_; + + attrib_t attrib_; + std::vector shapes_; + std::vector materials_; + + std::string warning_; + std::string error_; +}; + +/// ==>>========= Legacy v1 API ============================================= + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning message into `warn`, and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working +/// directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +/// Option 'default_vcols_fallback' specifies whether vertex colors should +/// always be defined, even if no colors are given (fallback to white). +bool LoadObj(attrib_t* attrib, std::vector* shapes, std::vector* materials, std::string* warn, std::string* err, const char* filename, + const char* mtl_basedir = NULL, const char* mtl_custom_file = NULL, bool triangulate = true, bool default_vcols_fallback = true); + +bool LoadObjMaterials(std::vector* materials, std::string* warn, std::string* err, const char* filename, const char* mtl_basedir = NULL, + const char* mtl_custom_file = NULL); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning message into `warn`, and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream& inStream, const callback_t& callback, void* user_data = NULL, MaterialReader* readMatFn = NULL, std::string* warn = NULL, + std::string* err = NULL); + +/// Loads object from a std::istream, uses `readMatFn` to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t* attrib, std::vector* shapes, std::vector* materials, std::string* warn, std::string* err, std::istream* inStream, + MaterialReader* readMatFn, const std::string& customMaterials, bool triangulate = true, bool default_vcols_fallback = true); + +bool LoadObjMaterials(std::vector* materials, std::string* warn, std::string* err, std::istream* inStream, MaterialReader* readMatFn, + const std::string& customMaterials); + +/// Loads materials into std::map +void LoadMtl(std::map* material_map, std::vector* materials, std::istream* inStream, std::string* warning, std::string* err); + +/// +/// Parse texture name and texture option for custom texture parameter through +/// material::unknown_parameter +/// +/// @param[out] texname Parsed texture name +/// @param[out] texopt Parsed texopt +/// @param[in] linebuf Input string +/// +bool ParseTextureNameAndOption(std::string* texname, texture_option_t* texopt, const char* linebuf); + +/// =<<========== Legacy v1 API ============================================= + +} // namespace tinyobj + +#endif // TINY_OBJ_LOADER_H_ + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT + +#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT +// Assume earcut.hpp is included outside of tiny_obj_loader.h +#else + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +#include +#include "mapbox/earcut.hpp" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#endif // TINYOBJLOADER_USE_MAPBOX_EARCUT + +namespace tinyobj { + +MaterialReader::~MaterialReader() { +} + +struct vertex_index_t { + int v_idx, vt_idx, vn_idx; + vertex_index_t() + : v_idx(-1) + , vt_idx(-1) + , vn_idx(-1) { + } + explicit vertex_index_t(int idx) + : v_idx(idx) + , vt_idx(idx) + , vn_idx(idx) { + } + vertex_index_t(int vidx, int vtidx, int vnidx) + : v_idx(vidx) + , vt_idx(vtidx) + , vn_idx(vnidx) { + } +}; + +// Internal data structure for face representation +// index + smoothing group. +struct face_t { + unsigned int smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() + : smoothing_group_id(0) + , pad_(0) { + } +}; + +// Internal data structure for line representation +struct __line_t { + // l v1/vt1 v2/vt2 ... + // In the specification, line primitrive does not have normal index, but + // TinyObjLoader allow it + std::vector vertex_indices; +}; + +// Internal data structure for points representation +struct __points_t { + // p v1 v2 ... + // In the specification, point primitrive does not have normal index and + // texture coord index, but TinyObjLoader allow it. + std::vector vertex_indices; +}; + +struct tag_sizes { + tag_sizes() + : num_ints(0) + , num_reals(0) + , num_strings(0) { + } + int num_ints; + int num_reals; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// +// Manages group of primitives(face, line, points, ...) +struct PrimGroup { + std::vector faceGroup; + std::vector<__line_t> lineGroup; + std::vector<__points_t> pointsGroup; + + void clear() { + faceGroup.clear(); + lineGroup.clear(); + pointsGroup.clear(); + } + + bool IsEmpty() const { + return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty(); + } + + // TODO(syoyo): bspline, surface, ... +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream& safeGetline(std::istream& is, std::string& t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf* sb = is.rdbuf(); + + if (se) { + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') + sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) + is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } + } + + return is; +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline bool fixIndex(int idx, int n, int* ret) { + if (!ret) { + return false; + } + + if (idx > 0) { + (*ret) = idx - 1; + return true; + } + + if (idx == 0) { + // zero is not allowed according to the spec. + return false; + } + + if (idx < 0) { + (*ret) = n + idx; // negative value = relative + return true; + } + + return false; // never reach here. +} + +static inline std::string parseString(const char** token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char** token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char* s, const char* s_end, double* result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const* curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + bool leading_decimal_dots = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + if ((curr != s_end) && (*curr == '.')) { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else if (*curr == '.') { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + if (!leading_decimal_dots) { + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) + goto fail; + } + + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) + goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, + 0.1, + 0.01, + 0.001, + 0.0001, + 0.00001, + 0.000001, + 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) + goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + if (exponent > std::numeric_limits::max() / 10) { + // Integer overflow + goto fail; + } + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) + goto fail; + } + +assemble: + *result = (sign == '+' ? 1 : -1) * (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa); + return true; +fail: + return false; +} + +static inline real_t parseReal(const char** token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + real_t f = static_cast(val); + (*token) = end; + return f; +} + +static inline bool parseReal(const char** token, real_t* out) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + double val; + bool ret = tryParseDouble((*token), end, &val); + if (ret) { + real_t f = static_cast(val); + (*out) = f; + } + (*token) = end; + return ret; +} + +static inline void parseReal2(real_t* x, real_t* y, const char** token, const double default_x = 0.0, const double default_y = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); +} + +static inline void parseReal3(real_t* x, real_t* y, real_t* z, const char** token, const double default_x = 0.0, const double default_y = 0.0, const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); +} + +static inline void parseV(real_t* x, real_t* y, real_t* z, real_t* w, const char** token, const double default_x = 0.0, const double default_y = 0.0, const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + (*w) = parseReal(token, default_w); +} + +// Extension: parse vertex with colors(6 items) +static inline bool parseVertexWithColor(real_t* x, real_t* y, real_t* z, real_t* r, real_t* g, real_t* b, const char** token, const double default_x = 0.0, + const double default_y = 0.0, const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + + const bool found_color = parseReal(token, r) && parseReal(token, g) && parseReal(token, b); + + if (!found_color) { + (*r) = (*g) = (*b) = 1.0; + } + + return found_color; +} + +static inline bool parseOnOff(const char** token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == _strnicmp((*token), "on", 2))) { + ret = true; + } else if ((0 == _strnicmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType(const char** token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == _strnicmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == _strnicmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == _strnicmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == _strnicmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == _strnicmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == _strnicmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == _strnicmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char** token) { + tag_sizes ts; + + (*token) += strspn((*token), " \t"); + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + + (*token)++; // Skip '/' + + (*token) += strspn((*token), " \t"); + ts.num_reals = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; // Skip '/' + + ts.num_strings = parseInt(token); + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static bool parseTriple(const char** token, int vsize, int vnsize, int vtsize, vertex_index_t* ret) { + if (!ret) { + return false; + } + + vertex_index_t vi(-1); + + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + (*ret) = vi; + return true; + } + + // i/j/k or i/j + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + + // i/j/k + (*token)++; // skip '/' + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + + (*ret) = vi; + + return true; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index_t parseRawTriple(const char** token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +bool ParseTextureNameAndOption(std::string* texname, texture_option_t* texopt, const char* linebuf) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + const char* token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + token += strspn(token, " \t"); // skip space + if ((0 == _strnicmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == _strnicmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == _strnicmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == _strnicmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseReal(&token, 1.0); + } else if ((0 == _strnicmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseReal(&token, 1.0); + } else if ((0 == _strnicmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), &(texopt->origin_offset[2]), &token); + } else if ((0 == _strnicmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), &token, 1.0, 1.0, 1.0); + } else if ((0 == _strnicmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), &(texopt->turbulence[2]), &token); + } else if ((0 == _strnicmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == _strnicmp(token, "-texres", 7)) && IS_SPACE((token[7]))) { + token += 7; + // TODO(syoyo): Check if arg is int type. + texopt->texture_resolution = parseInt(&token); + } else if ((0 == _strnicmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char* end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == _strnicmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else if ((0 == _strnicmp(token, "-colorspace", 11)) && IS_SPACE((token[11]))) { + token += 12; + texopt->colorspace = parseString(&token); + } else { +// Assume texture filename +#if 0 + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space +#else + // Read filename until line end to parse filename containing whitespace + // TODO(syoyo): Support parsing texture option flag after the filename. + texture_name = std::string(token); + token += texture_name.length(); +#endif + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitTexOpt(texture_option_t* texopt, const bool is_bump) { + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = static_cast(1.0); + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = static_cast(1.0); + texopt->brightness = static_cast(0.0); + texopt->contrast = static_cast(1.0); + texopt->origin_offset[0] = static_cast(0.0); + texopt->origin_offset[1] = static_cast(0.0); + texopt->origin_offset[2] = static_cast(0.0); + texopt->scale[0] = static_cast(1.0); + texopt->scale[1] = static_cast(1.0); + texopt->scale[2] = static_cast(1.0); + texopt->turbulence[0] = static_cast(0.0); + texopt->turbulence[1] = static_cast(0.0); + texopt->turbulence[2] = static_cast(0.0); + texopt->texture_resolution = -1; + texopt->type = TEXTURE_TYPE_NONE; +} + +static void InitMaterial(material_t* material) { + InitTexOpt(&material->ambient_texopt, /* is_bump */ false); + InitTexOpt(&material->diffuse_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false); + InitTexOpt(&material->bump_texopt, /* is_bump */ true); + InitTexOpt(&material->displacement_texopt, /* is_bump */ false); + InitTexOpt(&material->alpha_texopt, /* is_bump */ false); + InitTexOpt(&material->reflection_texopt, /* is_bump */ false); + InitTexOpt(&material->roughness_texopt, /* is_bump */ false); + InitTexOpt(&material->metallic_texopt, /* is_bump */ false); + InitTexOpt(&material->sheen_texopt, /* is_bump */ false); + InitTexOpt(&material->emissive_texopt, /* is_bump */ false); + InitTexOpt(&material->normal_texopt, + /* is_bump */ false); // @fixme { is_bump will be true? } + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->reflection_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = static_cast(0.0); + material->diffuse[i] = static_cast(1.0); + material->specular[i] = static_cast(1.0); + material->transmittance[i] = static_cast(1.0); + material->emission[i] = static_cast(0.0); + } + material->illum = 0; + material->dissolve = static_cast(1.0); + material->shininess = static_cast(1.0); + material->ior = static_cast(1.0); + + material->roughness = static_cast(0.0); + material->metallic = static_cast(0.0); + material->sheen = static_cast(0.0); + material->clearcoat_thickness = static_cast(0.0); + material->clearcoat_roughness = static_cast(0.0); + material->anisotropy_rotation = static_cast(0.0); + material->anisotropy = static_cast(0.0); + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html +template +static int pnpoly(int nvert, T* vertx, T* verty, T testx, T testy) { + int i, j, c = 0; + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i])) + c = !c; + } + return c; +} + +// TODO(syoyo): refactor function. +static bool exportGroupsToShape(shape_t* shape, const PrimGroup& prim_group, const std::vector& tags, const int material_id, const std::string& name, bool triangulate, + const std::vector& v, std::string* warn) { + if (prim_group.IsEmpty()) { + return false; + } + + shape->name = name; + + // polygon + if (!prim_group.faceGroup.empty()) { + // Flatten vertices and indices + for (size_t i = 0; i < prim_group.faceGroup.size(); i++) { + const face_t& face = prim_group.faceGroup[i]; + + size_t npolys = face.vertex_indices.size(); + + if (npolys < 3) { + // Face must have 3+ vertices. + if (warn) { + (*warn) += "Degenerated face found\n."; + } + continue; + } + + if (triangulate) { + if (npolys == 4) { + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1 = face.vertex_indices[1]; + vertex_index_t i2 = face.vertex_indices[2]; + vertex_index_t i3 = face.vertex_indices[3]; + + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + size_t vi3 = size_t(i3.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + if (warn) { + (*warn) += "Face with invalid vertex index found.\n"; + } + continue; + } + + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t v3x = v[vi3 * 3 + 0]; + real_t v3y = v[vi3 * 3 + 1]; + real_t v3z = v[vi3 * 3 + 2]; + + // There are two candidates to split the quad into two triangles. + // + // Choose the shortest edge. + // TODO: Is it better to determine the edge to split by calculating + // the area of each triangle? + // + // +---+ + // |\ | + // | \ | + // | \| + // +---+ + // + // +---+ + // | /| + // | / | + // |/ | + // +---+ + + real_t e02x = v2x - v0x; + real_t e02y = v2y - v0y; + real_t e02z = v2z - v0z; + real_t e13x = v3x - v1x; + real_t e13y = v3y - v1y; + real_t e13z = v3z - v1z; + + real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z; + real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z; + + index_t idx0, idx1, idx2, idx3; + + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + idx3.vertex_index = i3.v_idx; + idx3.normal_index = i3.vn_idx; + idx3.texcoord_index = i3.vt_idx; + + if (sqr02 < sqr13) { + // [0, 1, 2], [0, 2, 3] + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx2); + shape->mesh.indices.push_back(idx3); + } else { + // [0, 1, 3], [1, 2, 3] + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx3); + + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + shape->mesh.indices.push_back(idx3); + } + + // Two triangle faces + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.num_face_vertices.push_back(3); + + shape->mesh.material_ids.push_back(material_id); + shape->mesh.material_ids.push_back(material_id); + + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + + } else { + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; + + // find the two axes to work in + size_t axes[2] = {1, 2}; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + i2 = face.vertex_indices[(k + 2) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || ((3 * vi2 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + continue; + } + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t e0x = v1x - v0x; + real_t e0y = v1y - v0y; + real_t e0z = v1z - v0z; + real_t e1x = v2x - v1x; + real_t e1y = v2y - v1y; + real_t e1z = v2z - v1z; + real_t cx = std::fabs(e0y * e1z - e0z * e1y); + real_t cy = std::fabs(e0z * e1x - e0x * e1z); + real_t cz = std::fabs(e0x * e1y - e0y * e1x); + constexpr real_t epsilon = std::numeric_limits::epsilon(); + // std::cout << "cx " << cx << ", cy " << cy << ", cz " << cz << + // "\n"; + if (cx > epsilon || cy > epsilon || cz > epsilon) { + // std::cout << "corner\n"; + // found a corner + if (cx > cy && cx > cz) { + // std::cout << "pattern0\n"; + } else { + // std::cout << "axes[0] = 0\n"; + axes[0] = 0; + if (cz > cx && cz > cy) { + // std::cout << "axes[1] = 1\n"; + axes[1] = 1; + } + } + break; + } + } + +#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT + using Point = std::array; + + // first polyline define the main polygon. + // following polylines define holes(not used in tinyobj). + std::vector > polygon; + + std::vector polyline; + + // Fill polygon data(facevarying vertices). + for (size_t k = 0; k < npolys; k++) { + i0 = face.vertex_indices[k]; + size_t vi0 = size_t(i0.v_idx); + + assert(((3 * vi0 + 2) < v.size())); + + real_t v0x = v[vi0 * 3 + axes[0]]; + real_t v0y = v[vi0 * 3 + axes[1]]; + + polyline.push_back({v0x, v0y}); + } + + polygon.push_back(polyline); + std::vector indices = mapbox::earcut(polygon); + // => result = 3 * faces, clockwise + + assert(indices.size() % 3 == 0); + + // Reconstruct vertex_index_t + for (size_t k = 0; k < indices.size() / 3; k++) { + { + index_t idx0, idx1, idx2; + idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx; + idx0.normal_index = face.vertex_indices[indices[3 * k + 0]].vn_idx; + idx0.texcoord_index = face.vertex_indices[indices[3 * k + 0]].vt_idx; + idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx; + idx1.normal_index = face.vertex_indices[indices[3 * k + 1]].vn_idx; + idx1.texcoord_index = face.vertex_indices[indices[3 * k + 1]].vt_idx; + idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx; + idx2.normal_index = face.vertex_indices[indices[3 * k + 2]].vn_idx; + idx2.texcoord_index = face.vertex_indices[indices[3 * k + 2]].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + } + +#else // Built-in ear clipping triangulation + + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; + real_t vx[3]; + real_t vy[3]; + + // How many iterations can we do without decreasing the remaining + // vertices. + size_t remainingIterations = face.vertex_indices.size(); + size_t previousRemainingVertices = remainingFace.vertex_indices.size(); + + while (remainingFace.vertex_indices.size() > 3 && remainingIterations > 0) { + // std::cout << "remainingIterations " << remainingIterations << + // "\n"; + + npolys = remainingFace.vertex_indices.size(); + if (guess_vert >= npolys) { + guess_vert -= npolys; + } + + if (previousRemainingVertices != npolys) { + // The number of remaining vertices decreased. Reset counters. + previousRemainingVertices = npolys; + remainingIterations = npolys; + } else { + // We didn't consume a vertex on previous iteration, reduce the + // available iterations. + remainingIterations--; + } + + for (size_t k = 0; k < 3; k++) { + ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + if (((vi * 3 + axes[0]) >= v.size()) || ((vi * 3 + axes[1]) >= v.size())) { + // ??? + vx[k] = static_cast(0.0); + vy[k] = static_cast(0.0); + } else { + vx[k] = v[vi * 3 + axes[0]]; + vy[k] = v[vi * 3 + axes[1]]; + } + } + + // + // area is calculated per face + // + real_t e0x = vx[1] - vx[0]; + real_t e0y = vy[1] - vy[0]; + real_t e1x = vx[2] - vx[1]; + real_t e1y = vy[2] - vy[1]; + real_t cross = e0x * e1y - e0y * e1x; + // std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n"; + // std::cout << "e0x, e0y, e1x, e1y " << e0x << ", " << e0y << ", " + // << e1x << ", " << e1y << "\n"; + + real_t area = (vx[0] * vy[1] - vy[0] * vx[1]) * static_cast(0.5); + // std::cout << "cross " << cross << ", area " << area << "\n"; + // if an internal angle + if (cross * area < static_cast(0.0)) { + // std::cout << "internal \n"; + guess_vert += 1; + // std::cout << "guess vert : " << guess_vert << "\n"; + continue; + } + + // check all other verts in case they are inside this triangle + bool overlap = false; + for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { + size_t idx = (guess_vert + otherVert) % npolys; + + if (idx >= remainingFace.vertex_indices.size()) { + // std::cout << "???0\n"; + // ??? + continue; + } + + size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx); + + if (((ovi * 3 + axes[0]) >= v.size()) || ((ovi * 3 + axes[1]) >= v.size())) { + // std::cout << "???1\n"; + // ??? + continue; + } + real_t tx = v[ovi * 3 + axes[0]]; + real_t ty = v[ovi * 3 + axes[1]]; + if (pnpoly(3, vx, vy, tx, ty)) { + // std::cout << "overlap\n"; + overlap = true; + break; + } + } + + if (overlap) { + // std::cout << "overlap2\n"; + guess_vert += 1; + continue; + } + + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) { + remainingFace.vertex_indices[removed_vert_index] = remainingFace.vertex_indices[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.vertex_indices.pop_back(); + } + + // std::cout << "remainingFace.vi.size = " << + // remainingFace.vertex_indices.size() << "\n"; + if (remainingFace.vertex_indices.size() == 3) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + } +#endif + } // npolys + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back(static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); // per face + } + } + + shape->mesh.tags = tags; + } + + // line + if (!prim_group.lineGroup.empty()) { + // Flatten indices + for (size_t i = 0; i < prim_group.lineGroup.size(); i++) { + for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size(); j++) { + const vertex_index_t& vi = prim_group.lineGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->lines.indices.push_back(idx); + } + + shape->lines.num_line_vertices.push_back(int(prim_group.lineGroup[i].vertex_indices.size())); + } + } + + // points + if (!prim_group.pointsGroup.empty()) { + // Flatten & convert indices + for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) { + for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size(); j++) { + const vertex_index_t& vi = prim_group.pointsGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->points.indices.push_back(idx); + } + } + } + + return true; +} + +// Split a string with specified delimiter character and escape character. +// https://rosettacode.org/wiki/Tokenize_a_string_with_escaping#C.2B.2B +static void SplitString(const std::string& s, char delim, char escape, std::vector& elems) { + std::string token; + + bool escaping = false; + for (size_t i = 0; i < s.size(); ++i) { + char ch = s[i]; + if (escaping) { + escaping = false; + } else if (ch == escape) { + escaping = true; + continue; + } else if (ch == delim) { + if (!token.empty()) { + elems.push_back(token); + } + token.clear(); + continue; + } + token += ch; + } + + elems.push_back(token); +} + +static std::string JoinPath(const std::string& dir, const std::string& filename) { + if (dir.empty()) { + return filename; + } else { + // check '/' + char lastChar = *dir.rbegin(); + if (lastChar != '/') { + return dir + std::string("/") + filename; + } else { + return dir + filename; + } + } +} + +void LoadMtl(std::map* material_map, std::vector* materials, std::istream* inStream, std::string* warning, std::string* err) { + (void)err; + + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification. + bool has_d = false; + bool has_tr = false; + + // has_kd is used to set a default diffuse value when map_Kd is present + // and Kd is not. + bool has_kd = false; + + std::stringstream warn_ss; + + size_t line_no = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + line_no++; + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') + continue; // empty line + + if (token[0] == '#') + continue; // comment line + + // new mtl + if ((0 == _strnicmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair(material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + has_d = false; + has_tr = false; + + // set new mtl name + token += 7; + { + std::stringstream sstr; + sstr << token; + material.name = sstr.str(); + } + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + has_kd = true; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseReal(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseReal(&token); + continue; + } + + // illum model + if (0 == _strnicmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseReal(&token); + + if (has_tr) { + warn_ss << "Both `d` and `Tr` parameters defined for \"" << material.name << "\". Use the value of `d` for dissolve (line " << line_no << " in .mtl.)\n"; + } + has_d = true; + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + if (has_d) { + // `d` wins. Ignore `Tr` value. + warn_ss << "Both `d` and `Tr` parameters defined for \"" << material.name << "\". Use the value of `d` for dissolve (line " << line_no << " in .mtl.)\n"; + } else { + // We invert value of Tr(assume Tr is in range [0, 1]) + // NOTE: Interpretation of Tr is application(exporter) dependent. For + // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) + material.dissolve = static_cast(1.0) - parseReal(&token); + } + has_tr = true; + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseReal(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseReal(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseReal(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseReal(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == _strnicmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseReal(&token); + continue; + } + + // PBR: anisotropy + if ((0 == _strnicmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseReal(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == _strnicmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseReal(&token); + continue; + } + + // ambient texture + if ((0 == _strnicmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), &(material.ambient_texopt), token); + continue; + } + + // diffuse texture + if ((0 == _strnicmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), &(material.diffuse_texopt), token); + + // Set a decent diffuse default value if a diffuse texture is specified + // without a matching Kd value. + if (!has_kd) { + material.diffuse[0] = static_cast(0.6); + material.diffuse[1] = static_cast(0.6); + material.diffuse[2] = static_cast(0.6); + } + + continue; + } + + // specular texture + if ((0 == _strnicmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), &(material.specular_texopt), token); + continue; + } + + // specular highlight texture + if ((0 == _strnicmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), &(material.specular_highlight_texopt), token); + continue; + } + + // bump texture + if ((0 == _strnicmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), &(material.bump_texopt), token); + continue; + } + + // bump texture + if ((0 == _strnicmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), &(material.bump_texopt), token); + continue; + } + + // alpha texture + if ((0 == _strnicmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), &(material.alpha_texopt), token); + continue; + } + + // displacement texture + if ((0 == _strnicmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), &(material.displacement_texopt), token); + continue; + } + + // reflection map + if ((0 == _strnicmp(token, "refl", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.reflection_texname), &(material.reflection_texopt), token); + continue; + } + + // PBR: roughness texture + if ((0 == _strnicmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), &(material.roughness_texopt), token); + continue; + } + + // PBR: metallic texture + if ((0 == _strnicmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), &(material.metallic_texopt), token); + continue; + } + + // PBR: sheen texture + if ((0 == _strnicmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), &(material.sheen_texopt), token); + continue; + } + + // PBR: emissive texture + if ((0 == _strnicmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), &(material.emissive_texopt), token); + continue; + } + + // PBR: normal map texture + if ((0 == _strnicmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.normal_texname), &(material.normal_texopt), token); + continue; + } + + // unknown parameter + const char* _space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert(std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair(material.name, static_cast(materials->size()))); + materials->push_back(material); + + if (warning) { + (*warning) = warn_ss.str(); + } +} + +bool MaterialFileReader::operator()(const std::string& matId, std::vector* materials, std::map* matMap, std::string* warn, std::string* err) { + if (!m_mtlBaseDir.empty()) { +#ifdef _WIN32 + char sep = ';'; +#else + char sep = ':'; +#endif + + // https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g + std::vector paths; + std::istringstream f(m_mtlBaseDir); + + std::string s; + while (getline(f, s, sep)) { + paths.push_back(s); + } + + for (size_t i = 0; i < paths.size(); i++) { + std::string filepath = JoinPath(paths[i], matId); + + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + } + + std::stringstream ss; + ss << "Material file [ " << matId << " ] not found in a path : " << m_mtlBaseDir << "\n"; + if (warn) { + (*warn) += ss.str(); + } + return false; + + } else { + std::string filepath = matId; + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + + std::stringstream ss; + ss << "Material file [ " << filepath << " ] not found in a path : " << m_mtlBaseDir << "\n"; + if (warn) { + (*warn) += ss.str(); + } + + return false; + } +} + +bool MaterialStreamReader::operator()(const std::string& matId, std::vector* materials, std::map* matMap, std::string* warn, std::string* err) { + (void)err; + (void)matId; + if (!m_inStream) { + std::stringstream ss; + ss << "Material stream in error state. \n"; + if (warn) { + (*warn) += ss.str(); + } + return false; + } + + LoadMtl(matMap, materials, &m_inStream, warn, err); + + return true; +} + +bool LoadObj(attrib_t* attrib, std::vector* shapes, std::vector* materials, std::string* warn, std::string* err, const char* filename, const char* mtl_basedir, + const char* mtl_custom_file, bool triangulate, bool default_vcols_fallback) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + attrib->colors.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]\n"; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir = mtl_basedir ? mtl_basedir : ""; + if (!baseDir.empty()) { +#ifndef _WIN32 + const char dirsep = '/'; +#else + const char dirsep = '\\'; +#endif + if (baseDir[baseDir.length() - 1] != dirsep) + baseDir += dirsep; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader, mtl_custom_file, triangulate, default_vcols_fallback); +} + +bool LoadObjMaterials(std::vector* materials, std::string* warn, std::string* err, const char* filename, const char* mtl_basedir, const char* mtl_custom_file) { + std::stringstream errss; + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]\n"; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir = mtl_basedir ? mtl_basedir : ""; + if (!baseDir.empty()) { +#ifndef _WIN32 + const char dirsep = '/'; +#else + const char dirsep = '\\'; +#endif + if (baseDir[baseDir.length() - 1] != dirsep) + baseDir += dirsep; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObjMaterials(materials, warn, err, &ifs, &matFileReader, mtl_custom_file); +} + +bool LoadObj(attrib_t* attrib, std::vector* shapes, std::vector* materials, std::string* warn, std::string* err, std::istream* inStream, + MaterialReader* readMatFn, const std::string& customMaterials, bool triangulate, bool default_vcols_fallback) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector vc; + std::vector vw; + std::vector tags; + PrimGroup prim_group; + std::string name; + + // material + std::map material_map; + int material = -1; + + // smoothing group id + unsigned int current_smoothing_id = 0; // Initial value. 0 means no smoothing. + + int greatest_v_idx = -1; + int greatest_vn_idx = -1; + int greatest_vt_idx = -1; + + shape_t shape; + + bool found_all_colors = true; + + size_t line_num = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + line_num++; + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') + continue; // empty line + + if (token[0] == '#') + continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + real_t x, y, z; + real_t r, g, b; + + found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token); + + v.push_back(x); + v.push_back(y); + v.push_back(z); + + if (found_all_colors || default_vcols_fallback) { + vc.push_back(r); + vc.push_back(g); + vc.push_back(b); + } + + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y; + parseReal2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // skin weight. tinyobj extension + if (token[0] == 'v' && token[1] == 'w' && IS_SPACE((token[2]))) { + token += 3; + + // vw ... + // example: + // vw 0 0 0.25 1 0.25 2 0.5 + + // TODO(syoyo): Add syntax check + int vid = 0; + vid = parseInt(&token); + + skin_weight_t sw; + + sw.vertex_id = vid; + + while (!IS_NEW_LINE(token[0])) { + real_t j, w; + // joint_id should not be negative, weight may be negative + // TODO(syoyo): # of elements check + parseReal2(&j, &w, &token, -1.0); + + if (j < static_cast(0)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `vw' line. joint_id is negative. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + joint_and_weight_t jw; + + jw.joint_id = int(j); + jw.weight = w; + + sw.weightValues.push_back(jw); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + vw.push_back(sw); + } + + // line + if (token[0] == 'l' && IS_SPACE((token[1]))) { + token += 2; + + __line_t line; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), static_cast(vn.size() / 3), static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `l' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + line.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.lineGroup.push_back(line); + + continue; + } + + // points + if (token[0] == 'p' && IS_SPACE((token[1]))) { + token += 2; + + __points_t pts; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), static_cast(vn.size() / 3), static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `p' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + pts.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.pointsGroup.push_back(pts); + + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), static_cast(vn.size() / 3), static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `f' line(e.g. zero value for face index. line " << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; + greatest_vn_idx = greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; + greatest_vt_idx = greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; + + face.vertex_indices.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + prim_group.faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == _strnicmp(token, "usemtl", 6))) { + token += 6; + std::string namebuf = parseString(&token); + + int newMaterialId = -1; + std::map::const_iterator it = material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { error!! material not found } + if (warn) { + (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n"; + } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportGroupsToShape()` call. + exportGroupsToShape(&shape, prim_group, tags, material, name, triangulate, v, warn); + prim_group.faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == _strnicmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + if (customMaterials.empty()) { + SplitString(std::string(token), ' ', '\\', filenames); + } else { + filenames.emplace_back(customMaterials); + } + + if (filenames.empty()) { + if (warn) { + std::stringstream ss; + ss << "Looks like empty filename for mtllib. Use default " + "material (line " + << line_num << ".)\n"; + + (*warn) += ss.str(); + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), materials, &material_map, &warn_mtl, &err_mtl); + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, triangulate, v, warn); + (void)ret; // return value not used. + + if (shape.mesh.indices.size() > 0) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + prim_group.clear(); + + std::vector names; + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + // names[0] must be 'g' + + if (names.size() < 2) { + // 'g' with empty names + if (warn) { + std::stringstream ss; + ss << "Empty group name. line: " << line_num << "\n"; + (*warn) += ss.str(); + name = ""; + } + } else { + std::stringstream ss; + ss << names[1]; + + // tinyobjloader does not support multiple groups for a primitive. + // Currently we concatinate multiple group names with a space to get + // single group name. + + for (size_t i = 2; i < names.size(); i++) { + ss << " " << names[i]; + } + + name = ss.str(); + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, triangulate, v, warn); + (void)ret; // return value not used. + + if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 || shape.points.indices.size() > 0) { + shapes->push_back(shape); + } + + // material = -1; + prim_group.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + token += 2; + std::stringstream ss; + ss << token; + name = ss.str(); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize. + tag_t tag; + + token += 2; + + tag.name = parseString(&token); + + tag_sizes ts = parseTagTriple(&token); + + if (ts.num_ints < 0) { + ts.num_ints = 0; + } + if (ts.num_ints > max_tag_nums) { + ts.num_ints = max_tag_nums; + } + + if (ts.num_reals < 0) { + ts.num_reals = 0; + } + if (ts.num_reals > max_tag_nums) { + ts.num_reals = max_tag_nums; + } + + if (ts.num_strings < 0) { + ts.num_strings = 0; + } + if (ts.num_strings > max_tag_nums) { + ts.num_strings = max_tag_nums; + } + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = parseInt(&token); + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + tag.stringValues[i] = parseString(&token); + } + + tags.push_back(tag); + + continue; + } + + if (token[0] == 's' && IS_SPACE(token[1])) { + // smoothing group id + token += 2; + + // skip space. + token += strspn(token, " \t"); // skip space + + if (token[0] == '\0') { + continue; + } + + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3 && token[0] == 'o' && token[1] == 'f' && token[2] == 'f') { + current_smoothing_id = 0; + } else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // parse error. force set to 0. + // FIXME(syoyo): Report warning. + current_smoothing_id = 0; + } else { + current_smoothing_id = static_cast(smGroupId); + } + } + + continue; + } // smoothing group id + + // Ignore unknown command. + } + + // not all vertices have colors, no default colors desired? -> clear colors + if (!found_all_colors && !default_vcols_fallback) { + vc.clear(); + } + + if (greatest_v_idx >= static_cast(v.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex indices out of bounds (line " << line_num << ".)\n\n"; + (*warn) += ss.str(); + } + } + if (greatest_vn_idx >= static_cast(vn.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex normal indices out of bounds (line " << line_num << ".)\n\n"; + (*warn) += ss.str(); + } + } + if (greatest_vt_idx >= static_cast(vt.size() / 2)) { + if (warn) { + std::stringstream ss; + ss << "Vertex texcoord indices out of bounds (line " << line_num << ".)\n\n"; + (*warn) += ss.str(); + } + } + + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, triangulate, v, warn); + // exportGroupsToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices.size()) { // FIXME(syoyo): Support other prims(e.g. lines) + shapes->push_back(shape); + } + prim_group.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->vertex_weights.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + attrib->texcoord_ws.swap(vt); + attrib->colors.swap(vc); + attrib->skin_weights.swap(vw); + + return true; +} + +bool LoadObjMaterials(std::vector* materials, std::string* warn, std::string* err, std::istream* inStream, MaterialReader* readMatFn, + const std::string& customMaterials) { + std::stringstream errss; + + // material + std::map material_map; + int material = -1; + + size_t line_num = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + line_num++; + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') + continue; // empty line + + if (token[0] == '#') + continue; // comment line + + // load mtl + if ((0 == _strnicmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + if (customMaterials.empty()) { + SplitString(std::string(token), ' ', '\\', filenames); + } else { + filenames.emplace_back(customMaterials); + } + + if (filenames.empty()) { + if (warn) { + std::stringstream ss; + ss << "Looks like empty filename for mtllib. Use default material (line " << line_num << ".)\n"; + (*warn) += ss.str(); + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), materials, &material_map, &warn_mtl, &err_mtl); + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found && warn) { + (*warn) += "Failed to load material file(s). Use default material.\n"; + } + } + } + return true; + } + } + + return false; +} +bool LoadObjWithCallback(std::istream& inStream, const callback_t& callback, void* user_data /*= NULL*/, MaterialReader* readMatFn /*= NULL*/, std::string* warn, /* = NULL*/ + std::string* err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') + continue; // empty line + + if (token[0] == '#') + continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + // TODO(syoyo): Support parsing vertex color extension. + real_t x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; // y and z are optional. default = 0.0 + parseReal3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == _strnicmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + std::stringstream ss; + ss << token; + std::string namebuf = ss.str(); + + int newMaterialId = -1; + std::map::const_iterator it = material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { warn!! material not found } + if (warn && (!callback.usemtl_cb)) { + (*warn) += "material [ " + namebuf + " ] not found in .mtl\n"; + } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf.c_str(), material_id); + } + + continue; + } + + // load mtl + if ((0 == _strnicmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', '\\', filenames); + + if (filenames.empty()) { + if (warn) { + (*warn) += + "Looks like empty filename for mtllib. Use default " + "material. \n"; + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), &materials, &material_map, &warn_mtl, &err_mtl); + + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; // This should be warn message. + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } else { + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), static_cast(materials.size())); + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + token += 2; + + std::stringstream ss; + ss << token; + std::string object_name = ss.str(); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + token += 2; + std::stringstream ss; + ss << token; + tag.name = ss.str(); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + std::stringstream ss; + ss << token; + tag.stringValues[i] = ss.str(); + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} + +bool ObjReader::ParseFromFile(const std::string& filename, const std::string& customMataterials, const ObjReaderConfig& config) { + std::string mtl_search_path; + + if (config.mtl_search_path.empty()) { + // + // split at last '/'(for unixish system) or '\\'(for windows) to get + // the base directory of .obj file + // + size_t pos = filename.find_last_of("/\\"); + if (pos != std::string::npos) { + mtl_search_path = filename.substr(0, pos); + } + } else { + mtl_search_path = config.mtl_search_path; + } + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, filename.c_str(), mtl_search_path.c_str(), // + customMataterials.empty() ? nullptr : customMataterials.c_str(), config.triangulate, config.vertex_color); + + return valid_; +} + +bool ObjReader::ParseFromString(const std::string& obj_text, const std::string& mtl_text, const ObjReaderConfig& config) { + std::stringbuf obj_buf(obj_text); + std::stringbuf mtl_buf(mtl_text); + + std::istream obj_ifs(&obj_buf); + std::istream mtl_ifs(&mtl_buf); + + MaterialStreamReader mtl_ss(mtl_ifs); + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, &obj_ifs, &mtl_ss, {}, config.triangulate, config.vertex_color); + + return valid_; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace tinyobj + +#endif